diff --git a/.gitignore b/.gitignore index ba0492f..a380c9b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ /render_2D/render_2D_old/ /uploads/ +/render_3D/render_3D_old/ +/render_3D/tests_old/ diff --git a/kernel/kernel/include/event/Event.cpp b/kernel/kernel/include/event/Event.cpp new file mode 100644 index 0000000..c587d02 --- /dev/null +++ b/kernel/kernel/include/event/Event.cpp @@ -0,0 +1,29 @@ +#include "Event.hpp" +#include +namespace aethera { +namespace { +std::uint64_t event_steady_time_ns() noexcept { + return static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); +} +} // namespace + +Event::Event(Event_Type type) : Event(type, Event_Timeline_Time{event_steady_time_ns()}) {} + +Event::Event(Event_Type type, Event_Timeline_Time occurred_at) : type(type), occurred_at(occurred_at) {} + +Event::~Event() = default; + +Event::Event(Event&& other) noexcept : type(other.type), occurred_at(other.occurred_at), accepted(other.accepted) {} + +void Event::accept() noexcept { + accepted = true; +} + +bool Event::is_accepted() const noexcept { + return accepted; +} + +Key_Event::Key_Event(Event_Type type) : Event(type) {} + +Key_Event::Key_Event(Event_Type type, Event_Timeline_Time occurred_at) : Event(type, occurred_at) {} +} // namespace aethera diff --git a/kernel/kernel/include/event/Event.hpp b/kernel/kernel/include/event/Event.hpp new file mode 100644 index 0000000..a798890 --- /dev/null +++ b/kernel/kernel/include/event/Event.hpp @@ -0,0 +1,148 @@ +#pragma once +#include +#include +#include +namespace aethera { +enum struct Event_Type : std::uint8_t { + resize, + /* 视口尺寸发生变化。 */ + show, + /* 视图进入可见状态。 */ + hide, + /* 视图进入隐藏状态。 */ + leave, + /* 指针离开当前视图。 */ + pointer_move, + /* 指针位置发生变化。 */ + pointer_press, + /* 指针按键被按下。 */ + pointer_release, + /* 指针按键被释放。 */ + wheel, + /* 指针设备产生滚轮输入。 */ + key_press, + /* 键盘按键被按下。 */ + key_release + /* 键盘按键被释放。 */ +}; + +struct Event_Timeline_Time { + std::uint64_t nanoseconds{}; /* 输入生产者时间线上的事件发生时刻。 */ + bool operator==(const Event_Timeline_Time&) const = default; +}; + +enum struct Mouse_Button : std::uint8_t { + none, + /* 不是鼠标按键事件。 */ + left, + /* 鼠标左键。 */ + right, + /* 鼠标右键。 */ + middle + /* 鼠标中键。 */ +}; +using Mouse_Button_Mask = std::uint8_t; + +enum struct Keyboard_Modifier : std::uint8_t { + none = 0, + /* 没有修饰键。 */ + control = 1 << 0, + /* Control 修饰键。 */ + shift = 1 << 1, + /* Shift 修饰键。 */ + alt = 1 << 2, + /* Alt 修饰键。 */ + meta = 1 << 3 + /* 平台 Meta 修饰键。 */ +}; + +[[nodiscard]] constexpr Keyboard_Modifier operator|(Keyboard_Modifier left, Keyboard_Modifier right) noexcept; + +enum struct Key : std::uint16_t { + unknown, + /* 未映射的按键。 */ + escape, + /* Escape。 */ + enter, + /* Enter。 */ + space, + /* Space。 */ + delete_key, + /* Delete。 */ + backspace, + /* Backspace。 */ + left, + /* 左方向键。 */ + right, + /* 右方向键。 */ + up, + /* 上方向键。 */ + down, + /* 下方向键。 */ + home + /* Home。 */ +}; + +/* Scene 独占接收的事件基类;accepted 只由 Scene 的 advance 线程修改。 */ +struct Event { + explicit Event(Event_Type type); + Event(Event_Type type, Event_Timeline_Time occurred_at); + virtual ~Event(); + Event(const Event&) = delete; + Event& operator=(const Event&) = delete; + Event(Event&&) noexcept; + Event& operator=(Event&&) noexcept = delete; + void accept() noexcept; + [[nodiscard]] bool is_accepted() const noexcept; + const Event_Type type; /* 事件的业务类型。 */ + const Event_Timeline_Time occurred_at; /* 输入生产者提供的发生时刻。 */ + private: + bool accepted{}; /* 分发链是否已经消费事件;没有跨线程访问。 */ +}; + +template +concept Event_Object = std::derived_from, Event>; +template +concept Event_Point = std::default_initializable && requires(Type value) { value.x; value.y; }; +template +concept Event_Size = std::default_initializable && requires(Type value) { value.width; value.height; }; + +template +struct Basic_Pointer_Event : Event { + explicit Basic_Pointer_Event(Event_Type type = Event_Type::pointer_move); + Basic_Pointer_Event(Event_Type type, Event_Timeline_Time occurred_at); + Point position{}; /* 接收对象局部坐标。 */ + Point global_position{}; /* 全局窗口坐标。 */ + Mouse_Button button{Mouse_Button::none}; /* 本次按下或释放的按键。 */ + Mouse_Button_Mask buttons{}; /* 事件发生时保持按下的按键集合。 */ + Keyboard_Modifier modifiers{Keyboard_Modifier::none}; /* 事件发生时的修饰键集合。 */ +}; + +template +struct Basic_Wheel_Event : Basic_Pointer_Event { + Basic_Wheel_Event(); + explicit Basic_Wheel_Event(Event_Timeline_Time occurred_at); + double angle_delta_x{}; /* 水平方向滚轮角度增量。 */ + double angle_delta_y{}; /* 垂直方向滚轮角度增量。 */ + double pixel_delta_x{}; /* 水平方向高精度像素增量。 */ + double pixel_delta_y{}; /* 垂直方向高精度像素增量。 */ +}; + +template +struct Basic_Resize_Event : Event { + Basic_Resize_Event(); + explicit Basic_Resize_Event(Event_Timeline_Time occurred_at); + Size old_size{}; /* 调整前尺寸。 */ + Size new_size{}; /* 调整后尺寸。 */ +}; + +struct Key_Event : Event { + explicit Key_Event(Event_Type type); + Key_Event(Event_Type type, Event_Timeline_Time occurred_at); + Key key{Key::unknown}; /* 标准化按键。 */ + std::uint32_t native_key{}; /* 平台原生按键编码。 */ + Keyboard_Modifier modifiers{Keyboard_Modifier::none}; /* 事件发生时的修饰键集合。 */ + bool auto_repeat{}; /* 是否由系统自动重复产生。 */ +}; +} // namespace aethera +#include "Event.ipp" diff --git a/kernel/kernel/include/event/Event.ipp b/kernel/kernel/include/event/Event.ipp new file mode 100644 index 0000000..9822251 --- /dev/null +++ b/kernel/kernel/include/event/Event.ipp @@ -0,0 +1,24 @@ +#pragma once +namespace aethera { +constexpr Keyboard_Modifier operator|(Keyboard_Modifier left, Keyboard_Modifier right) noexcept { + return static_cast(static_cast(left) | static_cast(right)); +} + +template +Basic_Pointer_Event::Basic_Pointer_Event(Event_Type type) : Event(type) {} + +template +Basic_Pointer_Event::Basic_Pointer_Event(Event_Type type, Event_Timeline_Time occurred_at) : Event(type, occurred_at) {} + +template +Basic_Wheel_Event::Basic_Wheel_Event() : Basic_Pointer_Event(Event_Type::wheel) {} + +template +Basic_Wheel_Event::Basic_Wheel_Event(Event_Timeline_Time occurred_at) : Basic_Pointer_Event(Event_Type::wheel, occurred_at) {} + +template +Basic_Resize_Event::Basic_Resize_Event() : Event(Event_Type::resize) {} + +template +Basic_Resize_Event::Basic_Resize_Event(Event_Timeline_Time occurred_at) : Event(Event_Type::resize, occurred_at) {} +} // namespace aethera diff --git a/kernel/kernel/include/global.hpp b/kernel/kernel/include/global.hpp index 667979e..552a23a 100644 --- a/kernel/kernel/include/global.hpp +++ b/kernel/kernel/include/global.hpp @@ -34,6 +34,9 @@ PRO_MEM_DISPATCH(schedule_every); PRO_MEM_DISPATCH(reschedule); PRO_MEM_DISPATCH(cancel); PRO_MEM_DISPATCH(send); +PRO_MEM_DISPATCH(event_routing_distance); +PRO_MEM_DISPATCH(dispatch_event); +PRO_MEM_DISPATCH(composite); struct Non_Copyable { protected: Non_Copyable() = default; diff --git a/kernel/kernel/include/model/Model.hpp b/kernel/kernel/include/model/Model.hpp index 933fd18..64624d2 100644 --- a/kernel/kernel/include/model/Model.hpp +++ b/kernel/kernel/include/model/Model.hpp @@ -20,20 +20,20 @@ template > struct Collect_Model_Protocols; template struct Model_Tag_Value; -template -struct Model_Registration; -template -using Model_Value = typename Model_Registration::Type::template Value; +template +struct Find_Model_Entry; +template +using Model_Value = typename Find_Model_Entry::Type::template Value; template -using Registered_Model_Value = Model_Value; +using Materialized_Model_Value = Model_Value; template -using Registered_Model_Attachment = typename Model_Registration::Type::template Attachment; +using Materialized_Model_Attachment = typename Find_Model_Entry::Type::template Attachment; template struct Is_Model_Tag_Protocol : std::false_type {}; template concept Model_Tag_Uses_Protocol = Is_Model_Tag_Protocol::value; -template concept Model_Registration_Group = requires { typename Registration::Entries; }; +template concept Model_Attachment_Definition = requires { typename Definition::Entries; }; /* 三种选择器共用一套递归,避免为 Model、Builder、Private 分别维护组合算法。 */ struct Select_Model_API; struct Select_Model_Builder_API; @@ -42,11 +42,15 @@ template +template struct Endpoint_Attachments; template struct Model_State; -template +template +struct Concurrent_Private_View; +template +struct Concurrent_Const_Private_View; +template struct Model_Definition; /* 所有 Private 层通过这个虚基类指向 Root 唯一拥有的 endpoint state。 */ struct Model_Instance; @@ -61,6 +65,9 @@ struct Model_Private_Base; template typename Endpoint::Private& model_private(Endpoint& model) noexcept; template const typename Endpoint::Private& model_private(const Endpoint& model) noexcept; template inline constexpr unsigned char Model_Private_Type_Token{}; +template inline constexpr unsigned char Model_Tag_Type_Token{}; +template auto& model_attachment(Endpoint& model) noexcept; +template const auto& model_attachment(const Endpoint& model) noexcept; template struct Model_Private_Pointer { @@ -74,6 +81,10 @@ struct Model_State_Operations { void operator()(void* value) const noexcept; void (*destroy)(void*) noexcept {}; /* 与被擦除的实际 endpoint state 匹配。 */ void* (*resolve_private)(void*, const void*) noexcept {}; /* 将 Root 唯一 state 调整为请求层的 Private。 */ + void (*advance_concurrent)(void*, const void*) {}; /* 按 Tag 推进实际 endpoint 的并发附件。 */ + void* (*resolve_concurrent_value)(void*, const void*, const void*) noexcept {}; /* 将实际值调整为请求定义层的值基类。 */ + const void* (*resolve_const_concurrent_value)(const void*, const void*, const void*) noexcept {}; /* 只读解析不得触发附件写访问。 */ + void (*write_concurrent_value)(void*, const void*, const void*, void (*)(void*, void*), void*) {}; /* 在实际附件写入边界编辑请求层值。 */ }; struct Model_Instance { @@ -92,10 +103,22 @@ struct Model_Instance { friend struct Model_Builder_Instance; template friend typename Endpoint::Private& model_private(Endpoint& model) noexcept; template friend const typename Endpoint::Private& model_private(const Endpoint& model) noexcept; + template friend auto& model_attachment(Endpoint& model) noexcept; + template friend const auto& model_attachment(const Endpoint& model) noexcept; + template + friend struct Concurrent_Private_View; + template + friend struct Concurrent_Const_Private_View; template void initialize_endpoint(Args&&... args); template - Model_State& state() noexcept; + Model_State& state() noexcept; + template + const Model_State& state() const noexcept; + void advance_concurrent(const void* tag); + [[nodiscard]] void* resolve_concurrent_value(const void* tag, const void* layer) const noexcept; + [[nodiscard]] const void* resolve_const_concurrent_value(const void* tag, const void* layer) const noexcept; + void write_concurrent_value(const void* tag, const void* layer, void (*write)(void*, void*), void* context); std::unique_ptr state_owner; /* 唯一拥有实际 Private、附件及类型操作。 */ }; @@ -121,8 +144,8 @@ struct State_Tag { }; struct Root : detail::Model_Instance { - using Model_Layers = detail::Model_Type_List<>; - using Model_Registrations = detail::Model_Type_List<>; + using Model_Layers = detail::Model_Type_List<>; + using Model_Entries = detail::Model_Type_List<>; struct Private {}; protected: @@ -131,15 +154,15 @@ struct Root : detail::Model_Instance { }; /* 业务定义直接使用 Prev、Prev_Private 和 Builder;其余别名只供框架递归。 */ -template -struct Def : detail::Model_Definition::Public_Base { +template +struct Def : detail::Model_Definition::Public_Base { private: - using Definition = detail::Model_Definition; + using Definition = detail::Model_Definition; public: - using Model_Layers = typename detail::Merge_Model_Type_Lists>::Type; - using Model_Registrations = typename Definition::Registration_List; + using Model_Layers = typename detail::Merge_Model_Type_Lists>::Type; + using Model_Entries = typename Definition::Entry_List; template - using Prev = detail::Model_Value; + using Prev = detail::Model_Value; using Prev_Private = typename Definition::Private_Base; struct Builder : Definition::Builder_Base { diff --git a/kernel/kernel/include/model/Model.ipp b/kernel/kernel/include/model/Model.ipp index fd0b5f7..1260a9d 100644 --- a/kernel/kernel/include/model/Model.ipp +++ b/kernel/kernel/include/model/Model.ipp @@ -42,19 +42,19 @@ struct Model_Tag_Value; }; -/* 从完整注册链中定位 Tag;没有匹配项时保持未定义,让 requires 正常拒绝调用。 */ +/* 从完整附件项链中定位 Tag;没有匹配项时保持未定义,让 requires 正常拒绝调用。 */ template requires std::same_as -struct Model_Registration> { +struct Find_Model_Entry> { using Type = Entry; }; template requires (!std::same_as) -struct Model_Registration> : Model_Registration> {}; +struct Find_Model_Entry> : Find_Model_Entry> {}; template -struct Is_Model_Tag_Protocol::Type>> : std::bool_constant::Type::Protocol, Protocol>> {}; +struct Is_Model_Tag_Protocol::Type>> : std::bool_constant::Type::Protocol, Protocol>> {}; -template +template struct Unique_Model_Tags; template <> @@ -64,13 +64,13 @@ template struct Unique_Model_Tags> : std::bool_constant<(!std::same_as && ...) && Unique_Model_Tags>::value> {}; template -struct Materialized_Model_Attachment { +struct Materialized_Model_Entry { static_assert(Entry::template Valid, "registered attachment does not satisfy its protocol"); using Type = Model_Attachment>; }; template -struct Endpoint_Attachments> : Model_Attachment_Set::Type...> { +struct Endpoint_Attachments> : Model_Attachment_Set::Type...> { static_assert(Unique_Model_Tags>::value, "each model attachment tag can only be registered once"); }; @@ -100,11 +100,11 @@ struct Compose_Model_APIs>::Type; }; -/* 一次计算当前 Def 的注册链和协议表,三类 API 都从同一结果组合。 */ -template +/* 一次计算当前 Def 的附件项链和协议表,三类 API 都从同一结果组合。 */ +template struct Model_Definition { - using Registration_List = typename Merge_Model_Type_Lists::Type; - using Protocol_List = typename Collect_Model_Protocols::Type; + using Entry_List = typename Merge_Model_Type_Lists::Type; + using Protocol_List = typename Collect_Model_Protocols::Type; using Public_Base = typename Compose_Model_APIs::Type; using Private_Core = Model_Private_Base; using Private_Base = typename Compose_Model_APIs::Type; @@ -121,7 +121,7 @@ struct Model_Private_Base : Base_Private, virtual Model_Private_Access_Root { }; template -struct Model_State : Endpoint_Attachments { +struct Model_State : Endpoint_Attachments { template explicit Model_State(Args&&... args); typename Endpoint::Private private_data; /* 唯一实际 Private,包含完整的 Private 继承链。 */ @@ -146,6 +146,127 @@ void* resolve_model_state_private(void* state, const void* token) noexcept { return resolve_model_private(state, token, typename Endpoint::Model_Layers{}); } +template +void* adjust_model_value_to_layer(typename Entry::template Value* value, const void* layer) noexcept { + using Active_Value = typename Entry::template Value; + using Layer_Value = typename Model_Tag_Value::Type; + if constexpr (!std::same_as && std::derived_from) { + if (layer == &Model_Private_Type_Token) return static_cast(value); + } + return nullptr; +} + +template +void* adjust_model_value_to_layer(typename Entry::template Value* value, const void* layer, Model_Type_List) noexcept { + void* result{}; + ((result ? result : result = adjust_model_value_to_layer(value, layer)), ...); + return result; +} + +template +const void* adjust_const_model_value_to_layer(const typename Entry::template Value* value, const void* layer) noexcept { + using Active_Value = typename Entry::template Value; + using Layer_Value = typename Model_Tag_Value::Type; + if constexpr (!std::same_as && std::derived_from) { + if (layer == &Model_Private_Type_Token) return static_cast(value); + } + return nullptr; +} + +template +const void* adjust_const_model_value_to_layer(const typename Entry::template Value* value, const void* layer, Model_Type_List) noexcept { + const void* result{}; + ((result ? result : result = adjust_const_model_value_to_layer(value, layer)), ...); + return result; +} + +template +void advance_model_concurrent_entry(Model_State& state, const void* tag) { + if (tag != &Model_Tag_Type_Token) return; + auto& attachment = state.template get(); + if constexpr (requires { attachment.internal.advance(); }) attachment.internal.advance(); +} + +template +void advance_model_concurrent(void* state, const void* tag, Model_Type_List) { + auto& typed_state = *static_cast*>(state); + (advance_model_concurrent_entry(typed_state, tag), ...); +} + +template +void* resolve_model_concurrent_entry(Model_State& state, const void* tag, const void* layer) noexcept { + if (tag != &Model_Tag_Type_Token) return nullptr; + auto& attachment = state.template get(); + if constexpr (requires { attachment.internal.use(); }) { + auto* value = attachment.internal.use(); + return adjust_model_value_to_layer(value, layer, typename Active_Endpoint::Model_Layers{}); + } + return nullptr; +} + +template +void* resolve_model_concurrent(void* state, const void* tag, const void* layer, Model_Type_List) noexcept { + auto& typed_state = *static_cast*>(state); + void* result{}; + ((result ? result : result = resolve_model_concurrent_entry(typed_state, tag, layer)), ...); + return result; +} + +template +const void* resolve_const_model_concurrent_entry(const Model_State& state, const void* tag, const void* layer) noexcept { + if (tag != &Model_Tag_Type_Token) return nullptr; + const auto& attachment = state.template get(); + if constexpr (requires { attachment.internal.use(); }) { + const auto* value = attachment.internal.use(); + return adjust_const_model_value_to_layer(value, layer, typename Active_Endpoint::Model_Layers{}); + } + return nullptr; +} + +template +const void* resolve_const_model_concurrent(const void* state, const void* tag, const void* layer, Model_Type_List) noexcept { + const auto& typed_state = *static_cast*>(state); + const void* result{}; + ((result ? result : result = resolve_const_model_concurrent_entry(typed_state, tag, layer)), ...); + return result; +} + +template +void write_model_concurrent_entry(Model_State& state, const void* tag, const void* layer, void (*write)(void*, void*), void* context) { + if (tag != &Model_Tag_Type_Token) return; + auto& attachment = state.template get(); + auto operation = [&](auto& value) { + write(adjust_model_value_to_layer(std::addressof(value), layer, typename Active_Endpoint::Model_Layers{}), context); + }; + if constexpr (requires { attachment.set(operation); }) attachment.set(operation); +} + +template +void write_model_concurrent(void* state, const void* tag, const void* layer, void (*write)(void*, void*), void* context, Model_Type_List) { + auto& typed_state = *static_cast*>(state); + (write_model_concurrent_entry(typed_state, tag, layer, write, context), ...); +} + +template +void advance_model_state_concurrent(void* state, const void* tag) { + advance_model_concurrent(state, tag, typename Endpoint::Model_Entries{}); +} + +template +void* resolve_model_state_concurrent(void* state, const void* tag, const void* layer) noexcept { + return resolve_model_concurrent(state, tag, layer, typename Endpoint::Model_Entries{}); +} + +template +const void* resolve_const_model_state_concurrent(const void* state, const void* tag, const void* layer) noexcept { + return resolve_const_model_concurrent(state, tag, layer, typename Endpoint::Model_Entries{}); +} + +template +void write_model_state_concurrent(void* state, const void* tag, const void* layer, void (*write)(void*, void*), void* context) { + write_model_concurrent(state, tag, layer, write, context, typename Endpoint::Model_Entries{}); +} + inline Model_Instance::Model_Instance() : state_owner(nullptr, Model_State_Operations{}) {} inline Model_Instance::~Model_Instance() = default; @@ -178,7 +299,7 @@ template void Model_Instance::initialize_endpoint(Args&&... args) { auto state = std::make_unique>(std::forward(args)...); static_cast(state->private_data).instance = this; - state_owner = std::unique_ptr{state.release(), Model_State_Operations{destroy_model_state, resolve_model_state_private}}; + state_owner = std::unique_ptr{state.release(), Model_State_Operations{destroy_model_state, resolve_model_state_private, advance_model_state_concurrent, resolve_model_state_concurrent, resolve_const_model_state_concurrent, write_model_state_concurrent}}; } template @@ -186,6 +307,37 @@ Model_State& Model_Instance::state() noexcept { return *static_cast*>(state_owner.get()); } +template +const Model_State& Model_Instance::state() const noexcept { + return *static_cast*>(state_owner.get()); +} + +inline void Model_Instance::advance_concurrent(const void* tag) { + state_owner.get_deleter().advance_concurrent(state_owner.get(), tag); +} + +inline void* Model_Instance::resolve_concurrent_value(const void* tag, const void* layer) const noexcept { + return state_owner.get_deleter().resolve_concurrent_value(state_owner.get(), tag, layer); +} + +inline const void* Model_Instance::resolve_const_concurrent_value(const void* tag, const void* layer) const noexcept { + return state_owner.get_deleter().resolve_const_concurrent_value(state_owner.get(), tag, layer); +} + +inline void Model_Instance::write_concurrent_value(const void* tag, const void* layer, void (*write)(void*, void*), void* context) { + state_owner.get_deleter().write_concurrent_value(state_owner.get(), tag, layer, write, context); +} + +template +auto& model_attachment(Endpoint& model) noexcept { + return static_cast(model).template state().template get(); +} + +template +const auto& model_attachment(const Endpoint& model) noexcept { + return static_cast(model).template state().template get(); +} + template typename Endpoint::Private& model_private(Endpoint& model) noexcept { auto& instance = static_cast(model); @@ -226,19 +378,19 @@ std::unique_ptr Model_Builder_Instance::release_model() { } } // namespace aethera::detail namespace aethera { -template +template template -Def::Builder::Builder(First&& first, Rest&&... rest) { +Def::Builder::Builder(First&& first, Rest&&... rest) { this->initialize_model(std::forward(first), std::forward(rest)...); } -template -std::unique_ptr Def::Builder::build() { +template +std::unique_ptr Def::Builder::build() { return this->release_model(); } -template -bool Def::model_initialized() const noexcept { +template +bool Def::model_initialized() const noexcept { return this->initialized(); } diff --git a/kernel/kernel/include/model/attachment/dag/Dag_Relation.hpp b/kernel/kernel/include/model/attachment/dag/Dag_Relation.hpp index bf18d3a..c21fb8a 100644 --- a/kernel/kernel/include/model/attachment/dag/Dag_Relation.hpp +++ b/kernel/kernel/include/model/attachment/dag/Dag_Relation.hpp @@ -1,5 +1,6 @@ #pragma once #include "../../../global.hpp" +#include "../../detail/Relation_Definition.hpp" #include #include #include @@ -80,7 +81,9 @@ struct Dag_Relation::Editor { }; /* Model 可注册的拥有型 DAG 关系;内部 commit 在所有者安全点验证并提交待处理事务。 */ template -struct Owned_Dag_Relation { +struct Owned_Dag_Relation : detail::Relation_Definition, Node_Facade> { + template + using Attachment = Owned_Dag_Relation; using Graph = Dag_Relation; using Edit = std::move_only_function; using Edit_Completion = std::move_only_function)>; diff --git a/kernel/kernel/include/model/attachment/design.md b/kernel/kernel/include/model/attachment/design.md index f8dbc55..056f0a4 100644 --- a/kernel/kernel/include/model/attachment/design.md +++ b/kernel/kernel/include/model/attachment/design.md @@ -2,10 +2,10 @@ Model 的可组合能力统一分为两层: -- `model/registration` 保存协议 concept、注册项和 Model/Builder/Private 三组 CRTP API。 -- `model/attachment` 保存满足协议的具体附件实现。 +- `model/detail` 保存公共协议 concept 和 Model/Builder/Private 三组 CRTP API。 +- `model/attachment` 的每个具体类型同时定义注册项、实际存储和自己的能力来源。 -`Concurrent_Registration` 与 `Relation_Registration` 是同级协议。并发附件使用 `use/advance/builder_set` 和可选的外部 `set/get`;关系附件使用事务 `edit`、Builder 初始化 `relation` 和所有者安全点 `relation/commit`。DAG 不复用并发接口。 +`Concurrent_Definition` 与 `Relation_Definition` 是同级 CRTP 定义基类。并发附件使用 `use/advance/builder_set` 和可选的外部 `set/get`;关系附件使用事务 `edit`、Builder 初始化 `relation` 和所有者安全点 `relation/commit`。DAG 不复用并发接口。 ## 具体附件 @@ -18,12 +18,12 @@ Model 的可组合能力统一分为两层: ## 并发附件契约 -每个注册进 Model 的并发附件必须提供内部 `internal.use()`、`internal.advance()`、`internal.builder_set(...)`,外部 `set(...)`、`get(...)` 至少提供一个。`Concurrent_Registration` 向最终 endpoint 选择性附加实体 `set/get`、Builder `set` 和 Private `concurrent()`。 +每个注册进 Model 的并发附件必须提供内部 `internal.use()`、`internal.advance()`、`internal.builder_set(...)`,外部 `set(...)`、`get(...)` 至少提供一个。`Import_Struct_Concurrent` 等一段式定义直接向最终 endpoint 选择性附加实体 `set/get`、Builder `set` 和 Private `concurrent()`,并直接定义各 Tag 的实际存储。 -并发附件不提供同步等待、事件或快照。内部 `use()/advance()` 必须由同一内部线程串行调用;`use()` 返回的非拥有借用不得跨越下一次 `advance()`。外部回调在对应交换锁内执行,不得重入当前附件。 +并发附件不提供同步等待、事件或快照。内部 `use()/advance()` 必须由同一内部线程串行调用;`use()` 返回的非拥有借用不得跨越下一次 `advance()`。外部回调在对应交换锁内执行,不得重入当前附件。Private 继承链中的 `concurrent()` 是临时访问视图,由 Root 解析最终 endpoint 的唯一实际附件;需要检查附件实体本身时使用最终 Model,而不是保存该临时视图。 ## 关系附件契约 -关系附件必须提供权威 `Graph`、事务 `Edit`、事务完成回调,以及内部 `relation()`、`commit()`、`build(...)`。`Relation_Registration` 向最终 endpoint 选择性附加实体 `edit`、Builder `relation` 和 Private `relation/commit`。 +关系附件必须提供权威 `Graph`、事务 `Edit`、事务完成回调,以及内部 `relation()`、`commit()`、`build(...)`。`Owned_Dag_Relation` 自身是一段式定义和实际附件,向最终 endpoint 选择性附加实体 `edit`、Builder `relation` 和 Private `relation/commit`。 `Dag_Relation::Builder` 在构建期验证完整关系;`Dag_Relation::Editor` 只记录单次事务命令;`Owned_Dag_Relation` 由关系所有者在安全点验证并提交。编辑 completion 在调用 `commit()` 的内部线程执行,不是跨线程异常传播边界。 diff --git a/kernel/kernel/include/model/attachment/dirty/Dirty_Concurrent.hpp b/kernel/kernel/include/model/attachment/dirty/Dirty_Concurrent.hpp index cb87d79..0a652e5 100644 --- a/kernel/kernel/include/model/attachment/dirty/Dirty_Concurrent.hpp +++ b/kernel/kernel/include/model/attachment/dirty/Dirty_Concurrent.hpp @@ -49,16 +49,20 @@ struct Struct_Dirty_Concurrent_Hooks : Dirty_Concurrent_Hooks { bool pending_whole_property_dirty{}; /* 当前编辑面是否发生过整对象写入。 */ }; } -template -using Dirty_Export_Struct_Concurrent = Export_Struct_Concurrent; -template -using Dirty_Import_Struct_Concurrent = Import_Struct_Concurrent; -template -using Dirty_Import_List_Concurrent = Import_List_Concurrent; -template -using Dirty_Export_List_Concurrent = Export_List_Concurrent; -template -using Dirty_Readable_Import_Batch_Concurrent = Readable_Import_Batch_Concurrent; +template +struct Dirty_Export_Struct_Concurrent : detail::Export_Struct_Concurrent_Definition, detail::Struct_Dirty_Concurrent_Hooks, Tags...> {}; + +template +struct Dirty_Import_Struct_Concurrent : detail::Import_Struct_Concurrent_Definition, detail::Struct_Dirty_Concurrent_Hooks, Tags...> {}; + +template +struct Dirty_Import_List_Concurrent : detail::Import_List_Concurrent_Definition, detail::Dirty_Concurrent_Hooks, Tags...> {}; + +template +struct Dirty_Export_List_Concurrent : detail::Export_List_Concurrent_Definition, detail::Dirty_Concurrent_Hooks, Tags...> {}; + +template +struct Dirty_Readable_Import_Batch_Concurrent : detail::Readable_Import_Batch_Concurrent_Definition, detail::Dirty_Concurrent_Hooks, Tags...> {}; template concept Dirty_Revision_Source = requires(const Source& source) { { source.internal.dirty_revision() } noexcept -> std::same_as; }; diff --git a/kernel/kernel/include/model/attachment/list/List_Concurrent.hpp b/kernel/kernel/include/model/attachment/list/List_Concurrent.hpp index eebe12c..0151f14 100644 --- a/kernel/kernel/include/model/attachment/list/List_Concurrent.hpp +++ b/kernel/kernel/include/model/attachment/list/List_Concurrent.hpp @@ -1,72 +1,172 @@ #pragma once #include "../../../global.hpp" -#include "../../registration/Concurrent_Registration.hpp" +#include "../../detail/Concurrent_Definition.hpp" +#include #include +#include namespace aethera { +namespace detail { /* 外部写入批次,内部每次 advance 取走整批数据。 */ -template -struct Import_List_Concurrent { - template Fn> - void set(Fn&& fn); +template +struct Import_List_Concurrent_Definition : Concurrent_Definition { + template + struct Attachment { + using Value = typename Model_Tag_Value::Type; + static_assert(List_Value, "import list value must satisfy List_Value"); - struct Internal final : Concurrent_Hooks { - /* 仅同一内部线程可调用;返回借用不得保存到下一次 advance。 */ - Value* use(); - void advance(); template Fn> - void builder_set(Fn&& fn); - Value buf[2]{}; /* 两个循环复用的列表槽位。 */ - Value* internal{&buf[0]}; /* 当前内部角色的非拥有借用。 */ - Value* external{&buf[1]}; /* 当前外部角色的非拥有借用。 */ - mutable std::mutex exchange_mutex; /* 保护外部访问、角色交换和复用槽清理。 */ - }; + void set(Fn&& fn) { + std::lock_guard lock(internal.exchange_mutex); + if constexpr (requires { internal.on_write_access(); }) internal.on_write_access(); + std::invoke(std::forward(fn), *internal.external); + } - Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ + struct Internal final : Concurrent_Hooks { + Value* use() { + return internal; + } + const Value* use() const { + return internal; + } + void advance() { + std::lock_guard lock(exchange_mutex); + Value* const internal_before = internal; + Value* const external_before = external; + static_assert(noexcept(this->before_advance(internal_before, external_before))); + this->before_advance(internal_before, external_before); + std::swap(internal, external); + external->clear(); + static_assert(noexcept(this->after_advance(internal_before, external_before))); + this->after_advance(internal_before, external_before); + } + template Fn> + void builder_set(Fn&& fn) { + std::invoke(std::forward(fn), *internal); + } + + Value buf[2]{}; /* 两个循环复用的列表槽位。 */ + Value* internal{&buf[0]}; /* 当前内部角色的非拥有借用。 */ + Value* external{&buf[1]}; /* 当前外部角色的非拥有借用。 */ + mutable std::mutex exchange_mutex; /* 保护外部访问、角色交换和复用槽清理。 */ + }; + + Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ + }; }; /* 内部生产批次,外部读取最近一次 advance 发布的整批数据。 */ -template -struct Export_List_Concurrent { - template Fn> - void get(Fn&& fn) const; +template +struct Export_List_Concurrent_Definition : Concurrent_Definition { + template + struct Attachment { + using Value = typename Model_Tag_Value::Type; + static_assert(List_Value, "export list value must satisfy List_Value"); - struct Internal final : Concurrent_Hooks { - /* 仅同一内部线程可调用;可写借用会记录本轮修改,且不得跨越 advance。 */ - Value* use(); - void advance(); - template Fn> - void builder_set(Fn&& fn); - Value buf[2]{}; /* 两个循环复用的列表槽位。 */ - Value* internal{&buf[0]}; /* 当前内部角色的非拥有借用。 */ - Value* external{&buf[1]}; /* 当前外部角色的非拥有借用。 */ - mutable std::mutex exchange_mutex; /* 保护外部访问、角色交换和复用槽清理。 */ + template Fn> + void get(Fn&& fn) const { + std::lock_guard lock(internal.exchange_mutex); + std::invoke(std::forward(fn), std::as_const(*internal.external)); + } + + struct Internal final : Concurrent_Hooks { + Value* use() { + if constexpr (requires { this->on_write_access(); }) this->on_write_access(); + return internal; + } + const Value* use() const { + return internal; + } + void advance() { + std::lock_guard lock(exchange_mutex); + Value* const internal_before = internal; + Value* const external_before = external; + static_assert(noexcept(this->before_advance(internal_before, external_before))); + this->before_advance(internal_before, external_before); + std::swap(internal, external); + internal->clear(); + static_assert(noexcept(this->after_advance(internal_before, external_before))); + this->after_advance(internal_before, external_before); + } + template Fn> + void builder_set(Fn&& fn) { + std::invoke(std::forward(fn), *internal); + } + + Value buf[2]{}; /* 两个循环复用的列表槽位。 */ + Value* internal{&buf[0]}; /* 当前内部角色的非拥有借用。 */ + Value* external{&buf[1]}; /* 当前外部角色的非拥有借用。 */ + mutable std::mutex exchange_mutex; /* 保护外部访问、角色交换和复用槽清理。 */ + }; + + Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ }; - - Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ }; -/* 外部写入批次,内部消费后仍保留上一批供外部诊断读取。 */ -template -struct Readable_Import_Batch_Concurrent { - template Fn> - void set(Fn&& fn); - template Fn> - void get(Fn&& fn) const; +/* 外部写入批次,内部消费后保留上一批供外部诊断读取。 */ +template +struct Readable_Import_Batch_Concurrent_Definition : Concurrent_Definition { + template + struct Attachment { + using Value = typename Model_Tag_Value::Type; + static_assert(List_Value, "readable import batch value must satisfy List_Value"); - struct Internal final : Concurrent_Hooks { - /* 仅同一内部线程可调用;返回借用不得保存到下一次 advance。 */ - Value* use(); - void advance(); template Fn> - void builder_set(Fn&& fn); - Value buf[3]{}; /* 写入、内部消费、外部查询三个循环槽位。 */ - Value* external_write{&buf[0]}; /* 外部线程写入面的非拥有借用。 */ - Value* internal_read{&buf[1]}; /* 内部线程消费面的非拥有借用。 */ - Value* external_read{&buf[2]}; /* 外部线程查询面的非拥有借用。 */ - mutable std::mutex exchange_mutex; /* 保护两个外部角色、角色轮换和复用槽清理。 */ - }; + void set(Fn&& fn) { + std::lock_guard lock(internal.exchange_mutex); + if constexpr (requires { internal.on_write_access(); }) internal.on_write_access(); + std::invoke(std::forward(fn), *internal.external_write); + } + template Fn> + void get(Fn&& fn) const { + std::lock_guard lock(internal.exchange_mutex); + std::invoke(std::forward(fn), std::as_const(*internal.external_read)); + } - Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ + struct Internal final : Concurrent_Hooks { + Value* use() { + return internal_read; + } + const Value* use() const { + return internal_read; + } + void advance() { + std::lock_guard lock(exchange_mutex); + Value* const external_write_before = external_write; + Value* const internal_read_before = internal_read; + Value* const external_read_before = external_read; + static_assert(noexcept(this->before_advance(external_write_before, internal_read_before, external_read_before))); + this->before_advance(external_write_before, internal_read_before, external_read_before); + Value* const reuse = external_read; + external_read = internal_read; + internal_read = external_write; + external_write = reuse; + external_write->clear(); + static_assert(noexcept(this->after_advance(external_write_before, internal_read_before, external_read_before))); + this->after_advance(external_write_before, internal_read_before, external_read_before); + } + template Fn> + void builder_set(Fn&& fn) { + std::invoke(std::forward(fn), *internal_read); + } + + Value buf[3]{}; /* 写入、内部消费、外部查询三个循环槽位。 */ + Value* external_write{&buf[0]}; /* 外部线程写入面的非拥有借用。 */ + Value* internal_read{&buf[1]}; /* 内部线程消费面的非拥有借用。 */ + Value* external_read{&buf[2]}; /* 外部线程查询面的非拥有借用。 */ + mutable std::mutex exchange_mutex; /* 保护两个外部角色、角色轮换和复用槽清理。 */ + }; + + Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ + }; }; +} // namespace detail + +template +struct Import_List_Concurrent : detail::Import_List_Concurrent_Definition, detail::No_Concurrent_Hooks, Tags...> {}; + +template +struct Export_List_Concurrent : detail::Export_List_Concurrent_Definition, detail::No_Concurrent_Hooks, Tags...> {}; + +template +struct Readable_Import_Batch_Concurrent : detail::Readable_Import_Batch_Concurrent_Definition, detail::No_Concurrent_Hooks, Tags...> {}; } // namespace aethera -#include "List_Concurrent.ipp" diff --git a/kernel/kernel/include/model/attachment/list/List_Concurrent.ipp b/kernel/kernel/include/model/attachment/list/List_Concurrent.ipp deleted file mode 100644 index 2d2be9e..0000000 --- a/kernel/kernel/include/model/attachment/list/List_Concurrent.ipp +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once -#include -#include -namespace aethera { -template -template Fn> -void Import_List_Concurrent::set(Fn&& fn) { - std::lock_guard lock(internal.exchange_mutex); - if constexpr (requires { internal.on_write_access(); }) { - internal.on_write_access(); - } - std::invoke(std::forward(fn), *internal.external); -} - -template -template Fn> -void Import_List_Concurrent::Internal::builder_set(Fn&& fn) { - std::invoke(std::forward(fn), *internal); -} - -template -Value* Import_List_Concurrent::Internal::use() { - return this->internal; -} - -template -void Import_List_Concurrent::Internal::advance() { - std::lock_guard lock(exchange_mutex); - Value* const internal_before = this->internal; - Value* const external_before = this->external; - static_assert(noexcept(this->before_advance(internal_before, external_before))); - this->before_advance(internal_before, external_before); - std::swap(this->internal, this->external); - this->external->clear(); - static_assert(noexcept(this->after_advance(internal_before, external_before))); - this->after_advance(internal_before, external_before); -} - -template -template Fn> -void Export_List_Concurrent::get(Fn&& fn) const { - std::lock_guard lock(internal.exchange_mutex); - std::invoke(std::forward(fn), std::as_const(*internal.external)); -} - -template -template Fn> -void Export_List_Concurrent::Internal::builder_set(Fn&& fn) { - std::invoke(std::forward(fn), *internal); -} - -template -Value* Export_List_Concurrent::Internal::use() { - if constexpr (requires { this->on_write_access(); }) { - this->on_write_access(); - } - return this->internal; -} - -template -void Export_List_Concurrent::Internal::advance() { - std::lock_guard lock(exchange_mutex); - Value* const internal_before = this->internal; - Value* const external_before = this->external; - static_assert(noexcept(this->before_advance(internal_before, external_before))); - this->before_advance(internal_before, external_before); - std::swap(this->internal, this->external); - this->internal->clear(); - static_assert(noexcept(this->after_advance(internal_before, external_before))); - this->after_advance(internal_before, external_before); -} - -template -template Fn> -void Readable_Import_Batch_Concurrent::set(Fn&& fn) { - std::lock_guard lock(internal.exchange_mutex); - if constexpr (requires { internal.on_write_access(); }) { - internal.on_write_access(); - } - std::invoke(std::forward(fn), *internal.external_write); -} - -template -template Fn> -void Readable_Import_Batch_Concurrent::get(Fn&& fn) const { - std::lock_guard lock(internal.exchange_mutex); - std::invoke(std::forward(fn), std::as_const(*internal.external_read)); -} - -template -template Fn> -void Readable_Import_Batch_Concurrent::Internal::builder_set(Fn&& fn) { - std::invoke(std::forward(fn), *internal_read); -} - -template -Value* Readable_Import_Batch_Concurrent::Internal::use() { - return internal_read; -} - -template -void Readable_Import_Batch_Concurrent::Internal::advance() { - std::lock_guard lock(exchange_mutex); - Value* const external_write_before = external_write; - Value* const internal_read_before = internal_read; - Value* const external_read_before = external_read; - static_assert(noexcept(this->before_advance(external_write_before, internal_read_before, external_read_before))); - this->before_advance(external_write_before, internal_read_before, external_read_before); - Value* const reuse = external_read; - external_read = internal_read; - internal_read = external_write; - external_write = reuse; - external_write->clear(); - static_assert(noexcept(this->after_advance(external_write_before, internal_read_before, external_read_before))); - this->after_advance(external_write_before, internal_read_before, external_read_before); -} // namespace aethera -} diff --git a/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.hpp b/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.hpp index bf0c0e8..88bfe84 100644 --- a/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.hpp +++ b/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.hpp @@ -1,78 +1,141 @@ #pragma once #include "../../../global.hpp" -#include "../../registration/Concurrent_Registration.hpp" +#include "../../detail/Concurrent_Definition.hpp" +#include #include +#include namespace aethera { -/* 内部生产完整结构值,advance 后向外部发布一份稳定副本。 */ -template -struct Export_Struct_Concurrent { - template Fn> - void get(Fn&& fn) const; - template requires std::derived_from < Value +namespace detail { +/* 内部生产完整结构值,advance 后向外部发布稳定副本。 */ +template +struct Export_Struct_Concurrent_Definition : Concurrent_Definition { + template + struct Attachment { + using Value = typename Model_Tag_Value::Type; + static_assert(Exchange_Value, "export struct value must satisfy Exchange_Value"); - , - Owner - > - auto get(Member Owner::* member) const -> std::remove_cv_t; + template Fn> + void get(Fn&& fn) const { + std::lock_guard lock(internal.exchange_mutex); + std::invoke(std::forward(fn), std::as_const(internal.external_read)); + } + template requires std::derived_from + auto get(Member Owner::* member) const -> std::remove_cv_t { + std::lock_guard lock(internal.exchange_mutex); + return internal.external_read.*member; + } - struct Internal final : Concurrent_Hooks { - /* 仅同一内部线程可调用;可写借用会记录本轮修改,且不得跨越 advance。 */ - Value* use(); - void advance(); - template Fn> - void builder_set(Fn&& fn); - template T> requires std::derived_from < Value + struct Internal final : Concurrent_Hooks { + Value* use() { + if constexpr (requires { this->on_write_access(); }) this->on_write_access(); + return &internal_read; + } + const Value* use() const { + return &internal_read; + } + void advance() { + std::lock_guard lock(exchange_mutex); + Value* const internal_before = &internal_read; + Value* const external_before = &external_read; + static_assert(noexcept(this->before_advance(internal_before, external_before))); + this->before_advance(internal_before, external_before); + external_read = internal_read; + static_assert(noexcept(this->after_advance(internal_before, external_before))); + this->after_advance(internal_before, external_before); + } + template Fn> + void builder_set(Fn&& fn) { + std::invoke(std::forward(fn), internal_read); + external_read = internal_read; + } + template T> requires std::derived_from + void builder_set(Member Owner::* member, T&& value) { + internal_read.*member = std::forward(value); + external_read = internal_read; + } - , - Owner - > - void builder_set(Member Owner::* member, T&& value); - Value internal_read{}; /* 内部线程生产面。 */ - Value external_read{}; /* 外部线程稳定读面。 */ - mutable std::mutex exchange_mutex; /* 仅保护发布复制与外部读取。 */ + Value internal_read{}; /* 内部线程生产面。 */ + Value external_read{}; /* 外部线程稳定读面。 */ + mutable std::mutex exchange_mutex; /* 仅保护发布复制与外部读取。 */ + }; + + Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ }; - - Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ }; -/* 外部编辑完整结构值,advance 后为内部线程更新稳定副本。 */ -template -struct Import_Struct_Concurrent { - template Fn> - void set(Fn&& fn); - template T> requires std::derived_from < Value +/* 外部编辑完整结构值,advance 后向内部线程发布稳定副本。 */ +template +struct Import_Struct_Concurrent_Definition : Concurrent_Definition { + template + struct Attachment { + using Value = typename Model_Tag_Value::Type; + static_assert(Exchange_Value, "import struct value must satisfy Exchange_Value"); - , - Owner - > - void set(Member Owner::* member, T&& value); - template Fn> - void get(Fn&& fn) const; - template requires std::derived_from < Value - - , - Owner - > - auto get(Member Owner::* member) const -> std::remove_cv_t; - - struct Internal final : Concurrent_Hooks { - /* 仅同一内部线程可调用;返回借用不得保存到下一次 advance。 */ - Value* use(); - void advance(); template Fn> - void builder_set(Fn&& fn); - template T> requires std::derived_from < Value + void set(Fn&& fn) { + std::lock_guard lock(internal.exchange_mutex); + if constexpr (requires { internal.on_write_access(); }) internal.on_write_access(); + std::invoke(std::forward(fn), internal.external_write); + } + template T> requires std::derived_from + void set(Member Owner::* member, T&& value) { + std::lock_guard lock(internal.exchange_mutex); + if constexpr (requires { internal.on_write_access(internal.external_write, member); }) internal.on_write_access(internal.external_write, member); + else if constexpr (requires { internal.on_write_access(); }) internal.on_write_access(); + internal.external_write.*member = std::forward(value); + } + template Fn> + void get(Fn&& fn) const { + std::lock_guard lock(internal.exchange_mutex); + std::invoke(std::forward(fn), std::as_const(internal.external_write)); + } + template requires std::derived_from + auto get(Member Owner::* member) const -> std::remove_cv_t { + std::lock_guard lock(internal.exchange_mutex); + return internal.external_write.*member; + } - , - Owner - > - void builder_set(Member Owner::* member, T&& value); - Value internal_read{}; /* 内部线程稳定读面。 */ - Value external_write{}; /* 外部线程编辑面。 */ - mutable std::mutex exchange_mutex; /* 仅保护外部编辑与内部推进复制。 */ + struct Internal final : Concurrent_Hooks { + Value* use() { + return &internal_read; + } + const Value* use() const { + return &internal_read; + } + void advance() { + std::lock_guard lock(exchange_mutex); + Value* const internal_before = &internal_read; + Value* const external_before = &external_write; + static_assert(noexcept(this->before_advance(internal_before, external_before))); + this->before_advance(internal_before, external_before); + internal_read = external_write; + static_assert(noexcept(this->after_advance(internal_before, external_before))); + this->after_advance(internal_before, external_before); + } + template Fn> + void builder_set(Fn&& fn) { + std::invoke(std::forward(fn), internal_read); + external_write = internal_read; + } + template T> requires std::derived_from + void builder_set(Member Owner::* member, T&& value) { + internal_read.*member = std::forward(value); + external_write = internal_read; + } + + Value internal_read{}; /* 内部线程稳定读面。 */ + Value external_write{}; /* 外部线程编辑面。 */ + mutable std::mutex exchange_mutex; /* 仅保护外部编辑与内部推进复制。 */ + }; + + Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ }; - - Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */ }; +} // namespace detail + +template +struct Export_Struct_Concurrent : detail::Export_Struct_Concurrent_Definition, detail::No_Concurrent_Hooks, Tags...> {}; + +template +struct Import_Struct_Concurrent : detail::Import_Struct_Concurrent_Definition, detail::No_Concurrent_Hooks, Tags...> {}; } // namespace aethera -#include "Struct_Concurrent.ipp" diff --git a/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.ipp b/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.ipp deleted file mode 100644 index 94fb631..0000000 --- a/kernel/kernel/include/model/attachment/structure/Struct_Concurrent.ipp +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once -#include -#include -namespace aethera { -template -template Fn> -void Export_Struct_Concurrent::get(Fn&& fn) const { - std::lock_guard lock(internal.exchange_mutex); - std::invoke(std::forward(fn), std::as_const(internal.external_read)); -} - -template -template requires std::derived_from -auto Export_Struct_Concurrent::get(Member Owner::* member) const -> std::remove_cv_t { - std::lock_guard lock(internal.exchange_mutex); - return internal.external_read.*member; -} - -template -Value* Export_Struct_Concurrent::Internal::use() { - if constexpr (requires { this->on_write_access(); }) { - this->on_write_access(); - } - return &internal_read; -} - -template -void Export_Struct_Concurrent::Internal::advance() { - std::lock_guard lock(exchange_mutex); - Value* const internal_before = &internal_read; - Value* const external_before = &external_read; - static_assert(noexcept(this->before_advance(internal_before, external_before))); - this->before_advance(internal_before, external_before); - external_read = internal_read; - static_assert(noexcept(this->after_advance(internal_before, external_before))); - this->after_advance(internal_before, external_before); -} - -template -template Fn> -void Export_Struct_Concurrent::Internal::builder_set(Fn&& fn) { - std::invoke(std::forward(fn), internal_read); - external_read = internal_read; -} - -template -template T> requires std::derived_from -void Export_Struct_Concurrent::Internal::builder_set(Member Owner::* member, T&& value) { - internal_read.*member = std::forward(value); - external_read = internal_read; -} - -template -template Fn> -void Import_Struct_Concurrent::set(Fn&& fn) { - std::lock_guard lock(internal.exchange_mutex); - if constexpr (requires { internal.on_write_access(); }) { - internal.on_write_access(); - } - std::invoke(std::forward(fn), internal.external_write); -} - -template -template T> requires std::derived_from -void Import_Struct_Concurrent::set(Member Owner::* member, T&& value) { - std::lock_guard lock(internal.exchange_mutex); - if constexpr (requires { internal.on_write_access(internal.external_write, member); }) { - internal.on_write_access(internal.external_write, member); - } - else if constexpr (requires { internal.on_write_access(); }) { - internal.on_write_access(); - } - internal.external_write.*member = std::forward(value); -} - -template -template Fn> -void Import_Struct_Concurrent::get(Fn&& fn) const { - std::lock_guard lock(internal.exchange_mutex); - std::invoke(std::forward(fn), std::as_const(internal.external_write)); -} - -template -template requires std::derived_from -auto Import_Struct_Concurrent::get(Member Owner::* member) const -> std::remove_cv_t { - std::lock_guard lock(internal.exchange_mutex); - return internal.external_write.*member; -} - -template -Value* Import_Struct_Concurrent::Internal::use() { - return &internal_read; -} - -template -void Import_Struct_Concurrent::Internal::advance() { - std::lock_guard lock(exchange_mutex); - Value* const internal_before = &internal_read; - Value* const external_before = &external_write; - static_assert(noexcept(this->before_advance(internal_before, external_before))); - this->before_advance(internal_before, external_before); - internal_read = external_write; - static_assert(noexcept(this->after_advance(internal_before, external_before))); - this->after_advance(internal_before, external_before); -} - -template -template Fn> -void Import_Struct_Concurrent::Internal::builder_set(Fn&& fn) { - std::invoke(std::forward(fn), internal_read); - external_write = internal_read; -} - -template -template T> requires std::derived_from -void Import_Struct_Concurrent::Internal::builder_set(Member Owner::* member, T&& value) { - internal_read.*member = std::forward(value); - external_write = internal_read; -} -} // namespace aethera diff --git a/kernel/kernel/include/model/design.md b/kernel/kernel/include/model/design.md index dda1f76..93147ed 100644 --- a/kernel/kernel/include/model/design.md +++ b/kernel/kernel/include/model/design.md @@ -1,20 +1,19 @@ # Model 设计 -`Model` 只负责定义层、注册项、附件物化和 CRTP API 组合,不认识并发结构、关系结构或任何具体容器。注册协议统一放在 -`model/registration`,具体实现统一放在 `model/attachment`;新的能力族应在 `Concurrent_Registration`、 -`Relation_Registration` 的同级位置定义自己的注册协议,不得把协议分支加回 `Model`。 +`Model` 只负责定义层、附件项物化和 CRTP API 组合,不认识并发结构、关系结构或任何具体容器。具体能力定义统一放在 +`model/attachment`,公共组合协议放在 `model/detail`;新的能力族自行提供定义基类,不得把协议分支加回 `Model`。 -每个注册协议提供以下组成部分: +每个一段式附件定义提供以下组成部分: - `Entries`:一个注册组展开得到的注册项列表。 - 注册项:定义 `Tag_Type`、`Protocol`、`Value`、`Attachment` 和 `Valid`。 - `Protocol`:分别定义 `Model_API`、`Builder_API` 和 `Private_API`。 - concept:在最终 endpoint 物化时检查具体附件是否满足该协议。 -`Def` 累计各层注册项,对协议去重,然后选择性组合协议提供的 Model、Builder 和 Private CRTP +`Def` 累计各层附件项,对协议去重,然后选择性组合协议提供的 Model、Builder 和 Private CRTP API。没有注册某协议的最终类型不会继承该协议的函数。 -实现按四步阅读即可:`Merge_Model_Type_Lists` 合并注册项,`Collect_Model_Protocols` 对协议去重,`Compose_Model_APIs` +实现按四步阅读即可:`Merge_Model_Type_Lists` 合并附件项,`Collect_Model_Protocols` 对协议去重,`Compose_Model_APIs` 复用同一递归组合三类 API,`Endpoint_Attachments` 最后物化唯一附件集合。三类 API 不再各自维护一套递归模板。 业务值类型定义在所属类内并继承 `Prev`。派生层只增量定义自己的字段,最终 endpoint 的值类型自然包含完整继承链。每层都是普通类并把自身传给 @@ -24,13 +23,15 @@ Builder 在构建具体 endpoint 时,才由公共 `Root` 一次物化该 endpo 的待发布对象是私有唯一所有权,只能通过 `build()` 移出。被继承的定义层只贡献注册、值类型和 Private 基类,不创建自己的状态。相同 Tag 重复注册属于编译期错误。 -Root 的类型擦除 state 操作表只保存一份 Private 解析器,Def 层不再保存 `d` 指针。框架内部通过零状态 +Root 的类型擦除 state 操作表保存一份 Private 与附件解析器,Def 层不再保存 `d` 指针。框架内部通过零状态 `model_private(model)` 按模型的静态层选择类型化视图;模型转换为某个基类后,仍返回同一最终 Private 对象中的对应基类子对象。Model -实体必须通过 Builder 或 Model proxy 工厂物化;普通构造只建立定义对象,不产生运行状态。 +实体必须通过 Builder 或 Model proxy 工厂物化;普通构造只建立定义对象,不产生运行状态。基础层 Private 调用 +`concurrent()` 时,Root 从最终 endpoint 的唯一附件解析实际值,再调整为该定义层的值基类视图;不得把基础 endpoint 的附件布局强转到最终 state。 跨模块 facade 直接声明消费方需要的 Private 能力。`make_model_proxy`、`make_model_proxy_shared` 与 `model_proxy_view` 分别承载独占、共享和非拥有生命周期,同时把 proxy 解引用目标映射到 Model 的唯一 Private;实体公开类不实现 facade 值转发。 -并发结构使用 `Concurrent_Registration` 注册,关系结构使用 `Relation_Registration` -注册。一个具体实现可在同一注册组连续绑定多个 Tag。Builder 和实体只写 Tag,例如 `set(...)`;具体附件类型由注册项和最终 -endpoint 唯一确定。 +具体类型自身就是一段式附件定义。例如,并发结构使用 `Import_Struct_Concurrent`,拥有型 DAG 使用 +`Owned_Dag_Relation`。业务定义不再套额外的二段式注册包装。一个并发定义可连续绑定多个 +Tag;它继承 `Concurrent_Definition`,并在内部直接定义最终 endpoint 所物化的 `Attachment`。Builder +和实体只写 Tag,例如 `set(...)`;具体附件及其存储值由该定义和最终 endpoint 唯一确定。 diff --git a/kernel/kernel/include/model/detail/Concurrent_Definition.hpp b/kernel/kernel/include/model/detail/Concurrent_Definition.hpp new file mode 100644 index 0000000..b785db8 --- /dev/null +++ b/kernel/kernel/include/model/detail/Concurrent_Definition.hpp @@ -0,0 +1,195 @@ +#pragma once +#include "../Model.hpp" +#include +#include +#include +namespace aethera { +namespace detail { +/* 用同一个最小回调检查 builder_set 与外部 set/get 是否真实存在。 */ +struct Builder_Set_Probe { + template + void operator()(Value&) const; +}; + +/* 默认推进钩子不保存状态;参数是 advance 捕获的交换前角色。 */ +struct No_Concurrent_Hooks { + template + void before_advance(const Values*...) noexcept {} + template + void after_advance(const Values*...) noexcept {} +}; +} // namespace detail + +template +concept Concurrent_Internal = requires(Attachment& attachment, const Attachment& const_attachment) { + attachment.internal.advance(); + attachment.internal.use(); + const_attachment.internal.use(); + attachment.internal.builder_set(detail::Builder_Set_Probe{}); +}; + +template +concept Concurrent_External_Set = requires(Attachment& attachment, Args&&... args) { + attachment.set(std::forward(args)...); +}; + +template +concept Concurrent_External_Get = requires(const Attachment& attachment, Args&&... args) { + attachment.get(std::forward(args)...); +}; + +template +concept Concurrent_Attachment = Concurrent_Internal && (Concurrent_External_Set || Concurrent_External_Get); + +namespace detail { +template requires Value_Writer +void initialize_concurrent_value(Value& target, Fn&& fn) { + std::invoke(std::forward(fn), target); +} + +template requires std::derived_from && std::assignable_from +void initialize_concurrent_value(Value& target, Member Owner::* member, T&& value) { + target.*member = std::forward(value); +} + +template requires std::assignable_from +void initialize_concurrent_value(Value& target, T&& value) { + target = std::forward(value); +} + +template +concept Concurrent_Value_Initializer = requires(Value& value, Args&&... args) { + initialize_concurrent_value(value, std::forward(args)...); +}; + +template +struct Concurrent_Model_API; +template +struct Concurrent_Builder_API; +template +struct Concurrent_Private_API; + +template +struct Concurrent_Private_View { + using Value = Materialized_Model_Value; + struct Internal { + void advance() { + instance->advance_concurrent(&Model_Tag_Type_Token); + } + Value* use() { + return static_cast(instance->resolve_concurrent_value(&Model_Tag_Type_Token, &Model_Private_Type_Token)); + } + const Value* use() const { + return static_cast(instance->resolve_const_concurrent_value(&Model_Tag_Type_Token, &Model_Private_Type_Token)); + } + Model_Instance* instance; /* 非拥有借用;临时视图不超过当前 Private 调用。 */ + }; + template requires Concurrent_Value_Initializer + void set(Args&&... args) { + auto operation = [&](Value& value) { initialize_concurrent_value(value, std::forward(args)...); }; + const auto invoke = [](void* value, void* context) { (*static_cast(context))(*static_cast(value)); }; + instance->write_concurrent_value(&Model_Tag_Type_Token, &Model_Private_Type_Token, invoke, std::addressof(operation)); + } + Model_Instance* instance; /* 非拥有借用;与 internal 指向同一个 Root endpoint state。 */ + Internal internal{instance}; +}; + +template +struct Concurrent_Const_Private_View { + using Value = Materialized_Model_Value; + struct Internal { + const Value* use() const { + return static_cast(instance->resolve_const_concurrent_value(&Model_Tag_Type_Token, &Model_Private_Type_Token)); + } + const Model_Instance* instance; /* 非拥有借用;临时视图不超过当前 const Private 调用。 */ + }; + const Model_Instance* instance; /* 非拥有借用;只暴露内部稳定读面。 */ + Internal internal{instance}; +}; + +struct Concurrent_Protocol { + template + using Model_API = Concurrent_Model_API; + template + using Builder_API = Concurrent_Builder_API; + template + using Private_API = Concurrent_Private_API; +}; + +/* 具体并发定义负责 Attachment;公共协议只把定义与 Tag 接入 Model。 */ +template +struct Concurrent_Entry { + using Tag_Type = Tag; + using Protocol = typename Definition::Protocol; + template + using Value = typename Model_Tag_Value::Type; + template + using Attachment = typename Definition::template Attachment; + template + static constexpr bool Valid = Concurrent_Attachment>; +}; + +template +struct Concurrent_Definition { + static_assert(sizeof...(Tags) > 0, "a concurrent definition requires at least one tag"); + using Protocol = Concurrent_Protocol; + template + using Model_API = Concurrent_Model_API; + template + using Builder_API = Concurrent_Builder_API; + template + using Private_API = Concurrent_Private_API; + using Entries = Model_Type_List...>; +}; + +template +concept Concurrent_Model_Tag = Model_Tag_Uses_Protocol; +template +concept Builder_Settable_Concurrent = Concurrent_Model_Tag && Concurrent_Internal> && Concurrent_Value_Initializer, Args...>; +template +concept Settable_Concurrent = Concurrent_Model_Tag && Concurrent_External_Set, Args...>; +template +concept Gettable_Concurrent = Concurrent_Model_Tag && Concurrent_External_Get, Args...>; + +template +struct Concurrent_Model_API : Base { + template requires Settable_Concurrent + Endpoint& set(Args&&... args) { + auto& self = static_cast(*this); + model_attachment(self).set(std::forward(args)...); + return self; + } + template requires Gettable_Concurrent + const Endpoint& get(Args&&... args) const { + const auto& self = static_cast(*this); + model_attachment(self).get(std::forward(args)...); + return self; + } +}; + +template +struct Concurrent_Builder_API : Base { + template requires Builder_Settable_Concurrent + typename Endpoint::Builder& set(Args&&... args) { + auto& builder = static_cast(*this); + auto& concurrent = model_attachment(this->model()); + concurrent.internal.builder_set([&](auto& value) { + initialize_concurrent_value(value, std::forward(args)...); + }); + return builder; + } +}; + +template +struct Concurrent_Private_API : Base { + template requires Concurrent_Model_Tag + auto concurrent() noexcept { + return Concurrent_Private_View{this->instance}; + } + template requires Concurrent_Model_Tag + auto concurrent() const noexcept { + return Concurrent_Const_Private_View{this->instance}; + } +}; +} // namespace detail +} // namespace aethera diff --git a/kernel/kernel/include/model/detail/Relation_Definition.hpp b/kernel/kernel/include/model/detail/Relation_Definition.hpp new file mode 100644 index 0000000..4fa82cc --- /dev/null +++ b/kernel/kernel/include/model/detail/Relation_Definition.hpp @@ -0,0 +1,111 @@ +#pragma once +#include "../Model.hpp" +#include +#include +namespace aethera { +namespace detail { +/* 只验证 Builder 初始化入口,不保存任何关系状态。 */ +struct Relation_Build_Probe { + template + void operator()(Relation&) const; +}; +} // namespace detail + +template +concept Relation_Attachment = requires(Attachment& attachment, typename Attachment::Graph graph, typename Attachment::Edit edit, typename Attachment::Edit_Completion completion) { + { attachment.edit(std::move(graph)) } -> std::same_as; + { attachment.edit(std::move(edit), std::move(completion)) } -> std::same_as; + { attachment.internal.relation() } -> std::same_as; + { attachment.internal.commit() } -> std::same_as; + { attachment.internal.build(detail::Relation_Build_Probe{}) } -> std::same_as; +}; + +namespace detail { +template +struct Relation_Model_API; +template +struct Relation_Builder_API; +template +struct Relation_Private_API; + +struct Relation_Protocol { + template + using Model_API = Relation_Model_API; + template + using Builder_API = Relation_Builder_API; + template + using Private_API = Relation_Private_API; +}; + +/* 关系定义本身提供 Attachment;公共协议只负责把 Tag 能力组合到 endpoint。 */ +template +struct Relation_Entry { + using Tag_Type = Tag; + using Protocol = typename Definition::Protocol; + template + using Value = Tag; + template + using Attachment = typename Definition::template Attachment; + template + static constexpr bool Valid = Relation_Attachment>; +}; + +template +struct Relation_Definition { + static_assert(sizeof...(Tags) > 0, "a relation definition requires at least one tag"); + using Protocol = Relation_Protocol; + template + using Model_API = Relation_Model_API; + template + using Builder_API = Relation_Builder_API; + template + using Private_API = Relation_Private_API; + using Entries = Model_Type_List...>; +}; + +template +concept Relation_Model_Tag = Model_Tag_Uses_Protocol; +template +concept Editable_Relation = Relation_Model_Tag && requires(Materialized_Model_Attachment& relation, Args&&... args) { + relation.edit(std::forward(args)...); +}; +template +concept Buildable_Relation = Relation_Model_Tag && std::invocable::Graph&>; + +template +struct Relation_Model_API : Base { + template requires Editable_Relation + Endpoint& edit(Args&&... args) { + auto& self = static_cast(*this); + model_private(self).template relation_attachment().edit(std::forward(args)...); + return self; + } +}; + +template +struct Relation_Builder_API : Base { + template requires Buildable_Relation + typename Endpoint::Builder& relation(Fn&& fn) { + auto& builder = static_cast(*this); + model_private(this->model()).template relation_attachment().internal.build(std::forward(fn)); + return builder; + } +}; + +template +struct Relation_Private_API : Base { + template requires Relation_Model_Tag + auto& relation_attachment() noexcept { + return this->template attachment(); + } + template requires Relation_Model_Tag + auto& relation() noexcept { + return this->template attachment().internal.relation(); + } + template requires Relation_Model_Tag + void commit() { + this->template attachment().internal.commit(); + } +}; +} // namespace detail +} // namespace aethera diff --git a/kernel/kernel/include/model/registration/Concurrent_Registration.hpp b/kernel/kernel/include/model/registration/Concurrent_Registration.hpp deleted file mode 100644 index e7bb9ac..0000000 --- a/kernel/kernel/include/model/registration/Concurrent_Registration.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once -#include "../Model.hpp" -#include -#include -#include -namespace aethera { -namespace detail { -/* 用同一个最小回调检查 builder_set 与外部 set/get 是否真实存在。 */ -struct Builder_Set_Probe { - template - void operator()(Value&) const; -}; - -/* 默认推进钩子:不记录状态;参数是 advance 入口捕获的交换前角色。 */ -struct No_Concurrent_Hooks { - template - void before_advance(const Values*... before) noexcept; - template - void after_advance(const Values*... before) noexcept; -}; -} // namespace detail -template concept Concurrent_Internal = requires(Attachment& attachment) { - attachment.internal.advance(); attachment.internal.use(); attachment.internal.builder_set(detail::Builder_Set_Probe{}); -}; -template concept Concurrent_External_Set = requires(Attachment& attachment, Args&&... args) { - attachment.set(std::forward(args)...); -}; -template concept Concurrent_External_Get = requires(const Attachment& attachment, Args&&... args) { - attachment.get(std::forward(args)...); -}; -template concept Concurrent_Attachment = Concurrent_Internal && (Concurrent_External_Set || Concurrent_External_Get); -namespace detail { -/* Builder 支持回调、成员指针和值三种初始化形式,最终都归一为回调。 */ -template requires Value_Writer -void initialize_concurrent_value(Value& target, Fn&& fn); -template requires std::derived_from && std::assignable_from -void initialize_concurrent_value(Value& target, Member Owner::* member, T&& value); -template requires std::assignable_from -void initialize_concurrent_value(Value& target, T&& value); -template concept Concurrent_Value_Initializer = requires(Value& value, Args&&... args) { initialize_concurrent_value(value, std::forward(args)...); }; -template -struct Concurrent_Model_API; -template -struct Concurrent_Builder_API; -template -struct Concurrent_Private_API; - -struct Concurrent_Protocol { - template - using Model_API = Concurrent_Model_API; - template - using Builder_API = Concurrent_Builder_API; - template - using Private_API = Concurrent_Private_API; -}; - -template