架构优化
This commit is contained in:
@@ -238,13 +238,7 @@ struct Schema_Dependency_Indices<Schema, Property_Dependencies<Dependencies...>>
|
||||
template <Property_Schema Schema, std::size_t Index>
|
||||
consteval auto schema_property_dependency_indices() requires Schema_Property_Index<Schema, Index> {
|
||||
using dependency_spec = typename Schema::template property_type<Index>::dependency_spec;
|
||||
constexpr auto indices = Schema_Dependency_Indices<Schema, dependency_spec>::value;
|
||||
for (auto dependency : indices) {
|
||||
if (dependency == Index) {
|
||||
throw "computed property cannot depend on itself";
|
||||
}
|
||||
}
|
||||
return indices;
|
||||
return Schema_Dependency_Indices<Schema, dependency_spec>::value;
|
||||
}
|
||||
template <class Schema, std::size_t Index>
|
||||
inline constexpr std::size_t schema_property_dependency_count_v = schema_property_dependency_indices<Schema, Index>().size();
|
||||
@@ -271,6 +265,37 @@ consteval auto schema_property_dependency_matrix() {
|
||||
}(std::make_index_sequence<Schema::property_count>{});
|
||||
return matrix;
|
||||
}
|
||||
template <Property_Schema Schema>
|
||||
consteval bool schema_dependency_graph_acyclic() {
|
||||
constexpr auto dependencies = schema_property_dependency_matrix<Schema>();
|
||||
std::array<std::size_t, Schema::property_count> dependency_counts{};
|
||||
std::array<std::size_t, Schema::property_count> ready{};
|
||||
std::size_t ready_begin = 0;
|
||||
std::size_t ready_end = 0;
|
||||
for (std::size_t property = 0; property < Schema::property_count; ++property) {
|
||||
for (std::size_t dependency = 0; dependency < Schema::property_count; ++dependency) {
|
||||
dependency_counts[property] += dependencies[property][dependency] ? 1u : 0u;
|
||||
}
|
||||
if (dependency_counts[property] == 0) {
|
||||
ready[ready_end++] = property;
|
||||
}
|
||||
}
|
||||
std::size_t resolved_count = 0;
|
||||
while (ready_begin != ready_end) {
|
||||
auto resolved = ready[ready_begin++];
|
||||
++resolved_count;
|
||||
for (std::size_t property = 0; property < Schema::property_count; ++property) {
|
||||
if (!dependencies[property][resolved]) {
|
||||
continue;
|
||||
}
|
||||
--dependency_counts[property];
|
||||
if (dependency_counts[property] == 0) {
|
||||
ready[ready_end++] = property;
|
||||
}
|
||||
}
|
||||
}
|
||||
return resolved_count == Schema::property_count;
|
||||
}
|
||||
template <class Schema, std::size_t Index, class Category, class Fallback>
|
||||
struct Effective_Attribute {
|
||||
private:
|
||||
@@ -301,11 +326,11 @@ constexpr decltype(auto) declared_effective_attribute(const Schema& schema) requ
|
||||
}
|
||||
}
|
||||
template <class Schema>
|
||||
concept Valid_Property_Schema = Property_Schema<Schema>;
|
||||
concept Valid_Property_Schema = Property_Schema<Schema> && schema_dependency_graph_acyclic<Schema>();
|
||||
template <class Schema, std::size_t Index>
|
||||
inline constexpr bool property_requires_synchronization_v = Schema::template property_type<Index>::writable || Schema::template property_type<Index>::synchronized_view_read;
|
||||
template <class Schema, std::size_t Index>
|
||||
inline constexpr bool property_has_derived_synchronization_v = Schema::template property_type<Index>::synchronized_view_read && !Schema::template property_type<Index>::writable && Schema::template property_type<Index>::declares_dependencies;
|
||||
inline constexpr bool property_has_derived_synchronization_v = Schema::template property_type<Index>::synchronized_view_read && !Schema::template property_type<Index>::writable;
|
||||
template <class Schema, std::size_t Index>
|
||||
inline constexpr bool property_owns_synchronization_domain_v = Schema::template property_type<Index>::writable || (Schema::template property_type<Index>::synchronized_view_read && !property_has_derived_synchronization_v<Schema, Index>);
|
||||
template <class Schema, std::size_t Index>
|
||||
@@ -331,7 +356,6 @@ Resolved_Synchronization_Plan<Schema::property_count> resolve_synchronization_pl
|
||||
return std::array<bool, Schema::property_count>{property_has_derived_synchronization_v<Schema, Index>...};
|
||||
}(std::make_index_sequence<Schema::property_count>{});
|
||||
constexpr auto dependencies = schema_property_dependency_matrix<Schema>();
|
||||
constexpr auto keys = schema_property_keys<Schema>();
|
||||
std::array<std::size_t, Schema::property_count> logical{};
|
||||
std::array<bool, Schema::property_count> explicitly_configured{};
|
||||
std::size_t next_token = Schema::property_count + 1;
|
||||
@@ -407,18 +431,12 @@ Resolved_Synchronization_Plan<Schema::property_count> resolve_synchronization_pl
|
||||
}
|
||||
}
|
||||
if constexpr (Schema::property_count > 0) {
|
||||
std::array<unsigned char, Schema::property_count> dependency_state{};
|
||||
constexpr auto keys = schema_property_keys<Schema>();
|
||||
std::array<bool, Schema::property_count> dependency_resolved{};
|
||||
auto resolve_derived_slot = [&](auto&& self, std::size_t index) -> std::size_t {
|
||||
if (!derived_synchronization[index]) {
|
||||
if (!derived_synchronization[index] || dependency_resolved[index]) {
|
||||
return resolved.lock_slots[index];
|
||||
}
|
||||
if (dependency_state[index] == 2) {
|
||||
return resolved.lock_slots[index];
|
||||
}
|
||||
if (dependency_state[index] == 1) {
|
||||
throw std::invalid_argument("Computed property dependency cycle: " + std::string(keys[index]));
|
||||
}
|
||||
dependency_state[index] = 1;
|
||||
bool has_dependency_domain = false;
|
||||
std::size_t dependency_slot = unsynchronized_slot;
|
||||
for (std::size_t dependency = 0; dependency < Schema::property_count; ++dependency) {
|
||||
@@ -434,7 +452,7 @@ Resolved_Synchronization_Plan<Schema::property_count> resolve_synchronization_pl
|
||||
}
|
||||
}
|
||||
resolved.lock_slots[index] = has_dependency_domain ? dependency_slot : unsynchronized_slot;
|
||||
dependency_state[index] = 2;
|
||||
dependency_resolved[index] = true;
|
||||
return resolved.lock_slots[index];
|
||||
};
|
||||
for (std::size_t index = 0; index < Schema::property_count; ++index) {
|
||||
@@ -512,10 +530,13 @@ bool visit_schema_property(const Schema& schema, std::string_view key_value, Fun
|
||||
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>...>;
|
||||
static_assert(Valid_Property_Schema<schema_type>);
|
||||
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)...}};
|
||||
static_cast<void>(resolve_synchronization_plan(schema, schema.synchronization_plan()));
|
||||
if constexpr (valid_schema) {
|
||||
static_cast<void>(resolve_synchronization_plan(schema, schema.synchronization_plan()));
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
template <class Object, class Defaults, class Source, class... Properties>
|
||||
|
||||
Reference in New Issue
Block a user