From f597d20643efe336676d4104b35bc5c719f83d59 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 17:23:27 +0800 Subject: [PATCH 1/8] refactor: Rename test file from test_templates.cpp to test_underlying.cpp for clarity Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- tests/basic/{test_templates.cpp => test_underlying.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/basic/{test_templates.cpp => test_underlying.cpp} (100%) diff --git a/tests/basic/test_templates.cpp b/tests/basic/test_underlying.cpp similarity index 100% rename from tests/basic/test_templates.cpp rename to tests/basic/test_underlying.cpp From 86fdfdc091cf0eb83bef8e073cc0232ff8afcc5e Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 17:23:40 +0800 Subject: [PATCH 2/8] feat: Add unary and binary operation structs with traits for new operations Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- src/operations/impl.cppm | 104 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/operations/impl.cppm b/src/operations/impl.cppm index 338a3f3..60ac12d 100644 --- a/src/operations/impl.cppm +++ b/src/operations/impl.cppm @@ -4,14 +4,70 @@ import mcpplibs.primitives.operations.traits; export namespace mcpplibs::primitives::operations { +// Unary operations +struct Increment {}; +struct Decrement {}; +struct BitwiseNot {}; +struct UnaryPlus {}; +struct UnaryMinus {}; + +// Binary operations struct Addition {}; struct Subtraction {}; struct Multiplication {}; struct Division {}; +struct Modulus {}; +struct LeftShift {}; +struct RightShift {}; +struct BitwiseAnd {}; +struct BitwiseOr {}; +struct BitwiseXor {}; + +// Comparison operations struct Equal {}; struct NotEqual {}; struct ThreeWayCompare {}; +template <> struct traits { + using op_tag = Increment; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::unary; + static constexpr auto capability_mask = capability::arithmetic; +}; + +template <> struct traits { + using op_tag = Decrement; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::unary; + static constexpr auto capability_mask = capability::arithmetic; +}; + +template <> struct traits { + using op_tag = BitwiseNot; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::unary; + static constexpr auto capability_mask = capability::bitwise; +}; + +template <> struct traits { + using op_tag = UnaryPlus; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::unary; + static constexpr auto capability_mask = capability::arithmetic; +}; + +template <> struct traits { + using op_tag = UnaryMinus; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::unary; + static constexpr auto capability_mask = capability::arithmetic; +}; + template <> struct traits { using op_tag = Addition; @@ -44,6 +100,54 @@ template <> struct traits { static constexpr auto capability_mask = capability::arithmetic; }; +template <> struct traits { + using op_tag = Modulus; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::binary; + static constexpr auto capability_mask = capability::arithmetic; +}; + +template <> struct traits { + using op_tag = LeftShift; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::binary; + static constexpr auto capability_mask = capability::bitwise; +}; + +template <> struct traits { + using op_tag = RightShift; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::binary; + static constexpr auto capability_mask = capability::bitwise; +}; + +template <> struct traits { + using op_tag = BitwiseAnd; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::binary; + static constexpr auto capability_mask = capability::bitwise; +}; + +template <> struct traits { + using op_tag = BitwiseOr; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::binary; + static constexpr auto capability_mask = capability::bitwise; +}; + +template <> struct traits { + using op_tag = BitwiseXor; + + static constexpr bool enabled = true; + static constexpr auto arity = dimension::binary; + static constexpr auto capability_mask = capability::bitwise; +}; + template <> struct traits { using op_tag = Equal; From d8aa268ddd78260759541748fa1037fdf500f5b5 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 17:23:49 +0800 Subject: [PATCH 3/8] feat: Implement checked and unchecked operations for modulus, shifts, bitwise operations, and unary operations Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- src/operations/invoker.cppm | 675 ++++++++++++++++++++++++++++++++++++ 1 file changed, 675 insertions(+) diff --git a/src/operations/invoker.cppm b/src/operations/invoker.cppm index 569d04c..328d0d8 100644 --- a/src/operations/invoker.cppm +++ b/src/operations/invoker.cppm @@ -194,6 +194,217 @@ constexpr auto checked_div(T lhs, T rhs) -> policy::value::decision { "checked division not supported for negotiated common type", lhs, rhs); } +template +constexpr auto checked_mod(T lhs, T rhs) -> policy::value::decision { + if constexpr (!std::is_integral_v) { + if constexpr (requires { lhs % rhs; }) { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs % rhs); + return out; + } + return make_error( + policy::error::kind::unspecified, + "checked modulus not supported for negotiated common type", lhs, rhs); + } else { + if (rhs == T{}) { + return make_error(policy::error::kind::divide_by_zero, + "checked modulus by zero", lhs, rhs); + } + + if constexpr (std::is_signed_v) { + auto const minv = std::numeric_limits::min(); + if (lhs == minv && rhs == static_cast(-1)) { + return make_error(policy::error::kind::overflow, + "checked modulus overflow", lhs, rhs); + } + } + + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs % rhs); + return out; + } +} + +template +constexpr auto checked_unary_plus(T lhs) -> policy::value::decision { + policy::value::decision out{}; + if constexpr (requires { +lhs; }) { + out.has_value = true; + out.value = static_cast(+lhs); + return out; + } + return make_error(policy::error::kind::unspecified, + "checked unary plus not supported for negotiated " + "common type"); +} + +template +constexpr auto checked_unary_minus(T lhs) -> policy::value::decision { + if constexpr (std::is_integral_v && std::is_signed_v) { + auto const minv = std::numeric_limits::min(); + if (lhs == minv) { + return make_error(policy::error::kind::overflow, + "checked unary minus overflow", lhs); + } + } + + policy::value::decision out{}; + if constexpr (requires { -lhs; }) { + out.has_value = true; + out.value = static_cast(-lhs); + return out; + } + return make_error(policy::error::kind::unspecified, + "checked unary minus not supported for negotiated " + "common type"); +} + +template +constexpr auto checked_shift_left(T lhs, T rhs) -> policy::value::decision { + if constexpr (!std::is_integral_v || std::same_as) { + return make_error( + policy::error::kind::unspecified, + "checked left shift not supported for negotiated common type", lhs, + rhs); + } else { + using unsigned_t = std::make_unsigned_t; + constexpr auto bit_width = std::numeric_limits::digits; + + if constexpr (std::is_signed_v) { + if (rhs < T{}) { + return make_error(policy::error::kind::domain_error, + "checked left shift negative count", lhs, rhs); + } + } + + auto const shift = static_cast(rhs); + if (shift >= static_cast(bit_width)) { + return make_error(policy::error::kind::domain_error, + "checked left shift count out of range", lhs, rhs); + } + + if constexpr (std::is_signed_v) { + if (lhs < T{}) { + return make_error(policy::error::kind::domain_error, + "checked left shift negative lhs", lhs, rhs); + } + + auto const maxv = std::numeric_limits::max(); + if (lhs > static_cast(maxv >> shift)) { + return make_error(policy::error::kind::overflow, + "checked left shift overflow", lhs, rhs); + } + } + + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs << shift); + return out; + } +} + +template +constexpr auto checked_shift_right(T lhs, T rhs) + -> policy::value::decision { + if constexpr (!std::is_integral_v || std::same_as) { + return make_error( + policy::error::kind::unspecified, + "checked right shift not supported for negotiated common type", lhs, + rhs); + } else { + using unsigned_t = std::make_unsigned_t; + constexpr auto bit_width = std::numeric_limits::digits; + + if constexpr (std::is_signed_v) { + if (rhs < T{}) { + return make_error(policy::error::kind::domain_error, + "checked right shift negative count", lhs, rhs); + } + } + + auto const shift = static_cast(rhs); + if (shift >= static_cast(bit_width)) { + return make_error(policy::error::kind::domain_error, + "checked right shift count out of range", lhs, rhs); + } + + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs >> shift); + return out; + } +} + +template +constexpr auto checked_bit_and(T lhs, T rhs) -> policy::value::decision { + if constexpr (std::integral) { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs & rhs); + return out; + } + + return make_error( + policy::error::kind::unspecified, + "checked bitwise and not supported for negotiated common type", lhs, rhs); +} + +template +constexpr auto checked_bit_or(T lhs, T rhs) -> policy::value::decision { + if constexpr (std::integral) { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs | rhs); + return out; + } + + return make_error( + policy::error::kind::unspecified, + "checked bitwise or not supported for negotiated common type", lhs, rhs); +} + +template +constexpr auto checked_bit_xor(T lhs, T rhs) -> policy::value::decision { + if constexpr (std::integral) { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs ^ rhs); + return out; + } + + return make_error(policy::error::kind::unspecified, + "checked bitwise xor not supported for negotiated " + "common type", + lhs, rhs); +} + +template +constexpr auto checked_bit_not(T lhs) -> policy::value::decision { + if constexpr (std::integral) { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(~lhs); + return out; + } + + return make_error(policy::error::kind::unspecified, + "checked bitwise not not supported for negotiated " + "common type", + lhs); +} + +template +constexpr auto checked_inc(T lhs) -> policy::value::decision { + return checked_add(lhs, static_cast(1)); +} + +template +constexpr auto checked_dec(T lhs) -> policy::value::decision { + return checked_sub(lhs, static_cast(1)); +} + template constexpr auto compare_equal(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; @@ -330,6 +541,89 @@ constexpr auto unchecked_div(T lhs, T rhs) -> policy::value::decision { return out; } +template +constexpr auto unchecked_mod(T lhs, T rhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs % rhs); + return out; +} + +template +constexpr auto unchecked_shift_left(T lhs, T rhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs << rhs); + return out; +} + +template +constexpr auto unchecked_shift_right(T lhs, T rhs) + -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs >> rhs); + return out; +} + +template +constexpr auto unchecked_bit_and(T lhs, T rhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs & rhs); + return out; +} + +template +constexpr auto unchecked_bit_or(T lhs, T rhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs | rhs); + return out; +} + +template +constexpr auto unchecked_bit_xor(T lhs, T rhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(lhs ^ rhs); + return out; +} + +template +constexpr auto unchecked_bit_not(T lhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(~lhs); + return out; +} + +template +constexpr auto unchecked_unary_plus(T lhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(+lhs); + return out; +} + +template +constexpr auto unchecked_unary_minus(T lhs) -> policy::value::decision { + policy::value::decision out{}; + out.has_value = true; + out.value = static_cast(-lhs); + return out; +} + +template +constexpr auto unchecked_inc(T lhs) -> policy::value::decision { + return unchecked_add(lhs, static_cast(1)); +} + +template +constexpr auto unchecked_dec(T lhs) -> policy::value::decision { + return unchecked_sub(lhs, static_cast(1)); +} + template constexpr auto saturating_add(T lhs, T rhs) -> T { if constexpr (!std::is_integral_v || std::is_same_v) { return static_cast(lhs + rhs); @@ -409,6 +703,18 @@ template constexpr auto saturating_mul(T lhs, T rhs) -> T { } } +template constexpr auto saturating_unary_minus(T lhs) -> T { + return saturating_sub(static_cast(0), lhs); +} + +template constexpr auto saturating_inc(T lhs) -> T { + return saturating_add(lhs, static_cast(1)); +} + +template constexpr auto saturating_dec(T lhs) -> T { + return saturating_sub(lhs, static_cast(1)); +} + template constexpr auto make_unsupported(char const *reason) -> policy::value::decision { @@ -508,6 +814,131 @@ struct op_binding { } }; +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + if constexpr (requires { details::checked_mod(lhs, rhs); }) { + return details::checked_mod(lhs, rhs); + } + + return details::make_unsupported( + "checked modulus not supported for negotiated common type"); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + if constexpr (requires { details::checked_shift_left(lhs, rhs); }) { + return details::checked_shift_left(lhs, rhs); + } + + return details::make_unsupported( + "checked left shift not supported for negotiated common type"); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + if constexpr (requires { details::checked_shift_right(lhs, rhs); }) { + return details::checked_shift_right(lhs, rhs); + } + + return details::make_unsupported( + "checked right shift not supported for negotiated common type"); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::checked_bit_and(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::checked_bit_or(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::checked_bit_xor(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_inc(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_dec(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_unary_plus(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_unary_minus(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_bit_not(lhs); + } +}; + template struct op_binding { static constexpr bool enabled = true; @@ -548,6 +979,116 @@ struct op_binding { } }; +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::unchecked_mod(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::unchecked_shift_left(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::unchecked_shift_right(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::unchecked_bit_and(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::unchecked_bit_or(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::unchecked_bit_xor(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::unchecked_inc(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::unchecked_dec(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::unchecked_unary_plus(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::unchecked_unary_minus(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::unchecked_bit_not(lhs); + } +}; + template struct op_binding { static constexpr bool enabled = true; @@ -622,6 +1163,140 @@ struct op_binding { } }; +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return op_binding::apply(lhs, + rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return op_binding::apply(lhs, + rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return op_binding::apply( + lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::checked_bit_and(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::checked_bit_or(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep rhs) + -> policy::value::decision { + return details::checked_bit_xor(lhs, rhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + policy::value::decision out{}; + if constexpr (requires { details::saturating_inc(lhs); }) { + out.has_value = true; + out.value = details::saturating_inc(lhs); + return out; + } + return details::make_unsupported( + "saturating increment not supported for negotiated common type"); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + policy::value::decision out{}; + if constexpr (requires { details::saturating_dec(lhs); }) { + out.has_value = true; + out.value = details::saturating_dec(lhs); + return out; + } + return details::make_unsupported( + "saturating decrement not supported for negotiated common type"); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_unary_plus(lhs); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + policy::value::decision out{}; + if constexpr (requires { details::saturating_unary_minus(lhs); }) { + out.has_value = true; + out.value = details::saturating_unary_minus(lhs); + return out; + } + return details::make_unsupported( + "saturating unary minus not supported for negotiated common type"); + } +}; + +template +struct op_binding { + static constexpr bool enabled = true; + + static constexpr auto apply(CommonRep lhs, CommonRep) + -> policy::value::decision { + return details::checked_bit_not(lhs); + } +}; + template struct op_binding { static constexpr bool enabled = true; From a592abd88e2a61801a6010ccb799e802d2c9f3c4 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 17:24:09 +0800 Subject: [PATCH 4/8] feat: Add unary and binary operators for arithmetic and bitwise operations Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- src/operations/operators.cppm | 470 ++++++++++++++++++++++++++++++++++ 1 file changed, 470 insertions(+) diff --git a/src/operations/operators.cppm b/src/operations/operators.cppm index 3c04ca1..8bde8ab 100644 --- a/src/operations/operators.cppm +++ b/src/operations/operators.cppm @@ -110,6 +110,16 @@ template , Primitive, ErrorPayload>; +template +using unary_dispatch_result_t = + primitive_dispatch_result_t; + +template +constexpr auto apply_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t; + template constexpr auto apply(Lhs const &lhs, Rhs const &rhs) @@ -126,6 +136,16 @@ constexpr auto apply(Lhs const &lhs, Rhs const &rhs) return result_primitive{*raw}; } +template +constexpr auto apply_unary(Operand const &operand) + -> unary_dispatch_result_t { + using operand_traits = meta::traits; + using value_type = typename operand_traits::value_type; + auto const dummy = Operand{value_type{}}; + return apply(operand, dummy); +} + template constexpr auto apply(Lhs const &lhs, Rhs const &rhs) @@ -145,6 +165,44 @@ constexpr auto apply(Lhs const &lhs, Rhs const &rhs) return apply(bridge_lhs, rhs); } +// Unary operations +template +constexpr auto increment(Operand &operand) + -> unary_dispatch_result_t { + using operand_traits = meta::traits; + using value_type = typename operand_traits::value_type; + auto const dummy = Operand{value_type{}}; + return apply_assign(operand, dummy); +} + +template +constexpr auto decrement(Operand &operand) + -> unary_dispatch_result_t { + using operand_traits = meta::traits; + using value_type = typename operand_traits::value_type; + auto const dummy = Operand{value_type{}}; + return apply_assign(operand, dummy); +} + +template +constexpr auto bit_not(Operand const &operand) + -> unary_dispatch_result_t { + return apply_unary(operand); +} + +template +constexpr auto unary_plus(Operand const &operand) + -> unary_dispatch_result_t { + return apply_unary(operand); +} + +template +constexpr auto unary_minus(Operand const &operand) + -> unary_dispatch_result_t { + return apply_unary(operand); +} + +// Binary arithmetic operations template constexpr auto add(Lhs const &lhs, Rhs const &rhs) @@ -219,6 +277,139 @@ constexpr auto div(Lhs const &lhs, Rhs const &rhs) return apply(lhs, rhs); } +template +constexpr auto mod(Lhs const &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto mod(Lhs const &lhs, Rhs const &rhs) + -> mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto mod(Lhs const &lhs, Rhs const &rhs) + -> flipped_mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +// Binary bitwise operations +template +constexpr auto shift_left(Lhs const &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto shift_left(Lhs const &lhs, Rhs const &rhs) + -> mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto shift_left(Lhs const &lhs, Rhs const &rhs) + -> flipped_mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto shift_right(Lhs const &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto shift_right(Lhs const &lhs, Rhs const &rhs) + -> mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto shift_right(Lhs const &lhs, Rhs const &rhs) + -> flipped_mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_and(Lhs const &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_and(Lhs const &lhs, Rhs const &rhs) + -> mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_and(Lhs const &lhs, Rhs const &rhs) + -> flipped_mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_or(Lhs const &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_or(Lhs const &lhs, Rhs const &rhs) + -> mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_or(Lhs const &lhs, Rhs const &rhs) + -> flipped_mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_xor(Lhs const &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_xor(Lhs const &lhs, Rhs const &rhs) + -> mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + +template +constexpr auto bit_xor(Lhs const &lhs, Rhs const &rhs) + -> flipped_mixed_primitive_dispatch_result_t { + return apply(lhs, rhs); +} + template constexpr auto div(Lhs const &lhs, Rhs const &rhs) @@ -376,10 +567,106 @@ constexpr auto div_assign(Lhs &lhs, Rhs const &rhs) return apply_assign(lhs, rhs); } +template +constexpr auto mod_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply_assign(lhs, rhs); +} + +template +constexpr auto shift_left_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply_assign(lhs, rhs); +} + +template +constexpr auto shift_right_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply_assign(lhs, rhs); +} + +template +constexpr auto bit_and_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply_assign(lhs, rhs); +} + +template +constexpr auto bit_or_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply_assign(lhs, rhs); +} + +template +constexpr auto bit_xor_assign(Lhs &lhs, Rhs const &rhs) + -> primitive_dispatch_result_t { + return apply_assign(lhs, rhs); +} + } // namespace mcpplibs::primitives::operations export namespace mcpplibs::primitives::operators { +// Unary operators +template +constexpr auto operator++(Operand &operand) + -> operations::unary_dispatch_result_t { + return operations::increment(operand); +} + +template +constexpr auto operator++(Operand &operand, int) + -> operations::unary_dispatch_result_t { + auto const before = operand; + auto const stepped = operations::increment(operand); + if (!stepped.has_value()) { + return std::unexpected(stepped.error()); + } + return before; +} + +template +constexpr auto operator--(Operand &operand) + -> operations::unary_dispatch_result_t { + return operations::decrement(operand); +} + +template +constexpr auto operator--(Operand &operand, int) + -> operations::unary_dispatch_result_t { + auto const before = operand; + auto const stepped = operations::decrement(operand); + if (!stepped.has_value()) { + return std::unexpected(stepped.error()); + } + return before; +} + +template +constexpr auto operator+(Operand const &operand) + -> operations::unary_dispatch_result_t { + return operations::unary_plus(operand); +} + +template +constexpr auto operator-(Operand const &operand) + -> operations::unary_dispatch_result_t { + return operations::unary_minus(operand); +} + +template +constexpr auto operator~(Operand const &operand) + -> operations::unary_dispatch_result_t { + return operations::bit_not(operand); +} + +// Binary arithmetic operators template constexpr auto operator+(Lhs const &lhs, Rhs const &rhs) @@ -474,6 +761,147 @@ constexpr auto operator/(Lhs const &lhs, Rhs const &rhs) return operations::div(lhs, rhs); } +template +constexpr auto operator%(Lhs const &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::mod(lhs, rhs); +} + +template +constexpr auto operator%(Lhs const &lhs, Rhs const &rhs) + -> operations::mixed_primitive_dispatch_result_t { + return operations::mod(lhs, rhs); +} + +template +constexpr auto operator%(Lhs const &lhs, Rhs const &rhs) + -> operations::flipped_mixed_primitive_dispatch_result_t< + operations::Modulus, Lhs, Rhs> { + return operations::mod(lhs, rhs); +} + +// Binary bitwise operators +template +constexpr auto operator<<(Lhs const &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::shift_left(lhs, rhs); +} + +template +constexpr auto operator<<(Lhs const &lhs, Rhs const &rhs) + -> operations::mixed_primitive_dispatch_result_t { + return operations::shift_left(lhs, rhs); +} + +template +constexpr auto operator<<(Lhs const &lhs, Rhs const &rhs) + -> operations::flipped_mixed_primitive_dispatch_result_t< + operations::LeftShift, Lhs, Rhs> { + return operations::shift_left(lhs, rhs); +} + +template +constexpr auto operator>>(Lhs const &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::shift_right(lhs, rhs); +} + +template +constexpr auto operator>>(Lhs const &lhs, Rhs const &rhs) + -> operations::mixed_primitive_dispatch_result_t { + return operations::shift_right(lhs, rhs); +} + +template +constexpr auto operator>>(Lhs const &lhs, Rhs const &rhs) + -> operations::flipped_mixed_primitive_dispatch_result_t< + operations::RightShift, Lhs, Rhs> { + return operations::shift_right(lhs, rhs); +} + +template +constexpr auto operator&(Lhs const &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::bit_and(lhs, rhs); +} + +template +constexpr auto operator&(Lhs const &lhs, Rhs const &rhs) + -> operations::mixed_primitive_dispatch_result_t { + return operations::bit_and(lhs, rhs); +} + +template +constexpr auto operator&(Lhs const &lhs, Rhs const &rhs) + -> operations::flipped_mixed_primitive_dispatch_result_t< + operations::BitwiseAnd, Lhs, Rhs> { + return operations::bit_and(lhs, rhs); +} + +template +constexpr auto operator|(Lhs const &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::bit_or(lhs, rhs); +} + +template +constexpr auto operator|(Lhs const &lhs, Rhs const &rhs) + -> operations::mixed_primitive_dispatch_result_t { + return operations::bit_or(lhs, rhs); +} + +template +constexpr auto operator|(Lhs const &lhs, Rhs const &rhs) + -> operations::flipped_mixed_primitive_dispatch_result_t< + operations::BitwiseOr, Lhs, Rhs> { + return operations::bit_or(lhs, rhs); +} + +template +constexpr auto operator^(Lhs const &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::bit_xor(lhs, rhs); +} + +template +constexpr auto operator^(Lhs const &lhs, Rhs const &rhs) + -> operations::mixed_primitive_dispatch_result_t { + return operations::bit_xor(lhs, rhs); +} + +template +constexpr auto operator^(Lhs const &lhs, Rhs const &rhs) + -> operations::flipped_mixed_primitive_dispatch_result_t< + operations::BitwiseXor, Lhs, Rhs> { + return operations::bit_xor(lhs, rhs); +} + +// Binary comparison operators + template constexpr auto operator==(Lhs const &lhs, Rhs const &rhs) @@ -571,4 +999,46 @@ constexpr auto operator/=(Lhs &lhs, Rhs const &rhs) return operations::div_assign(lhs, rhs); } +template +constexpr auto operator%=(Lhs &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::mod_assign(lhs, rhs); +} + +template +constexpr auto operator<<=(Lhs &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::shift_left_assign(lhs, rhs); +} + +template +constexpr auto operator>>=(Lhs &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::shift_right_assign(lhs, rhs); +} + +template +constexpr auto operator&=(Lhs &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::bit_and_assign(lhs, rhs); +} + +template +constexpr auto operator|=(Lhs &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::bit_or_assign(lhs, rhs); +} + +template +constexpr auto operator^=(Lhs &lhs, Rhs const &rhs) + -> operations::primitive_dispatch_result_t { + return operations::bit_xor_assign(lhs, rhs); +} + } // namespace mcpplibs::primitives::operators From 110a2c59370b7110034a6788ca7f689e3cae7c29 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 17:24:20 +0800 Subject: [PATCH 5/8] test: Add tests for unary and binary operators, including compound assignments and error reporting Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- tests/basic/test_operations.cpp | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tests/basic/test_operations.cpp b/tests/basic/test_operations.cpp index a2cd1ff..0b5e512 100644 --- a/tests/basic/test_operations.cpp +++ b/tests/basic/test_operations.cpp @@ -784,6 +784,120 @@ TEST(OperationsTest, OperatorPlusDelegatesToDispatcher) { EXPECT_EQ(result->value(), 15); } +TEST(OperationsTest, UnaryOperatorsDelegateToDispatcher) { + using namespace mcpplibs::primitives::operators; + using value_t = + primitive; + + auto value = value_t{10}; + + auto const inc = ++value; + ASSERT_TRUE(inc.has_value()); + EXPECT_EQ(inc->value(), 11); + EXPECT_EQ(value.load(), 11); + + auto const dec = --value; + ASSERT_TRUE(dec.has_value()); + EXPECT_EQ(dec->value(), 10); + EXPECT_EQ(value.load(), 10); + + auto const post_inc = value++; + ASSERT_TRUE(post_inc.has_value()); + EXPECT_EQ(post_inc->value(), 10); + EXPECT_EQ(value.load(), 11); + + auto const post_dec = value--; + ASSERT_TRUE(post_dec.has_value()); + EXPECT_EQ(post_dec->value(), 11); + EXPECT_EQ(value.load(), 10); + + auto const pos = +value; + auto const neg = -value; + auto const inv = ~value; + + ASSERT_TRUE(pos.has_value()); + ASSERT_TRUE(neg.has_value()); + ASSERT_TRUE(inv.has_value()); + EXPECT_EQ(pos->value(), 10); + EXPECT_EQ(neg->value(), -10); + EXPECT_EQ(inv->value(), ~10); +} + +TEST(OperationsTest, NewBinaryOperatorsDelegateToDispatcher) { + using namespace mcpplibs::primitives::operators; + using value_t = + primitive; + + auto const lhs = value_t{12}; + auto const rhs = value_t{5}; + + auto const mod = lhs % rhs; + auto const shl = rhs << value_t{1}; + auto const shr = lhs >> value_t{2}; + auto const bit_and = lhs & value_t{10}; + auto const bit_or = lhs | value_t{10}; + auto const bit_xor = lhs ^ value_t{10}; + + ASSERT_TRUE(mod.has_value()); + ASSERT_TRUE(shl.has_value()); + ASSERT_TRUE(shr.has_value()); + ASSERT_TRUE(bit_and.has_value()); + ASSERT_TRUE(bit_or.has_value()); + ASSERT_TRUE(bit_xor.has_value()); + EXPECT_EQ(mod->value(), 2); + EXPECT_EQ(shl->value(), 10); + EXPECT_EQ(shr->value(), 3); + EXPECT_EQ(bit_and->value(), 8); + EXPECT_EQ(bit_or->value(), 14); + EXPECT_EQ(bit_xor->value(), 6); +} + +TEST(OperationsTest, NewCompoundAssignmentOperatorsMutateLhsOnSuccess) { + using namespace mcpplibs::primitives::operators; + using value_t = + primitive; + + auto value = value_t{12}; + + auto mod = (value %= value_t{5}); + ASSERT_TRUE(mod.has_value()); + EXPECT_EQ(value.load(), 2); + + auto shl = (value <<= value_t{2}); + ASSERT_TRUE(shl.has_value()); + EXPECT_EQ(value.load(), 8); + + auto shr = (value >>= value_t{1}); + ASSERT_TRUE(shr.has_value()); + EXPECT_EQ(value.load(), 4); + + auto bit_and = (value &= value_t{6}); + ASSERT_TRUE(bit_and.has_value()); + EXPECT_EQ(value.load(), 4); + + auto bit_or = (value |= value_t{1}); + ASSERT_TRUE(bit_or.has_value()); + EXPECT_EQ(value.load(), 5); + + auto bit_xor = (value ^= value_t{7}); + ASSERT_TRUE(bit_xor.has_value()); + EXPECT_EQ(value.load(), 2); +} + +TEST(OperationsTest, ModulusAndShiftReportExpectedErrors) { + using value_t = + primitive; + + auto const mod_zero = operations::mod(value_t{7}, value_t{0}); + ASSERT_FALSE(mod_zero.has_value()); + EXPECT_EQ(mod_zero.error(), policy::error::kind::divide_by_zero); + + auto const invalid_shift = operations::shift_left( + value_t{1}, value_t{std::numeric_limits::digits + 1}); + ASSERT_FALSE(invalid_shift.has_value()); + EXPECT_EQ(invalid_shift.error(), policy::error::kind::domain_error); +} + TEST(OperationsTest, ThreeWayCompareReturnsStrongOrderingForIntegers) { using namespace mcpplibs::primitives::operators; using value_t = From 90dd07033034e672ef92570b1c7d38b830c04197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9F=A0=E9=85=8D=E7=BB=BF=E8=8C=B6?= <64787592+FrozenLemonTee@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:35:58 +0800 Subject: [PATCH 6/8] Update src/operations/invoker.cppm Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/operations/invoker.cppm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operations/invoker.cppm b/src/operations/invoker.cppm index 328d0d8..d04a70e 100644 --- a/src/operations/invoker.cppm +++ b/src/operations/invoker.cppm @@ -390,7 +390,7 @@ constexpr auto checked_bit_not(T lhs) -> policy::value::decision { } return make_error(policy::error::kind::unspecified, - "checked bitwise not not supported for negotiated " + "checked bitwise not supported for negotiated " "common type", lhs); } From 5e85b09f28f1e100717da4c4f175f41b22892a76 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 18:01:06 +0800 Subject: [PATCH 7/8] refactor: Enhance unchecked operations with constexpr checks for type compatibility Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- src/operations/invoker.cppm | 72 ++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/src/operations/invoker.cppm b/src/operations/invoker.cppm index d04a70e..7c84208 100644 --- a/src/operations/invoker.cppm +++ b/src/operations/invoker.cppm @@ -545,7 +545,13 @@ template constexpr auto unchecked_mod(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(lhs % rhs); + + if constexpr (requires { lhs % rhs; }) { + out.value = static_cast(lhs % rhs); + return out; + } + + out.value = T{}; return out; } @@ -553,7 +559,13 @@ template constexpr auto unchecked_shift_left(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(lhs << rhs); + + if constexpr (requires { lhs << rhs; }) { + out.value = static_cast(lhs << rhs); + return out; + } + + out.value = T{}; return out; } @@ -562,7 +574,13 @@ constexpr auto unchecked_shift_right(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(lhs >> rhs); + + if constexpr (requires { lhs >> rhs; }) { + out.value = static_cast(lhs >> rhs); + return out; + } + + out.value = T{}; return out; } @@ -570,7 +588,13 @@ template constexpr auto unchecked_bit_and(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(lhs & rhs); + + if constexpr (requires { lhs & rhs; }) { + out.value = static_cast(lhs & rhs); + return out; + } + + out.value = T{}; return out; } @@ -578,7 +602,13 @@ template constexpr auto unchecked_bit_or(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(lhs | rhs); + + if constexpr (requires { lhs | rhs; }) { + out.value = static_cast(lhs | rhs); + return out; + } + + out.value = T{}; return out; } @@ -586,7 +616,13 @@ template constexpr auto unchecked_bit_xor(T lhs, T rhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(lhs ^ rhs); + + if constexpr (requires { lhs ^ rhs; }) { + out.value = static_cast(lhs ^ rhs); + return out; + } + + out.value = T{}; return out; } @@ -594,7 +630,13 @@ template constexpr auto unchecked_bit_not(T lhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(~lhs); + + if constexpr (requires { ~lhs; }) { + out.value = static_cast(~lhs); + return out; + } + + out.value = T{}; return out; } @@ -602,7 +644,13 @@ template constexpr auto unchecked_unary_plus(T lhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(+lhs); + + if constexpr (requires { +lhs; }) { + out.value = static_cast(+lhs); + return out; + } + + out.value = T{}; return out; } @@ -610,7 +658,13 @@ template constexpr auto unchecked_unary_minus(T lhs) -> policy::value::decision { policy::value::decision out{}; out.has_value = true; - out.value = static_cast(-lhs); + + if constexpr (requires { -lhs; }) { + out.value = static_cast(-lhs); + return out; + } + + out.value = T{}; return out; } From db906c3153d9f468acedca982468e1c72ca4e3d7 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 22 Mar 2026 18:01:15 +0800 Subject: [PATCH 8/8] refactor: Consolidate unary operation application logic into a single apply function Signed-off-by: FrozenlemonTee <1115306170@qq.com> --- src/operations/operators.cppm | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/operations/operators.cppm b/src/operations/operators.cppm index 8bde8ab..67f8b40 100644 --- a/src/operations/operators.cppm +++ b/src/operations/operators.cppm @@ -138,12 +138,9 @@ constexpr auto apply(Lhs const &lhs, Rhs const &rhs) template -constexpr auto apply_unary(Operand const &operand) +constexpr auto apply(Operand const &operand) -> unary_dispatch_result_t { - using operand_traits = meta::traits; - using value_type = typename operand_traits::value_type; - auto const dummy = Operand{value_type{}}; - return apply(operand, dummy); + return apply(operand, operand); } template constexpr auto increment(Operand &operand) -> unary_dispatch_result_t { - using operand_traits = meta::traits; - using value_type = typename operand_traits::value_type; - auto const dummy = Operand{value_type{}}; - return apply_assign(operand, dummy); + return apply_assign(operand, + operand); } template constexpr auto decrement(Operand &operand) -> unary_dispatch_result_t { - using operand_traits = meta::traits; - using value_type = typename operand_traits::value_type; - auto const dummy = Operand{value_type{}}; - return apply_assign(operand, dummy); + return apply_assign(operand, + operand); } template constexpr auto bit_not(Operand const &operand) -> unary_dispatch_result_t { - return apply_unary(operand); + return apply(operand); } template constexpr auto unary_plus(Operand const &operand) -> unary_dispatch_result_t { - return apply_unary(operand); + return apply(operand); } template constexpr auto unary_minus(Operand const &operand) -> unary_dispatch_result_t { - return apply_unary(operand); + return apply(operand); } // Binary arithmetic operations