146 lines
7.2 KiB
C++
146 lines
7.2 KiB
C++
#pragma once
|
|
#include "accessor.hpp"
|
|
#include "attributes.hpp"
|
|
#include "meta.hpp"
|
|
#include <cstddef>
|
|
#include <tuple>
|
|
#include <string_view>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
namespace structive {
|
|
template <class Value, class... Metadata>
|
|
consteval bool constraints_compatible() {
|
|
return (([] {
|
|
if constexpr (Property_Constraint<Metadata>) {
|
|
return Property_Constraint_For<Metadata, Value>;
|
|
}
|
|
return true;
|
|
}()) && ...);
|
|
}
|
|
template <Property_Accessor Accessor, class... Metadata>
|
|
struct Property_Descriptor {
|
|
using property_descriptor_tag = void;
|
|
using accessor_type = Accessor;
|
|
using object_type = typename Accessor::object_type;
|
|
using value_type = typename Accessor::value_type;
|
|
using storage_identity = typename Accessor::storage_identity;
|
|
using dependency_spec = typename Accessor::dependency_spec;
|
|
using metadata_types = Type_List<Metadata...>;
|
|
using capability_type = find_attribute_in_list_t<Capability_Category, metadata_types>;
|
|
static constexpr Property_Capability intrinsic_capability = [] {
|
|
if constexpr (!std::same_as<capability_type, void>) {
|
|
return capability_type::value;
|
|
} else if constexpr (Accessor::readable && Accessor::writable) {
|
|
return Property_Capability::read_write;
|
|
} else if constexpr (Accessor::readable) {
|
|
return Property_Capability::read;
|
|
} else if constexpr (Accessor::writable) {
|
|
return Property_Capability::write;
|
|
} else {
|
|
return Property_Capability::none;
|
|
}
|
|
}();
|
|
static constexpr bool readable = Accessor::readable && (intrinsic_capability == Property_Capability::read || intrinsic_capability == Property_Capability::read_write);
|
|
static constexpr bool writable = Accessor::writable && (intrinsic_capability == Property_Capability::write || intrinsic_capability == Property_Capability::read_write);
|
|
static constexpr bool synchronized_view_read = Accessor::synchronized_view_read;
|
|
static constexpr bool trusted_object_access = Accessor::trusted_object_access;
|
|
static constexpr std::size_t dependency_count = dependency_spec::count;
|
|
static constexpr bool runtime_copy_writable = writable && requires(const Accessor& accessor, object_type& object, const value_type& candidate) { accessor.write(object, candidate); };
|
|
static_assert((Property_Metadata<Metadata> && ...), "property metadata must be an Attribute or Constraint");
|
|
static_assert(unique_single_value_categories<Metadata...>());
|
|
static_assert(!((intrinsic_capability == Property_Capability::read || intrinsic_capability == Property_Capability::read_write) && !Accessor::readable), "property capability requests read from a non-readable accessor");
|
|
static_assert(!((intrinsic_capability == Property_Capability::write || intrinsic_capability == Property_Capability::read_write) && !Accessor::writable), "property capability requests write from a non-writable accessor");
|
|
using key_type = find_attribute_in_list_t<Key_Category, metadata_types>;
|
|
static_assert(!std::same_as<key_type, void>);
|
|
static_assert(key_type::value.view().size() > 0);
|
|
static_assert(constraints_compatible<value_type, Metadata...>());
|
|
[[no_unique_address]] Accessor accessor{};
|
|
std::tuple<Metadata...> metadata;
|
|
template <class Category>
|
|
using attribute_type = find_attribute_in_list_t<Category, metadata_types>;
|
|
template <class Category>
|
|
static constexpr std::size_t attribute_count = count_attribute_category<Category, Metadata...>();
|
|
template <class Category>
|
|
static constexpr bool has_attribute = attribute_count<Category> != 0;
|
|
template <class Category>
|
|
constexpr decltype(auto) attribute() const requires (attribute_count<Category> == 1) {
|
|
using target = attribute_type<Category>;
|
|
return std::get<target>(metadata);
|
|
}
|
|
constexpr std::string_view key() const noexcept {
|
|
return key_type::value.view();
|
|
}
|
|
template <class Function>
|
|
constexpr void for_each_metadata(Function&& function) const {
|
|
std::apply([&](const auto&... values) {
|
|
(function(values), ...);
|
|
}, metadata);
|
|
}
|
|
template <class Function>
|
|
constexpr void for_each_attribute(Function&& function) const {
|
|
std::apply([&](const auto&... values) {
|
|
([&] {
|
|
using type = std::remove_cvref_t<decltype(values)>;
|
|
if constexpr (Property_Attribute<type>) {
|
|
function(values);
|
|
}
|
|
}(), ...);
|
|
}, metadata);
|
|
}
|
|
template <class Category, class Function>
|
|
constexpr void for_each_attribute(Function&& function) const {
|
|
std::apply([&](const auto&... values) {
|
|
([&] {
|
|
using type = std::remove_cvref_t<decltype(values)>;
|
|
if constexpr (Property_Attribute<type> && std::same_as<attribute_category_of_t<type>, Category>) {
|
|
function(values);
|
|
}
|
|
}(), ...);
|
|
}, metadata);
|
|
}
|
|
template <class Function>
|
|
constexpr void for_each_constraint(Function&& function) const {
|
|
std::apply([&](const auto&... values) {
|
|
([&] {
|
|
using type = std::remove_cvref_t<decltype(values)>;
|
|
if constexpr (Property_Constraint<type>) {
|
|
function(values);
|
|
}
|
|
}(), ...);
|
|
}, metadata);
|
|
}
|
|
};
|
|
template <class Type>
|
|
concept Property_Descriptor_Type = requires {
|
|
typename Type::property_descriptor_tag;
|
|
typename Type::object_type;
|
|
typename Type::value_type;
|
|
typename Type::accessor_type;
|
|
typename Type::storage_identity;
|
|
};
|
|
template <auto Member, class... Metadata>
|
|
constexpr auto property(Metadata&&... metadata) {
|
|
using accessor = Member_Accessor<Member>;
|
|
return Property_Descriptor<accessor, std::decay_t<Metadata>...>{{}, {std::forward<Metadata>(metadata)...}};
|
|
}
|
|
template <auto Member, class... Metadata>
|
|
constexpr auto field(Metadata&&... metadata) {
|
|
return property<Member>(std::forward<Metadata>(metadata)...);
|
|
}
|
|
template <class Object, class Value, Property_Dependencies_Type Dependencies, class Function, class... Metadata>
|
|
constexpr auto computed_property(Dependencies, Function&& function, Metadata&&... metadata) {
|
|
using accessor = Synchronized_Computed_Accessor<Object, Value, std::decay_t<Function>, Dependencies>;
|
|
return Property_Descriptor<accessor, std::decay_t<Metadata>...>{accessor{std::forward<Function>(function)}, {std::forward<Metadata>(metadata)...}};
|
|
}
|
|
template <auto Getter, class... Metadata> requires Trusted_Getter_Function<Getter>
|
|
constexpr auto trusted_computed_property(Metadata&&... metadata) {
|
|
using accessor = Trusted_Computed_Accessor<Getter>;
|
|
return Property_Descriptor<accessor, std::decay_t<Metadata>...>{{}, {std::forward<Metadata>(metadata)...}};
|
|
}
|
|
template <auto Getter, auto Setter, class... Metadata> requires Trusted_Getter_Function<Getter> && Trusted_Setter_Function_For<Setter, trusted_getter_object_t<Getter>, trusted_getter_value_t<Getter>>
|
|
constexpr auto trusted_accessor_property(Metadata&&... metadata) {
|
|
using accessor = Trusted_Getter_Setter_Accessor<Getter, Setter>;
|
|
return Property_Descriptor<accessor, std::decay_t<Metadata>...>{{}, {std::forward<Metadata>(metadata)...}};
|
|
}
|
|
}
|