#pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace structive { enum class Synchronization_Default { independent, shared, unsynchronized }; struct Sync_Default_Rule { Synchronization_Default value{Synchronization_Default::independent}; }; struct Sync_Property_Rule { enum class Mode { independent, unsynchronized }; Mode mode{Mode::independent}; std::string property; }; struct Sync_Group_Rule { std::string name; std::vector properties; }; template struct Sync_Member_Rule { static constexpr auto member = Member; static constexpr auto mode = Mode; }; template struct Sync_Member_Group_Rule { static_assert(sizeof...(Members) > 0); std::string name; }; inline constexpr Sync_Default_Rule sync_all_independent{Synchronization_Default::independent}; inline constexpr Sync_Default_Rule sync_all_shared{Synchronization_Default::shared}; inline constexpr Sync_Default_Rule sync_all_unsynchronized{Synchronization_Default::unsynchronized}; inline Sync_Property_Rule sync_independent(std::string_view property) { return {Sync_Property_Rule::Mode::independent, std::string(property)}; } inline Sync_Property_Rule sync_unsynchronized(std::string_view property) { return {Sync_Property_Rule::Mode::unsynchronized, std::string(property)}; } template constexpr auto sync_independent() { return Sync_Member_Rule{}; } template constexpr auto sync_unsynchronized() { return Sync_Member_Rule{}; } template Sync_Member_Group_Rule sync_group(std::string_view name) { return {std::string(name)}; } template Sync_Group_Rule sync_group(std::string_view name, Properties&&... properties) requires (std::convertible_to && ...) { Sync_Group_Rule rule; rule.name = name; rule.properties.reserve(sizeof...(Properties)); (rule.properties.emplace_back(std::string_view(std::forward(properties))), ...); return rule; } class Synchronization_Plan { Synchronization_Default default_mode_{Synchronization_Default::independent}; std::vector property_rules_; std::vector group_rules_; public: using synchronization_plan_tag = void; Synchronization_Plan() = default; explicit Synchronization_Plan(Synchronization_Default mode) : default_mode_(mode) {} Synchronization_Default default_mode() const noexcept { return default_mode_; } const auto& property_rules() const noexcept { return property_rules_; } const auto& group_rules() const noexcept { return group_rules_; } Synchronization_Plan& set_default(Synchronization_Default mode) { default_mode_ = mode; return *this; } Synchronization_Plan& independent(std::string_view property) { property_rules_.push_back(sync_independent(property)); return *this; } Synchronization_Plan& unsynchronized(std::string_view property) { property_rules_.push_back(sync_unsynchronized(property)); return *this; } Synchronization_Plan& group(std::string_view name, std::span properties) { Sync_Group_Rule rule; rule.name = name; rule.properties.reserve(properties.size()); for (auto property : properties) { rule.properties.emplace_back(property); } group_rules_.push_back(std::move(rule)); return *this; } Synchronization_Plan& group(std::string_view name, std::initializer_list properties) { return group(name, std::span{properties.begin(), properties.size()}); } Synchronization_Plan& apply(Sync_Default_Rule rule) { default_mode_ = rule.value; return *this; } Synchronization_Plan& apply(Sync_Property_Rule rule) { property_rules_.push_back(std::move(rule)); return *this; } Synchronization_Plan& apply(Sync_Group_Rule rule) { group_rules_.push_back(std::move(rule)); return *this; } }; template concept Synchronization_Plan_Type = requires { typename Type::synchronization_plan_tag; }; template concept Runtime_Synchronization_Rule = std::same_as, Sync_Default_Rule> || std::same_as, Sync_Property_Rule> || std::same_as, Sync_Group_Rule>; template struct Synchronization_Spec { using synchronization_spec_tag = void; std::tuple rules; }; template concept Synchronization_Spec_Type = requires { typename Type::synchronization_spec_tag; }; template concept Synchronization_Source_Type = Synchronization_Plan_Type || Synchronization_Spec_Type; template auto synchronization(Rules&&... rules) { if constexpr ((Runtime_Synchronization_Rule && ...)) { Synchronization_Plan plan; (plan.apply(std::forward(rules)), ...); return plan; } else { return Synchronization_Spec...>{{std::forward(rules)...}}; } } template struct Resolved_Synchronization_Plan { static constexpr std::size_t unsynchronized_slot = std::numeric_limits::max(); std::array lock_slots{}; std::size_t lock_count{}; constexpr std::size_t slot(std::size_t property_index) const noexcept { return lock_slots[property_index]; } constexpr bool uses_lock(std::size_t property_index) const noexcept { return slot(property_index) != unsynchronized_slot; } }; }