补全边角

This commit is contained in:
2026-08-08 21:21:23 +08:00
parent a6d6f8c6d3
commit c51c9d2937
24 changed files with 359 additions and 56 deletions
+16 -2
View File
@@ -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 {
+13 -8
View File
@@ -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>...>;