补全边角
This commit is contained in:
@@ -43,6 +43,7 @@ struct Property_Descriptor {
|
||||
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 bool runtime_copy_writable = writable && requires(const Accessor& accessor, object_type& object, const value_type& candidate) { accessor.write(object, candidate); };
|
||||
static_assert(unique_single_value_categories<Attributes...>());
|
||||
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");
|
||||
@@ -55,9 +56,11 @@ struct Property_Descriptor {
|
||||
template <class Category>
|
||||
using attribute_type = find_attribute_in_list_t<Category, attribute_types>;
|
||||
template <class Category>
|
||||
static constexpr bool has_attribute = !std::same_as<attribute_type<Category>, void>;
|
||||
static constexpr std::size_t attribute_count = count_attribute_category<Category, Attributes...>();
|
||||
template <class Category>
|
||||
constexpr decltype(auto) attribute() const requires has_attribute<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>(attributes);
|
||||
}
|
||||
@@ -70,6 +73,17 @@ struct Property_Descriptor {
|
||||
(function(values), ...);
|
||||
}, attributes);
|
||||
}
|
||||
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 (std::same_as<attribute_category_of_t<type>, Category>) {
|
||||
function(values);
|
||||
}
|
||||
}(), ...);
|
||||
}, attributes);
|
||||
}
|
||||
template <class Function>
|
||||
constexpr void for_each_constraint(Function&& function) const {
|
||||
std::apply([&](const auto&... values) {
|
||||
|
||||
@@ -85,6 +85,7 @@ enum class Runtime_Access_Result {
|
||||
unknown_property,
|
||||
not_readable,
|
||||
not_writable,
|
||||
unsupported_runtime_write,
|
||||
type_mismatch
|
||||
};
|
||||
/// Callback used by `runtime_read`.
|
||||
@@ -123,8 +124,8 @@ public:
|
||||
Runtime_Access_Result runtime_read(std::string_view key, void* context, Runtime_Read_Callback callback) const {
|
||||
return runtime_interface_->read(*this, key, context, callback);
|
||||
}
|
||||
/// Looks up `key` at runtime and performs the same managed write used by typed `write`.
|
||||
/// `value_type` must exactly match the property's declared value type and `value` must point to a live object of that exact type for the duration of the call. No numeric, string or user-defined conversion is attempted.
|
||||
/// Looks up `key` at runtime and performs a copy-input managed write.
|
||||
/// `value_type` must exactly match the property's declared value type and `value` must point to a live object of that exact type for the duration of the call. No numeric, string or user-defined conversion is attempted. Intrinsically writable properties that require move-only input report `unsupported_runtime_write`; typed `write` remains available for them.
|
||||
Runtime_Access_Result runtime_write(std::string_view key, const std::type_info& value_type, const void* value) {
|
||||
return runtime_interface_->write(*this, key, value_type, value);
|
||||
}
|
||||
@@ -656,7 +657,7 @@ private:
|
||||
return Runtime_Access_Result::not_readable;
|
||||
}
|
||||
Runtime_Access_Result result = Runtime_Access_Result::unknown_property;
|
||||
visit_schema_property(type_descriptor<Derived>(), key, [&](auto property_index_constant, const auto&) {
|
||||
visit_schema_property_at(type_descriptor<Derived>(), *index, [&](auto property_index_constant, const auto&) {
|
||||
constexpr std::size_t property_index = decltype(property_index_constant)::value;
|
||||
using Property = typename Schema::template property_type<property_index>;
|
||||
using Value = typename Property::value_type;
|
||||
@@ -707,13 +708,12 @@ private:
|
||||
return Runtime_Access_Result::not_writable;
|
||||
}
|
||||
Runtime_Access_Result result = Runtime_Access_Result::unknown_property;
|
||||
visit_schema_property(type_descriptor<Derived>(), key, [&](auto property_index_constant, const auto&) {
|
||||
visit_schema_property_at(type_descriptor<Derived>(), *index, [&](auto property_index_constant, const auto&) {
|
||||
constexpr std::size_t property_index = decltype(property_index_constant)::value;
|
||||
using Property = typename Schema::template property_type<property_index>;
|
||||
using Accessor = typename Property::accessor_type;
|
||||
using Value = typename Property::value_type;
|
||||
if constexpr (!Schema::template property_type<property_index>::writable || !requires(const Accessor& accessor, Derived& object, const Value& candidate) { accessor.write(object, candidate); }) {
|
||||
result = Runtime_Access_Result::not_writable;
|
||||
if constexpr (!Property::runtime_copy_writable) {
|
||||
result = Runtime_Access_Result::unsupported_runtime_write;
|
||||
} else if (value_type != typeid(Value)) {
|
||||
result = Runtime_Access_Result::type_mismatch;
|
||||
} else {
|
||||
|
||||
@@ -24,7 +24,7 @@ consteval std::string_view declared_property_key() {
|
||||
}
|
||||
template <class... Properties>
|
||||
consteval bool unique_property_keys() {
|
||||
constexpr std::array keys{declared_property_key<Properties>()...};
|
||||
constexpr std::array<std::string_view, sizeof...(Properties)> keys{declared_property_key<Properties>()...};
|
||||
for (std::size_t i = 0; i < keys.size(); ++i) {
|
||||
for (std::size_t j = i + 1; j < keys.size(); ++j) {
|
||||
if (keys[i] == keys[j]) {
|
||||
@@ -374,19 +374,24 @@ Synchronization_Plan materialize_synchronization_plan(Source&& source) {
|
||||
}
|
||||
}
|
||||
template <Valid_Property_Schema Schema, class Function>
|
||||
bool visit_schema_property(const Schema& schema, std::string_view key_value, Function&& function) {
|
||||
bool visit_schema_property_at(const Schema& schema, std::size_t index_value, Function&& function) {
|
||||
bool found = false;
|
||||
schema.for_each_property([&](auto index, const auto& descriptor) {
|
||||
if (!found) {
|
||||
using property_type = std::remove_cvref_t<decltype(descriptor)>;
|
||||
if (declared_property_key<property_type>() == key_value) {
|
||||
std::invoke(function, index, descriptor);
|
||||
found = true;
|
||||
}
|
||||
if (!found && decltype(index)::value == index_value) {
|
||||
std::invoke(function, index, descriptor);
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
template <Valid_Property_Schema Schema, class Function>
|
||||
bool visit_schema_property(const Schema& schema, std::string_view key_value, Function&& function) {
|
||||
auto index = schema_property_index<Schema>(key_value);
|
||||
if (!index) {
|
||||
return false;
|
||||
}
|
||||
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>...>;
|
||||
|
||||
Reference in New Issue
Block a user