Files
Adminive/backend/library/include/adminive/managed.hpp
T
2026-08-28 11:49:05 +08:00

416 lines
18 KiB
C++

#pragma once
#include "adminive/descriptor.hpp"
#include <structive/property/property.hpp>
#include <array>
#include <concepts>
#include <cstddef>
#include <functional>
#include <optional>
#include <ranges>
#include <span>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
namespace adminive {
template <class Mutex>
struct Mutex_Policy {
using mutex_type = Mutex;
};
template <class T, structive::Synchronization_Policy Policy = structive::Shared_Mutex_Policy>
class Managed_Value;
template <class Managed, std::size_t Root_Index, auto... Members>
class Managed_Field;
namespace detail {
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 Managed_Callback_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 <std::size_t Value>
consteval std::size_t decimal_digits() {
std::size_t result = 1;
std::size_t current = Value;
while(current >= 10) {
current /= 10;
++result;
}
return result;
}
template <std::size_t Index>
consteval auto make_managed_key_text() {
constexpr std::string_view prefix = "__adminive_";
constexpr std::size_t digits = decimal_digits<Index>();
std::array<char, prefix.size() + digits> result{};
for(std::size_t position = 0; position < prefix.size(); ++position) {
result[position] = prefix[position];
}
std::size_t value = Index;
for(std::size_t position = 0; position < digits; ++position) {
result[prefix.size() + digits - position - 1] = static_cast<char>('0' + value % 10);
value /= 10;
}
return result;
}
template <std::size_t Index>
struct Managed_Key_Value {
static constexpr auto text = make_managed_key_text<Index>();
constexpr std::string_view view() const noexcept {
return {text.data(), text.size()};
}
};
template <std::size_t Index>
struct Managed_Key_Attribute {
using attribute_category = structive::Key_Category;
static constexpr bool single_valued = true;
static constexpr bool inheritable = false;
static constexpr Managed_Key_Value<Index> value{};
};
template <class T>
consteval bool member_type_has_managed_writes() {
using Value = std::remove_cvref_t<T>;
if constexpr(Described_Type<Value>) {
return described_type_has_managed_writes<Value>();
}
return false;
}
template <class Field>
inline constexpr bool managed_field_writable_v = Field::managed_writable || member_type_has_managed_writes<typename Field::member_type>();
template <class Field>
consteval bool field_requires_synchronization();
template <class T>
consteval bool member_type_requires_synchronization() {
using Value = std::remove_cvref_t<T>;
if constexpr(Described_Type<Value>) {
using Fields = Descriptor_Fields<Value>;
return []<std::size_t... Indexes>(std::index_sequence<Indexes...>) {
return (field_requires_synchronization<std::tuple_element_t<Indexes, Fields>>() || ...);
}(std::make_index_sequence<std::tuple_size_v<Fields>>{});
}
return false;
}
template <class Field>
consteval bool field_requires_synchronization() {
if constexpr(Field::managed_writable) {
return Field::synchronized;
}
return member_type_requires_synchronization<typename Field::member_type>();
}
template <class T, std::size_t Index>
const auto& managed_descriptor_field() {
static const auto descriptor = describe<T>();
return std::get<Index>(descriptor.fields());
}
template <class Managed, class Field, std::size_t Index>
struct Managed_Field_Accessor {
using object_type = Managed;
using value_type = typename Field::member_type;
struct storage_identity {};
using dependency_spec = structive::No_Property_Dependencies;
static constexpr bool readable = true;
static constexpr bool writable = managed_field_writable_v<Field>;
static constexpr bool synchronized_view_read = false;
static constexpr bool trusted_object_access = false;
decltype(auto) read(const object_type& object) const
noexcept(noexcept(managed_descriptor_field<typename Managed::value_type, Index>().get(
object.unsafe_value()))) {
return managed_descriptor_field<typename Managed::value_type, Index>().get(
object.unsafe_value());
}
decltype(auto) read(object_type& object) const
noexcept(noexcept(managed_descriptor_field<typename Managed::value_type, Index>().get(
object.unsafe_value()))) {
return managed_descriptor_field<typename Managed::value_type, Index>().get(
object.unsafe_value());
}
template <class Value>
void write(object_type& object, Value&& value) const
requires writable && requires {
managed_descriptor_field<typename Managed::value_type, Index>().set(
object.unsafe_value(), std::forward<Value>(value));
} {
managed_descriptor_field<typename Managed::value_type, Index>().set(
object.unsafe_value(), std::forward<Value>(value));
}
};
template <class Managed, class Field, std::size_t Index>
auto make_structive_property() {
using Accessor = Managed_Field_Accessor<Managed, Field, Index>;
using Key = Managed_Key_Attribute<Index>;
if constexpr(managed_field_writable_v<Field>) {
using Capability = structive::Property_Capability_Attribute<structive::Property_Capability::read_write>;
return structive::Property_Descriptor<Accessor, Key, Capability>{{}, {Key{}, Capability{}}};
} else {
using Capability = structive::Property_Capability_Attribute<structive::Property_Capability::read>;
return structive::Property_Descriptor<Accessor, Key, Capability>{{}, {Key{}, Capability{}}};
}
}
template <class Managed, class T, std::size_t... Indexes>
auto make_managed_schema_impl(std::index_sequence<Indexes...>) {
using Fields = Descriptor_Fields<T>;
structive::Synchronization_Plan plan;
([&] {
using Field = std::tuple_element_t<Indexes, Fields>;
if constexpr(managed_field_writable_v<Field> && !field_requires_synchronization<Field>()) {
plan.unsynchronized(Managed_Key_Attribute<Indexes>::value.view());
}
}(), ...);
return structive::object<Managed>(std::move(plan), make_structive_property<Managed, std::tuple_element_t<Indexes, Fields>, Indexes>()...);
}
template <class Managed, Described_Type T>
auto make_managed_schema() {
return make_managed_schema_impl<Managed, T>(std::make_index_sequence<std::tuple_size_v<Descriptor_Fields<T>>>{});
}
template <Described_Type T, auto Member, std::size_t Index = 0>
consteval std::size_t described_member_index() {
using Fields = Descriptor_Fields<T>;
if constexpr(Index == std::tuple_size_v<Fields>) {
return Index;
} else {
using Field = std::tuple_element_t<Index, Fields>;
using Accessor = typename Field::accessor_type;
if constexpr(requires { Accessor::member; } && std::same_as<std::remove_cv_t<decltype(Accessor::member)>, decltype(Member)>) {
if constexpr(Accessor::member == Member) {
return Index;
}
}
return described_member_index<T, Member, Index + 1>();
}
}
template <class Current, auto Member, auto... Rest>
consteval bool managed_member_path_writable() {
static_assert(Described_Type<std::remove_cvref_t<Current>>);
constexpr auto index = described_member_index<std::remove_cvref_t<Current>, Member>();
using Field = Descriptor_Field<std::remove_cvref_t<Current>, index>;
if constexpr(sizeof...(Rest) == 0) {
return Field::managed_writable;
} else {
return managed_member_path_writable<typename Field::member_type, Rest...>();
}
}
template <class Current, auto Member, auto... Rest>
consteval bool managed_member_path_requires_synchronization() {
static_assert(Described_Type<std::remove_cvref_t<Current>>);
constexpr auto index = described_member_index<std::remove_cvref_t<Current>, Member>();
using Field = Descriptor_Field<std::remove_cvref_t<Current>, index>;
if constexpr(Field::managed_writable) {
return Field::synchronized;
} else if constexpr(sizeof...(Rest) == 0) {
return false;
} else {
return managed_member_path_requires_synchronization<typename Field::member_type, Rest...>();
}
}
template <class Root, std::size_t Root_Index, auto... Members>
consteval bool managed_path_writable() {
using Field = Descriptor_Field<Root, Root_Index>;
if constexpr(sizeof...(Members) == 0) {
return Field::managed_writable;
} else {
return managed_member_path_writable<typename Field::member_type, Members...>();
}
}
template <class Root, std::size_t Root_Index, auto... Members>
consteval bool managed_path_requires_synchronization() {
using Field = Descriptor_Field<Root, Root_Index>;
if constexpr(Field::managed_writable) {
return Field::synchronized;
} else if constexpr(sizeof...(Members) == 0) {
return false;
} else {
return managed_member_path_requires_synchronization<typename Field::member_type, Members...>();
}
}
template <class Object, auto Member, auto... Rest>
decltype(auto) path_value(Object& object) {
auto&& next = object.*Member;
if constexpr(sizeof...(Rest) == 0) {
return std::forward<decltype(next)>(next);
} else {
return path_value<decltype(next), Rest...>(next);
}
}
template <class Object, auto Member, auto... Rest>
decltype(auto) path_value(const Object& object) {
auto&& next = object.*Member;
if constexpr(sizeof...(Rest) == 0) {
return std::forward<decltype(next)>(next);
} else {
return path_value<decltype(next), Rest...>(next);
}
}
template <class T, std::size_t Root_Index, auto... Members>
decltype(auto) managed_path_value(T& object) {
using Field = Descriptor_Field<T, Root_Index>;
auto&& root = managed_descriptor_field<T, Root_Index>().get(object);
if constexpr(sizeof...(Members) == 0) {
return std::forward<decltype(root)>(root);
} else {
return path_value<decltype(root), Members...>(root);
}
}
template <class T, std::size_t Root_Index, auto... Members>
decltype(auto) managed_path_value(const T& object) {
using Field = Descriptor_Field<T, Root_Index>;
auto&& root = managed_descriptor_field<T, Root_Index>().get(object);
if constexpr(sizeof...(Members) == 0) {
return std::forward<decltype(root)>(root);
} else {
return path_value<decltype(root), Members...>(root);
}
}
template <class T, std::size_t... Indexes>
auto managed_key_array_impl(std::index_sequence<Indexes...>) {
return std::array<std::string_view, sizeof...(Indexes)>{Managed_Key_Attribute<Indexes>::value.view()...};
}
template <Described_Type T>
const auto& managed_key_array() {
static const auto value = managed_key_array_impl<T>(std::make_index_sequence<std::tuple_size_v<Descriptor_Fields<T>>>{});
return value;
}
}
}
namespace structive {
template <class T, Synchronization_Policy Policy>
struct Type_Descriptor<adminive::Managed_Value<T, Policy>> {
static auto get() {
return adminive::detail::make_managed_schema<adminive::Managed_Value<T, Policy>, T>();
}
};
}
namespace adminive {
template <class T, structive::Synchronization_Policy Policy>
class Managed_Value : public structive::Property_Object<Managed_Value<T, Policy>, Policy> {
using Base = structive::Property_Object<Managed_Value<T, Policy>, Policy>;
public:
using value_type = T;
using policy_type = Policy;
Managed_Value() requires std::default_initializable<T> = default;
explicit Managed_Value(T value) : value_(std::move(value)) {}
explicit Managed_Value(structive::Property_Synchronization synchronization) : Base(std::move(synchronization)) {}
Managed_Value(T value, structive::Property_Synchronization synchronization) : Base(std::move(synchronization)), value_(std::move(value)) {}
Managed_Value(const Managed_Value&) requires std::copy_constructible<T> = default;
Managed_Value(Managed_Value&&) noexcept(std::is_nothrow_move_constructible_v<T>) requires std::move_constructible<T> = default;
Managed_Value& operator=(const Managed_Value&) requires std::is_copy_assignable_v<T> = default;
Managed_Value& operator=(Managed_Value&&) noexcept(std::is_nothrow_move_assignable_v<T>) requires std::is_move_assignable_v<T> = default;
T& unsafe_value() noexcept {
return value_;
}
const T& unsafe_value() const noexcept {
return value_;
}
template <class Function>
decltype(auto) read(Function&& function) const requires std::invocable<Function, const T&> && detail::Managed_Callback_Result<std::invoke_result_t<Function, const T&>> {
return this->with_all_readable_locked([&](const auto&) -> decltype(auto) {
return std::invoke(std::forward<Function>(function), std::as_const(value_));
});
}
template <class Function>
decltype(auto) write(Function&& function) requires std::invocable<Function, T&> && detail::Managed_Callback_Result<std::invoke_result_t<Function, T&>> {
using Result = std::invoke_result_t<Function, T&>;
if constexpr(std::is_void_v<Result>) {
this->with_all_writable_locked([&](auto&) {
std::invoke(std::forward<Function>(function), value_);
});
} else {
using Value_Result = std::remove_cvref_t<Result>;
std::optional<Value_Result> result;
this->with_all_writable_locked([&](auto&) {
result.emplace(std::invoke(std::forward<Function>(function), value_));
});
return Value_Result(std::move(*result));
}
}
T snapshot() const requires std::copy_constructible<T> {
return read([](const T& value) {
return value;
});
}
template <auto Member>
auto member() {
constexpr auto index = detail::described_member_index<T, Member>();
static_assert(index < std::tuple_size_v<Descriptor_Fields<T>>);
return Managed_Field<Managed_Value, index>{*this};
}
template <auto Member>
auto member() const {
constexpr auto index = detail::described_member_index<T, Member>();
static_assert(index < std::tuple_size_v<Descriptor_Fields<T>>);
return Managed_Field<const Managed_Value, index>{*this};
}
template <std::size_t Index>
auto field() {
static_assert(Index < std::tuple_size_v<Descriptor_Fields<T>>);
return Managed_Field<Managed_Value, Index>{*this};
}
template <std::size_t Index>
auto field() const {
static_assert(Index < std::tuple_size_v<Descriptor_Fields<T>>);
return Managed_Field<const Managed_Value, Index>{*this};
}
private:
T value_{};
};
template <class Managed, std::size_t Root_Index, auto... Members>
class Managed_Field {
using Owner = std::remove_const_t<Managed>;
using Root = typename Owner::value_type;
public:
using owner_type = Managed;
using value_type = std::remove_cvref_t<decltype(detail::managed_path_value<Root, Root_Index, Members...>(std::declval<Root&>()))>;
explicit Managed_Field(Managed& owner) : owner_(&owner) {}
template <class Function>
decltype(auto) read(Function&& function) const requires std::invocable<Function, const value_type&> && detail::Managed_Callback_Result<std::invoke_result_t<Function, const value_type&>> {
return owner_->template with_read_index<Root_Index>([&](const auto& root_value) -> decltype(auto) {
if constexpr(sizeof...(Members) == 0)
return std::invoke(std::forward<Function>(function), root_value);
else
return std::invoke(std::forward<Function>(function), detail::path_value<decltype(root_value), Members...>(root_value));
});
}
template <class Function>
decltype(auto) write(Function&& function) requires (!std::is_const_v<Managed>) && (detail::managed_path_writable<Root, Root_Index, Members...>()) && std::invocable<Function, value_type&> && detail::Managed_Callback_Result<std::invoke_result_t<Function, value_type&>> {
if constexpr(detail::managed_path_requires_synchronization<Root, Root_Index, Members...>()) {
const auto key = detail::Managed_Key_Attribute<Root_Index>::value.view();
auto guard = owner_->lock_unique({key});
auto& value = detail::managed_path_value<Root, Root_Index, Members...>(owner_->unsafe_value());
return std::invoke(std::forward<Function>(function), value);
} else {
auto& value = detail::managed_path_value<Root, Root_Index, Members...>(owner_->unsafe_value());
return std::invoke(std::forward<Function>(function), value);
}
}
value_type snapshot() const requires std::copy_constructible<value_type> {
return read([](const value_type& value) {
return value;
});
}
template <auto Member>
auto member() requires (!std::is_const_v<Managed>) {
return Managed_Field<Managed, Root_Index, Members..., Member>{*owner_};
}
template <auto Member>
auto member() const {
return Managed_Field<const Owner, Root_Index, Members..., Member>{*owner_};
}
Managed& owner() const noexcept {
return *owner_;
}
private:
Managed* owner_;
};
template <class T>
struct Is_Managed_Value : std::false_type {};
template <class T, structive::Synchronization_Policy Policy>
struct Is_Managed_Value<Managed_Value<T, Policy>> : std::true_type {};
template <class T>
concept Managed_Value_Type = Is_Managed_Value<std::remove_cvref_t<T>>::value;
template <class T>
struct Is_Managed_Field : std::false_type {};
template <class Managed, std::size_t Root_Index, auto... Members>
struct Is_Managed_Field<Managed_Field<Managed, Root_Index, Members...>> : std::true_type {};
template <class T>
concept Managed_Field_Type = Is_Managed_Field<std::remove_cvref_t<T>>::value;
}