Files
Adminive/backend/library/include/adminive/synchronized.hpp
T
2026-08-07 09:25:55 +08:00

455 lines
19 KiB
C++

#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>;
}