Skip to content

Commit b2bcf19

Browse files
docs: Update README.md and the example program
1 parent e68d725 commit b2bcf19

File tree

3 files changed

+205
-15
lines changed

3 files changed

+205
-15
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,39 @@
44
55
本仓库实现了底层强类型 primitive 基础设施(traits、policy、underlying 类型分类),供上层 `Integer`/`Floating`/`Boolean` 等封装使用。
66

7+
> [!WARNING]
8+
> 目前项目还在开发中,API会随着后续演进而改变
9+
710
## 特性
811

9-
- **C++23 模块**`import mcpplibs.templates;`
12+
- **C++23 模块**`import mcpplibs.primitives;`
1013
- **双构建系统** — 同时支持 xmake 和 CMake
1114
- **CI/CD** — GitHub Actions 多平台构建(Linux / macOS / Windows)
1215
- **标准化结构** — 遵循 [mcpp-style-ref](https://github.com/mcpp-community/mcpp-style-ref) 编码规范
1316
- **开箱即用** — 包含示例、测试和架构文档
1417

18+
## Operators
19+
20+
该库在 `primitive` 类型上重载了常见的 C++ 算术、位运算和一元运算符。算术行为受策略(policy)控制:
21+
22+
- 值策略(`checked_value` / `saturating_value` / `unchecked_value`)决定溢出行为;
23+
- 错误策略(`throw_error` / `expected_error` / `terminate_error`)决定在 `checked_value` 且发生错误时的处理方式。
24+
25+
示例:
26+
27+
```cpp
28+
import mcpplibs.primitives;
29+
using namespace mcpplibs::primitives;
30+
using namespace mcpplibs::primitives::policy;
31+
32+
primitive<int> a{1}, b{2};
33+
auto c = a + b; // primitive<int>
34+
35+
primitive<int, expected_error> x{std::numeric_limits<int>::max()};
36+
primitive<int, expected_error> y{1};
37+
auto maybe = x + y; // std::expected<primitive<int, expected_error>, std::overflow_error>
38+
```
39+
1540
## 项目结构
1641
1742
```

examples/basic.cpp

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,50 @@
11
#include <iostream>
2+
#include <limits>
23

34
import mcpplibs.primitives;
45

56
int main() {
67
using namespace mcpplibs::primitives;
78
using namespace mcpplibs::primitives::policy;
9+
using namespace mcpplibs::primitives::operators;
10+
using namespace mcpplibs::primitives::types;
811

9-
std::cout << "=== mcpplibs.primitives traits & policy example ===\n";
10-
std::cout << std::boolalpha;
11-
std::cout << "int is std_integer: " << std_integer<int> << "\n";
12-
std::cout << "double is std_floating: " << std_floating<double> << "\n";
13-
std::cout << "int is underlying_type: " << underlying_type<int> << "\n";
14-
15-
std::cout
16-
<< "default value policy is unchecked_value: "
17-
<< std::is_same_v<default_value, checked_value> << "\n";
18-
19-
std::cout << "checked_value is a policy_type: "
20-
<< policy_type<checked_value> << "\n";
21-
std::cout << "checked_value category == value: "
22-
<< (policy::traits<checked_value>::kind == category::value)
12+
// Operators
13+
I32<> a{3};
14+
I32<> b{4};
15+
auto c = a + b; // primitive<int>
16+
std::cout << "3 + 4 = " << static_cast<int>(c) << "\n";
17+
18+
// Error handling
19+
I32<checked_value> lhs{1};
20+
I32<checked_value> rhs{std::numeric_limits<std::int32_t>::max()};
21+
22+
try {
23+
auto res = lhs + rhs;
24+
} catch (const std::exception &e) {
25+
std::cout << "An exception occurred: " << e.what() << "\n";
26+
}
27+
28+
I64<checked_value, expected_error> lhs2{1};
29+
I64<checked_value, expected_error> rhs2{std::numeric_limits<std::int64_t>::max()};
30+
31+
auto res2 = lhs2 + rhs2;
32+
33+
// Saturating
34+
I32<saturating_value> s1{std::numeric_limits<std::int32_t>::max()};
35+
I32<saturating_value> s2{1};
36+
auto sat = s1 + s2; // saturating -> stays max
37+
std::cout << "saturating max + 1 = " << static_cast<std::int32_t>(sat)
2338
<< "\n";
2439

40+
// Mixed-type addition
41+
using expected_type = I64<category_compatible_type>;
42+
expected_type L1{5};
43+
I32<category_compatible_type> L2{6};
44+
auto mix = L1 + L2; // common_type -> I64
45+
std::cout << "5 + 6 = " << mix.value() << "\n";
46+
std::cout << std::boolalpha;
47+
std::cout << "Does type of mix is I64<category_compatible_type>: " << std::same_as<decltype(mix), expected_type> << std::endl;
48+
2549
return 0;
2650
}

src/operations/operators.cppm

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
module;
2+
#include <type_traits>
3+
export module mcpplibs.primitives.operations.operators;
4+
5+
import mcpplibs.primitives.underlying;
6+
import mcpplibs.primitives.policy;
7+
import mcpplibs.primitives.primitive;
8+
import mcpplibs.primitives.operations.impl;
9+
10+
export namespace mcpplibs::primitives::operators {
11+
template <typename T, policy::policy_type... Policies>
12+
requires std_numeric<T>
13+
constexpr auto operator~(const primitive<T, Policies...> &p) {
14+
// Placeholder: unary bitwise NOT not yet forwarded to operations layer.
15+
// TODO: forward to operations::bit_not when implemented.
16+
return primitives::primitive<T, Policies...>(~p.value());
17+
}
18+
19+
template <typename T, policy::policy_type... Policies>
20+
requires std_numeric<T>
21+
constexpr auto operator+(const primitive<T, Policies...> &p) {
22+
// Placeholder: unary plus not yet forwarded to operations layer.
23+
// TODO: forward to operations::unary_plus when implemented.
24+
return primitives::primitive<T, Policies...>(+p.value());
25+
}
26+
27+
template <typename T, policy::policy_type... Policies>
28+
requires std_numeric<T>
29+
constexpr auto operator-(const primitive<T, Policies...> &p) {
30+
// Placeholder: unary minus not yet forwarded to operations layer.
31+
// TODO: forward to operations::unary_neg when implemented.
32+
return primitives::primitive<T, Policies...>(-p.value());
33+
}
34+
35+
template <typename LHS, typename RHS, policy::policy_type... PoliciesLHS,
36+
policy::policy_type... PoliciesRHS>
37+
requires std_numeric<LHS> && std_numeric<RHS>
38+
constexpr auto operator+(const primitive<LHS, PoliciesLHS...> &lhs,
39+
const primitive<RHS, PoliciesRHS...> &rhs) {
40+
return operations::add(lhs, rhs);
41+
}
42+
43+
template <typename LHS, typename RHS, policy::policy_type... PoliciesLHS,
44+
policy::policy_type... PoliciesRHS>
45+
requires std_numeric<LHS> && std_numeric<RHS>
46+
constexpr auto operator-(const primitive<LHS, PoliciesLHS...> &lhs,
47+
const primitive<RHS, PoliciesRHS...> &rhs) {
48+
return operations::sub(lhs, rhs);
49+
}
50+
51+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
52+
policy::policy_type... PoliciesRHS>
53+
constexpr auto operator*(const primitive<LHS, PoliciesLHS...> &lhs,
54+
const primitive<RHS, PoliciesRHS...> &rhs) {
55+
return operations::mul(lhs, rhs);
56+
}
57+
58+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
59+
policy::policy_type... PoliciesRHS>
60+
constexpr auto operator/(const primitive<LHS, PoliciesLHS...> &lhs,
61+
const primitive<RHS, PoliciesRHS...> &rhs) {
62+
// Placeholder: division not yet forwarded to operations layer.
63+
// TODO: forward to operations::div when implemented (handle policies).
64+
using result_type = std::common_type_t<LHS, RHS>;
65+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
66+
static_cast<result_type>(lhs.value()) /
67+
static_cast<result_type>(rhs.value()));
68+
}
69+
70+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
71+
policy::policy_type... PoliciesRHS>
72+
constexpr auto operator%(const primitive<LHS, PoliciesLHS...> &lhs,
73+
const primitive<RHS, PoliciesRHS...> &rhs) {
74+
// Placeholder: modulo not yet forwarded to operations layer.
75+
// TODO: forward to operations::mod when implemented (handle policies).
76+
using result_type = std::common_type_t<LHS, RHS>;
77+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
78+
static_cast<result_type>(lhs.value()) %
79+
static_cast<result_type>(rhs.value()));
80+
}
81+
82+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
83+
policy::policy_type... PoliciesRHS>
84+
constexpr auto operator<<(const primitive<LHS, PoliciesLHS...> &lhs,
85+
const primitive<RHS, PoliciesRHS...> &rhs) {
86+
// Placeholder: left shift not yet forwarded to operations layer.
87+
// TODO: forward to operations::shl when implemented (handle policies).
88+
using result_type = std::common_type_t<LHS, RHS>;
89+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
90+
static_cast<result_type>(lhs.value())
91+
<< static_cast<result_type>(rhs.value()));
92+
}
93+
94+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
95+
policy::policy_type... PoliciesRHS>
96+
constexpr auto operator>>(const primitive<LHS, PoliciesLHS...> &lhs,
97+
const primitive<RHS, PoliciesRHS...> &rhs) {
98+
// Placeholder: right shift not yet forwarded to operations layer.
99+
// TODO: forward to operations::shr when implemented (handle policies).
100+
using result_type = std::common_type_t<LHS, RHS>;
101+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
102+
static_cast<result_type>(lhs.value()) >>
103+
static_cast<result_type>(rhs.value()));
104+
}
105+
106+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
107+
policy::policy_type... PoliciesRHS>
108+
constexpr auto operator&(const primitive<LHS, PoliciesLHS...> &lhs,
109+
const primitive<RHS, PoliciesRHS...> &rhs) {
110+
// Placeholder: bitwise AND not yet forwarded to operations layer.
111+
// TODO: forward to operations::bit_and when implemented (handle policies).
112+
using result_type = std::common_type_t<LHS, RHS>;
113+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
114+
static_cast<result_type>(lhs.value()) &
115+
static_cast<result_type>(rhs.value()));
116+
}
117+
118+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
119+
policy::policy_type... PoliciesRHS>
120+
constexpr auto operator|(const primitive<LHS, PoliciesLHS...> &lhs,
121+
const primitive<RHS, PoliciesRHS...> &rhs) {
122+
// Placeholder: bitwise OR not yet forwarded to operations layer.
123+
// TODO: forward to operations::bit_or when implemented (handle policies).
124+
using result_type = std::common_type_t<LHS, RHS>;
125+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
126+
static_cast<result_type>(lhs.value()) |
127+
static_cast<result_type>(rhs.value()));
128+
}
129+
130+
template <std_numeric LHS, std_numeric RHS, policy::policy_type... PoliciesLHS,
131+
policy::policy_type... PoliciesRHS>
132+
constexpr auto operator^(const primitive<LHS, PoliciesLHS...> &lhs,
133+
const primitive<RHS, PoliciesRHS...> &rhs) {
134+
// Placeholder: bitwise XOR not yet forwarded to operations layer.
135+
// TODO: forward to operations::bit_xor when implemented (handle policies).
136+
using result_type = std::common_type_t<LHS, RHS>;
137+
return primitives::primitive<result_type, PoliciesLHS..., PoliciesRHS...>(
138+
static_cast<result_type>(lhs.value()) ^
139+
static_cast<result_type>(rhs.value()));
140+
}
141+
} // namespace mcpplibs::primitives::operators

0 commit comments

Comments
 (0)