模板改好

This commit is contained in:
2026-09-02 22:28:42 +08:00
parent 7c36b35179
commit a7b56b8785
30 changed files with 107 additions and 170 deletions
@@ -1,35 +0,0 @@
#pragma once
#include <concepts>
#include <utility>
namespace aethera {
namespace detail {
struct Builder_Set_Probe {
template <typename Value> void operator()(Value&) const;
};
}
template <typename Attachment>
concept Concurrent_Internal = requires(Attachment& attachment) {
attachment.internal.advance();
attachment.internal.use();
attachment.internal.builder_set(detail::Builder_Set_Probe{});
};
template <typename Attachment, typename... Args>
concept Concurrent_External_Set = requires(Attachment& attachment, Args&&... args) {
attachment.set(std::forward<Args>(args)...);
};
template <typename Attachment, typename... Args>
concept Concurrent_External_Get = requires(const Attachment& attachment, Args&&... args) {
attachment.get(std::forward<Args>(args)...);
};
template <typename Attachment>
concept Concurrent_Attachment = Concurrent_Internal<Attachment> && (Concurrent_External_Set<Attachment, detail::Builder_Set_Probe> || Concurrent_External_Get<Attachment, detail::Builder_Set_Probe>);
}
namespace aethera::detail {
/* 默认推进钩子:不记录状态;参数是 advance 入口捕获的交换前角色。 */
struct No_Concurrent_Hooks {
template <typename... Values> void before_advance(const Values*... before) noexcept;
template <typename... Values> void after_advance(const Values*... before) noexcept;
};
}
#include "Concurrent.ipp"
@@ -1,5 +0,0 @@
#pragma once
namespace aethera::detail {
template <typename... Values> void No_Concurrent_Hooks::before_advance(const Values*...) noexcept {}
template <typename... Values> void No_Concurrent_Hooks::after_advance(const Values*...) noexcept {}
}
@@ -1,59 +0,0 @@
# 并发结构设计
并发结构是一种可由 Model 选择性组合的协议,和关系结构同级;DAG 不属于并发结构,也不复用本协议的函数名。
## 文件职责
| 文件 | 职责 |
|---|---|
| `Concurrent.hpp` | 定义并发附件 concept 和推进钩子。 |
| `Concurrent_Registration.hpp` | 定义注册项以及 Model、Builder、Private 三组 CRTP API。 |
| `structure/Struct.hpp` | 定义结构值的导入、导出并发实现。 |
| `list/List.hpp` | 定义双槽列表和可外部查询的三槽导入批次。 |
| `dirty/Dirty.hpp` | 定义可选整体/属性 dirty revision 和绑定器。 |
| `model/detail/Attachment.hpp` | 按编译期 Tag 组合并定位所有协议共用的模型附件。 |
声明位于 `.hpp`,模板实现位于同名 `.ipp`。具体并发实现是公开的透明机制对象,不使用 View、兼容转发或额外能力标记。
## 协议
每个注册进 Model 的并发附件必须提供:
- 内部 `internal.use()`:取得当前内部角色的非拥有借用。
- 内部 `internal.advance()`:在安全点推进角色或发布值。
- 内部 `internal.builder_set(...)`:仅供 Builder 初始化尚未发布的值。
- 外部 `set(...)``get(...)` 至少一个;可同时提供。
`Concurrent_Registration<Concrete, Tags...>` 为所有 Tag 实例化同一个具体并发模板,并向最终 endpoint 选择性附加实体 `set<Tag>/get<Tag>`、Builder `set<Tag>` 和 Private `concurrent<Tag>()`。concept 直接检查真实函数,未注册 Tag 或能力不匹配的调用在编译期拒绝。
## 具体实现
| 类型 | 外部操作 | `advance()` |
|---|---|---|
| `Export_Struct_Concurrent` | 读取已发布值 | 将内部值复制到外部读面。 |
| `Import_Struct_Concurrent` | 编辑外部写面 | 将外部值复制到内部读面。 |
| `Import_List_Concurrent` | 追加外部列表 | 交换内外列表并清空复用槽。 |
| `Export_List_Concurrent` | 读取已发布列表 | 交换内外列表并清空新的内部写槽。 |
| `Readable_Import_Batch_Concurrent` | 写入新批次、查询上一内部批次 | 三槽轮换并清空新的外部写槽。 |
列表交换槽位,结构值按 `Exchange_Value` 契约复制。当前角色指针是槽位身份的唯一来源。
## 推进与 Dirty
- 各实现的 `advance()` 直接保证钩子、角色推进和 dirty 顺序,不判断业务值是否变化。
- 前置和后置钩子接收同一组交换前角色的非拥有裸指针,只在当前 `advance()` 内有效。
- List 只有整体 revisionStruct 同时提供整体 revision 和属性 revision。
- `set(member, value)` 只标记对应属性;回调写入和内部 `use()` 按整对象写入处理。
- 成员接口接受当前值类型及其公开基类的成员指针,Model 值继承链可用声明属性的原始成员指针初始化、读写和查询 dirty。
- 一次 `advance()` 最多推进一次整体 revision;属性记录最近一次发布对应的整体 revision,不维护第二套计数器。
- `Dirty_Binder` 消费一个或多个并发附件的整体 dirty;`Property_Dirty_Binder` 消费同一 Struct 附件的固定成员。
## 线程契约
- 并发附件不提供同步等待、事件或快照;Struct 的发布复制和 List 的角色交换只使用各自交换锁保护。
- 内部 `use()` 可与外部稳定角色的 `get()/set()` 并行;`advance()` 通过交换锁与同一附件的外部操作互斥。
- 同一附件的 `use()/advance()` 必须由同一内部线程串行调用。
- `use()` 返回当前内部角色的非拥有裸指针;指针不得跨越下一次 `advance()`,也不得交给其他线程。
- 钩子必须 `noexcept`,不得保存参数指针或重入同一附件。
- `get()/set()` 的回调在交换锁内执行,只允许直接访问传入值;禁止重入当前附件或调用可能反向进入所属策略的函数。
- 属性 revision 表首次使用成员写入时增长;成员写入不得与 binder 查询或 `advance()` 重叠。
@@ -1,5 +1,5 @@
#pragma once
#include "../../global.hpp"
#include "../../../global.hpp"
#include <cstdint>
#include <expected>
#include <functional>
@@ -0,0 +1,29 @@
# Model 附件设计
Model 的可组合能力统一分为两层:
- `model/registration` 保存协议 concept、注册项和 Model/Builder/Private 三组 CRTP API。
- `model/attachment` 保存满足协议的具体附件实现。
`Concurrent_Registration``Relation_Registration` 是同级协议。并发附件使用 `use/advance/builder_set` 和可选的外部 `set/get`;关系附件使用事务 `edit`、Builder 初始化 `relation` 和所有者安全点 `relation/commit`。DAG 不复用并发接口。
## 具体附件
| 文件 | 类型 | 语义 |
|---|---|---|
| `structure/Struct_Concurrent.hpp` | `Import_Struct_Concurrent``Export_Struct_Concurrent` | 结构值的导入与发布。 |
| `list/List_Concurrent.hpp` | `Import_List_Concurrent``Export_List_Concurrent``Readable_Import_Batch_Concurrent` | 双槽列表和三槽导入批次。 |
| `dirty/Dirty_Concurrent.hpp` | `Dirty_*_Concurrent`、dirty binder | 为并发附件附加整体或属性 revision。 |
| `dag/Dag_Relation.hpp` | `Dag_Relation``Owned_Dag_Relation` | 拥有节点 proxy、依赖边和待提交事务的 DAG 关系。 |
## 并发附件契约
每个注册进 Model 的并发附件必须提供内部 `internal.use()``internal.advance()``internal.builder_set(...)`,外部 `set(...)``get(...)` 至少提供一个。`Concurrent_Registration<Concrete, Tags...>` 向最终 endpoint 选择性附加实体 `set<Tag>/get<Tag>`、Builder `set<Tag>` 和 Private `concurrent<Tag>()`
并发附件不提供同步等待、事件或快照。内部 `use()/advance()` 必须由同一内部线程串行调用;`use()` 返回的非拥有借用不得跨越下一次 `advance()`。外部回调在对应交换锁内执行,不得重入当前附件。
## 关系附件契约
关系附件必须提供权威 `Graph`、事务 `Edit`、事务完成回调,以及内部 `relation()``commit()``build(...)``Relation_Registration<Relation, Tags...>` 向最终 endpoint 选择性附加实体 `edit<Tag>`、Builder `relation<Tag>` 和 Private `relation<Tag>/commit<Tag>`
`Dag_Relation::Builder` 在构建期验证完整关系;`Dag_Relation::Editor` 只记录单次事务命令;`Owned_Dag_Relation` 由关系所有者在安全点验证并提交。编辑 completion 在调用 `commit()` 的内部线程执行,不是跨线程异常传播边界。
@@ -5,8 +5,8 @@
#include <tuple>
#include <utility>
#include <vector>
#include "../list/List.hpp"
#include "../structure/Struct.hpp"
#include "../list/List_Concurrent.hpp"
#include "../structure/Struct_Concurrent.hpp"
namespace aethera {
namespace detail {
/*
@@ -90,4 +90,4 @@ struct Property_Dirty_Binder : Non_Copyable {
std::array<std::uint64_t, sizeof...(Members)> seen{}; /* 本消费者已处理的成员 revision。 */
};
}
#include "Dirty.ipp"
#include "Dirty_Concurrent.ipp"
@@ -1,6 +1,6 @@
#pragma once
#include "../../global.hpp"
#include "../Concurrent.hpp"
#include "../../../global.hpp"
#include "../../registration/Concurrent_Registration.hpp"
#include <mutex>
namespace aethera {
template <List_Value Val, typename Concurrent_Hooks = detail::No_Concurrent_Hooks> struct Import_List_Concurrent {
@@ -48,4 +48,4 @@ template <List_Value Val, typename Concurrent_Hooks = detail::No_Concurrent_Hook
Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */
};
}
#include "List.ipp"
#include "List_Concurrent.ipp"
@@ -1,6 +1,6 @@
#pragma once
#include "../../global.hpp"
#include "../Concurrent.hpp"
#include "../../../global.hpp"
#include "../../registration/Concurrent_Registration.hpp"
#include <mutex>
namespace aethera {
template <Exchange_Value Val, typename Concurrent_Hooks = detail::No_Concurrent_Hooks>
@@ -44,4 +44,4 @@ struct Import_Struct_Concurrent {
Internal internal{}; /* 内部线程入口;use/advance 必须由同一线程调用。 */
};
} // namespace aethera
#include "Struct.ipp"
#include "Struct_Concurrent.ipp"
+1 -1
View File
@@ -1,6 +1,6 @@
# Model 设计
`Model` 只负责定义层、注册项、附件物化和 CRTP API 组合,不认识并发结构、关系结构或任何具体容器。新的能力族应在 `Concurrent_Registration``Relation_Registration` 的同级位置定义自己的注册协议,不得把协议分支加回 `Model`
`Model` 只负责定义层、注册项、附件物化和 CRTP API 组合,不认识并发结构、关系结构或任何具体容器。注册协议统一放在 `model/registration`,具体实现统一放在 `model/attachment`新的能力族应在 `Concurrent_Registration``Relation_Registration` 的同级位置定义自己的注册协议,不得把协议分支加回 `Model`
每个注册协议提供以下组成部分:
@@ -1,11 +1,37 @@
#pragma once
#include "Concurrent.hpp"
#include "../model/Model.hpp"
#include "../Model.hpp"
#include <concepts>
#include <functional>
#include <type_traits>
#include <utility>
namespace aethera {
namespace detail {
struct Builder_Set_Probe {
template <typename Value> void operator()(Value&) const;
};
/* 默认推进钩子:不记录状态;参数是 advance 入口捕获的交换前角色。 */
struct No_Concurrent_Hooks {
template <typename... Values> void before_advance(const Values*... before) noexcept;
template <typename... Values> void after_advance(const Values*... before) noexcept;
};
} // namespace detail
template <typename Attachment>
concept Concurrent_Internal = requires(Attachment& attachment) {
attachment.internal.advance();
attachment.internal.use();
attachment.internal.builder_set(detail::Builder_Set_Probe{});
};
template <typename Attachment, typename... Args>
concept Concurrent_External_Set = requires(Attachment& attachment, Args&&... args) {
attachment.set(std::forward<Args>(args)...);
};
template <typename Attachment, typename... Args>
concept Concurrent_External_Get = requires(const Attachment& attachment, Args&&... args) {
attachment.get(std::forward<Args>(args)...);
};
template <typename Attachment>
concept Concurrent_Attachment = Concurrent_Internal<Attachment> && (Concurrent_External_Set<Attachment, detail::Builder_Set_Probe> || Concurrent_External_Get<Attachment, detail::Builder_Set_Probe>);
namespace detail {
template <typename Value, typename Fn> requires Value_Writer<Fn, Value> void initialize_concurrent_value(Value& target, Fn&& fn);
template <typename Value, typename Owner, typename Member, typename T> requires std::derived_from<Value, Owner> && std::assignable_from<Member&, T> void initialize_concurrent_value(Value& target, Member Owner::* member, T&& value);
template <typename Value, typename T> requires std::assignable_from<Value&, T> void initialize_concurrent_value(Value& target, T&& value);
@@ -1,5 +1,7 @@
#pragma once
namespace aethera::detail {
template <typename... Values> void No_Concurrent_Hooks::before_advance(const Values*...) noexcept {}
template <typename... Values> void No_Concurrent_Hooks::after_advance(const Values*...) noexcept {}
template <typename Value, typename Fn> requires Value_Writer<Fn, Value>
void initialize_concurrent_value(Value& target, Fn&& fn) { std::invoke(std::forward<Fn>(fn), target); }
template <typename Value, typename Owner, typename Member, typename T> requires std::derived_from<Value, Owner> && std::assignable_from<Member&, T>
@@ -1,10 +1,23 @@
#pragma once
#include "Relation.hpp"
#include "../model/Model.hpp"
#include "../Model.hpp"
#include <concepts>
#include <type_traits>
#include <utility>
namespace aethera {
namespace detail {
struct Relation_Build_Probe {
template <typename Relation> void operator()(Relation&) const;
};
} // namespace detail
template <typename Attachment>
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<void>;
{ attachment.edit(std::move(edit), std::move(completion)) } -> std::same_as<void>;
{ attachment.internal.relation() } -> std::same_as<typename Attachment::Graph&>;
{ attachment.internal.commit() } -> std::same_as<void>;
{ attachment.internal.build(detail::Relation_Build_Probe{}) } -> std::same_as<void>;
};
namespace detail {
template <typename Endpoint, typename Base> struct Relation_Model_API;
template <typename Endpoint, typename Base> struct Relation_Builder_API;
template <typename Endpoint, typename Base> struct Relation_Private_API;
@@ -1,18 +0,0 @@
#pragma once
#include <concepts>
#include <utility>
namespace aethera {
namespace detail {
struct Relation_Build_Probe {
template <typename Relation> void operator()(Relation&) const;
};
}
template <typename Attachment>
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<void>;
{ attachment.edit(std::move(edit), std::move(completion)) } -> std::same_as<void>;
{ attachment.internal.relation() } -> std::same_as<typename Attachment::Graph&>;
{ attachment.internal.commit() } -> std::same_as<void>;
{ attachment.internal.build(detail::Relation_Build_Probe{}) } -> std::same_as<void>;
};
} // namespace aethera
-14
View File
@@ -1,14 +0,0 @@
# 关系结构设计
关系结构与并发结构是同级协议,不共享 `set/get/advance` 语义。`Relation_Registration<Relation, Tags...>` 负责把一种关系实现连续注册给一个或多个 Tag,并提供三组按需组合的能力:实体侧事务 `edit<Tag>(...)`、Builder 侧 `relation<Tag>(...)` 初始化,以及 Private 侧 `relation<Tag>()/commit<Tag>()`
`Relation_Attachment` 是关系实现的约束。实现必须提供权威 `Graph`、事务 `Edit`、事务完成回调,以及内部 `relation()``commit()``build(...)`。新关系类型只要满足该协议即可注册,不需要修改 `Model`
`dag/Dag_Relation.hpp` 是 DAG 这一种具体关系实现:
- `Dag_Relation<Node_Facade>` 唯一拥有节点 proxy 和依赖边,拓扑顺序按权威关系即时计算。
- `Dag_Relation::Builder` 负责构建期整体校验。
- `Dag_Relation::Editor` 只记录单次事务命令。
- `Owned_Dag_Relation<Node_Facade>` 接收外部事务,并由关系所有者在安全点调用 `commit()` 验证和提交。
关系模块不提供同步等待、事件或快照。编辑完成回调在调用 `commit()` 的内部线程执行;调用方不得把它当成跨线程异常传播边界。
@@ -1,8 +1,8 @@
#pragma once
#include "../export/export.h"
#include "scene/export/export.h"
#include "concurrent/Concurrent_Registration.hpp"
#include "concurrent/dirty/Dirty.hpp"
#include "model/registration/Concurrent_Registration.hpp"
#include "model/attachment/dirty/Dirty_Concurrent.hpp"
#include "model/Model.hpp"
#include "statistics/Sliding_Statistics.hpp"
#include <chrono>
+2 -2
View File
@@ -1,8 +1,8 @@
#pragma once
#include "../export/export.h"
#include "model/Model.hpp"
#include "relation/dag/Dag_Relation.hpp"
#include "relation/Relation_Registration.hpp"
#include "model/attachment/dag/Dag_Relation.hpp"
#include "model/registration/Relation_Registration.hpp"
#include <functional>
#include <proxy/proxy.h>
#include "../rely_facade.h"
+4 -4
View File
@@ -1,7 +1,7 @@
#include "concurrent/Concurrent_Registration.hpp"
#include "concurrent/dirty/Dirty.hpp"
#include "concurrent/list/List.hpp"
#include "concurrent/structure/Struct.hpp"
#include "model/registration/Concurrent_Registration.hpp"
#include "model/attachment/dirty/Dirty_Concurrent.hpp"
#include "model/attachment/list/List_Concurrent.hpp"
#include "model/attachment/structure/Struct_Concurrent.hpp"
#include "model/Model.hpp"
#include <gtest/gtest.h>
#include <vector>
@@ -1,6 +1,6 @@
#include "concurrent/Concurrent.hpp"
#include "concurrent/list/List.hpp"
#include "concurrent/structure/Struct.hpp"
#include "model/registration/Concurrent_Registration.hpp"
#include "model/attachment/list/List_Concurrent.hpp"
#include "model/attachment/structure/Struct_Concurrent.hpp"
#include "model/detail/Attachment.hpp"
#include <gtest/gtest.h>
@@ -1,6 +1,6 @@
#include "model/Model.hpp"
#include "relation/Relation_Registration.hpp"
#include "relation/dag/Dag_Relation.hpp"
#include "model/registration/Relation_Registration.hpp"
#include "model/attachment/dag/Dag_Relation.hpp"
#include <gtest/gtest.h>
#include <optional>
namespace {
@@ -1,4 +1,4 @@
#include "concurrent/dirty/Dirty.hpp"
#include "model/attachment/dirty/Dirty_Concurrent.hpp"
#include <gtest/gtest.h>
@@ -1,4 +1,4 @@
#include "concurrent/list/List.hpp"
#include "model/attachment/list/List_Concurrent.hpp"
#include <gtest/gtest.h>
@@ -1,4 +1,4 @@
#include "concurrent/structure/Struct.hpp"
#include "model/attachment/structure/Struct_Concurrent.hpp"
#include <gtest/gtest.h>
+1 -3
View File
@@ -64,10 +64,8 @@ if (Aethera_BUILD_TESTS)
GTest::gtest)
append_glob_source(Aethera_Kernel_module_test_sources
"${Aethera_Kernel_test_dir}/concurrent"
"${Aethera_Kernel_test_dir}/error"
"${Aethera_Kernel_test_dir}/model"
"${Aethera_Kernel_test_dir}/relation")
"${Aethera_Kernel_test_dir}/model")
foreach (Aethera_Kernel_module_test_source IN LISTS Aethera_Kernel_module_test_sources)
if (NOT Aethera_Kernel_module_test_source MATCHES "\\.(c|cc|cpp|cxx)$")
continue()
+1 -1
View File
@@ -7,7 +7,7 @@
- 注册只描述协议、Tag 和具体附件的映射。完整注册链按 Builder 正在构建的最终 endpoint 求值,并由公共 `Root` 一次物化唯一的 `Private + Model_Attachment_Set`
- Builder 只拥有一个最终 endpoint 对象槽;被继承的 Def 层不得创建自己的 endpoint state、对象副本或附件。每层 `d` 只是同一 Root 状态的非拥有 Private 视图。
- Model 实体必须通过 `Builder``make_model_proxy` 或接收已完成 Builder 对象的 proxy 工厂物化;普通构造不创建运行状态。
- 新协议必须与 `Concurrent_Registration``Relation_Registration` 同级,并自行提供 concept、注册项和 Model/Builder/Private 三组 CRTP API。禁止在 `Model` 内增加协议分支。
- 新协议必须放入 `model/registration``Concurrent_Registration``Relation_Registration` 同级,并自行提供 concept、注册项和 Model/Builder/Private 三组 CRTP API。具体附件统一放入 `model/attachment`,禁止重新建立顶层 `concurrent``relation` 分类目录,也禁止在 `Model` 内增加协议分支。
- 最终 endpoint 只继承实际注册协议的 API;未注册关系结构的 Builder 和实体不得出现关系函数,未注册并发结构的类型不得出现并发函数。
- 每个注册进 Model 的并发附件必须提供内部 `advance/use/builder_set`,外部 `set/get` 至少提供一个。Builder 的 `set<Tag>` 只进入 `internal.builder_set`,实体 `set/get` 只进入外部接口。
- 关系结构不统一成并发接口。关系实体通过 `edit<Tag>` 提交事务,Builder 通过 `relation<Tag>` 初始化,Private 在所有者安全点通过 `relation<Tag>/commit<Tag>` 使用和提交。