Skip to content

Commit bb5e527

Browse files
Merge pull request #19 from mcpplibs/feat-algorithms
Enhance algorithms and limits modules with improved functionality and tests
2 parents a74666e + 43bcc15 commit bb5e527

File tree

10 files changed

+458
-51
lines changed

10 files changed

+458
-51
lines changed

.agents/docs/plans/implementation-plan.md

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
# Primitives 下一步实现计划清单(2026-03-23
1+
# Primitives 下一步实现计划清单(2026-03-26
22

33
## 总体原则
44

55
- [ ] 先定义稳定 API 边界,再落地实现
66
- [ ] 每个能力都配套 tests + examples + docs
77
- [ ] 高风险转换默认禁止隐式触发,只允许显式 API
8+
- [ ] 明确分层职责:`algorithms` 负责值域/排序/边界元信息与值算法;`conversion` 负责显式类型变换
9+
- [ ] 明确依赖方向:`conversion` 可依赖 `algorithms``algorithms` 不反向依赖 `conversion`
810

911
## M1. C API 互操作层(双向)
1012

@@ -27,21 +29,30 @@
2729
### 工作清单
2830

2931
- [ ] 扩展 concept 分层(category/representation/policy-capability)
30-
- [ ] 完善 `traits<T>` 元信息(`kind``rep_type`、limits、policy tags)
31-
- [ ] 提供检测类 API(可转换性/是否有损/错误模型能力)
32+
- [ ] 明确 `underlying::traits<T>``algorithms::traits<T>` 的职责边界:前者描述表示层;后者描述值算法层
33+
- [ ] 完善 `traits<T>` 元信息(`kind``rep_type`、policy tags)
34+
- [ ] 设计 `algorithms::traits<T>`,内容参考 `std::numeric_limits`,但只保留算法/比较所需子集:
35+
- [ ] `min()` / `lowest()` / `max()` / `epsilon()` / `infinity()` / `quiet_nan()`
36+
- [ ] `is_bounded` / `is_exact` / `is_signed` / `is_integer` / `is_iec559`
37+
- [ ] `has_infinity` / `has_quiet_nan` / `digits` / `digits10` / `radix`
38+
- [ ] 增加排序能力元信息:`comparison_category``totally_ordered``partially_ordered``unordered_possible`
39+
- [ ] 提供双参聚合元信息:`algorithms::common_traits<Lhs, Rhs>`,统一暴露 `common_rep`、可比较性、边界查询与策略兼容性
40+
- [ ] 提供检测类 API(可比较性/可裁剪性/可转换性/是否有损/错误模型能力)
3241
- [ ] 统一 `constexpr` 查询入口,减少分散 traits 访问
3342
- [ ] 增加编译期测试矩阵(`static_assert` 覆盖)
3443

3544
### 验收标准
3645

3746
- [ ] 上层模块仅依赖公开 concept/traits,不依赖 `details::*`
38-
- [ ] 元信息可支撑转换层与算法层的约束判定
47+
- [ ] `algorithms::traits` 可直接支撑算法层判定,并作为 conversion 的元信息依赖
48+
- [ ] `std::numeric_limits` 相关逻辑不再散落在 `conversion`/`operations` 内部
3949

4050
## M3. 显式转换层(任意策略组适用)
4151

4252
### 工作清单
4353

4454
- [ ] 设计统一接口族(建议):`explicit_cast``try_cast``checked_cast`
55+
- [ ] 将边界、NaN、无穷大、精度与排序相关判定统一改为依赖 `algorithms::traits` / `algorithms::common_traits`
4556
- [ ] 支持任意策略组组合,不绑定特定策略实现
4657
- [ ] 风险可见化(截断/溢出/精度损失)并可程序化读取
4758
- [ ] 定义失败语义(错误码或 expected 风格,按策略可配置)
@@ -51,28 +62,37 @@
5162

5263
- [ ] 所有跨类高风险转换必须走显式 API
5364
- [ ] 风险信息可在编译期或运行期被确定性获取
65+
- [ ] `conversion` 模块仅消费 `algorithms` 提供的元信息,不反向定义算法层协议
5466

55-
## M4. 算法层(以 max/min 为起点)
67+
## M4. 算法层(traits 先行,以 max/min 为起点)
5668

5769
### 工作清单
5870

71+
- [ ] 确定模块结构:`mcpplibs.primitives.algorithms``mcpplibs.primitives.algorithms.traits``mcpplibs.primitives.algorithms.compare``mcpplibs.primitives.algorithms.minmax`
72+
- [ ] 先实现 `algorithms::traits``algorithms::common_traits`,作为整个算法层与 conversion 的基础依赖
73+
- [ ] 约束算法职责只涉及值的比较、选择、裁剪与边界处理,不提供目标类型导向的 cast API
74+
- [ ] `max`/`min` 内部仅允许做 `common_rep` 归一化或排序语义协商,不绕回 conversion 层
5975
- [ ] 实现 `max`/`min`,并预留 `clamp`/`compare` 扩展位
60-
- [ ] 算法统一依赖 M2+M3 的公开接口,不绕过转换层
61-
- [ ] 支持同类与受约束的异类输入
76+
- [ ] 支持同类输入与受约束的异类输入;异类场景必须满足 `common_rep`、排序能力与策略组约束
77+
- [ ] 明确 `partial_ordering` / `unordered` 语义,尤其是浮点 `NaN` 路径
78+
- [ ]`clamp`/`compare` 抽出复用内核:公共比较、边界判定、值选择
6279
- [ ] 在可行范围保持 `constexpr`/`noexcept` 特性
63-
- [ ] 增加边界测试(极值、NaN、有符号/无符号混合)
80+
- [ ] 增加边界测试(极值、NaN、有符号/无符号混合、不同 `comparison_category`
6481

6582
### 验收标准
6683

6784
- [ ] 算法行为与策略约束一致
6885
- [ ] 风险路径始终显式、可审计
86+
- [ ] `algorithms` 可独立编译并被 `conversion` 依赖,不形成反向模块耦合
87+
- [ ] 算法层实现不通过“显式转换 API”间接完成值比较
6988

7089
## 建议推进顺序
7190

7291
1. M2(先夯实约束与元信息基础)
73-
2. M1(建立跨语言边界)
74-
3. M3(收敛转换风险)
75-
4. M4(复用基础能力实现算法)
92+
2. M4 前半:`algorithms::traits` / `common_traits` / 排序能力查询
93+
3. M3(让 conversion 改为依赖 algorithms 元信息)
94+
4. M4 后半:`max` / `min` / `clamp` / `compare`
95+
5. M1(建立跨语言边界,可按需求并行推进)
7696

7797
## 总体完成跟踪
7898

src/algorithms/algorithms.cppm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module;
2+
3+
export module mcpplibs.primitives.algorithms;
4+
5+
export import mcpplibs.primitives.algorithms.hash;
6+
export import mcpplibs.primitives.algorithms.limits;

src/algorithms/hash.cppm

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
module;
2+
3+
#include <concepts>
4+
#include <cstddef>
5+
#include <functional>
6+
#include <type_traits>
7+
8+
export module mcpplibs.primitives.algorithms.hash;
9+
10+
import mcpplibs.primitives.underlying;
11+
12+
namespace mcpplibs::primitives::algorithms::details {
13+
14+
template <typename T>
15+
concept std_hashable = requires(std::remove_cv_t<T> const &value) {
16+
{
17+
std::hash<std::remove_cv_t<T>>{}(value)
18+
} -> std::convertible_to<std::size_t>;
19+
};
20+
21+
} // namespace mcpplibs::primitives::algorithms::details
22+
23+
export namespace mcpplibs::primitives::algorithms {
24+
25+
template <typename T> struct hash {
26+
using value_type = std::remove_cv_t<T>;
27+
using result_type = std::size_t;
28+
29+
static constexpr bool enabled = false;
30+
31+
auto operator()(value_type const &) const noexcept -> result_type {
32+
return result_type{};
33+
}
34+
};
35+
36+
template <typename T>
37+
using hash_result_t = hash<std::remove_cvref_t<T>>::result_type;
38+
39+
template <typename T>
40+
concept hashable = hash<std::remove_cvref_t<T>>::enabled;
41+
42+
template <typename T>
43+
requires details::std_hashable<T>
44+
struct hash<T> {
45+
using value_type = std::remove_cv_t<T>;
46+
using result_type = std::size_t;
47+
48+
static constexpr bool enabled = true;
49+
50+
auto operator()(value_type const &value) const noexcept(
51+
noexcept(std::hash<value_type>{}(value))) -> result_type {
52+
return std::hash<value_type>{}(value);
53+
}
54+
};
55+
56+
template <underlying_type T>
57+
requires (!details::std_hashable<T> &&
58+
!std::same_as<std::remove_cv_t<T>,
59+
typename underlying::traits<std::remove_cv_t<T>>::rep_type> &&
60+
hash<typename underlying::traits<std::remove_cv_t<T>>::rep_type>::enabled)
61+
struct hash<T> {
62+
using value_type = std::remove_cv_t<T>;
63+
using rep_type = underlying::traits<value_type>::rep_type;
64+
using result_type = hash_result_t<rep_type>;
65+
66+
static constexpr bool enabled = true;
67+
68+
auto operator()(value_type const &value) const noexcept(
69+
noexcept(hash<rep_type>{}(underlying::traits<value_type>::to_rep(value))))
70+
-> result_type {
71+
return hash<rep_type>{}(underlying::traits<value_type>::to_rep(value));
72+
}
73+
};
74+
75+
template <hashable T>
76+
auto hash_value(T const &value) noexcept(
77+
noexcept(hash<std::remove_cvref_t<T>>{}(value))) -> hash_result_t<T> {
78+
return hash<std::remove_cvref_t<T>>{}(value);
79+
}
80+
81+
} // namespace mcpplibs::primitives::algorithms

src/algorithms/limits.cppm

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
module;
2+
3+
#include <concepts>
4+
#include <limits>
5+
#include <type_traits>
6+
7+
export module mcpplibs.primitives.algorithms.limits;
8+
9+
import mcpplibs.primitives.underlying;
10+
11+
namespace mcpplibs::primitives::algorithms::details {
12+
13+
template <typename T>
14+
concept has_numeric_limits =
15+
std::numeric_limits<std::remove_cv_t<T>>::is_specialized;
16+
17+
template <typename T>
18+
consteval auto category_from_type() -> underlying::category {
19+
using value_type = std::remove_cv_t<T>;
20+
if constexpr (std_bool<value_type>) {
21+
return underlying::category::boolean;
22+
} else if constexpr (std_char<value_type>) {
23+
return underlying::category::character;
24+
} else if constexpr (std::numeric_limits<value_type>::is_integer) {
25+
return underlying::category::integer;
26+
} else {
27+
return underlying::category::floating;
28+
}
29+
}
30+
31+
} // namespace mcpplibs::primitives::algorithms::details
32+
33+
export namespace mcpplibs::primitives::algorithms {
34+
35+
template <typename T> struct limits {
36+
using value_type = std::remove_cv_t<T>;
37+
using rep_type = value_type;
38+
39+
static constexpr bool enabled = false;
40+
static constexpr bool is_specialized = false;
41+
static constexpr bool is_bounded = false;
42+
static constexpr bool is_exact = false;
43+
static constexpr bool is_signed = false;
44+
static constexpr bool is_integer = false;
45+
static constexpr bool is_iec559 = false;
46+
static constexpr bool has_infinity = false;
47+
static constexpr bool has_quiet_nan = false;
48+
static constexpr int digits = 0;
49+
static constexpr int digits10 = 0;
50+
static constexpr int radix = 0;
51+
static constexpr auto kind = static_cast<underlying::category>(-1);
52+
53+
static constexpr auto min() noexcept -> value_type { return {}; }
54+
static constexpr auto lowest() noexcept -> value_type { return {}; }
55+
static constexpr auto max() noexcept -> value_type { return {}; }
56+
static constexpr auto epsilon() noexcept -> value_type { return {}; }
57+
static constexpr auto infinity() noexcept -> value_type { return {}; }
58+
static constexpr auto quiet_nan() noexcept -> value_type { return {}; }
59+
};
60+
61+
template <typename T>
62+
requires details::has_numeric_limits<T>
63+
struct limits<T> {
64+
using value_type = std::remove_cv_t<T>;
65+
using rep_type = value_type;
66+
67+
static constexpr bool enabled = true;
68+
static constexpr bool is_specialized = true;
69+
static constexpr bool is_bounded = std::numeric_limits<value_type>::is_bounded;
70+
static constexpr bool is_exact = std::numeric_limits<value_type>::is_exact;
71+
static constexpr bool is_signed = std::numeric_limits<value_type>::is_signed;
72+
static constexpr bool is_integer = std::numeric_limits<value_type>::is_integer;
73+
static constexpr bool is_iec559 = std::numeric_limits<value_type>::is_iec559;
74+
static constexpr bool has_infinity =
75+
std::numeric_limits<value_type>::has_infinity;
76+
static constexpr bool has_quiet_nan =
77+
std::numeric_limits<value_type>::has_quiet_NaN;
78+
static constexpr int digits = std::numeric_limits<value_type>::digits;
79+
static constexpr int digits10 = std::numeric_limits<value_type>::digits10;
80+
static constexpr int radix = std::numeric_limits<value_type>::radix;
81+
static constexpr auto kind = details::category_from_type<value_type>();
82+
83+
static constexpr auto min() noexcept -> value_type {
84+
return std::numeric_limits<value_type>::min();
85+
}
86+
87+
static constexpr auto lowest() noexcept -> value_type {
88+
return std::numeric_limits<value_type>::lowest();
89+
}
90+
91+
static constexpr auto max() noexcept -> value_type {
92+
return std::numeric_limits<value_type>::max();
93+
}
94+
95+
static constexpr auto epsilon() noexcept -> value_type {
96+
return std::numeric_limits<value_type>::epsilon();
97+
}
98+
99+
static constexpr auto infinity() noexcept -> value_type {
100+
return std::numeric_limits<value_type>::infinity();
101+
}
102+
103+
static constexpr auto quiet_nan() noexcept -> value_type {
104+
return std::numeric_limits<value_type>::quiet_NaN();
105+
}
106+
};
107+
108+
template <underlying_type T>
109+
requires (!details::has_numeric_limits<T> &&
110+
!std::same_as<std::remove_cv_t<T>,
111+
typename underlying::traits<std::remove_cv_t<T>>::rep_type> &&
112+
limits<typename underlying::traits<std::remove_cv_t<T>>::rep_type>::enabled)
113+
struct limits<T> {
114+
using value_type = std::remove_cv_t<T>;
115+
using rep_type = underlying::traits<value_type>::rep_type;
116+
using rep_limits = limits<rep_type>;
117+
118+
static constexpr bool enabled = true;
119+
static constexpr bool is_specialized = rep_limits::is_specialized;
120+
static constexpr bool is_bounded = rep_limits::is_bounded;
121+
static constexpr bool is_exact = rep_limits::is_exact;
122+
static constexpr bool is_signed = rep_limits::is_signed;
123+
static constexpr bool is_integer = rep_limits::is_integer;
124+
static constexpr bool is_iec559 = rep_limits::is_iec559;
125+
static constexpr bool has_infinity = rep_limits::has_infinity;
126+
static constexpr bool has_quiet_nan = rep_limits::has_quiet_nan;
127+
static constexpr int digits = rep_limits::digits;
128+
static constexpr int digits10 = rep_limits::digits10;
129+
static constexpr int radix = rep_limits::radix;
130+
static constexpr auto kind = underlying::traits<value_type>::kind;
131+
132+
static constexpr auto min() noexcept -> value_type {
133+
return underlying::traits<value_type>::from_rep(rep_limits::min());
134+
}
135+
136+
static constexpr auto lowest() noexcept -> value_type {
137+
return underlying::traits<value_type>::from_rep(rep_limits::lowest());
138+
}
139+
140+
static constexpr auto max() noexcept -> value_type {
141+
return underlying::traits<value_type>::from_rep(rep_limits::max());
142+
}
143+
144+
static constexpr auto epsilon() noexcept -> value_type {
145+
return underlying::traits<value_type>::from_rep(rep_limits::epsilon());
146+
}
147+
148+
static constexpr auto infinity() noexcept -> value_type {
149+
return underlying::traits<value_type>::from_rep(rep_limits::infinity());
150+
}
151+
152+
static constexpr auto quiet_nan() noexcept -> value_type {
153+
return underlying::traits<value_type>::from_rep(rep_limits::quiet_nan());
154+
}
155+
};
156+
157+
template <typename T>
158+
concept limited_type = limits<std::remove_cvref_t<T>>::enabled;
159+
160+
template <typename T>
161+
using limit_value_t = limits<std::remove_cvref_t<T>>::value_type;
162+
163+
template <limited_type T>
164+
constexpr auto min_value() noexcept(
165+
noexcept(limits<std::remove_cvref_t<T>>::min())) -> limit_value_t<T> {
166+
return limits<std::remove_cvref_t<T>>::min();
167+
}
168+
169+
template <limited_type T>
170+
constexpr auto lowest_value() noexcept(
171+
noexcept(limits<std::remove_cvref_t<T>>::lowest())) -> limit_value_t<T> {
172+
return limits<std::remove_cvref_t<T>>::lowest();
173+
}
174+
175+
template <limited_type T>
176+
constexpr auto max_value() noexcept(
177+
noexcept(limits<std::remove_cvref_t<T>>::max())) -> limit_value_t<T> {
178+
return limits<std::remove_cvref_t<T>>::max();
179+
}
180+
181+
template <limited_type T>
182+
constexpr auto epsilon_value() noexcept(
183+
noexcept(limits<std::remove_cvref_t<T>>::epsilon())) -> limit_value_t<T> {
184+
return limits<std::remove_cvref_t<T>>::epsilon();
185+
}
186+
187+
template <limited_type T>
188+
constexpr auto infinity_value() noexcept(
189+
noexcept(limits<std::remove_cvref_t<T>>::infinity())) -> limit_value_t<T> {
190+
return limits<std::remove_cvref_t<T>>::infinity();
191+
}
192+
193+
template <limited_type T>
194+
constexpr auto quiet_nan_value() noexcept(
195+
noexcept(limits<std::remove_cvref_t<T>>::quiet_nan())) -> limit_value_t<T> {
196+
return limits<std::remove_cvref_t<T>>::quiet_nan();
197+
}
198+
199+
} // namespace mcpplibs::primitives::algorithms

0 commit comments

Comments
 (0)