Skip to content

Commit 34c19a8

Browse files
Merge pull request #6 from mcpplibs/extract-type-handler-common-rep
Extract type handler common rep
2 parents 298978f + c480a5a commit 34c19a8

14 files changed

Lines changed: 480 additions & 21 deletions

examples/ex01_default_arithmetic.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Example: ex01_default_arithmetic
3+
*
4+
* Purpose:
5+
* Demonstrate the default primitive aliases and operator pipeline for
6+
* arithmetic operations without custom policy overrides.
7+
*
8+
* Expected results:
9+
* - All four operations (+, -, *, /) succeed through dispatcher.
10+
* - The printed values match: sum=42, diff=38, prod=80, quot=20.
11+
* - Program exits with code 0; otherwise prints an error and exits non-zero.
12+
*/
13+
114
#include <cstdint>
215
#include <iostream>
316

examples/ex02_type_policy.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
/*
2+
* Example: ex02_type_policy
3+
*
4+
* Purpose:
5+
* Compare type negotiation behavior between strict and compatible policies.
6+
*
7+
* Expected results:
8+
* - strict policy rejects mixed reps (int + long long) at compile-time
9+
* negotiation, yielding common_rep=void.
10+
* - compatible policy accepts mixed arithmetic reps and negotiates
11+
* common_rep=long long.
12+
* - Program prints a success message and exits with code 0.
13+
*/
14+
115
#include <iostream>
216
#include <type_traits>
317

examples/ex03_value_policy.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
/*
2+
* Example: ex03_value_policy
3+
*
4+
* Purpose:
5+
* Show how checked, unchecked, and saturating value policies behave under
6+
* the same overflow input.
7+
*
8+
* Expected results:
9+
* - checked: reports overflow as an error.
10+
* - unchecked: wraps according to native arithmetic semantics.
11+
* - saturating: clamps to the representable upper bound.
12+
* - Program prints observed values and exits with code 0.
13+
*/
14+
115
#include <cstdint>
216
#include <iostream>
317

examples/ex04_error_policy.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
/*
2+
* Example: ex04_error_policy
3+
*
4+
* Purpose:
5+
* Compare error handling styles (expected vs throwing) under divide-by-zero.
6+
*
7+
* Expected results:
8+
* - expected policy returns error::kind::divide_by_zero.
9+
* - throwing policy throws std::runtime_error.
10+
* - Program validates both paths and exits with code 0.
11+
*/
12+
113
#include <iostream>
214
#include <stdexcept>
315

examples/ex05_concurrency_policy.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Example: ex05_concurrency_policy
3+
*
4+
* Purpose:
5+
* Demonstrate the atomic concurrency policy path under multi-threaded
6+
* repeated dispatch.
7+
*
8+
* Expected results:
9+
* - Concurrent add operations consistently produce value 42.
10+
* - mismatch_count remains zero after all worker threads join.
11+
* - Program prints a success message and exits with code 0.
12+
*/
13+
114
#include <atomic>
215
#include <iostream>
316
#include <thread>

examples/ex06_custom_underlying.cpp

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
1+
/*
2+
* Example: ex06_custom_underlying
3+
*
4+
* Purpose:
5+
* Demonstrate custom underlying integration, including rep bridge,
6+
* rep validation, and extensible common_rep negotiation.
7+
*
8+
* Expected results:
9+
* - UserInteger path succeeds and computes 40 + 2 = 42.
10+
* - NonNegativeInt path rejects invalid rep and returns domain_error.
11+
* - TaggedLhs/TaggedRhs path uses custom common_rep_traits to negotiate
12+
* TaggedCommonRep, then computes 40 + 2 = 42.
13+
* - Program prints a success message and exits with code 0.
14+
*/
15+
116
#include <iostream>
17+
#include <type_traits>
218

319
import mcpplibs.primitives;
420

@@ -13,6 +29,110 @@ struct NonNegativeInt {
1329
int value;
1430
};
1531

32+
struct TaggedLhs {
33+
int value;
34+
35+
friend constexpr auto operator+(TaggedLhs lhs, TaggedLhs rhs) noexcept
36+
-> TaggedLhs {
37+
return TaggedLhs{lhs.value + rhs.value};
38+
}
39+
40+
friend constexpr auto operator-(TaggedLhs lhs, TaggedLhs rhs) noexcept
41+
-> TaggedLhs {
42+
return TaggedLhs{lhs.value - rhs.value};
43+
}
44+
45+
friend constexpr auto operator*(TaggedLhs lhs, TaggedLhs rhs) noexcept
46+
-> TaggedLhs {
47+
return TaggedLhs{lhs.value * rhs.value};
48+
}
49+
50+
friend constexpr auto operator/(TaggedLhs lhs, TaggedLhs rhs) noexcept
51+
-> TaggedLhs {
52+
return TaggedLhs{lhs.value / rhs.value};
53+
}
54+
55+
friend constexpr auto operator==(TaggedLhs lhs, TaggedLhs rhs) noexcept
56+
-> bool {
57+
return lhs.value == rhs.value;
58+
}
59+
60+
constexpr explicit operator long long() const noexcept {
61+
return static_cast<long long>(value);
62+
}
63+
};
64+
65+
struct TaggedRhs {
66+
int value;
67+
68+
friend constexpr auto operator+(TaggedRhs lhs, TaggedRhs rhs) noexcept
69+
-> TaggedRhs {
70+
return TaggedRhs{lhs.value + rhs.value};
71+
}
72+
73+
friend constexpr auto operator-(TaggedRhs lhs, TaggedRhs rhs) noexcept
74+
-> TaggedRhs {
75+
return TaggedRhs{lhs.value - rhs.value};
76+
}
77+
78+
friend constexpr auto operator*(TaggedRhs lhs, TaggedRhs rhs) noexcept
79+
-> TaggedRhs {
80+
return TaggedRhs{lhs.value * rhs.value};
81+
}
82+
83+
friend constexpr auto operator/(TaggedRhs lhs, TaggedRhs rhs) noexcept
84+
-> TaggedRhs {
85+
return TaggedRhs{lhs.value / rhs.value};
86+
}
87+
88+
friend constexpr auto operator==(TaggedRhs lhs, TaggedRhs rhs) noexcept
89+
-> bool {
90+
return lhs.value == rhs.value;
91+
}
92+
93+
constexpr explicit operator long long() const noexcept {
94+
return static_cast<long long>(value);
95+
}
96+
};
97+
98+
struct TaggedCommonRep {
99+
long long value;
100+
101+
constexpr TaggedCommonRep() noexcept = default;
102+
constexpr explicit TaggedCommonRep(long long v) noexcept : value(v) {}
103+
constexpr explicit TaggedCommonRep(TaggedLhs v) noexcept : value(v.value) {}
104+
constexpr explicit TaggedCommonRep(TaggedRhs v) noexcept : value(v.value) {}
105+
106+
friend constexpr auto operator+(TaggedCommonRep lhs,
107+
TaggedCommonRep rhs) noexcept
108+
-> TaggedCommonRep {
109+
return TaggedCommonRep{lhs.value + rhs.value};
110+
}
111+
112+
friend constexpr auto operator-(TaggedCommonRep lhs,
113+
TaggedCommonRep rhs) noexcept
114+
-> TaggedCommonRep {
115+
return TaggedCommonRep{lhs.value - rhs.value};
116+
}
117+
118+
friend constexpr auto operator*(TaggedCommonRep lhs,
119+
TaggedCommonRep rhs) noexcept
120+
-> TaggedCommonRep {
121+
return TaggedCommonRep{lhs.value * rhs.value};
122+
}
123+
124+
friend constexpr auto operator/(TaggedCommonRep lhs,
125+
TaggedCommonRep rhs) noexcept
126+
-> TaggedCommonRep {
127+
return TaggedCommonRep{lhs.value / rhs.value};
128+
}
129+
130+
friend constexpr auto operator==(TaggedCommonRep lhs,
131+
TaggedCommonRep rhs) noexcept -> bool {
132+
return lhs.value == rhs.value;
133+
}
134+
};
135+
16136
// Point 6 / Step 2: Register underlying::traits for UserInteger.
17137
// This type has a full int bridge and accepts all reps.
18138
template <> struct mcpplibs::primitives::underlying::traits<UserInteger> {
@@ -55,6 +175,74 @@ template <> struct mcpplibs::primitives::underlying::traits<NonNegativeInt> {
55175
}
56176
};
57177

178+
template <> struct mcpplibs::primitives::underlying::traits<TaggedLhs> {
179+
using value_type = TaggedLhs;
180+
using rep_type = TaggedLhs;
181+
182+
static constexpr bool enabled = true;
183+
static constexpr auto kind = category::integer;
184+
185+
static constexpr auto to_rep(value_type value) noexcept -> rep_type {
186+
return value;
187+
}
188+
189+
static constexpr auto from_rep(rep_type value) noexcept -> value_type {
190+
return value;
191+
}
192+
193+
static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; }
194+
};
195+
196+
template <> struct mcpplibs::primitives::underlying::traits<TaggedRhs> {
197+
using value_type = TaggedRhs;
198+
using rep_type = TaggedRhs;
199+
200+
static constexpr bool enabled = true;
201+
static constexpr auto kind = category::integer;
202+
203+
static constexpr auto to_rep(value_type value) noexcept -> rep_type {
204+
return value;
205+
}
206+
207+
static constexpr auto from_rep(rep_type value) noexcept -> value_type {
208+
return value;
209+
}
210+
211+
static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; }
212+
};
213+
214+
template <> struct mcpplibs::primitives::underlying::traits<TaggedCommonRep> {
215+
using value_type = TaggedCommonRep;
216+
using rep_type = TaggedCommonRep;
217+
218+
static constexpr bool enabled = true;
219+
static constexpr auto kind = category::integer;
220+
221+
static constexpr auto to_rep(value_type value) noexcept -> rep_type {
222+
return value;
223+
}
224+
225+
static constexpr auto from_rep(rep_type value) noexcept -> value_type {
226+
return value;
227+
}
228+
229+
static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; }
230+
};
231+
232+
template <>
233+
struct mcpplibs::primitives::underlying::common_rep_traits<TaggedLhs,
234+
TaggedRhs> {
235+
using type = TaggedCommonRep;
236+
static constexpr bool enabled = true;
237+
};
238+
239+
template <>
240+
struct mcpplibs::primitives::underlying::common_rep_traits<TaggedRhs,
241+
TaggedLhs> {
242+
using type = TaggedCommonRep;
243+
static constexpr bool enabled = true;
244+
};
245+
58246
int main() {
59247
// Point 6 / Step 4A: Call operations on UserInteger custom underlying.
60248
using user_t =
@@ -81,6 +269,27 @@ int main() {
81269
return 1;
82270
}
83271

272+
// Point 6 / Step 4C: Demonstrate extensible common_rep negotiation.
273+
using lhs_t = primitive<TaggedLhs, policy::value::checked,
274+
policy::type::transparent, policy::error::expected>;
275+
using rhs_t = primitive<TaggedRhs, policy::value::checked,
276+
policy::type::transparent, policy::error::expected>;
277+
278+
using transparent_handler =
279+
policy::type::handler<policy::type::transparent, operations::Addition,
280+
TaggedLhs, TaggedRhs>;
281+
static_assert(transparent_handler::allowed);
282+
static_assert(
283+
std::same_as<typename transparent_handler::common_rep, TaggedCommonRep>);
284+
285+
auto const lhs = lhs_t{TaggedLhs{40}};
286+
auto const rhs = rhs_t{TaggedRhs{2}};
287+
auto const mixed_result = operations::add(lhs, rhs);
288+
if (!mixed_result.has_value() || mixed_result->value().value != 42) {
289+
std::cerr << "custom common_rep negotiation failed\n";
290+
return 1;
291+
}
292+
84293
std::cout << "custom underlying demo passed\n";
85294
return 0;
86295
}

examples/ex07_custom_policy.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
/*
2+
* Example: ex07_custom_policy
3+
*
4+
* Purpose:
5+
* Show end-to-end customization of all policy dimensions (type, value,
6+
* error, concurrency) and custom operation binding integration.
7+
*
8+
* Expected results:
9+
* - Custom policy traits are recognized and selected by dispatcher.
10+
* - Custom value finalize step adjusts addition result by +1.
11+
* - Input 20 and 21 produces final value 42.
12+
* - Program prints a success message and exits with code 0.
13+
*/
14+
115
#include <expected>
216
#include <iostream>
317
#include <type_traits>

examples/ex08_custom_operation.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/*
2+
* Example: ex08_custom_operation
3+
*
4+
* Purpose:
5+
* Demonstrate how to register new operation tags, declare operation traits,
6+
* and provide runtime op_binding specializations.
7+
*
8+
* Expected results:
9+
* - Custom operations Average, GreaterThan, and BitAnd dispatch successfully.
10+
* - For inputs 10 and 6, outputs are avg=8, gt=1, bitand=2.
11+
* - Program prints computed values and exits with code 0.
12+
*/
13+
114
#include <iostream>
215

316
import mcpplibs.primitives;

src/policy/impl.cppm

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module;
2-
#include <string>
32
#include <concepts>
43
#include <exception>
54
#include <expected>
65
#include <stdexcept>
6+
#include <string>
77
#include <type_traits>
88

9+
910
export module mcpplibs.primitives.policy.impl;
1011

1112
import mcpplibs.primitives.operations.traits;
@@ -149,6 +150,7 @@ struct type::handler<type::compatible, OpTag, LhsRep, RhsRep> {
149150
static constexpr bool enabled = true;
150151
static constexpr bool allowed =
151152
std::is_arithmetic_v<LhsRep> && std::is_arithmetic_v<RhsRep> &&
153+
has_common_rep<LhsRep, RhsRep> &&
152154
!details::rejects_arithmetic_for_boolean_or_character_v<OpTag, LhsRep,
153155
RhsRep>;
154156
static constexpr unsigned diagnostic_id =
@@ -157,17 +159,19 @@ struct type::handler<type::compatible, OpTag, LhsRep, RhsRep> {
157159
? 3u
158160
: (allowed ? 0u : 2u);
159161
using common_rep =
160-
std::conditional_t<allowed, std::common_type_t<LhsRep, RhsRep>, void>;
162+
std::conditional_t<allowed, common_rep_t<LhsRep, RhsRep>, void>;
161163
};
162164

163165
template <operations::operation OpTag, typename LhsRep, typename RhsRep>
164166
struct type::handler<type::transparent, OpTag, LhsRep, RhsRep> {
165167
static constexpr bool enabled = true;
166168
static constexpr bool allowed =
169+
has_common_rep<LhsRep, RhsRep> &&
167170
!details::rejects_arithmetic_for_boolean_or_character_v<OpTag, LhsRep,
168171
RhsRep>;
169172
static constexpr unsigned diagnostic_id = allowed ? 0u : 3u;
170-
using common_rep = std::common_type_t<LhsRep, RhsRep>;
173+
using common_rep =
174+
std::conditional_t<allowed, common_rep_t<LhsRep, RhsRep>, void>;
171175
};
172176

173177
template <operations::operation OpTag, typename CommonRep,

0 commit comments

Comments
 (0)