|
|
|
@@ -82,21 +82,52 @@ struct No_Defaults {
|
|
|
|
|
std::tuple<> attributes;
|
|
|
|
|
};
|
|
|
|
|
inline constexpr No_Defaults no_defaults{};
|
|
|
|
|
template <class Object, class Defaults, class... Properties>
|
|
|
|
|
|
|
|
|
|
template <class... Attributes>
|
|
|
|
|
struct Type_Metadata {
|
|
|
|
|
using type_metadata_tag = void;
|
|
|
|
|
using attribute_types = Type_List<Attributes...>;
|
|
|
|
|
static_assert((Property_Attribute<Attributes> && ...));
|
|
|
|
|
static_assert(unique_single_value_categories<Attributes...>());
|
|
|
|
|
std::tuple<Attributes...> attributes;
|
|
|
|
|
};
|
|
|
|
|
template <class Type>
|
|
|
|
|
concept Type_Metadata_Type = requires {
|
|
|
|
|
typename Type::type_metadata_tag;
|
|
|
|
|
typename Type::attribute_types;
|
|
|
|
|
};
|
|
|
|
|
template <class... Attributes>
|
|
|
|
|
constexpr auto type_metadata(Attributes&&... attributes) {
|
|
|
|
|
return Type_Metadata<std::decay_t<Attributes>...>{
|
|
|
|
|
{std::forward<Attributes>(attributes)...}};
|
|
|
|
|
}
|
|
|
|
|
using No_Type_Metadata = Type_Metadata<>;
|
|
|
|
|
inline constexpr No_Type_Metadata no_type_metadata{};
|
|
|
|
|
|
|
|
|
|
template <class Object, class Defaults, class Type_Metadata_Value, class... Properties>
|
|
|
|
|
class Object_Schema {
|
|
|
|
|
[[no_unique_address]] Defaults object_defaults_;
|
|
|
|
|
[[no_unique_address]] Type_Metadata_Value type_metadata_;
|
|
|
|
|
Synchronization_Plan synchronization_plan_;
|
|
|
|
|
std::tuple<Properties...> properties_;
|
|
|
|
|
public:
|
|
|
|
|
using property_schema_tag = void;
|
|
|
|
|
using object_type = Object;
|
|
|
|
|
using defaults_type = Defaults;
|
|
|
|
|
using type_metadata_type = Type_Metadata_Value;
|
|
|
|
|
using type_attribute_types = typename Type_Metadata_Value::attribute_types;
|
|
|
|
|
using property_types = Type_List<Properties...>;
|
|
|
|
|
static constexpr std::size_t property_count = sizeof...(Properties);
|
|
|
|
|
static_assert((std::same_as<typename Properties::object_type, Object> && ...));
|
|
|
|
|
static_assert(unique_property_keys<Properties...>());
|
|
|
|
|
static_assert(unique_property_storage<Properties...>());
|
|
|
|
|
Object_Schema(Defaults object_defaults, Synchronization_Plan synchronization_plan, std::tuple<Properties...> properties) : object_defaults_(std::move(object_defaults)), synchronization_plan_(std::move(synchronization_plan)), properties_(std::move(properties)) {}
|
|
|
|
|
Object_Schema(Defaults object_defaults, Type_Metadata_Value type_metadata_value,
|
|
|
|
|
Synchronization_Plan synchronization_plan,
|
|
|
|
|
std::tuple<Properties...> properties)
|
|
|
|
|
: object_defaults_(std::move(object_defaults)),
|
|
|
|
|
type_metadata_(std::move(type_metadata_value)),
|
|
|
|
|
synchronization_plan_(std::move(synchronization_plan)),
|
|
|
|
|
properties_(std::move(properties)) {}
|
|
|
|
|
Object_Schema(const Object_Schema&) = default;
|
|
|
|
|
Object_Schema(Object_Schema&&) noexcept = default;
|
|
|
|
|
Object_Schema& operator=(const Object_Schema&) = delete;
|
|
|
|
@@ -106,6 +137,40 @@ public:
|
|
|
|
|
const Defaults& object_defaults() const noexcept {
|
|
|
|
|
return object_defaults_;
|
|
|
|
|
}
|
|
|
|
|
const Type_Metadata_Value& metadata() const noexcept {
|
|
|
|
|
return type_metadata_;
|
|
|
|
|
}
|
|
|
|
|
template <class Category>
|
|
|
|
|
using type_attribute_type = find_attribute_in_list_t<Category, type_attribute_types>;
|
|
|
|
|
template <class Category>
|
|
|
|
|
static constexpr std::size_t type_attribute_count =
|
|
|
|
|
[]<class... Attributes>(Type_List<Attributes...>) {
|
|
|
|
|
return count_attribute_category<Category, Attributes...>();
|
|
|
|
|
}(type_attribute_types{});
|
|
|
|
|
template <class Category>
|
|
|
|
|
static constexpr bool has_type_attribute = type_attribute_count<Category> != 0;
|
|
|
|
|
template <class Category>
|
|
|
|
|
constexpr decltype(auto) type_attribute() const
|
|
|
|
|
requires (type_attribute_count<Category> == 1) {
|
|
|
|
|
using target = type_attribute_type<Category>;
|
|
|
|
|
return std::get<target>(type_metadata_.attributes);
|
|
|
|
|
}
|
|
|
|
|
template <class Function>
|
|
|
|
|
constexpr void for_each_type_attribute(Function&& function) const {
|
|
|
|
|
std::apply([&](const auto&... attributes) {
|
|
|
|
|
(function(attributes), ...);
|
|
|
|
|
}, type_metadata_.attributes);
|
|
|
|
|
}
|
|
|
|
|
template <class Category, class Function>
|
|
|
|
|
constexpr void for_each_type_attribute(Function&& function) const {
|
|
|
|
|
std::apply([&](const auto&... attributes) {
|
|
|
|
|
([&] {
|
|
|
|
|
using type = std::remove_cvref_t<decltype(attributes)>;
|
|
|
|
|
if constexpr (std::same_as<attribute_category_of_t<type>, Category>)
|
|
|
|
|
function(attributes);
|
|
|
|
|
}(), ...);
|
|
|
|
|
}, type_metadata_.attributes);
|
|
|
|
|
}
|
|
|
|
|
template <auto Selector>
|
|
|
|
|
constexpr const auto& property() const {
|
|
|
|
|
if constexpr (std::integral<decltype(Selector)>) {
|
|
|
|
@@ -148,6 +213,8 @@ concept Property_Schema = requires {
|
|
|
|
|
typename Schema::property_schema_tag;
|
|
|
|
|
typename Schema::object_type;
|
|
|
|
|
typename Schema::defaults_type;
|
|
|
|
|
typename Schema::type_metadata_type;
|
|
|
|
|
typename Schema::type_attribute_types;
|
|
|
|
|
typename Schema::property_types;
|
|
|
|
|
{ Schema::property_count } -> std::convertible_to<std::size_t>;
|
|
|
|
|
};
|
|
|
|
@@ -527,33 +594,82 @@ bool visit_schema_property(const Schema& schema, std::string_view key_value, Fun
|
|
|
|
|
}
|
|
|
|
|
return visit_schema_property_at(schema, *index, std::forward<Function>(function));
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Defaults, class Source, class... Properties>
|
|
|
|
|
auto make_object_schema(Defaults&& object_defaults, Source&& synchronization_source, Properties&&... properties) requires Synchronization_Source_Type<std::remove_cvref_t<Source>> {
|
|
|
|
|
using schema_type = Object_Schema<Object, std::decay_t<Defaults>, std::decay_t<Properties>...>;
|
|
|
|
|
template <class Object, class Defaults, class Metadata, class Source, class... Properties>
|
|
|
|
|
auto make_object_schema(Defaults&& object_defaults, Metadata&& metadata,
|
|
|
|
|
Source&& synchronization_source, Properties&&... properties)
|
|
|
|
|
requires Object_Defaults_Type<std::remove_cvref_t<Defaults>> &&
|
|
|
|
|
Type_Metadata_Type<std::remove_cvref_t<Metadata>> &&
|
|
|
|
|
Synchronization_Source_Type<std::remove_cvref_t<Source>> {
|
|
|
|
|
using schema_type = Object_Schema<Object, std::decay_t<Defaults>,
|
|
|
|
|
std::decay_t<Metadata>, std::decay_t<Properties>...>;
|
|
|
|
|
constexpr bool valid_schema = Valid_Property_Schema<schema_type>;
|
|
|
|
|
static_assert(valid_schema, "property dependency graph must be valid and acyclic");
|
|
|
|
|
auto plan = materialize_synchronization_plan<schema_type>(std::forward<Source>(synchronization_source));
|
|
|
|
|
schema_type schema{std::forward<Defaults>(object_defaults), std::move(plan), std::tuple<std::decay_t<Properties>...>{std::forward<Properties>(properties)...}};
|
|
|
|
|
schema_type schema{std::forward<Defaults>(object_defaults),
|
|
|
|
|
std::forward<Metadata>(metadata), std::move(plan),
|
|
|
|
|
std::tuple<std::decay_t<Properties>...>{
|
|
|
|
|
std::forward<Properties>(properties)...}};
|
|
|
|
|
if constexpr (valid_schema) {
|
|
|
|
|
static_cast<void>(resolve_synchronization_plan(schema, schema.synchronization_plan()));
|
|
|
|
|
}
|
|
|
|
|
return schema;
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Defaults, class Metadata, class Source, class... Properties>
|
|
|
|
|
auto object_schema(Defaults&& object_defaults, Metadata&& metadata,
|
|
|
|
|
Source&& synchronization_source, Properties&&... properties)
|
|
|
|
|
requires Object_Defaults_Type<std::remove_cvref_t<Defaults>> &&
|
|
|
|
|
Type_Metadata_Type<std::remove_cvref_t<Metadata>> &&
|
|
|
|
|
Synchronization_Source_Type<std::remove_cvref_t<Source>> &&
|
|
|
|
|
(Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(std::forward<Defaults>(object_defaults),
|
|
|
|
|
std::forward<Metadata>(metadata),
|
|
|
|
|
std::forward<Source>(synchronization_source),
|
|
|
|
|
std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Metadata, class Source, class... Properties>
|
|
|
|
|
auto object_schema(Metadata&& metadata, Source&& synchronization_source,
|
|
|
|
|
Properties&&... properties)
|
|
|
|
|
requires Type_Metadata_Type<std::remove_cvref_t<Metadata>> &&
|
|
|
|
|
Synchronization_Source_Type<std::remove_cvref_t<Source>> &&
|
|
|
|
|
(Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(no_defaults, std::forward<Metadata>(metadata),
|
|
|
|
|
std::forward<Source>(synchronization_source),
|
|
|
|
|
std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Defaults, class Source, class... Properties>
|
|
|
|
|
auto object_schema(Defaults&& object_defaults, Source&& synchronization_source, Properties&&... properties) requires Object_Defaults_Type<std::remove_cvref_t<Defaults>> && Synchronization_Source_Type<std::remove_cvref_t<Source>> && (Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(std::forward<Defaults>(object_defaults), std::forward<Source>(synchronization_source), std::forward<Properties>(properties)...);
|
|
|
|
|
return make_object_schema<Object>(std::forward<Defaults>(object_defaults), no_type_metadata, std::forward<Source>(synchronization_source), std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Source, class... Properties>
|
|
|
|
|
auto object_schema(Source&& synchronization_source, Properties&&... properties) requires Synchronization_Source_Type<std::remove_cvref_t<Source>> && (Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(no_defaults, std::forward<Source>(synchronization_source), std::forward<Properties>(properties)...);
|
|
|
|
|
return make_object_schema<Object>(no_defaults, no_type_metadata, std::forward<Source>(synchronization_source), std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Defaults, class Metadata, class... Properties>
|
|
|
|
|
auto object_schema(Defaults&& object_defaults, Metadata&& metadata,
|
|
|
|
|
Properties&&... properties)
|
|
|
|
|
requires Object_Defaults_Type<std::remove_cvref_t<Defaults>> &&
|
|
|
|
|
Type_Metadata_Type<std::remove_cvref_t<Metadata>> &&
|
|
|
|
|
(Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(std::forward<Defaults>(object_defaults),
|
|
|
|
|
std::forward<Metadata>(metadata),
|
|
|
|
|
Synchronization_Plan{},
|
|
|
|
|
std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Metadata, class... Properties>
|
|
|
|
|
auto object_schema(Metadata&& metadata, Properties&&... properties)
|
|
|
|
|
requires Type_Metadata_Type<std::remove_cvref_t<Metadata>> &&
|
|
|
|
|
(Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(no_defaults, std::forward<Metadata>(metadata),
|
|
|
|
|
Synchronization_Plan{},
|
|
|
|
|
std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class Defaults, class... Properties>
|
|
|
|
|
auto object_schema(Defaults&& object_defaults, Properties&&... properties) requires Object_Defaults_Type<std::remove_cvref_t<Defaults>> && (Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(std::forward<Defaults>(object_defaults), Synchronization_Plan{}, std::forward<Properties>(properties)...);
|
|
|
|
|
return make_object_schema<Object>(std::forward<Defaults>(object_defaults), no_type_metadata, Synchronization_Plan{}, std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class... Properties>
|
|
|
|
|
auto object_schema(Properties&&... properties) requires (Property_Descriptor_Type<std::remove_cvref_t<Properties>> && ...) {
|
|
|
|
|
return make_object_schema<Object>(no_defaults, Synchronization_Plan{}, std::forward<Properties>(properties)...);
|
|
|
|
|
return make_object_schema<Object>(no_defaults, no_type_metadata, Synchronization_Plan{}, std::forward<Properties>(properties)...);
|
|
|
|
|
}
|
|
|
|
|
template <class Object, class... Arguments>
|
|
|
|
|
requires requires(Arguments&&... arguments) {
|
|
|
|
|