更新接口
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
#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 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 {};
|
||||
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;
|
||||
const value_type& read(const object_type& object) const noexcept(noexcept(Field::accessor_type::get(object.unsafe_value()))) {
|
||||
return Field::accessor_type::get(object.unsafe_value());
|
||||
}
|
||||
value_type& read(object_type& object) const noexcept(noexcept(Field::accessor_type::get(object.unsafe_value()))) {
|
||||
return Field::accessor_type::get(object.unsafe_value());
|
||||
}
|
||||
template <class Value>
|
||||
void write(object_type& object, Value&& value) const requires writable && std::assignable_from<value_type&, Value> {
|
||||
Field::accessor_type::get(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 = Field::accessor_type::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 = Field::accessor_type::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&>> {
|
||||
const auto& keys = detail::managed_key_array<T>();
|
||||
auto guard = this->lock_shared(std::span<const std::string_view>{keys});
|
||||
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 {
|
||||
std::optional<std::remove_cvref_t<Result>> result;
|
||||
this->with_all_writable_locked([&](auto&) {
|
||||
result.emplace(std::invoke(std::forward<Function>(function), value_));
|
||||
});
|
||||
return 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&>> {
|
||||
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_shared({key});
|
||||
const auto& value = detail::managed_path_value<Root, Root_Index, Members...>(owner_->unsafe_value());
|
||||
return std::invoke(std::forward<Function>(function), value);
|
||||
} else {
|
||||
const auto& value = detail::managed_path_value<Root, Root_Index, Members...>(owner_->unsafe_value());
|
||||
return std::invoke(std::forward<Function>(function), 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;
|
||||
}
|
||||
Reference in New Issue
Block a user