Skip to content

Commit 99f3f2a

Browse files
Merge pull request #12 from mcpplibs/fix-merger-rules-of-policies-group
Fix merger rules of policies group issue
2 parents e7948f3 + 49794cd commit 99f3f2a

File tree

13 files changed

+1569
-331
lines changed

13 files changed

+1569
-331
lines changed

.github/copilot-instructions.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
## 正在进行中的计划
1616

17-
- 计划目录:`../.github/prompts/`
18-
- 当前计划:`../.github/prompts/plan-policyBehaviorProtocol.prompt.md`
17+
- 当前计划目录:`../.github/prompts/`
1918

2019
## 说明
2120

Lines changed: 51 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,66 @@
1-
## Plan: Policy 行为协议与分发规范
1+
## Plan: 策略组一致性 + Primitive/Underlying 混合操作(增量)
22

3-
基于现有 traits/concept 架构,采用“policy handler 协议 + 固定 dispatcher + primitive 路由层”的设计。type 协商前移到编译期静态决议,运行期 dispatcher 固定为三层并按外到内调用:concurrency -> value(已知 common type)-> error。第一阶段覆盖四则运算(加减乘除),错误通道统一为 expected 返回;跨底层类型运算由 type policy 在编译期决定“是否允许 + common type”;value 层负责溢出判定与值调整/错误下放且需要接收 concurrency 层注入;error 层按策略执行最终错误处理。用户扩展边界限定为仅可特化 policy handler,以保持上层接口可复用、低耦合且强约束
3+
本计划仅覆盖新增规则与新增重载,不重复已完成的分层协议与分发基建
44

5-
**Steps**
6-
1. 明确协议核心抽象(阻塞后续步骤)
7-
2. 在 policy 层定义行为协议接口(依赖步骤 1)
8-
3. 在 operations 层建立统一分发入口(依赖步骤 2)
9-
4. 在 primitive 层实现运算路由与返回类型统一(依赖步骤 3)
10-
5. 为跨类型运算定义 type policy 协商规则(依赖步骤 4,部分可与步骤 6 并行)
11-
6. 建立编译期约束与诊断信息(依赖步骤 2,可并行于步骤 5)
12-
7. 增加测试矩阵与示例验证(依赖步骤 4、5、6)
13-
8. 文档化协议与扩展边界(依赖步骤 7)
5+
### A. 已确认规则(实现目标)
6+
1. 单个 `primitive` 的策略组规则保持不变
7+
- 同类别策略标签重复时,编译期报错。
148

15-
**Phase 1: 协议基线(接口层)**
16-
1.[src/policy/traits.cppm](src/policy/traits.cppm) 复用 category 与 policy_type 概念,新增“行为协议概念”所需的基础类型约束(仅声明契约,不放具体行为)。
17-
2.[src/policy/impl.cppm](src/policy/impl.cppm) 保留现有标签与 traits 特化,补充“策略能力声明位”对应的 traits 扩展位(用于编译期判定策略是否实现某 operation)。
18-
3. 新增 policy 协议模块(建议命名 mcpplibs.primitives.policy.handler),内容包含:
19-
4. `policy_handler<Policy, OperationTag, Lhs, Rhs>` 主模板(默认禁用)
20-
5. `policy_handler_available` 概念(用于约束上层调用)
21-
6. 标准返回别名(统一为 expected 语义)
22-
7. 明确用户扩展点:只允许特化 handler,不开放分发规则特化。
9+
2. 两个 `primitive` 的策略组合并规则
10+
- 先按默认策略补全四类策略(`value/type/error/concurrency`)。
11+
- 补全后两边策略组必须完全一致(忽略声明顺序),否则编译期报错。
2312

24-
**Phase 2: Operation 分发层(固定三层运行期链路)**
25-
1.[src/operations/impl.cppm](src/operations/impl.cppm) 维持 operation tag + arity 元数据,增加“可分发 operation”约束入口(例如合法 operation 概念)。
26-
2.[src/operations/operators.cppm](src/operations/operators.cppm) 将 type 协商前移为编译期预处理,并实现运行期固定 dispatcher:
27-
3. concurrency handler:负责并发包装(如加锁/解锁、内存屏障注入;具体机制可后续细化),并向 value 层注入并发执行上下文。
28-
4. value handler:接收已决议的 common type + concurrency 注入上下文,在 common type 上执行值域与溢出判定,决定“本层修正结果值”或“下放错误处理请求”。
29-
5. error handler:接收上层错误请求并按策略完成最终处理,统一映射到 expected 错误值。
30-
6. dispatcher 对外统一返回 expected,且不依赖具体 primitive 别名,仅依赖 traits 协议。
13+
3. 两个 `primitive` 底层类型不同时的二元操作规则
14+
- 先满足规则 2。
15+
- `type::strict`:编译期拒绝。
16+
- `type::compatible`:两侧 `underlying category` 必须一致,且 `common_rep_traits` 可用且推导结果非 `void`
17+
- `type::transparent`:忽略 `category`,但 `common_rep_traits` 必须可用且推导结果非 `void`
3118

32-
**Phase 3: Primitive 路由层(上层调用面)**
33-
1.[src/primitive/traits.cppm](src/primitive/traits.cppm) 复用 primitive_traits 与 resolve_policy_t,新增:
34-
2. 跨类型运算协商 trait(由 type policy 决定是否允许、结果 common type)
35-
3. 结果 primitive 重建工具(保持策略传播一致)
36-
4. 在 primitive 对外运算入口中接入 operations dispatcher,覆盖加减乘除四个操作。
37-
5. 返回类型统一为 expected(成功值为 primitive,失败值为错误域类型)。
19+
4. 不新增策略标签
20+
- 维持 `compatible` / `transparent` 现有策略集合,不引入新 policy。
3821

39-
**Phase 4: 聚合导出与契约稳定**
40-
1.[src/primitives.cppm](src/primitives.cppm) 增加新协议模块与分发层导出,保持聚合入口一致。
41-
2.[src/policy/utility.cppm](src/policy/utility.cppm) 保持 common policy 选择逻辑不变,仅补充与 handler 可用性相关的辅助别名(若需要)。
22+
### B. 新增范围:Primitive 与 Underlying 混合作为二元操作数
23+
1.`apply/operation` 层新增 `underlying` 参与重载
24+
- 支持 `(primitive, underlying)`
25+
- 若是自由函数,必须同时支持 `(underlying, primitive)`(左右位置都可用)。
4226

43-
**Phase 5: 验证与回归**
44-
1.[tests](tests) 新增 policy 行为协议测试:
45-
2. handler 未实现时应在编译期失败(约束强)
46-
3. 四则运算均返回 expected
47-
4. 相同 type policy 下跨类型协商正确/错误路径正确
48-
5.[examples/basic.cpp](examples/basic.cpp) 增加最小示例:
49-
6. 默认策略下四则运算
50-
7. 自定义 policy handler 的单点扩展示例(仅特化 handler)
27+
2. 返回类型约束
28+
- 算术类型操作结果始终返回 `primitive`(不返回裸 `underlying`)。
5129

30+
3. 策略选择约束
31+
- 混合操作中仅有一个 `primitive` 时,`type` 策略取该 `primitive` 的策略。
32+
- 其余策略(`value/error/concurrency`)同样取该 `primitive`,保持策略来源单一。
5233

53-
**Interface Contracts(最小签名清单)**
54-
1. Dispatcher 总入口(放在 [src/operations/operators.cppm](src/operations/operators.cppm)):
55-
2. 输入:OperationTag、Lhs Primitive、Rhs Primitive、四类 policy(由 primitive_traits 解析)。
56-
3. 输出:expected<ResultPrimitive, ErrorPayload>。
57-
4. 约束:type 协商在编译期完成;运行期调用顺序固定为 concurrency -> value -> error。
58-
5. 编译期 type 协商合约(静态层,不进入运行期链路):
59-
6. 输入:操作标签、Lhs/Rhs 静态类型信息、type policy。
60-
7. 输出:type_decision(is_allowed、common_type、diagnostic_id)。
61-
8. 责任:拒绝非法运算并确定 common_type;其结果作为运行期 value 层输入前提。
62-
9. concurrency handler 合约(放在 policy handler 模块):
63-
10. 输入:operation_context、下一层 continuation、type_decision。
64-
11. 输出:concurrency_injection + 下一层 expected 透传能力。
65-
12. 责任:加锁/解锁、内存屏障、线程可见性包装;向 value 层注入并发执行上下文,不做值域判定。
66-
13. value handler 合约:
67-
14. 输入:common_type 下的 lhs/rhs、operation_context、concurrency_injection。
68-
15. 输出:二选一路径:
69-
16. 路径 A:直接给出成功值(已修正或原值)。
70-
17. 路径 B:下发 error_request(包含错误类别、上下文、候选回退值)。
71-
18. 责任:执行溢出/下溢/除零等值域检查,并决定是否本层修正。
72-
19. error handler 合约:
73-
20. 输入:error_request + operation_context。
74-
21. 输出:expected<ResultPrimitive, ErrorPayload> 的最终错误分支或恢复成功值分支。
75-
22. 责任:按 error policy 落地处理(例如映射错误域、终止、抛错转译为 expected 错误值)。
76-
23. 跨层数据结构建议:
77-
24. operation_context:封装 op tag、源 primitive traits、policy 句柄、调试标签。
78-
25. type_decision:封装 is_allowed、common_type、diagnostic_id。
79-
26. concurrency_injection:封装 guard_handle、memory_order/屏障策略、可选调度标签。
80-
27. value_decision:封装 has_value、value、error_request。
81-
28. error_request:封装 error_kind、reason、operation_context、可选 fallback。
82-
29. 扩展边界:
83-
30. 用户只可特化三类运行期 handler(concurrency/value/error)与静态 type 协商策略实现,不可替换 dispatcher 顺序、不可改动跨层数据结构主骨架。
34+
4. 底层类型推导约束
35+
- 混合操作的 `underlying` 推导与“两侧都是 primitive”的规则一致:
36+
- 走相同的 `type` 协商路径,使用同一套 `common_rep_traits` 可用性与非 `void` 判定。
8437

85-
**Relevant files**
86-
- [src/policy/traits.cppm](src/policy/traits.cppm) — 复用并扩展 policy 概念边界,承载行为协议约束基础。
87-
- [src/policy/impl.cppm](src/policy/impl.cppm) — 保持标签定义,补充策略能力元信息挂点。
88-
- [src/policy/utility.cppm](src/policy/utility.cppm) — 与 common_policies 选择逻辑对齐,必要时提供 handler 检查辅助。
89-
- [src/operations/impl.cppm](src/operations/impl.cppm) — operation 元数据与分发前置约束。
90-
- [src/operations/operators.cppm](src/operations/operators.cppm) — dispatcher 核心实现位置。
91-
- [src/primitive/traits.cppm](src/primitive/traits.cppm) — policy 解析与跨类型协商 trait 的主落点。
92-
- [src/primitives.cppm](src/primitives.cppm) — 对外聚合导出。
93-
- [tests](tests) — 编译期约束与行为结果验证。
94-
- [examples/basic.cpp](examples/basic.cpp) — API 用法与扩展示例。
38+
### C. 代码改动计划
39+
1. `src/operations/dispatcher.cppm`
40+
- 增加“跨 primitive 策略组补全后一致”的编译期断言。
41+
- 增加 `compatible``category` 一致性判定(与 `common_rep` 可用性判定协同)。
42+
- 补齐 `common_rep``void` 的显式断言。
9543

96-
**Verification**
97-
1. 编译期契约验证:
98-
2. 未提供对应 policy_handler 的 operation 调用必须报清晰静态断言。
99-
3. type policy 禁止的跨类型运算必须在编译期拒绝。
100-
4. 固定链路验证:
101-
5. type 协商必须在编译期完成,运行期 dispatcher 必须按 concurrency -> value -> error 顺序调用,禁止跳层与重排。
102-
6. value 层必须验证“接收 concurrency 注入”这一前提生效。
103-
7. value 层“值修正”与“错误下放”两条路径都需覆盖测试。
104-
8. 行为一致性验证:
105-
9. 四则运算对默认策略与自定义策略均返回 expected。
106-
10. 失败路径(溢出/除零/不兼容类型)按 error policy 语义编码到 expected 错误值。
107-
11. unchecked_value 路径验证:
108-
12. 不触发 error policy,保持原生算术语义(含 UB 风险)并通过测试明确边界。
109-
13. 导出稳定性验证:
110-
14. 通过聚合模块导入可直接访问 policy 协议、operation 分发、primitive 运算。
111-
15. 运行 tests 与示例构建,确认无回归。
44+
2. `src/operations/operators.cppm`
45+
- 为自由函数 `apply/add/sub/mul/div/equal/not_equal/three_way_compare` 增加混合重载:
46+
- `(primitive, underlying)``(underlying, primitive)`
47+
- 保证非交换操作(如 `sub/div/<=>`)保留正确操作数顺序语义。
11248

113-
**Decisions**
114-
- 错误通道:默认路径统一返回 expected。
115-
- dispatcher 形态:type 协商前移到编译期,运行期固定三层链路 concurrency -> value -> error,不开放顺序重排。
116-
- 跨底层类型运算:由 type policy 在编译期决定可行性与 common type。
117-
- value 层职责:判定溢出并决定“本层值修正”或“下放 error 层处理”。
118-
- unchecked_value 语义:不做错误处理,不调用 error policy,行为尽量贴近原生 C/C++(包含 UB 风险)。
119-
- 扩展边界:仅开放 policy handler 特化,不开放分发规则。
120-
- 第一阶段覆盖范围:Addition/Subtraction/Multiplication/Division 全部纳入。
121-
- In scope:policy 行为协议、operation 分发、primitive 路由、测试与文档。
122-
- Out of scope:并发策略的运行时同步原语实现细节(atomic/lock-free/锁策略具体执行体)。
49+
3. `src/primitive/impl.cppm`(如需)
50+
- 若存在 primitive access 的自由函数入口,同步补齐混合重载的左右位置版本。
51+
- 成员函数形式的 access API 不做左右重载扩展。
12352

124-
## Underlying Bridge Execution Contract (Runtime)
53+
4. `tests/basic/test_operations.cpp`
54+
- 新增混合重载测试:
55+
- `(primitive, underlying)``(underlying, primitive)` 都可编译并语义正确。
56+
- 算术结果类型恒为 `primitive`
57+
- 策略组不一致时编译期失败。
58+
- `strict/compatible/transparent` 下的跨底层类型判定符合规则 A-3。
12559

126-
1. `dispatch` 在 value 阶段前统一执行 `to_rep`,将原始 value 映射到可协商的 `rep_type`
127-
2. `type_handler` 的协商对象是 `lhs_rep/rhs_rep`,而非原始 value type
128-
3. 若任一输入 `is_valid_rep(...) == false`,立即构造 `runtime_error_kind::domain_error` 并进入 error policy
129-
4. 通过校验后执行 `from_rep -> to_rep` 规范化,再进入 value handler 与 op binding
130-
5. 当前结果值仍按 `common_rep` 回传;comparison 最小闭环采用 `0/1` 表示(`static_cast<common_rep>(bool)`)。
131-
6. 本契约不改变 dispatcher 链路顺序,也不改变错误枚举体系
60+
### D. 验收标准
61+
1. 所有新增约束均在编译期可判定,不引入运行期兜底分支
62+
2. 混合操作重载完整覆盖左右操作数位置(自由函数)
63+
3. 算术混合操作返回类型恒为 `primitive`
64+
4. 混合操作的 `type` 策略来源唯一且可预测(取 primitive 操作数)。
65+
5. 与现有行为无回归,新增正反测试通过
13266

133-
**Further Considerations**
134-
1. expected 的错误载体类型建议先统一为轻量错误枚举,再逐步演进到可扩展错误域,以减少首版模板复杂度。
135-
2. type policy 的 common type 规则建议先采用“显式白名单 + static_assert 诊断”,避免首版引入过宽的隐式提升。
136-
3. 后续可新增“native 快速路径”作为可选 API:当组合为 primitive<unchecked_value, transparent_type, single_thread> 时,提供非 expected 返回通道以最大化贴近原生 C/C++ 性能与行为。
137-
4. 后续可新增 C API 适配层(extern "C" 薄封装,POD 入参与返回值),内部复用 unchecked/native 路径,优先保障与现有 C 调用约定兼容。

examples/ex03_value_policy.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ int main() {
2929
policy::error::expected>;
3030

3131
// Same overflow input for all three policies.
32-
auto const lhs_checked = checked_t{65530};
33-
auto const rhs_checked = checked_t{20};
32+
auto const lhs_checked = checked_t{static_cast<std::uint16_t>(65530)};
33+
auto const rhs_checked = checked_t{static_cast<std::uint16_t>(20)};
3434
auto const checked_result = operations::add(lhs_checked, rhs_checked);
3535

36-
auto const lhs_unchecked = unchecked_t{65530};
37-
auto const rhs_unchecked = unchecked_t{20};
36+
auto const lhs_unchecked = unchecked_t{static_cast<std::uint16_t>(65530)};
37+
auto const rhs_unchecked = unchecked_t{static_cast<std::uint16_t>(20)};
3838
auto const unchecked_result = operations::add(lhs_unchecked, rhs_unchecked);
3939

40-
auto const lhs_saturating = saturating_t{65530};
41-
auto const rhs_saturating = saturating_t{20};
40+
auto const lhs_saturating = saturating_t{static_cast<std::uint16_t>(65530)};
41+
auto const rhs_saturating = saturating_t{static_cast<std::uint16_t>(20)};
4242
auto const saturating_result =
4343
operations::add(lhs_saturating, rhs_saturating);
4444

@@ -48,11 +48,13 @@ int main() {
4848
std::cerr << "checked policy should report overflow\n";
4949
return 1;
5050
}
51-
if (!unchecked_result.has_value() || unchecked_result->value() != 14) {
51+
if (!unchecked_result.has_value() ||
52+
unchecked_result->value() != static_cast<std::uint16_t>(14)) {
5253
std::cerr << "unchecked policy should wrap\n";
5354
return 1;
5455
}
55-
if (!saturating_result.has_value() || saturating_result->value() != 65535) {
56+
if (!saturating_result.has_value() ||
57+
saturating_result->value() != static_cast<std::uint16_t>(65535)) {
5658
std::cerr << "saturating policy should clamp\n";
5759
return 1;
5860
}

0 commit comments

Comments
 (0)