From c82e13d42eb034daf48ded93b10b2aa31d89c534 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 15 Mar 2026 23:12:47 +0800 Subject: [PATCH 1/7] chore: Set version 0.1.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f1cd713..d7ab2b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -project(mcpplibs-primitives VERSION 1.0.0 LANGUAGES CXX) +project(mcpplibs-primitives VERSION 0.1.0 LANGUAGES CXX) find_package(Threads REQUIRED) From 272bfc610ac6f01962fe05fab133a7af6a984c8e Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 15 Mar 2026 23:13:49 +0800 Subject: [PATCH 2/7] feat: Add new submodule operations --- src/operations/impl.cppm | 516 +++++++++++++++++++++++++++++++++ src/operations/operations.cppm | 6 + src/operations/traits.cppm | 168 +++++++++++ src/primitives.cppm | 3 +- 4 files changed, 692 insertions(+), 1 deletion(-) create mode 100644 src/operations/impl.cppm create mode 100644 src/operations/operations.cppm create mode 100644 src/operations/traits.cppm diff --git a/src/operations/impl.cppm b/src/operations/impl.cppm new file mode 100644 index 0000000..dc53e31 --- /dev/null +++ b/src/operations/impl.cppm @@ -0,0 +1,516 @@ +module; +#include +#include +#include +#include +#include + +export module mcpplibs.primitives.operations.impl; + +import mcpplibs.primitives.operations.traits; +import mcpplibs.primitives.policy; +import mcpplibs.primitives.primitive; +import mcpplibs.primitives.underlying; + +export namespace mcpplibs::primitives::operations { + +namespace details { + +template +constexpr bool add_overflow(T lhs, T rhs) noexcept { + if constexpr (!std::is_integral_v) { + return false; + } else if constexpr (std::is_signed_v) { + using limits = std::numeric_limits; + return (rhs > 0 && lhs > limits::max() - rhs) || + (rhs < 0 && lhs < limits::min() - rhs); + } else { + using limits = std::numeric_limits; + return lhs > limits::max() - rhs; + } +} + +template +constexpr bool sub_overflow(T lhs, T rhs) noexcept { + if constexpr (!std::is_integral_v) { + return false; + } else if constexpr (std::is_signed_v) { + using limits = std::numeric_limits; + return (rhs < 0 && lhs > limits::max() + rhs * static_cast(-1)) || + (rhs > 0 && lhs < limits::min() + rhs); + } else { + return lhs < rhs; + } +} + +template +constexpr bool mul_overflow(T lhs, T rhs) noexcept { + if constexpr (!std::is_integral_v) { + return false; + } else if (lhs == 0 || rhs == 0) { + return false; + } else if constexpr (std::is_signed_v) { + using limits = std::numeric_limits; + if (lhs == -1) { + return rhs == limits::min(); + } + if (rhs == -1) { + return lhs == limits::min(); + } + if (lhs > 0) { + return (rhs > 0) ? lhs > limits::max() / rhs + : rhs < limits::min() / lhs; + } + return (rhs > 0) ? lhs < limits::min() / rhs + : lhs != 0 && rhs < limits::max() / lhs; + } else { + using limits = std::numeric_limits; + return lhs > limits::max() / rhs; + } +} + +template +constexpr T saturating_add(T lhs, T rhs) noexcept { + if constexpr (!std::is_integral_v) { + return static_cast(lhs + rhs); + } else { + using limits = std::numeric_limits; + if (!add_overflow(lhs, rhs)) { + return static_cast(lhs + rhs); + } + if constexpr (std::is_signed_v) { + return rhs >= 0 ? limits::max() : limits::min(); + } else { + return limits::max(); + } + } +} + +template +constexpr T saturating_sub(T lhs, T rhs) noexcept { + if constexpr (!std::is_integral_v) { + return static_cast(lhs - rhs); + } else { + using limits = std::numeric_limits; + if (!sub_overflow(lhs, rhs)) { + return static_cast(lhs - rhs); + } + if constexpr (std::is_signed_v) { + return rhs > 0 ? limits::min() : limits::max(); + } else { + return limits::min(); + } + } +} + +template +constexpr T saturating_mul(T lhs, T rhs) noexcept { + if constexpr (!std::is_integral_v) { + return static_cast(lhs * rhs); + } else { + using limits = std::numeric_limits; + if (!mul_overflow(lhs, rhs)) { + return static_cast(lhs * rhs); + } + if constexpr (std::is_signed_v) { + return ((lhs < 0) ^ (rhs < 0)) ? limits::min() : limits::max(); + } else { + return limits::max(); + } + } +} + +} // namespace details + +// ===== Built-in value policy behaviors ===== + +template +struct value_policy_behavior { + template + static constexpr T add(T lhs, T rhs) noexcept { + return static_cast(lhs + rhs); + } + + template + static constexpr T sub(T lhs, T rhs) noexcept { + return static_cast(lhs - rhs); + } + + template + static constexpr T mul(T lhs, T rhs) noexcept { + return static_cast(lhs * rhs); + } +}; + +template +struct value_policy_behavior { + template + static constexpr T add(T lhs, T rhs) noexcept { + return static_cast(lhs + rhs); + } + + template + static constexpr T sub(T lhs, T rhs) noexcept { + return static_cast(lhs - rhs); + } + + template + static constexpr T mul(T lhs, T rhs) noexcept { + return static_cast(lhs * rhs); + } +}; + +template +struct value_policy_behavior { + template + static constexpr T add(T lhs, T rhs) noexcept { + return details::saturating_add(lhs, rhs); + } + + template + static constexpr T sub(T lhs, T rhs) noexcept { + return details::saturating_sub(lhs, rhs); + } + + template + static constexpr T mul(T lhs, T rhs) noexcept { + return details::saturating_mul(lhs, rhs); + } +}; + +// ===== Built-in type policy behaviors ===== + +template +struct type_policy_behavior { + template + using result_type = std::remove_cv_t; + + template + static constexpr Out cast_lhs(In const &value) noexcept { + return static_cast(value); + } + + template + static constexpr Out cast_rhs(In const &value) noexcept { + static_assert(std::same_as, std::remove_cv_t>, + "strict_type requires both operands to have same type"); + return static_cast(value); + } +}; + +template +struct type_policy_behavior { + template + using result_type = std::common_type_t; + + template + static constexpr Out cast_lhs(In const &value) noexcept { + return static_cast(value); + } + + template + static constexpr Out cast_rhs(In const &value) noexcept { + static_assert( + underlying::traits>::kind == + underlying::traits>::kind, + "category_compatible_type requires same underlying category"); + return static_cast(value); + } +}; + +template +struct type_policy_behavior { + template + using result_type = std::common_type_t; + + template + static constexpr Out cast_lhs(In const &value) noexcept { + return static_cast(value); + } + + template + static constexpr Out cast_rhs(In const &value) noexcept { + return static_cast(value); + } +}; + +// ===== Built-in error policy behaviors ===== + +template +struct error_policy_behavior { + template + static constexpr Result evaluate(Fn &&fn) noexcept(noexcept(fn())) { + return static_cast(fn()); + } +}; + +template +struct error_policy_behavior { + template + static constexpr Result evaluate(Fn &&fn) noexcept(noexcept(fn())) { + return static_cast(fn()); + } +}; + +template +struct error_policy_behavior { + template + static Result evaluate(Fn &&fn) noexcept { + if constexpr (noexcept(fn())) { + return static_cast(fn()); + } else { + try { + return static_cast(fn()); + } catch (...) { + std::terminate(); + } + } + } +}; + +// ===== Built-in concurrency policy behaviors ===== + +template +struct concurrency_policy_behavior { + template + static constexpr auto execute(Fn &&fn) noexcept(noexcept(fn())) + -> decltype(fn()) { + return fn(); + } +}; + +template +struct concurrency_policy_behavior { + template + static auto execute(Fn &&fn) noexcept(noexcept(fn())) -> decltype(fn()) { + std::atomic_signal_fence(std::memory_order_seq_cst); + auto result = fn(); + std::atomic_signal_fence(std::memory_order_seq_cst); + return result; + } +}; + +// default underlying operations + +template +struct traits { + static constexpr bool enabled = true; + static constexpr bool noexcept_invocable = true; + + using value_policy = resolved_value_policy_t; + using type_policy = resolved_type_policy_t; + using error_policy = resolved_error_policy_t; + using concurrency_policy = resolved_concurrency_policy_t; + + using result_type = + type_policy_behavior::template result_type; + + static constexpr result_type invoke(L const &lhs, R const &rhs) noexcept { + return concurrency_policy_behavior::execute( + [&]() constexpr noexcept { + return error_policy_behavior::template evaluate< + result_type>([&]() constexpr noexcept { + return value_policy_behavior::template add( + type_policy_behavior::template cast_lhs( + lhs), + type_policy_behavior::template cast_rhs( + rhs)); + }); + }); + } +}; + +template +struct traits { + static constexpr bool enabled = true; + static constexpr bool noexcept_invocable = true; + + using value_policy = resolved_value_policy_t; + using type_policy = resolved_type_policy_t; + using error_policy = resolved_error_policy_t; + using concurrency_policy = resolved_concurrency_policy_t; + + using result_type = + type_policy_behavior::template result_type; + + static constexpr result_type invoke(L const &lhs, R const &rhs) noexcept { + return concurrency_policy_behavior::execute( + [&]() constexpr noexcept { + return error_policy_behavior::template evaluate< + result_type>([&]() constexpr noexcept { + return value_policy_behavior::template sub( + type_policy_behavior::template cast_lhs( + lhs), + type_policy_behavior::template cast_rhs( + rhs)); + }); + }); + } +}; + +template +struct traits { + static constexpr bool enabled = true; + static constexpr bool noexcept_invocable = true; + + using value_policy = resolved_value_policy_t; + using type_policy = resolved_type_policy_t; + using error_policy = resolved_error_policy_t; + using concurrency_policy = resolved_concurrency_policy_t; + + using result_type = + type_policy_behavior::template result_type; + + static constexpr result_type invoke(L const &lhs, R const &rhs) noexcept { + return concurrency_policy_behavior::execute( + [&]() constexpr noexcept { + return error_policy_behavior::template evaluate< + result_type>([&]() constexpr noexcept { + return value_policy_behavior::template mul( + type_policy_behavior::template cast_lhs( + lhs), + type_policy_behavior::template cast_rhs( + rhs)); + }); + }); + } +}; + +// primitive operations (keep lhs policy set by default) +template +struct traits, primitive, Policies...> { + static constexpr bool enabled = true; + static constexpr bool noexcept_invocable = true; + + using value_policy = resolved_value_policy_t; + using type_policy = resolved_type_policy_t; + using error_policy = resolved_error_policy_t; + using concurrency_policy = resolved_concurrency_policy_t; + + using rep_type = + type_policy_behavior::template result_type; + using result_type = primitive; + + static constexpr result_type invoke(primitive const &lhs, + primitive const &rhs) noexcept { + return result_type{concurrency_policy_behavior::execute( + [&]() constexpr noexcept { + return error_policy_behavior::template evaluate( + [&]() constexpr noexcept { + return value_policy_behavior::template add( + type_policy_behavior::template cast_lhs( + lhs.value()), + type_policy_behavior::template cast_rhs( + rhs.value())); + }); + })}; + } +}; + +template +struct traits, primitive, Policies...> { + static constexpr bool enabled = true; + static constexpr bool noexcept_invocable = true; + + using value_policy = resolved_value_policy_t; + using type_policy = resolved_type_policy_t; + using error_policy = resolved_error_policy_t; + using concurrency_policy = resolved_concurrency_policy_t; + + using rep_type = + type_policy_behavior::template result_type; + using result_type = primitive; + + static constexpr result_type invoke(primitive const &lhs, + primitive const &rhs) noexcept { + return result_type{concurrency_policy_behavior::execute( + [&]() constexpr noexcept { + return error_policy_behavior::template evaluate( + [&]() constexpr noexcept { + return value_policy_behavior::template sub( + type_policy_behavior::template cast_lhs( + lhs.value()), + type_policy_behavior::template cast_rhs( + rhs.value())); + }); + })}; + } +}; + +template +struct traits, primitive, Policies...> { + static constexpr bool enabled = true; + static constexpr bool noexcept_invocable = true; + + using value_policy = resolved_value_policy_t; + using type_policy = resolved_type_policy_t; + using error_policy = resolved_error_policy_t; + using concurrency_policy = resolved_concurrency_policy_t; + + using rep_type = + type_policy_behavior::template result_type; + using result_type = primitive; + + static constexpr result_type invoke(primitive const &lhs, + primitive const &rhs) noexcept { + return result_type{concurrency_policy_behavior::execute( + [&]() constexpr noexcept { + return error_policy_behavior::template evaluate( + [&]() constexpr noexcept { + return value_policy_behavior::template mul( + type_policy_behavior::template cast_lhs( + lhs.value()), + type_policy_behavior::template cast_rhs( + rhs.value())); + }); + })}; + } +}; + +struct add_fn { + template + requires binary_operation + constexpr auto operator()(L &&lhs, R &&rhs) const + noexcept(nothrow_binary_operation) + -> result_t { + using impl = + traits, std::remove_cvref_t, + Policies...>; + return impl::invoke(lhs, rhs); + } +}; + +struct sub_fn { + template + requires binary_operation + constexpr auto operator()(L &&lhs, R &&rhs) const + noexcept(nothrow_binary_operation) + -> result_t { + using impl = + traits, std::remove_cvref_t, + Policies...>; + return impl::invoke(lhs, rhs); + } +}; + +struct mul_fn { + template + requires binary_operation + constexpr auto operator()(L &&lhs, R &&rhs) const + noexcept(nothrow_binary_operation) + -> result_t { + using impl = + traits, std::remove_cvref_t, + Policies...>; + return impl::invoke(lhs, rhs); + } +}; + +inline constexpr add_fn add{}; +inline constexpr sub_fn sub{}; +inline constexpr mul_fn mul{}; + +} // namespace mcpplibs::primitives::operations diff --git a/src/operations/operations.cppm b/src/operations/operations.cppm new file mode 100644 index 0000000..b69683e --- /dev/null +++ b/src/operations/operations.cppm @@ -0,0 +1,6 @@ +module; + +export module mcpplibs.primitives.operations; + +export import mcpplibs.primitives.operations.traits; +export import mcpplibs.primitives.operations.impl; \ No newline at end of file diff --git a/src/operations/traits.cppm b/src/operations/traits.cppm new file mode 100644 index 0000000..ac18323 --- /dev/null +++ b/src/operations/traits.cppm @@ -0,0 +1,168 @@ +module; +#include +#include +#include + +export module mcpplibs.primitives.operations.traits; + +import mcpplibs.primitives.policy; +import mcpplibs.primitives.primitive; +import mcpplibs.primitives.underlying; + +export namespace mcpplibs::primitives::operations { + +struct add_tag {}; +struct sub_tag {}; +struct mul_tag {}; + +template +struct traits { + static constexpr bool enabled = false; + static constexpr bool noexcept_invocable = false; + using result_type = void; +}; + +template +concept binary_operation = + traits, std::remove_cvref_t, + Policies...>::enabled; + +template +concept nothrow_binary_operation = + binary_operation && + traits, std::remove_cvref_t, + Policies...>::noexcept_invocable; + +template +using result_t = + traits, std::remove_cvref_t, + Policies...>::result_type; + +namespace details { + +template +struct first_value_policy_impl { + using type = Fallback; +}; + +template +struct first_value_policy_impl { + using type = std::conditional_t< + policy::value_policy, First, + typename first_value_policy_impl::type>; +}; + +template +struct first_type_policy_impl { + using type = Fallback; +}; + +template +struct first_type_policy_impl { + using type = std::conditional_t< + policy::type_policy, First, + typename first_type_policy_impl::type>; +}; + +template +struct first_error_policy_impl { + using type = Fallback; +}; + +template +struct first_error_policy_impl { + using type = std::conditional_t< + policy::error_policy, First, + typename first_error_policy_impl::type>; +}; + +template +struct first_concurrency_policy_impl { + using type = Fallback; +}; + +template +struct first_concurrency_policy_impl { + using type = std::conditional_t< + policy::concurrency_policy, First, + typename first_concurrency_policy_impl::type>; +}; + +} // namespace details + +template +struct value_policy_behavior { + template + static constexpr T add(T lhs, T rhs) noexcept { + return static_cast(lhs + rhs); + } + + template + static constexpr T sub(T lhs, T rhs) noexcept { + return static_cast(lhs - rhs); + } + + template + static constexpr T mul(T lhs, T rhs) noexcept { + return static_cast(lhs * rhs); + } +}; + +template +struct type_policy_behavior { + template + using result_type = std::common_type_t; + + template + static constexpr Out cast_lhs(In const &value) noexcept { + return static_cast(value); + } + + template + static constexpr Out cast_rhs(In const &value) noexcept { + return static_cast(value); + } +}; + +template +struct error_policy_behavior { + template + static constexpr Result evaluate(Fn &&fn) noexcept(noexcept(fn())) { + return static_cast(std::forward(fn)()); + } +}; + +template +struct concurrency_policy_behavior { + template + static constexpr auto execute(Fn &&fn) noexcept(noexcept(fn())) + -> decltype(fn()) { + return std::forward(fn)(); + } +}; + +template +using resolved_value_policy_t = + details::first_value_policy_impl< + std::tuple_element_t<0, policy::common_policies_t>, + Policies...>::type; + +template +using resolved_type_policy_t = + details::first_type_policy_impl< + std::tuple_element_t<1, policy::common_policies_t>, + Policies...>::type; + +template +using resolved_error_policy_t = + details::first_error_policy_impl< + std::tuple_element_t<2, policy::common_policies_t>, + Policies...>::type; + +template +using resolved_concurrency_policy_t = + details::first_concurrency_policy_impl< + std::tuple_element_t<3, policy::common_policies_t>, + Policies...>::type; + +} // namespace mcpplibs::primitives::operations diff --git a/src/primitives.cppm b/src/primitives.cppm index 7a67d97..72e168e 100644 --- a/src/primitives.cppm +++ b/src/primitives.cppm @@ -4,4 +4,5 @@ export module mcpplibs.primitives; export import mcpplibs.primitives.underlying; export import mcpplibs.primitives.policy; -export import mcpplibs.primitives.primitive; \ No newline at end of file +export import mcpplibs.primitives.primitive; +export import mcpplibs.primitives.operations; \ No newline at end of file From 512ba53a561ba70bd5cd06ada6d4013d25b0930e Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 15 Mar 2026 23:14:02 +0800 Subject: [PATCH 3/7] feat: Add tests for new submodule operations --- tests/basic/test_operations.cpp | 185 ++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 tests/basic/test_operations.cpp diff --git a/tests/basic/test_operations.cpp b/tests/basic/test_operations.cpp new file mode 100644 index 0000000..a74c136 --- /dev/null +++ b/tests/basic/test_operations.cpp @@ -0,0 +1,185 @@ +#include +#include +#include + +import mcpplibs.primitives; + +using namespace mcpplibs::primitives; + +namespace { + +struct debug_value_policy {}; +struct debug_type_policy {}; +struct debug_error_policy {}; +struct debug_concurrency_policy {}; + +} // namespace + +template <> +struct policy::traits { + using policy_type = debug_value_policy; + static constexpr bool enabled = true; + static constexpr auto kind = category::value; +}; + +template <> +struct policy::traits { + using policy_type = debug_type_policy; + static constexpr bool enabled = true; + static constexpr auto kind = category::type; +}; + +template <> +struct policy::traits { + using policy_type = debug_error_policy; + static constexpr bool enabled = true; + static constexpr auto kind = category::error; +}; + +template <> +struct policy::traits { + using policy_type = debug_concurrency_policy; + static constexpr bool enabled = true; + static constexpr auto kind = + category::concurrency; +}; + +template +struct operations::value_policy_behavior< + debug_value_policy, OpTag> { + template + static constexpr T add(T lhs, T rhs) noexcept { + return static_cast(lhs + rhs + 100); + } + + template + static constexpr T sub(T lhs, T rhs) noexcept { + return static_cast(lhs - rhs - 100); + } + + template + static constexpr T mul(T lhs, T rhs) noexcept { + return static_cast(lhs * rhs * 2); + } +}; + +template +struct operations::type_policy_behavior< + debug_type_policy, OpTag> { + template + using result_type = long long; + + template + static constexpr Out cast_lhs(In const &value) noexcept { + return static_cast(value + 1); + } + + template + static constexpr Out cast_rhs(In const &value) noexcept { + return static_cast(value + 2); + } +}; + +template +struct operations::error_policy_behavior< + debug_error_policy, OpTag> { + template + static constexpr Result evaluate(Fn &&fn) noexcept(noexcept(fn())) { + return static_cast(fn() + static_cast(1000)); + } +}; + +template +struct operations::concurrency_policy_behavior< + debug_concurrency_policy, OpTag> { + template + static constexpr auto execute(Fn &&fn) noexcept(noexcept(fn())) + -> decltype(fn()) { + return fn() + 7; + } +}; + + + +template <> +struct operations::value_policy_behavior< + debug_value_policy, operations::add_tag> { + template + static constexpr T add(T lhs, T rhs) noexcept { + return static_cast(lhs + rhs + 200); + } + + template + static constexpr T sub(T lhs, T rhs) noexcept { + return static_cast(lhs - rhs - 100); + } + + template + static constexpr T mul(T lhs, T rhs) noexcept { + return static_cast(lhs * rhs * 2); + } +}; + +TEST(OperationsTest, UnderlyingOperationsWork) { + static_assert(operations::binary_operation); + static_assert(operations::binary_operation); + static_assert(operations::binary_operation); + + EXPECT_EQ(operations::add(2, 3), 5); + EXPECT_EQ(operations::sub(9, 4), 5); + EXPECT_EQ(operations::mul(3, 4), 12); +} + +TEST(OperationsTest, PrimitiveOperationsWork) { + using namespace mcpplibs::primitives::types; + + using lhs_t = I8<>; + using rhs_t = I8<>; + + lhs_t lhs{10}; + rhs_t rhs{5}; + + auto added = operations::add(lhs, rhs); + auto subed = operations::sub(lhs, rhs); + auto muled = operations::mul(lhs, rhs); + + EXPECT_EQ(added.value(), 15); + EXPECT_EQ(subed.value(), 5); + EXPECT_EQ(muled.value(), 50); +} + +TEST(OperationsTest, PolicyBehaviorTraitsCoverAllPolicyCategories) { + EXPECT_EQ((operations::add.operator()< + debug_value_policy, debug_type_policy, debug_error_policy, + debug_concurrency_policy>(2, 3)), + 1215); + EXPECT_EQ((operations::sub.operator()< + debug_value_policy, debug_type_policy, debug_error_policy, + debug_concurrency_policy>(9, 4)), + 911); + EXPECT_EQ((operations::mul.operator()< + debug_value_policy, debug_type_policy, debug_error_policy, + debug_concurrency_policy>(3, 4)), + 1055); +} + + +TEST(OperationsTest, BuiltinPolicyTagsAreSpecialized) { + static_assert(std::is_same_v< + operations::result_t, + int>); + static_assert(std::is_same_v< + operations::result_t, + double>); + + constexpr int kMax = std::numeric_limits::max(); + constexpr int kMin = std::numeric_limits::min(); + + EXPECT_EQ((operations::add.operator()(kMax, 1)), + kMax); + EXPECT_EQ((operations::sub.operator()(kMin, 1)), + kMin); + EXPECT_EQ((operations::mul.operator()(kMax, 2)), + kMax); +} From 628a8bcf5d12e249b26481d1ba6af10c7203c884 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 15 Mar 2026 23:17:31 +0800 Subject: [PATCH 4/7] refactor: Add missing concepts --- src/underlying/traits.cppm | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/underlying/traits.cppm b/src/underlying/traits.cppm index 93353cf..f248bd9 100644 --- a/src/underlying/traits.cppm +++ b/src/underlying/traits.cppm @@ -25,6 +25,9 @@ template concept std_integer = std::integral> && (!std_bool) && (!std_char); +template +concept std_numeric = std_integer || std_floating; + template concept std_underlying_type = std_bool || std_char || std_integer || std_floating; @@ -122,5 +125,27 @@ concept underlying_type = underlying::details::has_std_rep_type && underlying::details::has_consistent_category; +template +concept boolean_underlying_type = + underlying_type && (underlying::traits>::kind == + underlying::category::boolean); + +template +concept character_underlying_type = + underlying_type && (underlying::traits>::kind == + underlying::category::character); + +template +concept integer_underlying_type = + underlying_type && (underlying::traits>::kind == + underlying::category::integer); + +template +concept floating_underlying_type = + underlying_type && (underlying::traits>::kind == + underlying::category::floating); + +template +concept numeric_underlying_type = integer_underlying_type || floating_underlying_type; } // namespace mcpplibs::primitives From 0ff65de2e1e448cd3a3b0bd8f075139540c72624 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Sun, 15 Mar 2026 23:18:32 +0800 Subject: [PATCH 5/7] refactor: Add type aliases --- src/primitive/impl.cppm | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/primitive/impl.cppm b/src/primitive/impl.cppm index 3737bfb..4c1fa23 100644 --- a/src/primitive/impl.cppm +++ b/src/primitive/impl.cppm @@ -1,4 +1,5 @@ module; +#include #include export module mcpplibs.primitives.primitive.impl; @@ -21,4 +22,44 @@ private: value_type value_; }; + namespace types { + template + using Bool = primitive; + + template + using UChar = primitive; + template + using Char8 = primitive; + template + using Char16 = primitive; + template + using Char32 = primitive; + template + using WChar = primitive; + + template + using U8 = primitive; + template + using U16 = primitive; + template + using U32 = primitive; + template + using U64 = primitive; + template + using I8 = primitive; + template + using I16 = primitive; + template + using I32 = primitive; + template + using I64 = primitive; + + template + using F32 = primitive; + template + using F64 = primitive; + template + using F80 = primitive; + } + } // namespace mcpplibs::primitives From e68d725cfd392935fb689a0822ffad3368b34e86 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Mon, 16 Mar 2026 00:42:13 +0800 Subject: [PATCH 6/7] fix: Fix issue in operations --- src/operations/impl.cppm | 374 ++++++++++++++++++++------------- src/operations/operations.cppm | 3 +- 2 files changed, 234 insertions(+), 143 deletions(-) diff --git a/src/operations/impl.cppm b/src/operations/impl.cppm index dc53e31..647f1b4 100644 --- a/src/operations/impl.cppm +++ b/src/operations/impl.cppm @@ -1,8 +1,10 @@ module; #include #include +#include #include #include +#include #include export module mcpplibs.primitives.operations.impl; @@ -17,7 +19,15 @@ export namespace mcpplibs::primitives::operations { namespace details { template -constexpr bool add_overflow(T lhs, T rhs) noexcept { +struct is_expected : std::false_type {}; + +template +struct is_expected> : std::true_type {}; + +template +inline constexpr bool is_expected_v = is_expected::value; + +template constexpr bool add_overflow(T lhs, T rhs) noexcept { if constexpr (!std::is_integral_v) { return false; } else if constexpr (std::is_signed_v) { @@ -30,8 +40,7 @@ constexpr bool add_overflow(T lhs, T rhs) noexcept { } } -template -constexpr bool sub_overflow(T lhs, T rhs) noexcept { +template constexpr bool sub_overflow(T lhs, T rhs) noexcept { if constexpr (!std::is_integral_v) { return false; } else if constexpr (std::is_signed_v) { @@ -43,8 +52,7 @@ constexpr bool sub_overflow(T lhs, T rhs) noexcept { } } -template -constexpr bool mul_overflow(T lhs, T rhs) noexcept { +template constexpr bool mul_overflow(T lhs, T rhs) noexcept { if constexpr (!std::is_integral_v) { return false; } else if (lhs == 0 || rhs == 0) { @@ -58,8 +66,7 @@ constexpr bool mul_overflow(T lhs, T rhs) noexcept { return lhs == limits::min(); } if (lhs > 0) { - return (rhs > 0) ? lhs > limits::max() / rhs - : rhs < limits::min() / lhs; + return (rhs > 0) ? lhs > limits::max() / rhs : rhs < limits::min() / lhs; } return (rhs > 0) ? lhs < limits::min() / rhs : lhs != 0 && rhs < limits::max() / lhs; @@ -69,8 +76,7 @@ constexpr bool mul_overflow(T lhs, T rhs) noexcept { } } -template -constexpr T saturating_add(T lhs, T rhs) noexcept { +template constexpr T saturating_add(T lhs, T rhs) noexcept { if constexpr (!std::is_integral_v) { return static_cast(lhs + rhs); } else { @@ -86,8 +92,7 @@ constexpr T saturating_add(T lhs, T rhs) noexcept { } } -template -constexpr T saturating_sub(T lhs, T rhs) noexcept { +template constexpr T saturating_sub(T lhs, T rhs) noexcept { if constexpr (!std::is_integral_v) { return static_cast(lhs - rhs); } else { @@ -103,8 +108,7 @@ constexpr T saturating_sub(T lhs, T rhs) noexcept { } } -template -constexpr T saturating_mul(T lhs, T rhs) noexcept { +template constexpr T saturating_mul(T lhs, T rhs) noexcept { if constexpr (!std::is_integral_v) { return static_cast(lhs * rhs); } else { @@ -126,54 +130,54 @@ constexpr T saturating_mul(T lhs, T rhs) noexcept { template struct value_policy_behavior { - template - static constexpr T add(T lhs, T rhs) noexcept { + template static T add(T lhs, T rhs) { + if (details::add_overflow(lhs, rhs)) { + throw std::overflow_error("overflow in add"); + } return static_cast(lhs + rhs); } - template - static constexpr T sub(T lhs, T rhs) noexcept { + template static T sub(T lhs, T rhs) { + if (details::sub_overflow(lhs, rhs)) { + throw std::overflow_error("overflow in sub"); + } return static_cast(lhs - rhs); } - template - static constexpr T mul(T lhs, T rhs) noexcept { + template static T mul(T lhs, T rhs) { + if (details::mul_overflow(lhs, rhs)) { + throw std::overflow_error("overflow in mul"); + } return static_cast(lhs * rhs); } }; template struct value_policy_behavior { - template - static constexpr T add(T lhs, T rhs) noexcept { + template static constexpr T add(T lhs, T rhs) noexcept { return static_cast(lhs + rhs); } - template - static constexpr T sub(T lhs, T rhs) noexcept { + template static constexpr T sub(T lhs, T rhs) noexcept { return static_cast(lhs - rhs); } - template - static constexpr T mul(T lhs, T rhs) noexcept { + template static constexpr T mul(T lhs, T rhs) noexcept { return static_cast(lhs * rhs); } }; template struct value_policy_behavior { - template - static constexpr T add(T lhs, T rhs) noexcept { + template static constexpr T add(T lhs, T rhs) noexcept { return details::saturating_add(lhs, rhs); } - template - static constexpr T sub(T lhs, T rhs) noexcept { + template static constexpr T sub(T lhs, T rhs) noexcept { return details::saturating_sub(lhs, rhs); } - template - static constexpr T mul(T lhs, T rhs) noexcept { + template static constexpr T mul(T lhs, T rhs) noexcept { return details::saturating_mul(lhs, rhs); } }; @@ -182,8 +186,7 @@ struct value_policy_behavior { template struct type_policy_behavior { - template - using result_type = std::remove_cv_t; + template using result_type = std::remove_cv_t; template static constexpr Out cast_lhs(In const &value) noexcept { @@ -210,10 +213,9 @@ struct type_policy_behavior { template static constexpr Out cast_rhs(In const &value) noexcept { - static_assert( - underlying::traits>::kind == - underlying::traits>::kind, - "category_compatible_type requires same underlying category"); + static_assert(underlying::traits>::kind == + underlying::traits>::kind, + "category_compatible_type requires same underlying category"); return static_cast(value); } }; @@ -248,7 +250,11 @@ template struct error_policy_behavior { template static constexpr Result evaluate(Fn &&fn) noexcept(noexcept(fn())) { - return static_cast(fn()); + if constexpr (details::is_expected_v) { + return Result{std::in_place, std::forward(fn)()}; + } else { + return static_cast(fn()); + } } }; @@ -303,20 +309,21 @@ struct traits { using concurrency_policy = resolved_concurrency_policy_t; using result_type = - type_policy_behavior::template result_type; + type_policy_behavior::template result_type; static constexpr result_type invoke(L const &lhs, R const &rhs) noexcept { - return concurrency_policy_behavior::execute( - [&]() constexpr noexcept { - return error_policy_behavior::template evaluate< - result_type>([&]() constexpr noexcept { - return value_policy_behavior::template add( - type_policy_behavior::template cast_lhs( - lhs), - type_policy_behavior::template cast_rhs( - rhs)); - }); - }); + return concurrency_policy_behavior< + concurrency_policy, add_tag>::execute([&]() constexpr noexcept { + return error_policy_behavior::template evaluate< + result_type>([&]() constexpr noexcept { + return value_policy_behavior::template add< + result_type>( + type_policy_behavior::template cast_lhs(lhs), + type_policy_behavior::template cast_rhs(rhs)); + }); + }); } }; @@ -331,20 +338,21 @@ struct traits { using concurrency_policy = resolved_concurrency_policy_t; using result_type = - type_policy_behavior::template result_type; + type_policy_behavior::template result_type; static constexpr result_type invoke(L const &lhs, R const &rhs) noexcept { - return concurrency_policy_behavior::execute( - [&]() constexpr noexcept { - return error_policy_behavior::template evaluate< - result_type>([&]() constexpr noexcept { - return value_policy_behavior::template sub( - type_policy_behavior::template cast_lhs( - lhs), - type_policy_behavior::template cast_rhs( - rhs)); - }); - }); + return concurrency_policy_behavior< + concurrency_policy, sub_tag>::execute([&]() constexpr noexcept { + return error_policy_behavior::template evaluate< + result_type>([&]() constexpr noexcept { + return value_policy_behavior::template sub< + result_type>( + type_policy_behavior::template cast_lhs(lhs), + type_policy_behavior::template cast_rhs(rhs)); + }); + }); } }; @@ -359,27 +367,29 @@ struct traits { using concurrency_policy = resolved_concurrency_policy_t; using result_type = - type_policy_behavior::template result_type; + type_policy_behavior::template result_type; static constexpr result_type invoke(L const &lhs, R const &rhs) noexcept { - return concurrency_policy_behavior::execute( - [&]() constexpr noexcept { - return error_policy_behavior::template evaluate< - result_type>([&]() constexpr noexcept { - return value_policy_behavior::template mul( - type_policy_behavior::template cast_lhs( - lhs), - type_policy_behavior::template cast_rhs( - rhs)); - }); - }); + return concurrency_policy_behavior< + concurrency_policy, mul_tag>::execute([&]() constexpr noexcept { + return error_policy_behavior::template evaluate< + result_type>([&]() constexpr noexcept { + return value_policy_behavior::template mul< + result_type>( + type_policy_behavior::template cast_lhs(lhs), + type_policy_behavior::template cast_rhs(rhs)); + }); + }); } }; // primitive operations (keep lhs policy set by default) template -struct traits, primitive, Policies...> { +struct traits, primitive, + Policies...> { static constexpr bool enabled = true; static constexpr bool noexcept_invocable = true; @@ -390,27 +400,58 @@ struct traits, primitive, Policies...> using rep_type = type_policy_behavior::template result_type; - using result_type = primitive; - - static constexpr result_type invoke(primitive const &lhs, - primitive const &rhs) noexcept { - return result_type{concurrency_policy_behavior::execute( - [&]() constexpr noexcept { - return error_policy_behavior::template evaluate( - [&]() constexpr noexcept { - return value_policy_behavior::template add( - type_policy_behavior::template cast_lhs( - lhs.value()), - type_policy_behavior::template cast_rhs( - rhs.value())); - }); - })}; + using raw_result_type = primitive; + using result_type = std::conditional_t< + std::is_same_v, + std::expected, raw_result_type>; + + static result_type invoke(primitive const &lhs, + primitive const &rhs) { + // Prepare casted representations + rep_type lhs_rep = + type_policy_behavior::template cast_lhs( + lhs.value()); + rep_type rhs_rep = + type_policy_behavior::template cast_rhs( + rhs.value()); + + // If value policy is checked, handle overflow according to error policy. + if constexpr (std::is_same_v) { + if (details::add_overflow(lhs_rep, rhs_rep)) { + if constexpr (std::is_same_v) { + throw std::overflow_error("overflow in add"); + } else if constexpr (std::is_same_v) { + std::terminate(); + } else if constexpr (std::is_same_v) { + return std::unexpected(std::overflow_error("overflow in add")); + } + } + } + + const auto rep = concurrency_policy_behavior::execute([&]() { + return error_policy_behavior::template evaluate([&]() { + return value_policy_behavior::template add(lhs_rep, + rhs_rep); + }); + }); + + if constexpr (std::is_same_v) { + return raw_result_type{rep}; + } else { + return raw_result_type{rep}; + } } }; template -struct traits, primitive, Policies...> { +struct traits, primitive, + Policies...> { static constexpr bool enabled = true; static constexpr bool noexcept_invocable = true; @@ -420,28 +461,56 @@ struct traits, primitive, Policies...> using concurrency_policy = resolved_concurrency_policy_t; using rep_type = - type_policy_behavior::template result_type; - using result_type = primitive; - - static constexpr result_type invoke(primitive const &lhs, - primitive const &rhs) noexcept { - return result_type{concurrency_policy_behavior::execute( - [&]() constexpr noexcept { - return error_policy_behavior::template evaluate( - [&]() constexpr noexcept { - return value_policy_behavior::template sub( - type_policy_behavior::template cast_lhs( - lhs.value()), - type_policy_behavior::template cast_rhs( - rhs.value())); - }); - })}; + type_policy_behavior::template result_type; + using raw_result_type = primitive; + using result_type = std::conditional_t< + std::is_same_v, + std::expected, raw_result_type>; + + static result_type invoke(primitive const &lhs, + primitive const &rhs) { + rep_type lhs_rep = + type_policy_behavior::template cast_lhs( + lhs.value()); + rep_type rhs_rep = + type_policy_behavior::template cast_rhs( + rhs.value()); + + if constexpr (std::is_same_v) { + if (details::sub_overflow(lhs_rep, rhs_rep)) { + if constexpr (std::is_same_v) { + throw std::overflow_error("overflow in sub"); + } else if constexpr (std::is_same_v) { + std::terminate(); + } else if constexpr (std::is_same_v) { + return std::unexpected(std::overflow_error("overflow in sub")); + } + } + } + + const auto rep = concurrency_policy_behavior::execute([&]() { + return error_policy_behavior::template evaluate([&]() { + return value_policy_behavior::template sub< + rep_type>(lhs_rep, rhs_rep); + }); + }); + + if constexpr (std::is_same_v) { + return raw_result_type{rep}; + } else { + return raw_result_type{rep}; + } } }; template -struct traits, primitive, Policies...> { +struct traits, primitive, + Policies...> { static constexpr bool enabled = true; static constexpr bool noexcept_invocable = true; @@ -451,34 +520,59 @@ struct traits, primitive, Policies...> using concurrency_policy = resolved_concurrency_policy_t; using rep_type = - type_policy_behavior::template result_type; - using result_type = primitive; - - static constexpr result_type invoke(primitive const &lhs, - primitive const &rhs) noexcept { - return result_type{concurrency_policy_behavior::execute( - [&]() constexpr noexcept { - return error_policy_behavior::template evaluate( - [&]() constexpr noexcept { - return value_policy_behavior::template mul( - type_policy_behavior::template cast_lhs( - lhs.value()), - type_policy_behavior::template cast_rhs( - rhs.value())); - }); - })}; + type_policy_behavior::template result_type; + using raw_result_type = primitive; + using result_type = std::conditional_t< + std::is_same_v, + std::expected, raw_result_type>; + + static result_type invoke(primitive const &lhs, + primitive const &rhs) { + rep_type lhs_rep = + type_policy_behavior::template cast_lhs( + lhs.value()); + rep_type rhs_rep = + type_policy_behavior::template cast_rhs( + rhs.value()); + + if constexpr (std::is_same_v) { + if (details::mul_overflow(lhs_rep, rhs_rep)) { + if constexpr (std::is_same_v) { + throw std::overflow_error("overflow in mul"); + } else if constexpr (std::is_same_v) { + std::terminate(); + } else if constexpr (std::is_same_v) { + return std::unexpected(std::overflow_error("overflow in mul")); + } + } + } + + const auto rep = concurrency_policy_behavior::execute([&]() { + return error_policy_behavior::template evaluate([&]() { + return value_policy_behavior::template mul< + rep_type>(lhs_rep, rhs_rep); + }); + }); + + if constexpr (std::is_same_v) { + return raw_result_type{rep}; + } else { + return raw_result_type{rep}; + } } }; struct add_fn { template requires binary_operation - constexpr auto operator()(L &&lhs, R &&rhs) const - noexcept(nothrow_binary_operation) - -> result_t { - using impl = - traits, std::remove_cvref_t, - Policies...>; + auto operator()(L &&lhs, R &&rhs) const + -> result_t { + using impl = traits, std::remove_cvref_t, + Policies...>; return impl::invoke(lhs, rhs); } }; @@ -486,12 +580,10 @@ struct add_fn { struct sub_fn { template requires binary_operation - constexpr auto operator()(L &&lhs, R &&rhs) const - noexcept(nothrow_binary_operation) - -> result_t { - using impl = - traits, std::remove_cvref_t, - Policies...>; + auto operator()(L &&lhs, R &&rhs) const + -> result_t { + using impl = traits, std::remove_cvref_t, + Policies...>; return impl::invoke(lhs, rhs); } }; @@ -499,12 +591,10 @@ struct sub_fn { struct mul_fn { template requires binary_operation - constexpr auto operator()(L &&lhs, R &&rhs) const - noexcept(nothrow_binary_operation) - -> result_t { - using impl = - traits, std::remove_cvref_t, - Policies...>; + auto operator()(L &&lhs, R &&rhs) const + -> result_t { + using impl = traits, std::remove_cvref_t, + Policies...>; return impl::invoke(lhs, rhs); } }; diff --git a/src/operations/operations.cppm b/src/operations/operations.cppm index b69683e..f7efa82 100644 --- a/src/operations/operations.cppm +++ b/src/operations/operations.cppm @@ -3,4 +3,5 @@ module; export module mcpplibs.primitives.operations; export import mcpplibs.primitives.operations.traits; -export import mcpplibs.primitives.operations.impl; \ No newline at end of file +export import mcpplibs.primitives.operations.impl; +export import mcpplibs.primitives.operations.operators; \ No newline at end of file From b2bcf197fd69fbf9dbd191db99f3dde8f89f9850 Mon Sep 17 00:00:00 2001 From: FrozenlemonTee <1115306170@qq.com> Date: Mon, 16 Mar 2026 00:43:23 +0800 Subject: [PATCH 7/7] docs: Update README.md and the example program --- README.md | 27 ++++++- examples/basic.cpp | 52 +++++++++---- src/operations/operators.cppm | 141 ++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 src/operations/operators.cppm diff --git a/README.md b/README.md index 08e9550..3cb412f 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,39 @@ 本仓库实现了底层强类型 primitive 基础设施(traits、policy、underlying 类型分类),供上层 `Integer`/`Floating`/`Boolean` 等封装使用。 +> [!WARNING] +> 目前项目还在开发中,API会随着后续演进而改变 + ## 特性 -- **C++23 模块** — `import mcpplibs.templates;` +- **C++23 模块** — `import mcpplibs.primitives;` - **双构建系统** — 同时支持 xmake 和 CMake - **CI/CD** — GitHub Actions 多平台构建(Linux / macOS / Windows) - **标准化结构** — 遵循 [mcpp-style-ref](https://github.com/mcpp-community/mcpp-style-ref) 编码规范 - **开箱即用** — 包含示例、测试和架构文档 +## Operators + +该库在 `primitive` 类型上重载了常见的 C++ 算术、位运算和一元运算符。算术行为受策略(policy)控制: + +- 值策略(`checked_value` / `saturating_value` / `unchecked_value`)决定溢出行为; +- 错误策略(`throw_error` / `expected_error` / `terminate_error`)决定在 `checked_value` 且发生错误时的处理方式。 + +示例: + +```cpp +import mcpplibs.primitives; +using namespace mcpplibs::primitives; +using namespace mcpplibs::primitives::policy; + +primitive a{1}, b{2}; +auto c = a + b; // primitive + +primitive x{std::numeric_limits::max()}; +primitive y{1}; +auto maybe = x + y; // std::expected, std::overflow_error> +``` + ## 项目结构 ``` diff --git a/examples/basic.cpp b/examples/basic.cpp index 89f7354..83b2790 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -1,26 +1,50 @@ #include +#include import mcpplibs.primitives; int main() { using namespace mcpplibs::primitives; using namespace mcpplibs::primitives::policy; + using namespace mcpplibs::primitives::operators; + using namespace mcpplibs::primitives::types; - std::cout << "=== mcpplibs.primitives traits & policy example ===\n"; - std::cout << std::boolalpha; - std::cout << "int is std_integer: " << std_integer << "\n"; - std::cout << "double is std_floating: " << std_floating << "\n"; - std::cout << "int is underlying_type: " << underlying_type << "\n"; - - std::cout - << "default value policy is unchecked_value: " - << std::is_same_v << "\n"; - - std::cout << "checked_value is a policy_type: " - << policy_type << "\n"; - std::cout << "checked_value category == value: " - << (policy::traits::kind == category::value) + // Operators + I32<> a{3}; + I32<> b{4}; + auto c = a + b; // primitive + std::cout << "3 + 4 = " << static_cast(c) << "\n"; + + // Error handling + I32 lhs{1}; + I32 rhs{std::numeric_limits::max()}; + + try { + auto res = lhs + rhs; + } catch (const std::exception &e) { + std::cout << "An exception occurred: " << e.what() << "\n"; + } + + I64 lhs2{1}; + I64 rhs2{std::numeric_limits::max()}; + + auto res2 = lhs2 + rhs2; + + // Saturating + I32 s1{std::numeric_limits::max()}; + I32 s2{1}; + auto sat = s1 + s2; // saturating -> stays max + std::cout << "saturating max + 1 = " << static_cast(sat) << "\n"; + // Mixed-type addition + using expected_type = I64; + expected_type L1{5}; + I32 L2{6}; + auto mix = L1 + L2; // common_type -> I64 + std::cout << "5 + 6 = " << mix.value() << "\n"; + std::cout << std::boolalpha; + std::cout << "Does type of mix is I64: " << std::same_as << std::endl; + return 0; } diff --git a/src/operations/operators.cppm b/src/operations/operators.cppm new file mode 100644 index 0000000..e7e9219 --- /dev/null +++ b/src/operations/operators.cppm @@ -0,0 +1,141 @@ +module; +#include +export module mcpplibs.primitives.operations.operators; + +import mcpplibs.primitives.underlying; +import mcpplibs.primitives.policy; +import mcpplibs.primitives.primitive; +import mcpplibs.primitives.operations.impl; + +export namespace mcpplibs::primitives::operators { +template + requires std_numeric +constexpr auto operator~(const primitive &p) { + // Placeholder: unary bitwise NOT not yet forwarded to operations layer. + // TODO: forward to operations::bit_not when implemented. + return primitives::primitive(~p.value()); +} + +template + requires std_numeric +constexpr auto operator+(const primitive &p) { + // Placeholder: unary plus not yet forwarded to operations layer. + // TODO: forward to operations::unary_plus when implemented. + return primitives::primitive(+p.value()); +} + +template + requires std_numeric +constexpr auto operator-(const primitive &p) { + // Placeholder: unary minus not yet forwarded to operations layer. + // TODO: forward to operations::unary_neg when implemented. + return primitives::primitive(-p.value()); +} + +template + requires std_numeric && std_numeric +constexpr auto operator+(const primitive &lhs, + const primitive &rhs) { + return operations::add(lhs, rhs); +} + +template + requires std_numeric && std_numeric +constexpr auto operator-(const primitive &lhs, + const primitive &rhs) { + return operations::sub(lhs, rhs); +} + +template +constexpr auto operator*(const primitive &lhs, + const primitive &rhs) { + return operations::mul(lhs, rhs); +} + +template +constexpr auto operator/(const primitive &lhs, + const primitive &rhs) { + // Placeholder: division not yet forwarded to operations layer. + // TODO: forward to operations::div when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) / + static_cast(rhs.value())); +} + +template +constexpr auto operator%(const primitive &lhs, + const primitive &rhs) { + // Placeholder: modulo not yet forwarded to operations layer. + // TODO: forward to operations::mod when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) % + static_cast(rhs.value())); +} + +template +constexpr auto operator<<(const primitive &lhs, + const primitive &rhs) { + // Placeholder: left shift not yet forwarded to operations layer. + // TODO: forward to operations::shl when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) + << static_cast(rhs.value())); +} + +template +constexpr auto operator>>(const primitive &lhs, + const primitive &rhs) { + // Placeholder: right shift not yet forwarded to operations layer. + // TODO: forward to operations::shr when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) >> + static_cast(rhs.value())); +} + +template +constexpr auto operator&(const primitive &lhs, + const primitive &rhs) { + // Placeholder: bitwise AND not yet forwarded to operations layer. + // TODO: forward to operations::bit_and when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) & + static_cast(rhs.value())); +} + +template +constexpr auto operator|(const primitive &lhs, + const primitive &rhs) { + // Placeholder: bitwise OR not yet forwarded to operations layer. + // TODO: forward to operations::bit_or when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) | + static_cast(rhs.value())); +} + +template +constexpr auto operator^(const primitive &lhs, + const primitive &rhs) { + // Placeholder: bitwise XOR not yet forwarded to operations layer. + // TODO: forward to operations::bit_xor when implemented (handle policies). + using result_type = std::common_type_t; + return primitives::primitive( + static_cast(lhs.value()) ^ + static_cast(rhs.value())); +} +} // namespace mcpplibs::primitives::operators \ No newline at end of file