156 lines
7.6 KiB
C++
156 lines
7.6 KiB
C++
#pragma once
|
|
#include "fixed_string.hpp"
|
|
#include <concepts>
|
|
#include <functional>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
namespace structive {
|
|
template <auto Member>
|
|
struct Member_Property_Dependency {
|
|
static constexpr auto member = Member;
|
|
};
|
|
template <Fixed_String Key>
|
|
struct Key_Property_Dependency {
|
|
static constexpr auto key = Key;
|
|
};
|
|
template <class... Dependencies>
|
|
struct Property_Dependencies {
|
|
using property_dependencies_tag = void;
|
|
static constexpr std::size_t count = sizeof...(Dependencies);
|
|
};
|
|
template <class Type>
|
|
concept Property_Dependencies_Type = requires {
|
|
typename Type::property_dependencies_tag;
|
|
{ Type::count } -> std::convertible_to<std::size_t>;
|
|
};
|
|
template <auto... Members>
|
|
inline constexpr Property_Dependencies<Member_Property_Dependency<Members>...> depends_on{};
|
|
template <Fixed_String... Keys>
|
|
inline constexpr Property_Dependencies<Key_Property_Dependency<Keys>...> depends_on_keys{};
|
|
using No_Property_Dependencies = Property_Dependencies<>;
|
|
template <class>
|
|
struct Member_Pointer_Traits;
|
|
template <class Object, class Value>
|
|
struct Member_Pointer_Traits<Value Object::*> {
|
|
using object_type = Object;
|
|
using value_type = Value;
|
|
};
|
|
template <class>
|
|
struct Member_Function_Traits;
|
|
template <class Object, class Return, class... Args>
|
|
struct Member_Function_Traits<Return (Object::*)(Args...)> {
|
|
using object_type = Object;
|
|
using return_type = Return;
|
|
};
|
|
template <class Object, class Return, class... Args>
|
|
struct Member_Function_Traits<Return (Object::*)(Args...) const> {
|
|
using object_type = Object;
|
|
using return_type = Return;
|
|
};
|
|
template <class Object, class Return, class... Args>
|
|
struct Member_Function_Traits<Return (Object::*)(Args...) noexcept> : Member_Function_Traits<Return (Object::*)(Args...)> {};
|
|
template <class Object, class Return, class... Args>
|
|
struct Member_Function_Traits<Return (Object::*)(Args...) const noexcept> : Member_Function_Traits<Return (Object::*)(Args...) const> {};
|
|
template <auto Member>
|
|
struct Member_Storage_Identity {};
|
|
template <auto Getter>
|
|
concept Trusted_Getter_Function = requires {
|
|
typename Member_Function_Traits<decltype(Getter)>::object_type;
|
|
} && requires(const typename Member_Function_Traits<decltype(Getter)>::object_type& object) {
|
|
std::invoke(Getter, object);
|
|
} && (!std::is_void_v<std::invoke_result_t<decltype(Getter), const typename Member_Function_Traits<decltype(Getter)>::object_type&>>) && (!std::is_rvalue_reference_v<std::invoke_result_t<decltype(Getter), const typename Member_Function_Traits<decltype(Getter)>::object_type&>>) && (!(std::is_lvalue_reference_v<std::invoke_result_t<decltype(Getter), const typename Member_Function_Traits<decltype(Getter)>::object_type&>> && !std::is_const_v<std::remove_reference_t<std::invoke_result_t<decltype(Getter), const typename Member_Function_Traits<decltype(Getter)>::object_type&>>>));
|
|
template <auto Getter>
|
|
using trusted_getter_object_t = typename Member_Function_Traits<decltype(Getter)>::object_type;
|
|
template <auto Getter>
|
|
using trusted_getter_value_t = std::remove_cvref_t<std::invoke_result_t<decltype(Getter), const trusted_getter_object_t<Getter>&>>;
|
|
template <auto Setter, class Object, class Value>
|
|
concept Trusted_Setter_Function_For = requires {
|
|
typename Member_Function_Traits<decltype(Setter)>::object_type;
|
|
} && std::same_as<typename Member_Function_Traits<decltype(Setter)>::object_type, Object> && requires(Object& object, Value value) {
|
|
{ std::invoke(Setter, object, std::move(value)) } -> std::same_as<void>;
|
|
};
|
|
template <auto Member>
|
|
struct Member_Accessor {
|
|
using traits = Member_Pointer_Traits<decltype(Member)>;
|
|
using object_type = typename traits::object_type;
|
|
using value_type = typename traits::value_type;
|
|
using storage_identity = Member_Storage_Identity<Member>;
|
|
static constexpr bool readable = true;
|
|
static constexpr bool writable = !std::is_const_v<value_type>;
|
|
static constexpr bool synchronized_view_read = false;
|
|
static constexpr bool trusted_object_access = false;
|
|
using dependency_spec = No_Property_Dependencies;
|
|
static constexpr auto member = Member;
|
|
constexpr const value_type& read(const object_type& object) const {
|
|
return object.*Member;
|
|
}
|
|
constexpr value_type& read(object_type& object) const {
|
|
return object.*Member;
|
|
}
|
|
template <class Value>
|
|
constexpr void write(object_type& object, Value&& value) const requires writable && std::assignable_from<value_type&, Value> {
|
|
object.*Member = std::forward<Value>(value);
|
|
}
|
|
};
|
|
template <class Object, class Value, class Function, Property_Dependencies_Type Dependencies>
|
|
struct Synchronized_Computed_Accessor {
|
|
using object_type = Object;
|
|
using value_type = Value;
|
|
using storage_identity = void;
|
|
static constexpr bool readable = true;
|
|
static constexpr bool writable = false;
|
|
static constexpr bool synchronized_view_read = true;
|
|
static constexpr bool trusted_object_access = false;
|
|
using dependency_spec = Dependencies;
|
|
[[no_unique_address]] Function function;
|
|
template <class View>
|
|
constexpr value_type read(const View& view) const requires std::invocable<const Function&, const View&> && std::constructible_from<value_type, std::invoke_result_t<const Function&, const View&>> {
|
|
return value_type(std::invoke(function, view));
|
|
}
|
|
};
|
|
template <auto Getter> requires Trusted_Getter_Function<Getter>
|
|
struct Trusted_Computed_Accessor {
|
|
using object_type = trusted_getter_object_t<Getter>;
|
|
using value_type = trusted_getter_value_t<Getter>;
|
|
using storage_identity = void;
|
|
static constexpr bool readable = true;
|
|
static constexpr bool writable = false;
|
|
static constexpr bool synchronized_view_read = false;
|
|
static constexpr bool trusted_object_access = true;
|
|
using dependency_spec = No_Property_Dependencies;
|
|
constexpr decltype(auto) read(const object_type& object) const noexcept(std::is_nothrow_invocable_v<decltype(Getter), const object_type&>) {
|
|
return std::invoke(Getter, object);
|
|
}
|
|
};
|
|
template <auto Getter, auto Setter> requires Trusted_Getter_Function<Getter> && Trusted_Setter_Function_For<Setter, trusted_getter_object_t<Getter>, trusted_getter_value_t<Getter>>
|
|
struct Trusted_Getter_Setter_Accessor {
|
|
using object_type = trusted_getter_object_t<Getter>;
|
|
using value_type = trusted_getter_value_t<Getter>;
|
|
using storage_identity = void;
|
|
static constexpr bool readable = true;
|
|
static constexpr bool writable = true;
|
|
static constexpr bool synchronized_view_read = false;
|
|
static constexpr bool trusted_object_access = true;
|
|
using dependency_spec = No_Property_Dependencies;
|
|
constexpr decltype(auto) read(const object_type& object) const noexcept(std::is_nothrow_invocable_v<decltype(Getter), const object_type&>) {
|
|
return std::invoke(Getter, object);
|
|
}
|
|
template <class Value>
|
|
constexpr void write(object_type& object, Value&& value) const requires std::invocable<decltype(Setter), object_type&, Value> && std::same_as<std::invoke_result_t<decltype(Setter), object_type&, Value>, void> {
|
|
std::invoke(Setter, object, std::forward<Value>(value));
|
|
}
|
|
};
|
|
template <class Accessor>
|
|
concept Property_Accessor = requires {
|
|
typename Accessor::object_type;
|
|
typename Accessor::value_type;
|
|
typename Accessor::storage_identity;
|
|
typename Accessor::dependency_spec;
|
|
requires Property_Dependencies_Type<typename Accessor::dependency_spec>;
|
|
{ Accessor::readable } -> std::convertible_to<bool>;
|
|
{ Accessor::writable } -> std::convertible_to<bool>;
|
|
{ Accessor::synchronized_view_read } -> std::convertible_to<bool>;
|
|
{ Accessor::trusted_object_access } -> std::convertible_to<bool>;
|
|
};
|
|
}
|