From d60372f0a0913e861da56b902c00cc448e278b50 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee Date: Wed, 18 Mar 2026 14:08:08 +0800 Subject: [PATCH 1/8] feat: Add `common_rep_traits` and `has_common_rep` concept for common representation types --- src/underlying/traits.cppm | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/underlying/traits.cppm b/src/underlying/traits.cppm index c63396a..75ef394 100644 --- a/src/underlying/traits.cppm +++ b/src/underlying/traits.cppm @@ -58,6 +58,21 @@ template struct traits { } }; +template +struct common_rep_traits { + static constexpr bool enabled = false; +}; + +template +struct common_rep_traits< + LhsRep, RhsRep, + std::void_t, + std::remove_cv_t>>> { + using type = + std::common_type_t, std::remove_cv_t>; + static constexpr bool enabled = true; +}; + } // namespace underlying } // namespace mcpplibs::primitives @@ -134,6 +149,15 @@ concept has_consistent_category = (traits>::kind == category::integer || traits>::kind == category::floating))); +template +concept has_common_rep = + common_rep_traits, + std::remove_cv_t>::enabled && + requires { + typename common_rep_traits, + std::remove_cv_t>::type; + }; + } // namespace mcpplibs::primitives::underlying::details export namespace mcpplibs::primitives { @@ -168,4 +192,12 @@ concept floating_underlying_type = template concept numeric_underlying_type = integer_underlying_type || floating_underlying_type; + +template +concept has_common_rep = underlying::details::has_common_rep; + +template +using common_rep_t = + underlying::common_rep_traits, + std::remove_cv_t>::type; } // namespace mcpplibs::primitives From a831a1a864313b016d6d04d37f871e6a4cbeda75 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee Date: Wed, 18 Mar 2026 14:10:58 +0800 Subject: [PATCH 2/8] fix: Add missing `#include ` and update common_rep logic --- src/policy/impl.cppm | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/policy/impl.cppm b/src/policy/impl.cppm index ff2c8a3..5888221 100644 --- a/src/policy/impl.cppm +++ b/src/policy/impl.cppm @@ -1,11 +1,12 @@ module; -#include #include #include #include #include +#include #include + export module mcpplibs.primitives.policy.impl; import mcpplibs.primitives.operations.traits; @@ -149,6 +150,7 @@ struct type::handler { static constexpr bool enabled = true; static constexpr bool allowed = std::is_arithmetic_v && std::is_arithmetic_v && + has_common_rep && !details::rejects_arithmetic_for_boolean_or_character_v; static constexpr unsigned diagnostic_id = @@ -157,17 +159,19 @@ struct type::handler { ? 3u : (allowed ? 0u : 2u); using common_rep = - std::conditional_t, void>; + std::conditional_t, void>; }; template struct type::handler { static constexpr bool enabled = true; static constexpr bool allowed = + has_common_rep && !details::rejects_arithmetic_for_boolean_or_character_v; static constexpr unsigned diagnostic_id = allowed ? 0u : 3u; - using common_rep = std::common_type_t; + using common_rep = + std::conditional_t, void>; }; template Date: Wed, 18 Mar 2026 14:11:40 +0800 Subject: [PATCH 3/8] refactor: Reorganize and format includes in test_operations.cpp --- tests/basic/test_operations.cpp | 34 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/basic/test_operations.cpp b/tests/basic/test_operations.cpp index e321cb3..d8bdf4b 100644 --- a/tests/basic/test_operations.cpp +++ b/tests/basic/test_operations.cpp @@ -1,10 +1,11 @@ -#include -#include #include #include +#include #include +#include #include + import mcpplibs.primitives; using namespace mcpplibs::primitives; @@ -23,7 +24,8 @@ TEST(OperationsTest, AddReturnsExpectedPrimitive) { } TEST(OperationsTest, DivisionByZeroReturnsError) { - using value_t = primitive; + using value_t = + primitive; auto const lhs = value_t{100}; auto const rhs = value_t{0}; @@ -60,8 +62,8 @@ TEST(OperationsTest, CheckedAdditionReportsUnsignedOverflow) { } TEST(OperationsTest, UncheckedAdditionWrapsUnsignedOverflow) { - using value_t = - primitive; + using value_t = primitive; auto const lhs = value_t{static_cast(65530)}; auto const rhs = value_t{static_cast(20)}; @@ -86,8 +88,9 @@ TEST(OperationsTest, UncheckedDivisionUsesRawArithmeticWhenValid) { } TEST(OperationsTest, AtomicPolicyPathReturnsExpectedValue) { - using value_t = primitive; + using value_t = + primitive; auto const lhs = value_t{12}; auto const rhs = value_t{30}; @@ -99,8 +102,9 @@ TEST(OperationsTest, AtomicPolicyPathReturnsExpectedValue) { } TEST(OperationsTest, AtomicPolicyConcurrentInvocationsRemainConsistent) { - using value_t = primitive; + using value_t = + primitive; constexpr int kThreadCount = 8; constexpr int kIterationsPerThread = 20000; @@ -147,8 +151,8 @@ TEST(OperationsTest, AtomicPolicyConcurrentInvocationsRemainConsistent) { TEST(OperationsTest, StrictTypeRejectsMixedTypesAtCompileTime) { using lhs_t = primitive; - using rhs_t = primitive; + using rhs_t = primitive; using strict_handler = policy::type::handler); + static_assert(std::is_same_v); EXPECT_EQ(char_handler::diagnostic_id, 3u); } @@ -312,7 +316,8 @@ TEST(OperationsTest, OperatorPlusDelegatesToDispatcher) { } TEST(OperationsTest, ThrowErrorPolicyThrowsException) { - using value_t = primitive; + using value_t = + primitive; auto const lhs = value_t{100}; auto const rhs = value_t{0}; @@ -321,7 +326,8 @@ TEST(OperationsTest, ThrowErrorPolicyThrowsException) { } TEST(OperationsTest, ThrowErrorPolicyExceptionHasReasonMessage) { - using value_t = primitive; + using value_t = + primitive; auto const lhs = value_t{100}; auto const rhs = value_t{0}; From 05f68b5e000c2c66808722e7667d38181aa5da30 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee Date: Wed, 18 Mar 2026 14:11:54 +0800 Subject: [PATCH 4/8] feat: Add explicit common representation traits and tests for custom types --- tests/basic/test_templates.cpp | 114 +++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tests/basic/test_templates.cpp b/tests/basic/test_templates.cpp index e68c560..574a38f 100644 --- a/tests/basic/test_templates.cpp +++ b/tests/basic/test_templates.cpp @@ -109,6 +109,47 @@ struct NonNegativeInt { int value; }; +struct ExplicitCommonLhs { + int value; +}; + +struct ExplicitCommonRhs { + int value; +}; + +struct ExplicitCommonRep { + long long value; + + friend constexpr auto operator+(ExplicitCommonRep lhs, + ExplicitCommonRep rhs) noexcept + -> ExplicitCommonRep { + return ExplicitCommonRep{lhs.value + rhs.value}; + } + + friend constexpr auto operator-(ExplicitCommonRep lhs, + ExplicitCommonRep rhs) noexcept + -> ExplicitCommonRep { + return ExplicitCommonRep{lhs.value - rhs.value}; + } + + friend constexpr auto operator*(ExplicitCommonRep lhs, + ExplicitCommonRep rhs) noexcept + -> ExplicitCommonRep { + return ExplicitCommonRep{lhs.value * rhs.value}; + } + + friend constexpr auto operator/(ExplicitCommonRep lhs, + ExplicitCommonRep rhs) noexcept + -> ExplicitCommonRep { + return ExplicitCommonRep{lhs.value / rhs.value}; + } + + friend constexpr auto operator==(ExplicitCommonRep lhs, + ExplicitCommonRep rhs) noexcept -> bool { + return lhs.value == rhs.value; + } +}; + } // namespace template <> struct mcpplibs::primitives::underlying::traits { @@ -232,6 +273,52 @@ template <> struct mcpplibs::primitives::underlying::traits { } }; +template <> struct mcpplibs::primitives::underlying::traits { + using value_type = ExplicitCommonLhs; + using rep_type = ExplicitCommonLhs; + + static constexpr bool enabled = true; + static constexpr auto kind = category::integer; + + static constexpr rep_type to_rep(value_type value) noexcept { return value; } + + static constexpr value_type from_rep(rep_type value) noexcept { + return value; + } + + static constexpr bool is_valid_rep(rep_type) noexcept { return true; } +}; + +template <> struct mcpplibs::primitives::underlying::traits { + using value_type = ExplicitCommonRhs; + using rep_type = ExplicitCommonRhs; + + static constexpr bool enabled = true; + static constexpr auto kind = category::integer; + + static constexpr rep_type to_rep(value_type value) noexcept { return value; } + + static constexpr value_type from_rep(rep_type value) noexcept { + return value; + } + + static constexpr bool is_valid_rep(rep_type) noexcept { return true; } +}; + +template <> +struct mcpplibs::primitives::underlying::common_rep_traits { + using type = ExplicitCommonRep; + static constexpr bool enabled = true; +}; + +template <> +struct mcpplibs::primitives::underlying::common_rep_traits { + using type = ExplicitCommonRep; + static constexpr bool enabled = true; +}; + TEST(PrimitiveTraitsTest, StandardTypeConcepts) { EXPECT_TRUE((mcpplibs::primitives::std_integer)); EXPECT_TRUE((mcpplibs::primitives::std_integer)); @@ -339,6 +426,33 @@ TEST(PrimitiveTraitsTest, EXPECT_FALSE((mcpplibs::primitives::underlying_type)); } +TEST(PrimitiveTraitsTest, UnderlyingCommonRepDefaultsToStdCommonType) { + static_assert(mcpplibs::primitives::has_common_rep); + static_assert(std::same_as, + long long>); + SUCCEED(); +} + +TEST(PrimitiveTraitsTest, UnderlyingCommonRepCanBeCustomizedViaTraits) { + static_assert(mcpplibs::primitives::has_common_rep); + static_assert( + std::same_as, + ExplicitCommonRep>); + + using handler_t = mcpplibs::primitives::policy::type::handler< + mcpplibs::primitives::policy::type::transparent, + mcpplibs::primitives::operations::Addition, ExplicitCommonLhs, + ExplicitCommonRhs>; + + static_assert(handler_t::enabled); + static_assert(handler_t::allowed); + static_assert( + std::same_as); + SUCCEED(); +} + int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From e2fe13bb16118eb72ed155409a6d3459132e858d Mon Sep 17 00:00:00 2001 From: FrozenlemonTee Date: Wed, 18 Mar 2026 14:12:37 +0800 Subject: [PATCH 5/8] docs: Add documentation and expected results for example files --- examples/ex01_default_arithmetic.cpp | 13 +++ examples/ex02_type_policy.cpp | 14 +++ examples/ex03_value_policy.cpp | 14 +++ examples/ex04_error_policy.cpp | 12 +++ examples/ex05_concurrency_policy.cpp | 13 +++ examples/ex06_custom_underlying.cpp | 136 +++++++++++++++++++++++++++ examples/ex07_custom_policy.cpp | 14 +++ examples/ex08_custom_operation.cpp | 13 +++ 8 files changed, 229 insertions(+) diff --git a/examples/ex01_default_arithmetic.cpp b/examples/ex01_default_arithmetic.cpp index 7d8285d..717d98e 100644 --- a/examples/ex01_default_arithmetic.cpp +++ b/examples/ex01_default_arithmetic.cpp @@ -1,3 +1,16 @@ +/* + * Example: ex01_default_arithmetic + * + * Purpose: + * Demonstrate the default primitive aliases and operator pipeline for + * arithmetic operations without custom policy overrides. + * + * Expected results: + * - All four operations (+, -, *, /) succeed through dispatcher. + * - The printed values match: sum=42, diff=38, prod=80, quot=20. + * - Program exits with code 0; otherwise prints an error and exits non-zero. + */ + #include #include diff --git a/examples/ex02_type_policy.cpp b/examples/ex02_type_policy.cpp index 0d1b531..9dcbf09 100644 --- a/examples/ex02_type_policy.cpp +++ b/examples/ex02_type_policy.cpp @@ -1,3 +1,17 @@ +/* + * Example: ex02_type_policy + * + * Purpose: + * Compare type negotiation behavior between strict and compatible policies. + * + * Expected results: + * - strict policy rejects mixed reps (int + long long) at compile-time + * negotiation, yielding common_rep=void. + * - compatible policy accepts mixed arithmetic reps and negotiates + * common_rep=long long. + * - Program prints a success message and exits with code 0. + */ + #include #include diff --git a/examples/ex03_value_policy.cpp b/examples/ex03_value_policy.cpp index 5054d01..0ce7f52 100644 --- a/examples/ex03_value_policy.cpp +++ b/examples/ex03_value_policy.cpp @@ -1,3 +1,17 @@ +/* + * Example: ex03_value_policy + * + * Purpose: + * Show how checked, unchecked, and saturating value policies behave under + * the same overflow input. + * + * Expected results: + * - checked: reports overflow as an error. + * - unchecked: wraps according to native arithmetic semantics. + * - saturating: clamps to the representable upper bound. + * - Program prints observed values and exits with code 0. + */ + #include #include diff --git a/examples/ex04_error_policy.cpp b/examples/ex04_error_policy.cpp index 60baa95..35d5bcd 100644 --- a/examples/ex04_error_policy.cpp +++ b/examples/ex04_error_policy.cpp @@ -1,3 +1,15 @@ +/* + * Example: ex04_error_policy + * + * Purpose: + * Compare error handling styles (expected vs throwing) under divide-by-zero. + * + * Expected results: + * - expected policy returns error::kind::divide_by_zero. + * - throwing policy throws std::runtime_error. + * - Program validates both paths and exits with code 0. + */ + #include #include diff --git a/examples/ex05_concurrency_policy.cpp b/examples/ex05_concurrency_policy.cpp index ac9e382..e4da76a 100644 --- a/examples/ex05_concurrency_policy.cpp +++ b/examples/ex05_concurrency_policy.cpp @@ -1,3 +1,16 @@ +/* + * Example: ex05_concurrency_policy + * + * Purpose: + * Demonstrate the atomic concurrency policy path under multi-threaded + * repeated dispatch. + * + * Expected results: + * - Concurrent add operations consistently produce value 42. + * - mismatch_count remains zero after all worker threads join. + * - Program prints a success message and exits with code 0. + */ + #include #include #include diff --git a/examples/ex06_custom_underlying.cpp b/examples/ex06_custom_underlying.cpp index f521627..16d11b5 100644 --- a/examples/ex06_custom_underlying.cpp +++ b/examples/ex06_custom_underlying.cpp @@ -1,4 +1,20 @@ +/* + * Example: ex06_custom_underlying + * + * Purpose: + * Demonstrate custom underlying integration, including rep bridge, + * rep validation, and extensible common_rep negotiation. + * + * Expected results: + * - UserInteger path succeeds and computes 40 + 2 = 42. + * - NonNegativeInt path rejects invalid rep and returns domain_error. + * - TaggedLhs/TaggedRhs path uses custom common_rep_traits to negotiate + * TaggedCommonRep, then computes 40 + 2 = 42. + * - Program prints a success message and exits with code 0. + */ + #include +#include import mcpplibs.primitives; @@ -13,6 +29,55 @@ struct NonNegativeInt { int value; }; +struct TaggedLhs { + int value; + + constexpr explicit operator long long() const noexcept { + return static_cast(value); + } +}; + +struct TaggedRhs { + int value; + + constexpr explicit operator long long() const noexcept { + return static_cast(value); + } +}; + +struct TaggedCommonRep { + long long value; + + friend constexpr auto operator+(TaggedCommonRep lhs, + TaggedCommonRep rhs) noexcept + -> TaggedCommonRep { + return TaggedCommonRep{lhs.value + rhs.value}; + } + + friend constexpr auto operator-(TaggedCommonRep lhs, + TaggedCommonRep rhs) noexcept + -> TaggedCommonRep { + return TaggedCommonRep{lhs.value - rhs.value}; + } + + friend constexpr auto operator*(TaggedCommonRep lhs, + TaggedCommonRep rhs) noexcept + -> TaggedCommonRep { + return TaggedCommonRep{lhs.value * rhs.value}; + } + + friend constexpr auto operator/(TaggedCommonRep lhs, + TaggedCommonRep rhs) noexcept + -> TaggedCommonRep { + return TaggedCommonRep{lhs.value / rhs.value}; + } + + friend constexpr auto operator==(TaggedCommonRep lhs, + TaggedCommonRep rhs) noexcept -> bool { + return lhs.value == rhs.value; + } +}; + // Point 6 / Step 2: Register underlying::traits for UserInteger. // This type has a full int bridge and accepts all reps. template <> struct mcpplibs::primitives::underlying::traits { @@ -55,6 +120,56 @@ template <> struct mcpplibs::primitives::underlying::traits { } }; +template <> struct mcpplibs::primitives::underlying::traits { + using value_type = TaggedLhs; + using rep_type = TaggedLhs; + + static constexpr bool enabled = true; + static constexpr auto kind = category::integer; + + static constexpr auto to_rep(value_type value) noexcept -> rep_type { + return value; + } + + static constexpr auto from_rep(rep_type value) noexcept -> value_type { + return value; + } + + static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; } +}; + +template <> struct mcpplibs::primitives::underlying::traits { + using value_type = TaggedRhs; + using rep_type = TaggedRhs; + + static constexpr bool enabled = true; + static constexpr auto kind = category::integer; + + static constexpr auto to_rep(value_type value) noexcept -> rep_type { + return value; + } + + static constexpr auto from_rep(rep_type value) noexcept -> value_type { + return value; + } + + static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; } +}; + +template <> +struct mcpplibs::primitives::underlying::common_rep_traits { + using type = TaggedCommonRep; + static constexpr bool enabled = true; +}; + +template <> +struct mcpplibs::primitives::underlying::common_rep_traits { + using type = TaggedCommonRep; + static constexpr bool enabled = true; +}; + int main() { // Point 6 / Step 4A: Call operations on UserInteger custom underlying. using user_t = @@ -81,6 +196,27 @@ int main() { return 1; } + // Point 6 / Step 4C: Demonstrate extensible common_rep negotiation. + using lhs_t = primitive; + using rhs_t = primitive; + + using transparent_handler = + policy::type::handler; + static_assert(transparent_handler::allowed); + static_assert( + std::same_as); + + auto const lhs = lhs_t{TaggedLhs{40}}; + auto const rhs = rhs_t{TaggedRhs{2}}; + auto const mixed_result = operations::add(lhs, rhs); + if (!mixed_result.has_value() || mixed_result->value().value != 42) { + std::cerr << "custom common_rep negotiation failed\n"; + return 1; + } + std::cout << "custom underlying demo passed\n"; return 0; } diff --git a/examples/ex07_custom_policy.cpp b/examples/ex07_custom_policy.cpp index b793012..0c6e0d1 100644 --- a/examples/ex07_custom_policy.cpp +++ b/examples/ex07_custom_policy.cpp @@ -1,3 +1,17 @@ +/* + * Example: ex07_custom_policy + * + * Purpose: + * Show end-to-end customization of all policy dimensions (type, value, + * error, concurrency) and custom operation binding integration. + * + * Expected results: + * - Custom policy traits are recognized and selected by dispatcher. + * - Custom value finalize step adjusts addition result by +1. + * - Input 20 and 21 produces final value 42. + * - Program prints a success message and exits with code 0. + */ + #include #include #include diff --git a/examples/ex08_custom_operation.cpp b/examples/ex08_custom_operation.cpp index 902a667..ec6f850 100644 --- a/examples/ex08_custom_operation.cpp +++ b/examples/ex08_custom_operation.cpp @@ -1,3 +1,16 @@ +/* + * Example: ex08_custom_operation + * + * Purpose: + * Demonstrate how to register new operation tags, declare operation traits, + * and provide runtime op_binding specializations. + * + * Expected results: + * - Custom operations Average, GreaterThan, and BitAnd dispatch successfully. + * - For inputs 10 and 6, outputs are avg=8, gt=1, bitand=2. + * - Program prints computed values and exits with code 0. + */ + #include import mcpplibs.primitives; From 54a905586923898762248860e6a0536f459f2de8 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee Date: Wed, 18 Mar 2026 14:16:42 +0800 Subject: [PATCH 6/8] refactor: Update import statements for traits in impl.cppm --- src/primitive/impl.cppm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/primitive/impl.cppm b/src/primitive/impl.cppm index 4c1fa23..5c0d682 100644 --- a/src/primitive/impl.cppm +++ b/src/primitive/impl.cppm @@ -4,8 +4,8 @@ module; export module mcpplibs.primitives.primitive.impl; -import mcpplibs.primitives.policy; -import mcpplibs.primitives.underlying; +import mcpplibs.primitives.underlying.traits; +import mcpplibs.primitives.policy.traits; export namespace mcpplibs::primitives { From b0654740f469edd1a31b0d4eb89b66ebd8040376 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee Date: Wed, 18 Mar 2026 14:20:26 +0800 Subject: [PATCH 7/8] refactor: Update import statements for traits in traits.cppm --- src/primitive/traits.cppm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/primitive/traits.cppm b/src/primitive/traits.cppm index 4328827..8726d5a 100644 --- a/src/primitive/traits.cppm +++ b/src/primitive/traits.cppm @@ -5,8 +5,9 @@ module; export module mcpplibs.primitives.primitive.traits; import mcpplibs.primitives.primitive.impl; -import mcpplibs.primitives.policy; -import mcpplibs.primitives.underlying; +import mcpplibs.primitives.policy.traits; +import mcpplibs.primitives.policy.impl; +import mcpplibs.primitives.underlying.traits; // Internal implementation details - not exported. namespace mcpplibs::primitives::traits::details { From 81df870ffe068defccad916497f50f1071cd410a Mon Sep 17 00:00:00 2001 From: FrozenLemonTee Date: Wed, 18 Mar 2026 21:40:25 +0800 Subject: [PATCH 8/8] fix: CI Test --- examples/ex06_custom_underlying.cpp | 73 +++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/examples/ex06_custom_underlying.cpp b/examples/ex06_custom_underlying.cpp index 16d11b5..fe27c5e 100644 --- a/examples/ex06_custom_underlying.cpp +++ b/examples/ex06_custom_underlying.cpp @@ -32,6 +32,31 @@ struct NonNegativeInt { struct TaggedLhs { int value; + friend constexpr auto operator+(TaggedLhs lhs, TaggedLhs rhs) noexcept + -> TaggedLhs { + return TaggedLhs{lhs.value + rhs.value}; + } + + friend constexpr auto operator-(TaggedLhs lhs, TaggedLhs rhs) noexcept + -> TaggedLhs { + return TaggedLhs{lhs.value - rhs.value}; + } + + friend constexpr auto operator*(TaggedLhs lhs, TaggedLhs rhs) noexcept + -> TaggedLhs { + return TaggedLhs{lhs.value * rhs.value}; + } + + friend constexpr auto operator/(TaggedLhs lhs, TaggedLhs rhs) noexcept + -> TaggedLhs { + return TaggedLhs{lhs.value / rhs.value}; + } + + friend constexpr auto operator==(TaggedLhs lhs, TaggedLhs rhs) noexcept + -> bool { + return lhs.value == rhs.value; + } + constexpr explicit operator long long() const noexcept { return static_cast(value); } @@ -40,6 +65,31 @@ struct TaggedLhs { struct TaggedRhs { int value; + friend constexpr auto operator+(TaggedRhs lhs, TaggedRhs rhs) noexcept + -> TaggedRhs { + return TaggedRhs{lhs.value + rhs.value}; + } + + friend constexpr auto operator-(TaggedRhs lhs, TaggedRhs rhs) noexcept + -> TaggedRhs { + return TaggedRhs{lhs.value - rhs.value}; + } + + friend constexpr auto operator*(TaggedRhs lhs, TaggedRhs rhs) noexcept + -> TaggedRhs { + return TaggedRhs{lhs.value * rhs.value}; + } + + friend constexpr auto operator/(TaggedRhs lhs, TaggedRhs rhs) noexcept + -> TaggedRhs { + return TaggedRhs{lhs.value / rhs.value}; + } + + friend constexpr auto operator==(TaggedRhs lhs, TaggedRhs rhs) noexcept + -> bool { + return lhs.value == rhs.value; + } + constexpr explicit operator long long() const noexcept { return static_cast(value); } @@ -48,6 +98,11 @@ struct TaggedRhs { struct TaggedCommonRep { long long value; + constexpr TaggedCommonRep() noexcept = default; + constexpr explicit TaggedCommonRep(long long v) noexcept : value(v) {} + constexpr explicit TaggedCommonRep(TaggedLhs v) noexcept : value(v.value) {} + constexpr explicit TaggedCommonRep(TaggedRhs v) noexcept : value(v.value) {} + friend constexpr auto operator+(TaggedCommonRep lhs, TaggedCommonRep rhs) noexcept -> TaggedCommonRep { @@ -156,6 +211,24 @@ template <> struct mcpplibs::primitives::underlying::traits { static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; } }; +template <> struct mcpplibs::primitives::underlying::traits { + using value_type = TaggedCommonRep; + using rep_type = TaggedCommonRep; + + static constexpr bool enabled = true; + static constexpr auto kind = category::integer; + + static constexpr auto to_rep(value_type value) noexcept -> rep_type { + return value; + } + + static constexpr auto from_rep(rep_type value) noexcept -> value_type { + return value; + } + + static constexpr auto is_valid_rep(rep_type) noexcept -> bool { return true; } +}; + template <> struct mcpplibs::primitives::underlying::common_rep_traits {