拆分核心库和服务
This commit is contained in:
@@ -0,0 +1,454 @@
|
||||
#pragma once
|
||||
#include "adminive/descriptor.hpp"
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <ranges>
|
||||
#include <shared_mutex>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
namespace adminive {
|
||||
struct Empty_Lock {
|
||||
void lock() noexcept {}
|
||||
bool try_lock() noexcept {
|
||||
return true;
|
||||
}
|
||||
void unlock() noexcept {}
|
||||
void lock_shared() noexcept {}
|
||||
bool try_lock_shared() noexcept {
|
||||
return true;
|
||||
}
|
||||
void unlock_shared() noexcept {}
|
||||
};
|
||||
template <class T>
|
||||
concept Basic_Lock = std::default_initializable<T> && requires(T& value) {
|
||||
value.lock();
|
||||
value.unlock();
|
||||
};
|
||||
template <class T>
|
||||
concept Shared_Basic_Lock = Basic_Lock<T> && requires(T& value) {
|
||||
value.lock_shared();
|
||||
value.unlock_shared();
|
||||
};
|
||||
template <class T>
|
||||
struct Is_Reference_Wrapper : std::false_type {};
|
||||
template <class T>
|
||||
struct Is_Reference_Wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||
template <class Result>
|
||||
concept Synchronized_Result = std::is_void_v<Result> || (!std::is_reference_v<Result> && !std::is_pointer_v<Result> && !Is_Reference_Wrapper<std::remove_cvref_t<Result>>::value && !std::ranges::view<std::remove_cvref_t<Result>>);
|
||||
template <Basic_Lock Lock>
|
||||
using Read_Lock_Guard = std::conditional_t<Shared_Basic_Lock<Lock>, std::shared_lock<Lock>, std::unique_lock<Lock>>;
|
||||
template <class T>
|
||||
using Descriptor_Type = decltype(Type_Descriptor<std::remove_cvref_t<T>>::get());
|
||||
template <class T>
|
||||
using Descriptor_Fields = std::remove_cvref_t<decltype(std::declval<Descriptor_Type<T>>().fields())>;
|
||||
namespace detail {
|
||||
template <std::size_t Index>
|
||||
struct Reflected_Field_Path_Key {
|
||||
static constexpr std::size_t index = Index;
|
||||
};
|
||||
template <class T>
|
||||
struct Is_Reflected_Field_Path_Key : std::false_type {};
|
||||
template <std::size_t Index>
|
||||
struct Is_Reflected_Field_Path_Key<Reflected_Field_Path_Key<Index>> : std::true_type {};
|
||||
template <class T>
|
||||
inline constexpr bool is_reflected_field_path_key_v = Is_Reflected_Field_Path_Key<std::remove_cvref_t<T>>::value;
|
||||
}
|
||||
template <class T, auto Key, std::size_t Index = 0>
|
||||
consteval std::size_t described_field_index() {
|
||||
using Object = std::remove_cvref_t<T>;
|
||||
using Fields = Descriptor_Fields<Object>;
|
||||
if constexpr(Index == std::tuple_size_v<Fields>) {
|
||||
return Index;
|
||||
} else {
|
||||
using Field = std::tuple_element_t<Index, Fields>;
|
||||
if constexpr(std::is_member_object_pointer_v<decltype(Key)>) {
|
||||
if constexpr(requires { Field::member; } && std::same_as<std::remove_cv_t<decltype(Field::member)>, decltype(Key)>) {
|
||||
if constexpr(Field::member == Key) {
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
} else if constexpr(detail::is_reflected_field_path_key_v<decltype(Key)>) {
|
||||
if constexpr(requires { Field::index; } && std::same_as<typename Field::owner_type, Object>) {
|
||||
if constexpr(Field::index == std::remove_cvref_t<decltype(Key)>::index) {
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return described_field_index<Object, Key, Index + 1>();
|
||||
}
|
||||
}
|
||||
template <class T, auto Member, std::size_t Index = 0>
|
||||
consteval std::size_t described_member_index() {
|
||||
return described_field_index<T, Member, Index>();
|
||||
}
|
||||
template <class T>
|
||||
inline constexpr std::size_t described_field_count_v = std::tuple_size_v<Descriptor_Fields<std::remove_cvref_t<T>>>;
|
||||
template <class T, auto Key>
|
||||
concept Described_Field_Key = Described_Type<std::remove_cvref_t<T>> && (described_field_index<T, Key>() < described_field_count_v<T>);
|
||||
template <class T, auto Member>
|
||||
concept Described_Member = std::is_member_object_pointer_v<decltype(Member)> && Described_Field_Key<T, Member>;
|
||||
template <class T, std::size_t Index>
|
||||
concept Described_Reflected_Field = Described_Field_Key<T, detail::Reflected_Field_Path_Key<Index>{}>;
|
||||
template <class T>
|
||||
bool described_type_requires_lock();
|
||||
template <class Field>
|
||||
bool descriptor_field_requires_lock(const Field& field) {
|
||||
if(field.lock_mode() == Field_Lock_Mode::enabled) {
|
||||
return true;
|
||||
}
|
||||
using Member = typename std::remove_cvref_t<Field>::member_type;
|
||||
if(field.lock_mode() == Field_Lock_Mode::disabled) {
|
||||
if constexpr(Described_Type<Member>) {
|
||||
return described_type_requires_lock<Member>();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(field.is_editable()) {
|
||||
return true;
|
||||
}
|
||||
if constexpr(Described_Type<Member>) {
|
||||
return described_type_requires_lock<Member>();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
bool described_type_requires_lock() {
|
||||
if constexpr(!Described_Type<std::remove_cvref_t<T>>) {
|
||||
return false;
|
||||
} else {
|
||||
static const bool result = [] {
|
||||
const auto descriptor = describe<std::remove_cvref_t<T>>();
|
||||
bool required{};
|
||||
std::apply([&](const auto&... field) {
|
||||
required = (descriptor_field_requires_lock(field) || ...);
|
||||
}, descriptor.fields());
|
||||
return required;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
template <class T, auto Key>
|
||||
requires Described_Field_Key<T, Key>
|
||||
bool described_field_requires_lock() {
|
||||
static const bool result = [] {
|
||||
const auto descriptor = describe<std::remove_cvref_t<T>>();
|
||||
constexpr std::size_t index = described_field_index<T, Key>();
|
||||
return descriptor_field_requires_lock(std::get<index>(descriptor.fields()));
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
template <class T, auto Member>
|
||||
requires Described_Member<T, Member>
|
||||
bool described_member_requires_lock() {
|
||||
return described_field_requires_lock<T, Member>();
|
||||
}
|
||||
template <auto Key, class Object>
|
||||
decltype(auto) synchronized_field_value(Object& object) noexcept {
|
||||
if constexpr(std::is_member_object_pointer_v<decltype(Key)>) {
|
||||
return object.*Key;
|
||||
} else {
|
||||
static_assert(detail::is_reflected_field_path_key_v<decltype(Key)>);
|
||||
using Owner = std::remove_cvref_t<Object>;
|
||||
return Reflection_Adapter<Owner>::template get<std::remove_cvref_t<decltype(Key)>::index>(object);
|
||||
}
|
||||
}
|
||||
template <class T, auto Key, auto... Rest>
|
||||
bool described_path_requires_lock() {
|
||||
if constexpr(sizeof...(Rest) == 0) {
|
||||
return described_field_requires_lock<T, Key>();
|
||||
} else {
|
||||
using Next = std::remove_cvref_t<decltype(synchronized_field_value<Key>(std::declval<T&>()))>;
|
||||
return described_path_requires_lock<Next, Rest...>();
|
||||
}
|
||||
}
|
||||
template <class Field, Basic_Lock Lock>
|
||||
struct Field_Lock_Node;
|
||||
template <class T, Basic_Lock Lock, bool Enabled = Described_Type<std::remove_cvref_t<T>>>
|
||||
class Field_Lock_Tree {};
|
||||
template <class T, Basic_Lock Lock>
|
||||
class Field_Lock_Tree<T, Lock, true> {
|
||||
private:
|
||||
using Fields = Descriptor_Fields<std::remove_cvref_t<T>>;
|
||||
template <std::size_t... Indexes>
|
||||
static auto make_nodes(std::index_sequence<Indexes...>) -> std::tuple<Field_Lock_Node<std::tuple_element_t<Indexes, Fields>, Lock>...>;
|
||||
public:
|
||||
using Nodes = decltype(make_nodes(std::make_index_sequence<std::tuple_size_v<Fields>>{}));
|
||||
template <std::size_t Index>
|
||||
auto& node() noexcept {
|
||||
return std::get<Index>(nodes_);
|
||||
}
|
||||
template <std::size_t Index>
|
||||
const auto& node() const noexcept {
|
||||
return std::get<Index>(nodes_);
|
||||
}
|
||||
private:
|
||||
Nodes nodes_{};
|
||||
};
|
||||
template <class Field, Basic_Lock Lock>
|
||||
struct Field_Lock_Node {
|
||||
using value_type = typename std::remove_cvref_t<Field>::member_type;
|
||||
mutable Lock lock{};
|
||||
Field_Lock_Tree<value_type, Lock> children{};
|
||||
};
|
||||
namespace detail {
|
||||
struct Synchronized_Access;
|
||||
}
|
||||
template <class Root, Basic_Lock Object_Lock, Basic_Lock Field_Lock, auto... Members>
|
||||
class Synchronized_Field;
|
||||
template <class T, Basic_Lock Lock = std::shared_mutex, Basic_Lock Field_Lock = Lock>
|
||||
class Synchronized_Value {
|
||||
public:
|
||||
using value_type = T;
|
||||
using lock_type = Lock;
|
||||
using field_lock_type = Field_Lock;
|
||||
Synchronized_Value() requires std::default_initializable<T> = default;
|
||||
explicit Synchronized_Value(T value) : value_(std::move(value)) {}
|
||||
Synchronized_Value(const Synchronized_Value&) = delete;
|
||||
Synchronized_Value& operator=(const Synchronized_Value&) = delete;
|
||||
template <class Function>
|
||||
requires Synchronized_Result<std::invoke_result_t<Function, const T&>>
|
||||
decltype(auto) read(Function&& function) const {
|
||||
std::unique_lock guard(lock_);
|
||||
return std::invoke(std::forward<Function>(function), std::as_const(value_));
|
||||
}
|
||||
template <class Function>
|
||||
requires Synchronized_Result<std::invoke_result_t<Function, T&>>
|
||||
decltype(auto) write(Function&& function) {
|
||||
std::unique_lock guard(lock_);
|
||||
return std::invoke(std::forward<Function>(function), value_);
|
||||
}
|
||||
T snapshot() const requires std::copy_constructible<T> {
|
||||
return read([](const T& value) {
|
||||
return value;
|
||||
});
|
||||
}
|
||||
void replace(T value) requires std::assignable_from<T&, T> {
|
||||
write([&](T& target) {
|
||||
target = std::move(value);
|
||||
});
|
||||
}
|
||||
template <auto Member>
|
||||
requires Described_Member<T, Member>
|
||||
auto member() noexcept {
|
||||
return Synchronized_Field<T, Lock, Field_Lock, Member>(*this);
|
||||
}
|
||||
template <auto Member>
|
||||
requires Described_Member<T, Member>
|
||||
auto member() const noexcept {
|
||||
return Synchronized_Field<const T, Lock, Field_Lock, Member>(*this);
|
||||
}
|
||||
template <std::size_t Index>
|
||||
requires Described_Reflected_Field<T, Index>
|
||||
auto field() noexcept {
|
||||
return Synchronized_Field<T, Lock, Field_Lock, detail::Reflected_Field_Path_Key<Index>{}>(*this);
|
||||
}
|
||||
template <std::size_t Index>
|
||||
requires Described_Reflected_Field<T, Index>
|
||||
auto field() const noexcept {
|
||||
return Synchronized_Field<const T, Lock, Field_Lock, detail::Reflected_Field_Path_Key<Index>{}>(*this);
|
||||
}
|
||||
private:
|
||||
friend struct detail::Synchronized_Access;
|
||||
T& unsafe_value() noexcept {
|
||||
return value_;
|
||||
}
|
||||
const T& unsafe_value() const noexcept {
|
||||
return value_;
|
||||
}
|
||||
Lock& mutex() const noexcept {
|
||||
return lock_;
|
||||
}
|
||||
template <class Root, Basic_Lock Object_Lock, Basic_Lock Member_Lock, auto... Members>
|
||||
friend class Synchronized_Field;
|
||||
T value_{};
|
||||
mutable Lock lock_{};
|
||||
mutable Field_Lock_Tree<T, Field_Lock> field_locks_{};
|
||||
};
|
||||
template <auto Key, class Object>
|
||||
decltype(auto) synchronized_path_value(Object& object) noexcept {
|
||||
return synchronized_field_value<Key>(object);
|
||||
}
|
||||
template <auto Key, auto Next, auto... Rest, class Object>
|
||||
decltype(auto) synchronized_path_value(Object& object) noexcept {
|
||||
return synchronized_path_value<Next, Rest...>(synchronized_field_value<Key>(object));
|
||||
}
|
||||
template <class Current, std::size_t Depth, auto Key, auto... Rest>
|
||||
struct Synchronized_Path_Owner {
|
||||
using Next = std::remove_cvref_t<decltype(synchronized_field_value<Key>(std::declval<Current&>()))>;
|
||||
using type = typename Synchronized_Path_Owner<Next, Depth - 1, Rest...>::type;
|
||||
};
|
||||
template <class Current, auto Key, auto... Rest>
|
||||
struct Synchronized_Path_Owner<Current, 0, Key, Rest...> {
|
||||
using type = Current;
|
||||
};
|
||||
template <class Root, Basic_Lock Object_Lock, Basic_Lock Field_Lock, auto... Members>
|
||||
class Synchronized_Field {
|
||||
static_assert(sizeof...(Members) > 0);
|
||||
public:
|
||||
using root_type = std::remove_const_t<Root>;
|
||||
using value_type = std::remove_cvref_t<decltype(synchronized_path_value<Members...>(std::declval<Root&>()))>;
|
||||
using lock_type = Object_Lock;
|
||||
using field_lock_type = Field_Lock;
|
||||
using owner_type = std::conditional_t<std::is_const_v<Root>, const Synchronized_Value<root_type, Object_Lock, Field_Lock>, Synchronized_Value<root_type, Object_Lock, Field_Lock>>;
|
||||
explicit Synchronized_Field(Synchronized_Value<root_type, Object_Lock, Field_Lock>& owner) requires (!std::is_const_v<Root>) : owner_(&owner) {}
|
||||
explicit Synchronized_Field(const Synchronized_Value<root_type, Object_Lock, Field_Lock>& owner) requires std::is_const_v<Root> : owner_(&owner) {}
|
||||
template <class Function>
|
||||
requires Synchronized_Result<std::invoke_result_t<Function, const value_type&>>
|
||||
decltype(auto) read(Function&& function) const {
|
||||
return with_read_lock([&] {
|
||||
return std::invoke(std::forward<Function>(function), std::as_const(unsafe_value()));
|
||||
});
|
||||
}
|
||||
template <class Function>
|
||||
requires (!std::is_const_v<Root>) && Synchronized_Result<std::invoke_result_t<Function, value_type&>>
|
||||
decltype(auto) write(Function&& function) {
|
||||
return with_write_lock([&] {
|
||||
return std::invoke(std::forward<Function>(function), unsafe_value());
|
||||
});
|
||||
}
|
||||
template <class Function>
|
||||
requires Synchronized_Result<std::invoke_result_t<Function, const value_type&>>
|
||||
decltype(auto) object_read(Function&& function) const {
|
||||
return read(std::forward<Function>(function));
|
||||
}
|
||||
template <class Function>
|
||||
requires (!std::is_const_v<Root>) && Synchronized_Result<std::invoke_result_t<Function, value_type&>>
|
||||
decltype(auto) object_write(Function&& function) {
|
||||
return write(std::forward<Function>(function));
|
||||
}
|
||||
value_type snapshot() const requires std::copy_constructible<value_type> {
|
||||
return object_read([](const value_type& value) {
|
||||
return value;
|
||||
});
|
||||
}
|
||||
void replace(value_type value) requires (!std::is_const_v<Root>) && std::assignable_from<value_type&, value_type> {
|
||||
object_write([&](value_type& target) {
|
||||
target = std::move(value);
|
||||
});
|
||||
}
|
||||
template <auto Member>
|
||||
requires Described_Member<value_type, Member>
|
||||
auto member() noexcept requires (!std::is_const_v<Root>) {
|
||||
return Synchronized_Field<root_type, Object_Lock, Field_Lock, Members..., Member>(*owner_);
|
||||
}
|
||||
template <auto Member>
|
||||
requires Described_Member<value_type, Member>
|
||||
auto member() const noexcept {
|
||||
return Synchronized_Field<const root_type, Object_Lock, Field_Lock, Members..., Member>(*owner_);
|
||||
}
|
||||
template <std::size_t Index>
|
||||
requires Described_Reflected_Field<value_type, Index>
|
||||
auto field() noexcept requires (!std::is_const_v<Root>) {
|
||||
return Synchronized_Field<root_type, Object_Lock, Field_Lock, Members..., detail::Reflected_Field_Path_Key<Index>{}>(*owner_);
|
||||
}
|
||||
template <std::size_t Index>
|
||||
requires Described_Reflected_Field<value_type, Index>
|
||||
auto field() const noexcept {
|
||||
return Synchronized_Field<const root_type, Object_Lock, Field_Lock, Members..., detail::Reflected_Field_Path_Key<Index>{}>(*owner_);
|
||||
}
|
||||
private:
|
||||
friend struct detail::Synchronized_Access;
|
||||
decltype(auto) unsafe_value() const noexcept {
|
||||
if constexpr(std::is_const_v<Root>) {
|
||||
return std::as_const(synchronized_path_value<Members...>(owner_->unsafe_value()));
|
||||
} else {
|
||||
return synchronized_path_value<Members...>(owner_->unsafe_value());
|
||||
}
|
||||
}
|
||||
Object_Lock& mutex() const noexcept {
|
||||
return owner_->mutex();
|
||||
}
|
||||
template <class Function>
|
||||
decltype(auto) with_read_lock(Function&& function) const {
|
||||
Read_Lock_Guard<Object_Lock> root_guard(owner_->mutex());
|
||||
if(!described_path_requires_lock<root_type, Members...>()) {
|
||||
return std::forward<Function>(function)();
|
||||
}
|
||||
return with_path_read_lock<0, Members...>(owner_->field_locks_, std::forward<Function>(function));
|
||||
}
|
||||
template <class Function>
|
||||
decltype(auto) with_write_lock(Function&& function) const {
|
||||
if(!described_path_requires_lock<root_type, Members...>()) {
|
||||
std::unique_lock root_guard(owner_->mutex());
|
||||
return std::forward<Function>(function)();
|
||||
}
|
||||
Read_Lock_Guard<Object_Lock> root_guard(owner_->mutex());
|
||||
return with_path_write_lock<0, Members...>(owner_->field_locks_, std::forward<Function>(function));
|
||||
}
|
||||
template <std::size_t Depth, auto Member, auto... Rest, class Tree, class Function>
|
||||
static decltype(auto) with_path_read_lock(Tree& tree, Function&& function) {
|
||||
using Object = typename Synchronized_Path_Owner<root_type, Depth, Members...>::type;
|
||||
constexpr std::size_t index = described_field_index<Object, Member>();
|
||||
auto& node = tree.template node<index>();
|
||||
const bool lock_required = described_field_requires_lock<Object, Member>();
|
||||
if constexpr(sizeof...(Rest) == 0) {
|
||||
if(!lock_required) {
|
||||
return std::forward<Function>(function)();
|
||||
}
|
||||
if constexpr(Described_Type<typename std::remove_cvref_t<decltype(node)>::value_type>) {
|
||||
if(described_type_requires_lock<typename std::remove_cvref_t<decltype(node)>::value_type>()) {
|
||||
std::unique_lock guard(node.lock);
|
||||
return std::forward<Function>(function)();
|
||||
}
|
||||
}
|
||||
Read_Lock_Guard<Field_Lock> guard(node.lock);
|
||||
return std::forward<Function>(function)();
|
||||
} else {
|
||||
if(lock_required) {
|
||||
Read_Lock_Guard<Field_Lock> guard(node.lock);
|
||||
return with_path_read_lock<Depth + 1, Rest...>(node.children, std::forward<Function>(function));
|
||||
}
|
||||
return with_path_read_lock<Depth + 1, Rest...>(node.children, std::forward<Function>(function));
|
||||
}
|
||||
}
|
||||
template <std::size_t Depth, auto Member, auto... Rest, class Tree, class Function>
|
||||
static decltype(auto) with_path_write_lock(Tree& tree, Function&& function) {
|
||||
using Object = typename Synchronized_Path_Owner<root_type, Depth, Members...>::type;
|
||||
constexpr std::size_t index = described_field_index<Object, Member>();
|
||||
auto& node = tree.template node<index>();
|
||||
const bool lock_required = described_field_requires_lock<Object, Member>();
|
||||
if constexpr(sizeof...(Rest) == 0) {
|
||||
if(lock_required) {
|
||||
std::unique_lock guard(node.lock);
|
||||
return std::forward<Function>(function)();
|
||||
}
|
||||
return std::forward<Function>(function)();
|
||||
} else {
|
||||
if(lock_required) {
|
||||
Read_Lock_Guard<Field_Lock> guard(node.lock);
|
||||
return with_path_write_lock<Depth + 1, Rest...>(node.children, std::forward<Function>(function));
|
||||
}
|
||||
return with_path_write_lock<Depth + 1, Rest...>(node.children, std::forward<Function>(function));
|
||||
}
|
||||
}
|
||||
owner_type* owner_;
|
||||
};
|
||||
namespace detail {
|
||||
struct Synchronized_Access {
|
||||
template <class T, Basic_Lock Lock, Basic_Lock Field_Lock>
|
||||
static T& value(Synchronized_Value<T, Lock, Field_Lock>& synchronized) noexcept {
|
||||
return synchronized.unsafe_value();
|
||||
}
|
||||
template <class T, Basic_Lock Lock, Basic_Lock Field_Lock>
|
||||
static const T& value(const Synchronized_Value<T, Lock, Field_Lock>& synchronized) noexcept {
|
||||
return synchronized.unsafe_value();
|
||||
}
|
||||
template <class T, Basic_Lock Lock, Basic_Lock Field_Lock>
|
||||
static Lock& mutex(const Synchronized_Value<T, Lock, Field_Lock>& synchronized) noexcept {
|
||||
return synchronized.mutex();
|
||||
}
|
||||
template <class Root, Basic_Lock Lock, Basic_Lock Field_Lock, auto... Members>
|
||||
static decltype(auto) value(const Synchronized_Field<Root, Lock, Field_Lock, Members...>& synchronized) noexcept {
|
||||
return synchronized.unsafe_value();
|
||||
}
|
||||
template <class Root, Basic_Lock Lock, Basic_Lock Field_Lock, auto... Members>
|
||||
static Lock& mutex(const Synchronized_Field<Root, Lock, Field_Lock, Members...>& synchronized) noexcept {
|
||||
return synchronized.mutex();
|
||||
}
|
||||
};
|
||||
}
|
||||
template <class Root, auto Member, Basic_Lock Lock, Basic_Lock Field_Lock = Lock>
|
||||
using Synchronized_Member = Synchronized_Field<Root, Lock, Field_Lock, Member>;
|
||||
}
|
||||
Reference in New Issue
Block a user