diff --git a/include/boost/safe_numbers.hpp b/include/boost/safe_numbers.hpp index e02865d..aab9494 100644 --- a/include/boost/safe_numbers.hpp +++ b/include/boost/safe_numbers.hpp @@ -5,8 +5,6 @@ #ifndef BOOST_SAFENUMBERS_HPP #define BOOST_SAFENUMBERS_HPP -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include @@ -23,6 +21,4 @@ #include #include -#undef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif //BOOST_SAFENUMBERS_HPP diff --git a/include/boost/safe_numbers/detail/int128/charconv.hpp b/include/boost/safe_numbers/detail/int128/charconv.hpp index a2f4cf6..a39f8a3 100644 --- a/include/boost/safe_numbers/detail/int128/charconv.hpp +++ b/include/boost/safe_numbers/detail/int128/charconv.hpp @@ -16,6 +16,10 @@ # define BOOST_CHARCONV_ENABLE_CUDA #endif +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_SYCL) && !defined(BOOST_CHARCONV_ENABLE_SYCL) +# define BOOST_CHARCONV_ENABLE_SYCL +#endif + #include #include #include @@ -44,23 +48,23 @@ struct make_signed { using type = int128::int128_t; }; template <> struct make_signed { using type = int128::int128_t; }; -#if defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA) +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) template <> -__host__ __device__ constexpr int128::uint128_t get_max_value() +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128::uint128_t get_max_value() { return std::numeric_limits::max(); } template <> -__host__ __device__ constexpr int128::int128_t get_max_value() +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128::int128_t get_max_value() { return std::numeric_limits::max(); } -#endif // __NVCC__ +#endif -#if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) +#if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) BOOST_SAFE_NUMBERS_DETAIL_INT128_INLINE_CONSTEXPR int128::uint128_t int128_pow10[39] = { @@ -109,7 +113,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_INLINE_CONSTEXPR int128::uint128_t int128_pow10 BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int num_digits(const int128::uint128_t& x) noexcept { - #if defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA) + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) constexpr int128::uint128_t int128_pow10[39] = { @@ -187,7 +191,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int num_digits(const int1 BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, const int128::uint128_t value, const int base = 10) noexcept { - #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) + #if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) if (base == 10) { @@ -201,7 +205,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_CHARCONV_CONSTEXPR to_chars_r BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, const int128::int128_t value, const int base = 10) noexcept { - #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) + #if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) if (base == 10) { diff --git a/include/boost/safe_numbers/detail/int128/cstdlib.hpp b/include/boost/safe_numbers/detail/int128/cstdlib.hpp index 161969f..8dbd37b 100644 --- a/include/boost/safe_numbers/detail/int128/cstdlib.hpp +++ b/include/boost/safe_numbers/detail/int128/cstdlib.hpp @@ -61,15 +61,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return i128div_t{0, 0}; } - #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) - - const auto builtin_x {static_cast(x)}; - const auto builtin_y {static_cast(y)}; - return i128div_t{static_cast(builtin_x / builtin_y), - static_cast(builtin_x % builtin_y)}; - - #else - const auto abs_lhs {static_cast(abs(x))}; const auto abs_rhs {static_cast(abs(y))}; @@ -78,19 +69,29 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return {0, x}; } - const auto unsigned_res {div(abs_lhs, abs_rhs)}; - const auto negative_quot {(x.high < 0) != (y.high < 0)}; const auto negative_rem {x.high < 0}; + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) + + if (abs_rhs.high != 0) + { + const auto builtin_x {static_cast(x)}; + const auto builtin_y {static_cast(y)}; + return i128div_t{static_cast(builtin_x / builtin_y), + static_cast(builtin_x % builtin_y)}; + } + + #endif + + const auto unsigned_res {div(abs_lhs, abs_rhs)}; + i128div_t res {static_cast(unsigned_res.quot), static_cast(unsigned_res.rem)}; res.quot = negative_quot ? -res.quot : res.quot; res.rem = negative_rem ? -res.rem : res.rem; return res; - - #endif } } // namespace int128 diff --git a/include/boost/safe_numbers/detail/int128/detail/common_div.hpp b/include/boost/safe_numbers/detail/int128/detail/common_div.hpp index dc318c2..8c15563 100644 --- a/include/boost/safe_numbers/detail/int128/detail/common_div.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/common_div.hpp @@ -7,6 +7,7 @@ #include #include +#include #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILD_MODULE @@ -67,6 +68,242 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO quotient.low |= (remainder / rhs) & UINT32_MAX; } +// Portable 128-bit by 64-bit unsigned division producing a 64-bit quotient and remainder. +// This is the classic Hacker's Delight divlu (two 32-bit "digit" steps over 64-bit words). +// Precondition: u1 < d so the quotient is guaranteed to fit in 64 bits. It is constexpr-safe +// and serves as the fallback for udiv_2by1 on every target without a hardware 128/64 divide. +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr std::uint64_t divlu(std::uint64_t u1, std::uint64_t u0, std::uint64_t d, std::uint64_t& r) noexcept +{ + constexpr std::uint64_t b {UINT64_C(1) << 32U}; // Number base (2^32) + + BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(u1 < d); // LCOV_EXCL_LINE + + // D.1: normalize so that the divisor's most significant bit is set + const auto s {countl_zero(d)}; + d <<= s; + + const auto vn1 {d >> 32U}; + const auto vn0 {d & UINT32_MAX}; + + // Shift the dividend left by s. The (64 - s) shift is undefined when s == 0, so guard it. + const auto un32 {s == 0 ? u1 : ((u1 << s) | (u0 >> (64 - s)))}; + const auto un10 {u0 << s}; + + const auto un1 {un10 >> 32U}; + const auto un0 {un10 & UINT32_MAX}; + + // First quotient digit + auto q1 {un32 / vn1}; + auto rhat {un32 - (q1 * vn1)}; + + while (q1 >= b || (q1 * vn0) > ((b * rhat) + un1)) + { + --q1; + rhat += vn1; + if (rhat >= b) + { + break; + } + } + + const auto un21 {(un32 * b) + un1 - (q1 * d)}; + + // Second quotient digit + auto q0 {un21 / vn1}; + rhat = un21 - (q0 * vn1); + + while (q0 >= b || (q0 * vn0) > ((b * rhat) + un0)) + { + --q0; + rhat += vn1; + if (rhat >= b) + { + break; + } + } + + // The remainder is shifted back down by the normalization amount + r = ((un21 * b) + un0 - (q0 * d)) >> s; + return (q1 * b) + q0; +} + +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_X86_64_DIVQ) + +// Inline asm cannot appear in a constexpr function body before C++20, so the x86-64 DIV +// instruction is wrapped in a non-constexpr helper that udiv_2by1 only calls at runtime. +BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE std::uint64_t udiv_2by1_divq(const std::uint64_t u1, const std::uint64_t u0, const std::uint64_t d, std::uint64_t& r) noexcept +{ + std::uint64_t q {}; + __asm__("divq %[d]" : "=a"(q), "=d"(r) : [d] "r"(d), "a"(u0), "d"(u1) : "cc"); + return q; +} + +#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_X86_64_DIVQ + +// Divides the 128-bit value (u1:u0) by d, returning a 64-bit quotient and the true remainder. +// Precondition: u1 < d. Mirrors common_mul.hpp::umul: a hardware instruction at runtime where +// one exists, and the portable divlu in constexpr evaluation and everywhere else. +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr std::uint64_t udiv_2by1(const std::uint64_t u1, const std::uint64_t u0, const std::uint64_t d, std::uint64_t& r) noexcept +{ + BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(u1 < d); // LCOV_EXCL_LINE + + #if (defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_X86_64_DIVQ) || (defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920)) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) + + if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(u1)) + { + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_X86_64_DIVQ) + + return udiv_2by1_divq(u1, u0, d, r); + + #else + + return _udiv128(u1, u0, d, &r); + + #endif + } + + #endif + + return divlu(u1, u0, d, r); +} + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4127) // Pre c++17 the if constexpr remainder part will hit this +#endif + +// Divides the 128-bit value (uh:ul) by the 128-bit divisor (vh:vl) where vh != 0. Because the +// divisor is >= 2^64 the quotient is guaranteed to fit in a single 64-bit word, which is +// returned. When need_remainder is true the 128-bit remainder is written to (rem_hi:rem_lo). +// +// This is one normalized quotient digit (Knuth Algorithm D specialized to a 2-word divisor). +// The top-limb estimate qhat (reusing udiv_2by1, a hardware divq on x86-64) is bounded by +// Knuth Theorem B to q <= qhat <= q + 2; the D3 refinement against d0 tightens it to q <= qhat +// <= q + 1, and the conditional add-back then corrects the remaining off-by-one. +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr std::uint64_t div3by2(const std::uint64_t uh, const std::uint64_t ul, + const std::uint64_t vh, const std::uint64_t vl, std::uint64_t& rem_hi, std::uint64_t& rem_lo) noexcept +{ + BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(vh != 0); // LCOV_EXCL_LINE + + // D.1: normalize so the divisor's most significant bit is set + const auto s {countl_zero(vh)}; + const auto cs {64 - s}; + + std::uint64_t d1 {}; + std::uint64_t d0 {}; + std::uint64_t u2 {}; + std::uint64_t u1 {}; + std::uint64_t u0 {}; + + if (s == 0) + { + d1 = vh; + d0 = vl; + u2 = 0; + u1 = uh; + u0 = ul; + } + else + { + d1 = (vh << s) | (vl >> cs); + d0 = vl << s; + u2 = uh >> cs; + u1 = (uh << s) | (ul >> cs); + u0 = ul << s; + } + + BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(u2 <= d1); // LCOV_EXCL_LINE + + // D.3: estimate the single quotient digit qhat = floor((u2:u1) / d1), clamped to 2^64 - 1. + // rhat is the remainder of that estimate. + std::uint64_t qhat {}; + std::uint64_t rhat {}; + bool rhat_overflow {false}; + if (u2 < d1) + { + qhat = udiv_2by1(u2, u1, d1, rhat); + } + else + { + // u2 == d1: floor((u2:u1)/d1) clamps to 2^64 - 1, leaving rhat == u1 + d1 (may carry). + qhat = UINT64_MAX; + rhat = u1 + d1; + rhat_overflow = rhat < u1; + } + + std::uint64_t qd0_hi {}; + auto qd0_lo {umul(qhat, d0, qd0_hi)}; + + // Refine qhat against d0 (Knuth D3). The top-limb estimate alone can exceed the true quotient + // by up to 2; this brings it down to at most one too large, which the add-back below corrects. + // At most two iterations run, and only while the running remainder rhat stays below 2^64. + if (!rhat_overflow) + { + while (qd0_hi > rhat || (qd0_hi == rhat && qd0_lo > u0)) + { + --qhat; + rhat += d1; + const auto rhat_carry {rhat < d1}; + qd0_lo = umul(qhat, d0, qd0_hi); + if (rhat_carry) + { + break; + } + } + } + + // D.4: multiply and subtract (u2:u1:u0) - qhat * (d1:d0). qd0 already holds qhat * d0. + std::uint64_t qd1_hi {}; + const auto qd1_lo {umul(qhat, d1, qd1_hi)}; + + const auto p0 {qd0_lo}; + const auto p1 {qd0_hi + qd1_lo}; + const auto p2 {qd1_hi + static_cast(p1 < qd0_hi)}; + + const auto r0 {u0 - p0}; + const auto borrow0 {static_cast(u0 < p0)}; + const auto t1 {u1 - p1}; + auto r1 {t1 - borrow0}; + const auto borrow1 {static_cast(u1 < p1) + static_cast(t1 < borrow0)}; + + // D.5/D.6: if the top limb borrowed, qhat was one too large. Correct it and add the divisor + // back into the remainder. The probability of this branch is small. + auto r0_final {r0}; + if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY((u2 < p2) || ((u2 - p2) < borrow1))) + { + --qhat; // LCOV_EXCL_LINE + const auto sum0 {r0 + d0}; // LCOV_EXCL_LINE + r0_final = sum0; // LCOV_EXCL_LINE + r1 = r1 + d1 + static_cast(sum0 < r0); // LCOV_EXCL_LINE + } + + BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (need_remainder) + { + if (s == 0) + { + rem_hi = r1; + rem_lo = r0_final; + } + else + { + rem_lo = (r0_final >> s) | (r1 << cs); + rem_hi = r1 >> s; + } + } + else + { + static_cast(rem_hi); + static_cast(rem_lo); + } + + return qhat; +} + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + namespace impl { #if defined(_MSC_VER) @@ -129,7 +366,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr void knuth_divide(std::ui while (q_hat > UINT32_MAX || (q_hat * vn[n-2]) > ((r_hat << 32) | un[j+n-2])) { - q_hat--; + --q_hat; r_hat += vn[n-1]; if (r_hat > UINT32_MAX) { @@ -267,218 +504,57 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO return {static_cast(high), low}; } -#if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 - -template -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr T div_mod_msvc(T dividend, T divisor, T& remainder) -{ - using high_word_type = decltype(T{}.high); - - // Skip normalization if divisor is already large enough - // use direct division and intrinsic - // This is only possible in the unsigned case - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (!std::numeric_limits::is_signed) - { - constexpr auto divisor_lower_bound{UINT64_MAX >> 1}; - if (divisor.high >= divisor_lower_bound) - { - T quotient{}; - - quotient.low = static_cast(dividend.high / divisor.high); - - std::uint64_t product0_high{}; - auto product0_low{_umul128(quotient.low, divisor.low, &product0_high)}; - - std::uint64_t product1_high{}; - auto product1_low{_umul128(quotient.low, static_cast(divisor.high), &product1_high)}; - - T product{}; - product.low = product0_low; - auto carry{BOOST_SAFE_NUMBERS_DETAIL_INT128_ADD_CARRY(0, product0_high, product1_low, reinterpret_cast(&product.high))}; - product1_high += static_cast(carry); - - if (product1_high > 0 || product > dividend) - { - --quotient.low; - - // Recalculate with adjusted quotient - product0_low = _umul128(quotient.low, divisor.low, &product0_high); - product1_low = _umul128(quotient.low, divisor.high, &product1_high); - - product.low = product0_low; - carry = BOOST_SAFE_NUMBERS_DETAIL_INT128_ADD_CARRY(0, product0_high, product1_low, reinterpret_cast(&product.high)); - product1_high += static_cast(carry); - } - - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR(needs_mod) - { - auto borrow{BOOST_SAFE_NUMBERS_DETAIL_INT128_SUB_BORROW(0, dividend.low, product.low, &remainder.low)}; - BOOST_SAFE_NUMBERS_DETAIL_INT128_SUB_BORROW(borrow, dividend.high, product.high, reinterpret_cast(&remainder.high)); - } - - return quotient; - } - } - - const auto shift_amount {countl_zero(static_cast(divisor.high))}; - divisor <<= shift_amount; - - auto high_digit {static_cast(shift_amount == 0 ? 0 : dividend.high >> (64 - shift_amount))}; - dividend <<= shift_amount; - - // Initial quotient estimate - T quotient {}; - const bool high_digit_gte_divisor {high_digit >= static_cast(divisor.high)}; - quotient.high = high_digit_gte_divisor ? 1 : 0; - std::uint64_t remainder_estimate {}; - - quotient.low = _udiv128(high_digit_gte_divisor ? high_digit - divisor.high : high_digit, - dividend.high, divisor.high, &remainder_estimate); - - // Bounded correction loop with early exit - // Typically 2 is the most number of corrections we need since this is only for 2x2 division - // Other cases have been filtered out well before we've made it this far - int correction_steps {}; - constexpr int max_corrections {2}; - - while (correction_steps < max_corrections) - { - T product{}; - product.low = _umul128(quotient.low, divisor.low, reinterpret_cast(&product.high)); - if (product <= T{static_cast(remainder_estimate), dividend.low}) - { - break; - } - - --quotient.low; - const auto sum {remainder_estimate + divisor.high}; - if (remainder_estimate > sum) - { - break; - } - remainder_estimate = sum; - - correction_steps++; - } - - // Final verification and adjustment - std::uint64_t product0_high{}; - auto product_low {_umul128(quotient.low, divisor.low, &product0_high)}; - auto borrow {BOOST_SAFE_NUMBERS_DETAIL_INT128_SUB_BORROW(0, dividend.low, product_low, ÷nd.low)}; - - std::uint64_t product1_high{}; - product_low = _umul128(quotient.low, divisor.high, &product1_high); - product1_high += static_cast(BOOST_SAFE_NUMBERS_DETAIL_INT128_ADD_CARRY(0, product_low, product0_high, &product_low)); - - borrow = BOOST_SAFE_NUMBERS_DETAIL_INT128_SUB_BORROW(borrow, static_cast(dividend.high), product_low, reinterpret_cast(÷nd.high)); - borrow = BOOST_SAFE_NUMBERS_DETAIL_INT128_SUB_BORROW(borrow, high_digit, product1_high, &high_digit); - quotient.low -= static_cast(borrow); - - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (needs_mod) - { - if (borrow) - { - auto carry { BOOST_SAFE_NUMBERS_DETAIL_INT128_ADD_CARRY(0, dividend.low, divisor.low, ÷nd.low) }; - BOOST_SAFE_NUMBERS_DETAIL_INT128_ADD_CARRY(carry, static_cast(dividend.high), static_cast(divisor.high), reinterpret_cast(÷nd.high)); - } - - dividend >>= shift_amount; - remainder = dividend; - } - - return quotient; -} - -#endif - } // namespace impl // We only need to take the time to process the remainder in the modulo case // In the division case it is a waste of cycles +// +// 128/64 -> 128-bit quotient (and optional 64-bit remainder) by two-step long division. +// The leading 64/64 yields the high quotient word and a remainder r < rhs, which satisfies +// the udiv_2by1 precondition for the low quotient word. This covers every rhs (including +// rhs <= UINT32_MAX) through the single hardware-or-portable udiv_2by1 primitive. template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint64_t rhs, T& quotient) noexcept { - #if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) - - if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) - { - using high_word_type = decltype(T{}.high); - - quotient.high = static_cast(static_cast(lhs.high) / rhs); - auto remainder {static_cast(lhs.high) % rhs}; - quotient.low = _udiv128(remainder, lhs.low, rhs, &remainder); - return; - } - - #endif - - if (rhs <= UINT32_MAX) - { - half_word_div(lhs, static_cast(rhs), quotient); - } - else - { - std::uint32_t u[4] {}; - std::uint32_t v[2] {}; - std::uint32_t q[4] {}; + using high_word_type = decltype(T{}.high); - const auto m {impl::to_words(lhs, u)}; - const auto n {impl::to_words(rhs, v)}; + BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(rhs != 0); // LCOV_EXCL_LINE - impl::knuth_divide(u, m, v, n, q); + const auto u_high {static_cast(lhs.high)}; - quotient = impl::from_words(q); - } + quotient.high = static_cast(u_high / rhs); + auto r {u_high % rhs}; + quotient.low = udiv_2by1(r, lhs.low, rhs, r); } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint64_t rhs, T& quotient, T& remainder) noexcept { - #if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) - - if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) - { - using high_word_type = decltype(T{}.high); - - quotient.high = static_cast(static_cast(lhs.high) / rhs); - remainder.low = static_cast(lhs.high) % rhs; - quotient.low = _udiv128(remainder.low, lhs.low, rhs, &remainder.low); - return; - } - - #endif + using high_word_type = decltype(T{}.high); - if (rhs <= UINT32_MAX) - { - half_word_div(lhs, static_cast(rhs), quotient, remainder); - } - else - { - std::uint32_t u[4] {}; - std::uint32_t v[2] {}; - std::uint32_t q[4] {}; + BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(rhs != 0); // LCOV_EXCL_LINE - const auto m {impl::to_words(lhs, u)}; - const auto n {impl::to_words(rhs, v)}; + const auto u_high {static_cast(lhs.high)}; - impl::knuth_divide(u, m, v, n, q); + quotient.high = static_cast(u_high / rhs); + auto r {u_high % rhs}; + quotient.low = udiv_2by1(r, lhs.low, rhs, r); - quotient = impl::from_words(q); - remainder = impl::from_words(u); - } + remainder.high = static_cast(0); + remainder.low = r; } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint32_t rhs, T& quotient, T& remainder) noexcept { - half_word_div(lhs, rhs, quotient, remainder); + one_word_div(lhs, static_cast(rhs), quotient, remainder); } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint32_t rhs, T& quotient) noexcept { - half_word_div(lhs, rhs, quotient); + one_word_div(lhs, static_cast(rhs), quotient); } #ifdef _MSC_VER @@ -492,62 +568,33 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO { BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(divisor != static_cast(0)); - #if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 - - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR(!std::numeric_limits::is_signed) - { - if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(dividend)) - { - T remainder{}; - return impl::div_mod_msvc(dividend, divisor, remainder); - } - } - - #endif - - std::uint32_t u[4]{}; - std::uint32_t v[4]{}; - std::uint32_t q[4]{}; - - const auto m{ impl::to_words(dividend, u) }; - const auto n{ impl::to_words(divisor, v) }; + using high_word_type = decltype(T{}.high); - impl::knuth_divide(u, m, v, n, q); + std::uint64_t rem_hi {}; + std::uint64_t rem_lo {}; - return impl::from_words(q); + const auto q {div3by2(static_cast(dividend.high), dividend.low, + static_cast(divisor.high), divisor.low, rem_hi, rem_lo)}; + return T{static_cast(0), q}; } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend, const T& divisor, T& remainder) noexcept { BOOST_SAFE_NUMBERS_DETAIL_INT128_ASSUME(divisor != static_cast(0)); - - #if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 - - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR(!std::numeric_limits::is_signed) - { - if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(dividend)) - { - return impl::div_mod_msvc(dividend, divisor, remainder); - } - } - - #endif - - std::uint32_t u[4]{}; - std::uint32_t v[4]{}; - std::uint32_t q[4]{}; + using high_word_type = decltype(T{}.high); - const auto m{ impl::to_words(dividend, u) }; - const auto n{ impl::to_words(divisor, v) }; + std::uint64_t rem_hi {}; + std::uint64_t rem_lo {}; - impl::knuth_divide(u, m, v, n, q); + const auto q {div3by2(static_cast(dividend.high), dividend.low, + static_cast(divisor.high), divisor.low, rem_hi, rem_lo)}; - remainder = impl::from_words(u); + remainder = T{static_cast(rem_hi), rem_lo}; - return impl::from_words(q); + return T{static_cast(0), q}; } #ifdef _MSC_VER diff --git a/include/boost/safe_numbers/detail/int128/detail/common_mul.hpp b/include/boost/safe_numbers/detail/int128/detail/common_mul.hpp index a9e49e0..08535c0 100644 --- a/include/boost/safe_numbers/detail/int128/detail/common_mul.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/common_mul.hpp @@ -10,7 +10,6 @@ #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILD_MODULE #include -#include #endif @@ -18,85 +17,89 @@ namespace boost { namespace int128 { namespace detail { -// See: The Art of Computer Programming Volume 2 (Semi-numerical algorithms) section 4.3.1 -// Algorithm M: Multiplication of Non-negative integers -template -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr ReturnType knuth_multiply(const std::uint32_t (&u)[u_size], - const std::uint32_t (&v)[v_size]) noexcept +// High 64 bits of the 64x64 -> 128 product, computed with four 32-bit partial products +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr std::uint64_t umulh_generic(const std::uint64_t a, const std::uint64_t b) noexcept { - using high_word_type = decltype(ReturnType{}.high); - - std::uint32_t w[u_size + v_size] {}; + const std::uint64_t a_lo {a & UINT32_MAX}; + const std::uint64_t a_hi {a >> 32U}; + const std::uint64_t b_lo {b & UINT32_MAX}; + const std::uint64_t b_hi {b >> 32U}; - // M.1 - for (std::size_t j {}; j < v_size; ++j) - { - // M.2 - if (v[j] == 0) - { - w[j + u_size] = 0; - continue; - } - - // M.3 - std::uint64_t t {}; - for (std::size_t i {}; i < u_size; ++i) - { - // M.4 - t += static_cast(u[i]) * v[j] + w[i + j]; - w[i + j] = static_cast(t); - t >>= 32u; - } - - // M.5 - w[j + u_size] = static_cast(t); - } + const std::uint64_t lo_lo {a_lo * b_lo}; + const std::uint64_t hi_lo {a_hi * b_lo}; + const std::uint64_t lo_hi {a_lo * b_hi}; + const std::uint64_t hi_hi {a_hi * b_hi}; - const auto low {static_cast(w[0]) | (static_cast(w[1]) << 32)}; - const auto high {static_cast(w[2]) | (static_cast(w[3]) << 32)}; + const std::uint64_t cross {(lo_lo >> 32U) + (hi_lo & UINT32_MAX) + (lo_hi & UINT32_MAX)}; - return {static_cast(high), low}; + return hi_hi + (hi_lo >> 32U) + (lo_hi >> 32U) + (cross >> 32U); } -template -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const T& x, std::uint32_t (&words)[4]) noexcept +// Full 64x64 -> 128 product +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr std::uint64_t umul(const std::uint64_t a, const std::uint64_t b, std::uint64_t& hi) noexcept { #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION - if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) + if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(a)) { - std::memcpy(&words, &x, sizeof(T)); - return; + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) + + const detail::builtin_u128 product {static_cast(a) * static_cast(b)}; + hi = static_cast(product >> 64U); + return static_cast(product); + + #elif defined(_M_AMD64) && !defined(__GNUC__) && !defined(__CUDA_ARCH__) && !defined(__SYCL_DEVICE_ONLY__) + + return _umul128(a, b, &hi); + + #elif defined(_M_ARM64) && !defined(__CUDA_ARCH__) && !defined(__SYCL_DEVICE_ONLY__) + + hi = __umulh(a, b); + return a * b; + + #endif } #endif - words[0] = static_cast(x.low & UINT32_MAX); // LCOV_EXCL_LINE - words[1] = static_cast(x.low >> 32); // LCOV_EXCL_LINE - words[2] = static_cast(static_cast(x.high) & UINT32_MAX); // LCOV_EXCL_LINE - words[3] = static_cast(static_cast(x.high) >> 32); // LCOV_EXCL_LINE + hi = umulh_generic(a, b); + return a * b; } +// Low 128 bits of a 128x128 product +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr ReturnType low_word_mul(const T& lhs, const T& rhs) noexcept +{ + using high_word_type = decltype(ReturnType{}.high); + + std::uint64_t result_high {}; + const std::uint64_t result_low {umul(lhs.low, rhs.low, result_high)}; + + result_high += lhs.low * static_cast(rhs.high); + result_high += static_cast(lhs.high) * rhs.low; + + return ReturnType{static_cast(result_high), result_low}; +} -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint64_t x, std::uint32_t (&words)[2]) noexcept +// Low 128 bits of a 128x64 product +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr ReturnType low_word_mul(const T& lhs, const std::uint64_t rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION + using high_word_type = decltype(ReturnType{}.high); - if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) - { - std::memcpy(&words, &x, sizeof(std::uint64_t)); - return; - } + std::uint64_t result_high {}; + const std::uint64_t result_low {umul(lhs.low, rhs, result_high)}; - #endif + result_high += static_cast(lhs.high) * rhs; - words[0] = static_cast(x & UINT32_MAX); // LCOV_EXCL_LINE - words[1] = static_cast(x >> 32); // LCOV_EXCL_LINE + return ReturnType{static_cast(result_high), result_low}; } -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint32_t x, std::uint32_t (&words)[1]) noexcept +// Low 128 bits of a 128x32 product +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr ReturnType low_word_mul(const T& lhs, const std::uint32_t rhs) noexcept { - words[0] = x; + return low_word_mul(lhs, static_cast(rhs)); } } // namespace detail diff --git a/include/boost/safe_numbers/detail/int128/detail/config.hpp b/include/boost/safe_numbers/detail/int128/detail/config.hpp index d476c7f..8517050 100644 --- a/include/boost/safe_numbers/detail/int128/detail/config.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/config.hpp @@ -5,12 +5,17 @@ #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_DETAIL_CONFIG_HPP #define BOOST_SAFE_NUMBERS_DETAIL_INT128_DETAIL_CONFIG_HPP -#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE) -# define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE +// The SYCL device target (spir64) has no native 128-bit integer, so force the portable +// code path on the device pass. This mirrors a user-supplied BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_BUILTIN_INT128 +// and keeps host/device selection consistent even though __x86_64__ stays defined on device. +#if defined(__SYCL_DEVICE_ONLY__) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_BUILTIN_INT128) +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_BUILTIN_INT128 #endif -// Use 128-bit integers -#if defined(BOOST_HAS_INT128) || (defined(__SIZEOF_INT128__) && !defined(_MSC_VER)) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_BUILTIN_INT128) +// Use 128-bit integers. +// The SYCL device target (spir64) has no native 128-bit integer, so on the device pass +// we fall back to the portable path (the same one used on platforms without __int128). +#if (defined(BOOST_HAS_INT128) || (defined(__SIZEOF_INT128__) && !defined(_MSC_VER)) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_BUILTIN_INT128)) && !defined(__SYCL_DEVICE_ONLY__) #define BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 @@ -37,7 +42,7 @@ using builtin_u128 = unsigned __int128; } // namespace int128 } // namespace boost -#elif __has_include(<__msvc_int128.hpp>) && _MSVC_LANG >= 202002L +#elif __has_include(<__msvc_int128.hpp>) && _MSVC_LANG >= 202002L && !defined(__SYCL_DEVICE_ONLY__) #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILD_MODULE #include <__msvc_int128.hpp> @@ -45,7 +50,11 @@ using builtin_u128 = unsigned __int128; #define BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128 +#if _MSC_VER >= 1945 +#define BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR constexpr +#else #define BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR inline +#endif namespace boost { namespace int128 { @@ -169,6 +178,12 @@ using builtin_u128 = std::_Unsigned128; #endif // Platform macros +// Hardware 128-bit by 64-bit unsigned division via the x86-64 DIV instruction +// Excluded on the CUDA and SYCL device passes (the device target is not x86-64) +#if defined(__x86_64__) && (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER) && !defined(__CUDA_ARCH__) && !defined(__SYCL_DEVICE_ONLY__) +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_X86_64_DIVQ +#endif + // The builtin is only constexpr from clang-7 or GCC-10 #ifdef __has_builtin # if __has_builtin(__builtin_sub_overflow) && ((defined(__clang__) && __clang_major__ >= 7) || (defined(__GNUC__) && __GNUC__ >= 10)) @@ -285,10 +300,26 @@ using builtin_u128 = std::_Unsigned128; # endif #endif +// GPU device support. CUDA is auto-detected via __CUDACC__ (opt-in with +// BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA). SYCL is fully opt-in via BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_SYCL; +// must be included before so SYCL_EXTERNAL exists. #if defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA) -# define BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE __host__ __device__ -#else -# define BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_CUDA_ENABLED __host__ __device__ +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT +#elif defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_SYCL) +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_SYCL_ENABLED SYCL_EXTERNAL +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT +#endif + +#ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_CUDA_ENABLED +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_CUDA_ENABLED #endif +#ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_SYCL_ENABLED +# define BOOST_SAFE_NUMBERS_DETAIL_INT128_SYCL_ENABLED +#endif + +// Exactly one sub-macro is ever non-empty; expands to "__host__ __device__" (CUDA), +// "SYCL_EXTERNAL" (SYCL), or nothing (host). +#define BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_CUDA_ENABLED BOOST_SAFE_NUMBERS_DETAIL_INT128_SYCL_ENABLED #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_DETAIL_CONFIG_HPP diff --git a/include/boost/safe_numbers/detail/int128/detail/conversions.hpp b/include/boost/safe_numbers/detail/int128/detail/conversions.hpp index 8db562f..1cd03de 100644 --- a/include/boost/safe_numbers/detail/int128/detail/conversions.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/conversions.hpp @@ -38,20 +38,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::uint128_t(cons #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ENDIAN_LITTLE_BYTE -//===================================== -// Conversion Operators -//===================================== - -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t::operator uint128_t() const noexcept -{ - return uint128_t{static_cast(this->high), static_cast(this->low)}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::operator int128_t() const noexcept -{ - return int128_t{static_cast(this->high), static_cast(this->low)}; -} - //===================================== // Comparison Operators //===================================== @@ -64,291 +50,278 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::operator int12 template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const T lhs, const U rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - static_assert(std::is_same::value, "Sign Compare Error, cast one type to the other for this operation"); - static_cast(lhs); - static_cast(rhs); - return true; - - #else - - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) - { - if (lhs < T{0}) - { - return false; - } - - return static_cast(lhs) == rhs; - } - else - { - if (rhs < T{0}) - { - return false; - } - - return lhs == static_cast(rhs); - } - - #endif + return static_cast(lhs) == static_cast(rhs); } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const T lhs, const U rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - static_assert(std::is_same::value, "Sign Compare Error, cast one type to the other for this operation"); - static_cast(lhs); - static_cast(rhs); - return true; - - #else - - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) - { - if (lhs < T{0}) - { - return true; - } - - return static_cast(lhs) != rhs; - } - else - { - if (rhs < T{0}) - { - return true; - } - - return lhs != static_cast(rhs); - } - - #endif + return static_cast(lhs) != static_cast(rhs); } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const T lhs, const U rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - static_assert(std::is_same::value, "Sign Compare Error, cast one type to the other for this operation"); - static_cast(lhs); - static_cast(rhs); - return true; + return static_cast(lhs) < static_cast(rhs); +} - #else +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) <= static_cast(rhs); +} - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) - { - if (lhs < T{0}) - { - return true; - } +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) > static_cast(rhs); +} - return static_cast(lhs) < rhs; - } - else - { - if (rhs < T{0}) - { - return false; - } +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) >= static_cast(rhs); +} - return lhs < static_cast(rhs); - } +//===================================== +// Arithmetic Operators +//===================================== - #endif +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) + static_cast(rhs); } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const T lhs, const U rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - static_assert(std::is_same::value, "Sign Compare Error, cast one type to the other for this operation"); - static_cast(lhs); - static_cast(rhs); - return true; + return static_cast(lhs) - static_cast(rhs); +} - #else +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) * static_cast(rhs); +} - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) - { - if (lhs < T{0}) - { - return true; - } +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) / static_cast(rhs); +} - return static_cast(lhs) <= rhs; - } - else - { - if (rhs < T{0}) - { - return false; - } +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) % static_cast(rhs); +} - return lhs <= static_cast(rhs); - } +//===================================== +// Cross-type Bitwise Operators +//===================================== - #endif +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) | static_cast(rhs); } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const T lhs, const U rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - static_assert(std::is_same::value, "Sign Compare Error, cast one type to the other for this operation"); - static_cast(lhs); - static_cast(rhs); - return true; + return static_cast(lhs) & static_cast(rhs); +} - #else +template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const T lhs, const U rhs) noexcept +{ + return static_cast(lhs) ^ static_cast(rhs); +} - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) - { - if (lhs < T{0}) - { - return false; - } +//===================================== +// Cross-type Shift Operators +//===================================== - return static_cast(lhs) > rhs; - } - else - { - if (rhs < T{0}) - { - return true; - } +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator<<(const int128_t lhs, const uint128_t rhs) noexcept +{ + return lhs << static_cast(rhs); +} - return lhs > static_cast(rhs); - } +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator<<(const uint128_t lhs, const int128_t rhs) noexcept +{ + return lhs << static_cast(rhs); +} - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator>>(const int128_t lhs, const uint128_t rhs) noexcept +{ + return lhs >> static_cast(rhs); } -template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator>>(const uint128_t lhs, const int128_t rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE + return lhs >> static_cast(rhs); +} - static_assert(std::is_same::value, "Sign Compare Error, cast one type to the other for this operation"); - static_cast(lhs); - static_cast(rhs); - return true; +//===================================== +// int128_t with builtin unsigned __int128 comparison operators +// +// These live here (not in int128_imp.hpp) +// to avoid C++20 rewritten-candidate ambiguity on MSVC +//===================================== - #else +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) - { - if (lhs < T{0}) - { - return false; - } +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) == rhs; +} - return static_cast(lhs) >= rhs; - } - else - { - if (rhs < T{0}) - { - return true; - } +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs == static_cast(rhs); +} - return lhs >= static_cast(rhs); - } +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) != rhs; +} - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs != static_cast(rhs); } -//===================================== -// Arithmetic Operators -//===================================== +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) < rhs; +} -template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION + return lhs < static_cast(rhs); +} - static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - static_cast(rhs); - return static_cast(lhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) <= rhs; +} - #else +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs <= static_cast(rhs); +} - return static_cast(lhs) + static_cast(rhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) > rhs; +} - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs > static_cast(rhs); } -template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION + return static_cast(lhs) >= rhs; +} - static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - static_cast(rhs); - return static_cast(lhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs >= static_cast(rhs); +} - #else +#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 - return static_cast(lhs) - static_cast(rhs); +//===================================== +// int128_t with builtin unsigned __int128 binary operators +//===================================== + +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator|(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) | rhs; } -template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator|(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION + return lhs | static_cast(rhs); +} - static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - static_cast(rhs); - return static_cast(lhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator&(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) & rhs; +} - #else +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator&(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs & static_cast(rhs); +} - return static_cast(lhs) * static_cast(rhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator^(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) ^ rhs; +} - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator^(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs ^ static_cast(rhs); } -template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION + return static_cast(lhs) + rhs; +} - static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - static_cast(rhs); - return static_cast(lhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs + static_cast(rhs); +} - #else +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) - rhs; +} - return static_cast(lhs) / static_cast(rhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs - static_cast(rhs); +} - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator*(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) * rhs; } -template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const T lhs, const U rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator*(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION + return lhs * static_cast(rhs); +} - static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - static_cast(rhs); - return static_cast(lhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) / rhs; +} - #else +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs / static_cast(rhs); +} - return static_cast(lhs) % static_cast(rhs); +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +{ + return static_cast(lhs) % rhs; +} - #endif +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + return lhs % static_cast(rhs); } +#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 + #ifdef _MSC_VER #pragma warning(pop) #endif diff --git a/include/boost/safe_numbers/detail/int128/detail/int128_imp.hpp b/include/boost/safe_numbers/detail/int128/detail/int128_imp.hpp index 2fd4c1b..299e498 100644 --- a/include/boost/safe_numbers/detail/int128/detail/int128_imp.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/int128_imp.hpp @@ -56,8 +56,7 @@ int128_t constexpr int128_t& operator=(int128_t&&) noexcept = default; // Requires a conversion file to be implemented - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr int128_t(const uint128_t& v) noexcept; - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator uint128_t() const noexcept; + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const uint128_t& v) noexcept; // Construct from integral types #if BOOST_SAFE_NUMBERS_DETAIL_INT128_ENDIAN_LITTLE_BYTE @@ -87,41 +86,45 @@ int128_t template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const UnsignedInteger v) noexcept : high {}, low {static_cast(v)} {} - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const detail::builtin_i128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v & detail::low_word_mask)} {} - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const detail::builtin_u128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v & detail::low_word_mask)} {} + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t(const detail::builtin_i128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v & detail::low_word_mask)} {} + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t(const detail::builtin_u128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v & detail::low_word_mask)} {} #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ENDIAN_LITTLE_BYTE + // Construct from floating-point types + template + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t(Float f) noexcept; + // Integer Conversion operators BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator bool() const noexcept { return low || high; } template - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator SignedInteger() const noexcept { return static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator SignedInteger() const noexcept { return static_cast(low); } template - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 // Conversion to float // This is basically the same as ldexp(static_cast(high), 64) + static_cast(low), // but can be constexpr at C++11 instead of C++26 - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator float() const noexcept; - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator double() const noexcept; + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator float() const noexcept; + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator double() const noexcept; - // Long double does not exist on device - #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) - explicit constexpr operator long double() const noexcept; + // Long double does not exist on the CUDA or SYCL (spir64) device + #if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) + constexpr operator long double() const noexcept; #endif // Compound Or @@ -297,7 +300,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t::operator double return static_cast(high) * detail::offset_value_v + static_cast(low); } -#if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) +#if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) constexpr int128_t::operator long double() const noexcept { @@ -306,6 +309,62 @@ constexpr int128_t::operator long double() const noexcept #endif +//===================================== +// Float Construction +//===================================== + +// Inverse of operator(Float). +// NaN -> 0; +// f >= 2^127 -> INT128_MAX; +// f < -2^127 -> INT128_MIN. +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t::int128_t(Float f) noexcept +{ + constexpr Float two_32 {static_cast(UINT64_C(1) << 32)}; + constexpr Float two_64 {two_32 * two_32}; + constexpr Float two_127 {two_64 * static_cast(UINT64_C(1) << 63)}; + + // NaN: leave default-initialized (zero). NaN compares false to everything, + // so neither >= 0 nor <= 0 holds. + if (!(f >= Float{0}) && !(f <= Float{0})) + { + return; + } + + if (f >= two_127) + { + high = (std::numeric_limits::max)(); + low = UINT64_MAX; + return; + } + + if (f <= -two_127) + { + high = (std::numeric_limits::min)(); + low = UINT64_C(0); + return; + } + + const bool negative {f < Float{0}}; + const Float abs_f {negative ? -f : f}; + + std::uint64_t h {static_cast(abs_f / two_64)}; + const Float remainder {abs_f - static_cast(h) * two_64}; + std::uint64_t l {static_cast(remainder)}; + + if (negative) + { + // Two's complement negation of (h, l): new_l = -l (with wraparound), + // new_h = ~h if a borrow occurred (l != 0), else ~h + 1. + const bool low_was_zero {l == UINT64_C(0)}; + l = UINT64_C(0) - l; + h = ~h + (low_was_zero ? UINT64_C(1) : UINT64_C(0)); + } + + high = static_cast(h); + low = l; +} + //===================================== // Unary Operators //===================================== @@ -375,35 +434,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const Sig BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - return lhs.high == 0 && lhs.low == static_cast(rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - return rhs.high == 0 && rhs.low == static_cast(lhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) @@ -418,36 +455,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) == rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs.high < 0 ? false : lhs == static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return rhs.high < 0 ? false : static_cast(lhs) == rhs; -} - -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 //===================================== @@ -511,35 +518,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const Sig BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - return lhs.high != 0 || lhs.low != static_cast(rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - return rhs.high != 0 || rhs.low != static_cast(lhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) @@ -554,36 +539,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) != rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs.high < 0 ? true : lhs != static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return rhs.high < 0 ? true : static_cast(lhs) != rhs; -} - -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 //===================================== @@ -624,35 +579,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs.high < 0 ? true : lhs.low < static_cast(rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return lhs.high < 0 || (lhs.high == 0 && lhs.low < static_cast(rhs)); } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs.high < 0 ? false : static_cast(lhs) < rhs.low; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return rhs.high > 0 || (rhs.high == 0 && static_cast(lhs) < rhs.low); } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -700,36 +633,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) < rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs.high < 0 ? false : lhs < static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return rhs.high < 0 ? true : static_cast(lhs) < rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 //===================================== @@ -782,35 +685,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const Sign BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs.high > 0 ? true : lhs.low > static_cast(rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return lhs.high > 0 || (lhs.high == 0 && lhs.low > static_cast(rhs)); } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs.high < 0 ? true : static_cast(lhs) > rhs.low; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return rhs.high < 0 || (rhs.high == 0 && static_cast(lhs) > rhs.low); } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) @@ -825,36 +706,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) > rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs.high < 0 ? false : lhs > static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return rhs.high < 0 ? true : static_cast(lhs) > rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 //===================================== @@ -907,35 +758,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const Sig BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs.high < 0 ? true : lhs.low <= static_cast(rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return lhs.high < 0 || (lhs.high == 0 && lhs.low <= static_cast(rhs)); } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs.high < 0 ? false : static_cast(lhs) <= rhs.low; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return rhs.high > 0 || (rhs.high == 0 && static_cast(lhs) <= rhs.low); } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) @@ -950,36 +779,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) <= rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs.high < 0 ? true : lhs <= static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return rhs.high < 0 ? false : static_cast(lhs) <= rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 //===================================== @@ -1032,35 +831,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const Sig BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs.high < 0 ? false : lhs.low >= static_cast(rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return lhs.high > 0 || (lhs.high == 0 && lhs.low >= static_cast(rhs)); } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs.high < 0 ? true : static_cast(lhs) >= rhs.low; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + return rhs.high < 0 || (rhs.high == 0 && static_cast(lhs) >= rhs.low); } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) @@ -1075,36 +852,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) >= rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs.high < 0 ? false : lhs >= static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return rhs.high < 0 ? true : static_cast(lhs) >= rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 //===================================== @@ -1166,8 +913,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering oper BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - if (lhs < rhs) { return std::strong_ordering::less; @@ -1180,22 +925,11 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering oper { return std::strong_ordering::greater; } - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return std::strong_ordering::less; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - if (lhs < rhs) { return std::strong_ordering::less; @@ -1208,15 +942,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering oper { return std::strong_ordering::greater; } - - #else - - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return std::strong_ordering::less; - - #endif } #endif @@ -1254,78 +979,27 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {lhs.high, lhs.low | static_cast(rhs)}; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {rhs.high, static_cast(lhs) | rhs.low}; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif -} - -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const detail::builtin_i128 rhs) noexcept -{ - return lhs | static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const detail::builtin_i128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs) | rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator|(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs | static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator|(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) | rhs; } -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 @@ -1336,11 +1010,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator|=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this | rhs; + *this = static_cast(*this | rhs); return *this; } @@ -1355,11 +1025,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator|=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - - *this = *this | rhs; + *this = static_cast(*this | rhs); return *this; } @@ -1389,92 +1055,37 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - - return {lhs.high, lhs.low & static_cast(rhs)}; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif + return {0, lhs.low & static_cast(rhs)}; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - - return {rhs.high, static_cast(lhs) & rhs.low}; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif + return {0, static_cast(lhs) & rhs.low}; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator&(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs & static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator&(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) & rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 + +#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128 + +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator&=(const Integer rhs) noexcept { - return lhs & static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs) & rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 - -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128 - -template -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator&=(const Integer rhs) noexcept -{ - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - - *this = *this & rhs; - return *this; + *this = static_cast(*this & rhs); + return *this; } #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128 @@ -1486,11 +1097,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator&=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this & rhs; + *this = static_cast(*this & rhs); return *this; } @@ -1524,78 +1131,27 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {lhs.high, lhs.low ^ static_cast(rhs)}; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {rhs.high, static_cast(lhs) ^ rhs.low}; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return int128_t{}; - - #endif } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const detail::builtin_i128 rhs) noexcept -{ - return lhs ^ static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const detail::builtin_i128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs) ^ rhs; -} - -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator^(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs ^ static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator^(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) ^ rhs; } -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 @@ -1606,11 +1162,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator^=(Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this ^ rhs; + *this = static_cast(*this ^ rhs); return *this; } @@ -1625,11 +1177,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator^=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - - *this = *this ^ rhs; + *this = static_cast(*this ^ rhs); return *this; } @@ -1706,6 +1254,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE int128_t intrinsic_ls_impl(const in #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 + // Left-shifting a negative builtin_i128 is UB pre-C++20 # if defined(__aarch64__) #if defined(__GNUC__) && __GNUC__ >= 8 @@ -1713,8 +1262,8 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE int128_t intrinsic_ls_impl(const in # pragma GCC diagnostic ignored "-Wclass-memaccess" #endif - builtin_i128 value; - std::memcpy(&value, &lhs, sizeof(builtin_i128)); + builtin_u128 value; + std::memcpy(&value, &lhs, sizeof(builtin_u128)); const auto res {value << rhs}; int128_t return_value; @@ -1727,7 +1276,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE int128_t intrinsic_ls_impl(const in # else - return static_cast(lhs) << rhs; + return int128_t{static_cast(lhs) << rhs}; # endif @@ -1807,9 +1356,9 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator<<(const return lhs << rhs.low; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator<<(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_u128 operator<<(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(detail::builtin_u128) * 8}; @@ -1817,11 +1366,11 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE { return 0; } - - return lhs << rhs.low; + + return lhs << static_cast(rhs.low); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator<<(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_i128 operator<<(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(detail::builtin_i128) * 8}; @@ -1830,7 +1379,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return 0; } - return lhs << rhs.low; + return lhs << static_cast(rhs.low); } #endif @@ -1869,7 +1418,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr unsigned operator<<(const template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator<<=(const Integer rhs) noexcept { - *this = *this << rhs; + *this = static_cast(*this << rhs); return *this; } @@ -1884,11 +1433,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator<<=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - - *this = *this << rhs; + *this = static_cast(*this << rhs); return *this; } @@ -2061,9 +1606,9 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return lhs >> rhs.low; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator>>(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_u128 operator>>(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(detail::builtin_u128) * 8}; @@ -2072,10 +1617,10 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return 0; } - return lhs >> rhs.low; + return lhs >> static_cast(rhs.low); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator>>(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_i128 operator>>(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(detail::builtin_i128) * 8}; @@ -2084,7 +1629,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return 0; } - return lhs >> rhs.low; + return lhs >> static_cast(rhs.low); } #endif @@ -2123,7 +1668,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr unsigned operator>>(const template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator>>=(const Integer rhs) noexcept { - *this = *this >> rhs; + *this = static_cast(*this >> rhs); return *this; } @@ -2138,11 +1683,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator>>=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - - *this = *this >> rhs; + *this = static_cast(*this >> rhs); return *this; } @@ -2214,7 +1755,8 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO { #if (defined(__x86_64__) || (defined(__aarch64__) && !defined(__APPLE__))) && !defined(_WIN32) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) - return static_cast(static_cast(lhs) + static_cast(rhs)); + // Compute in the unsigned domain so that overflow wraps modulo 2^128 + return int128_t{static_cast(lhs) + static_cast(rhs)}; #elif defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_BUILTIN_ADD_OVERFLOW) @@ -2276,7 +1818,8 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO #elif defined(__aarch64__) && !defined(__APPLE__) - return static_cast(static_cast(lhs) - static_cast(rhs)); + // Unsigned wrap for consistent two's-complement semantics + return int128_t{static_cast(lhs) - static_cast(rhs)}; #elif defined(_M_AMD64) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) @@ -2331,35 +1874,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return detail::default_add(lhs, rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return detail::default_add(rhs, lhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -2376,35 +1897,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return detail::default_add(lhs, static_cast(rhs)); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return detail::default_add(rhs, static_cast(lhs)); -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -2421,11 +1913,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BU template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator+=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this + rhs; + *this = static_cast(*this + rhs); return *this; } @@ -2440,7 +1928,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator+=(const Integer rhs) noexcept { - *this = *this + rhs; + *this = static_cast(*this + rhs); return *this; } @@ -2458,35 +1946,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return detail::default_sub(lhs, rhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return detail::default_add(-rhs, lhs); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -2503,35 +1969,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs - static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs) - rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -2548,11 +1985,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator-=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this - rhs; + *this = static_cast(*this - rhs); return *this; } @@ -2567,7 +2000,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator-=(const Integer rhs) noexcept { - *this = *this - rhs; + *this = static_cast(*this - rhs); return *this; } @@ -2579,57 +2012,14 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator namespace detail { -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr int128_t signed_shift_left_32(const std::uint64_t low) noexcept -{ - return {static_cast(low >> 32), low << 32}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_mul(const int128_t lhs, const int128_t rhs) noexcept -{ - const auto a {lhs.low >> 32U}; - const auto b {lhs.low & UINT32_MAX}; - const auto c {rhs.low >> 32U}; - const auto d {rhs.low & UINT32_MAX}; - - int128_t result { static_cast(static_cast(lhs.high) * rhs.low + static_cast(lhs.low) * rhs.high + a * c), b * d }; - result += signed_shift_left_32(a * d) + signed_shift_left_32(b * c); - - return result; -} - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const int128_t lhs, const std::uint64_t rhs) noexcept { - const auto low_res{lhs.low * rhs}; - - const auto a_lo{lhs.low & UINT32_MAX}; - const auto a_high{lhs.low >> 32U}; - const auto b_lo{rhs & UINT32_MAX}; - const auto b_high{rhs >> 32U}; - - const auto lo_lo{a_lo * b_lo}; - const auto lo_hi{a_lo * b_high}; - const auto hi_lo{a_high * b_lo}; - const auto hi_hi{a_high * b_high}; - - const auto mid{(lo_lo >> 32U) + (lo_hi & UINT32_MAX) + (hi_lo & UINT32_MAX)}; - - const auto carry{hi_hi + (lo_hi >> 32) + (hi_lo >> 32) + (mid >> 32)}; - - const auto high_res{lhs.high * static_cast(rhs) + static_cast(carry)}; - - return {high_res, low_res}; + return low_word_mul(lhs, rhs); } BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const int128_t lhs, const std::uint32_t rhs) noexcept { - const auto low_res{lhs.low * rhs}; - - const auto a_hi{lhs.low >> 32U}; - const auto hi_lo{a_hi * rhs}; - - const auto high_res{lhs.high * static_cast(rhs) + static_cast(hi_lo)}; - - return {high_res, low_res}; + return low_word_mul(lhs, rhs); } #if defined(_M_AMD64) && !defined(__GNUC__) @@ -2654,7 +2044,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO if (BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) { - return library_mul(lhs, rhs); + return low_word_mul(lhs, rhs); } else { @@ -2679,50 +2069,33 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO # elif defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) - return static_cast(static_cast(lhs) * static_cast(rhs)); + // Unsigned wrap for consistent two's-complement semantics + return int128_t{static_cast(lhs) * static_cast(rhs)}; # else - return library_mul(lhs, rhs); + return low_word_mul(lhs, rhs); # endif #elif defined(__aarch64__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) - return static_cast(static_cast(lhs) * static_cast(rhs)); + return int128_t{static_cast(lhs) * static_cast(rhs)}; #elif defined(_M_AMD64) && !defined(__GNUC__) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) if (BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(rhs)) { - return library_mul(lhs, rhs); // LCOV_EXCL_LINE + return low_word_mul(lhs, rhs); // LCOV_EXCL_LINE } else { return msvc_amd64_mul(lhs, rhs); } - #elif (defined(_M_IX86) || defined(_M_ARM) || defined(__arm__)) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) - - if (BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(rhs)) - { - return library_mul(lhs, rhs); // LCOV_EXCL_LINE - } - else - { - std::uint32_t lhs_words[4] {}; - std::uint32_t rhs_words[4] {}; - - // Since in all likelihood this equates to memcpy we don't need to convert to non-negative integers and back - to_words(lhs, lhs_words); - to_words(rhs, rhs_words); - - return knuth_multiply(lhs_words, rhs_words); - } - #else - return library_mul(lhs, rhs); + return low_word_mul(lhs, rhs); #endif } @@ -2737,37 +2110,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using local_eval_type = detail::evaluation_type_t; return detail::default_mul(lhs, static_cast(rhs)); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using local_eval_type = detail::evaluation_type_t; return detail::default_mul(rhs, static_cast(lhs)); - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } #ifdef _MSC_VER @@ -2793,44 +2144,14 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const # pragma warning(pop) #endif -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 - -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return static_cast(static_cast(lhs) * rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(static_cast(rhs) * lhs); -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator*(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return detail::default_mul(lhs, static_cast(rhs)); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator*(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return detail::default_mul(rhs, static_cast(lhs)); } @@ -2840,11 +2161,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator*=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this * rhs; + *this = static_cast(*this * rhs); return *this; } @@ -2859,7 +2176,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator*=(const Integer rhs) noexcept { - *this = *this * rhs; + *this = static_cast(*this * rhs); return *this; } @@ -2889,21 +2206,16 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE { return {0,0}; } - #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) - - return static_cast(static_cast(lhs) / static_cast(rhs)); - - #else - int128_t quotient {}; const auto negative_res {(lhs.high < 0) != (rhs.high < 0)}; - if (abs_rhs.high != 0) - { - quotient = detail::knuth_div(abs_lhs, abs_rhs); - } - else + // Narrow fast path: when the divisor magnitude fits in 64 bits, divide the magnitudes with + // the hardware-accelerated one_word_div and reapply the sign. This reuses the abs values + // computed above and beats native signed division (the out-of-line __divti3) for this case. + if (abs_rhs.high == 0) { + int128_t quotient {}; + if (abs_lhs.high == 0) { quotient = {0, abs_lhs.low / abs_rhs.low}; @@ -2912,17 +2224,25 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE { detail::one_word_div(abs_lhs, abs_rhs.low, quotient); } + + return negative_res ? -quotient : quotient; } + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) + + return static_cast(static_cast(lhs) / static_cast(rhs)); + + #else + + const auto quotient {detail::knuth_div(abs_lhs, abs_rhs)}; return negative_res ? -quotient : quotient; + #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(rhs == 0)) @@ -2935,22 +2255,11 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t quotient {}; detail::one_word_div(abs_lhs, static_cast(rhs), quotient); return lhs < 0 ? -quotient : quotient; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(rhs == 0)) { return {0, 0}; @@ -2967,15 +2276,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const const int128_t result {0, res}; return rhs < 0 ? -result : result; } - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -3028,79 +2328,21 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const } } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 - -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return static_cast(static_cast(lhs) / rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs / static_cast(rhs)); -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return static_cast(static_cast(lhs) / rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs / static_cast(rhs)); } #elif defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs / static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs) / rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -3117,11 +2359,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator/=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this / rhs; + *this = static_cast(*this / rhs); return *this; } @@ -3136,7 +2374,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator/=(const Integer rhs) noexcept { - *this = *this / rhs; + *this = static_cast(*this / rhs); return *this; } @@ -3169,8 +2407,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const UnsignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(rhs == 0)) @@ -3186,22 +2422,11 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const detail::one_word_div(abs_lhs, static_cast(rhs), quotient, remainder); return lhs < 0 ? -remainder : remainder; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const UnsignedInteger lhs, const int128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(rhs == 0)) @@ -3219,15 +2444,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const const int128_t remainder {0, static_cast(lhs) % abs_rhs.low}; return remainder; - - #else - - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return {0, 0}; - - #endif } template @@ -3257,23 +2473,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const { return lhs; } - #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) - else - { - return static_cast(static_cast(lhs) % static_cast(rhs)); - } - #else - const auto is_neg{static_cast(lhs < 0)}; - - int128_t remainder {}; + const auto is_neg {lhs < 0}; - if (abs_rhs.high != 0) - { - detail::knuth_div(abs_lhs, abs_rhs, remainder); - } - else + // Narrow fast path: when the divisor magnitude fits in 64 bits, take the remainder of the + // magnitudes with the hardware-accelerated one_word_div and reapply the dividend's sign. + if (abs_rhs.high == 0) { + int128_t remainder {}; + if (abs_lhs.high == 0) { remainder = int128_t{0, abs_lhs.low % abs_rhs.low}; @@ -3281,57 +2489,37 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const else { int128_t quotient {}; - detail::one_word_div(abs_lhs, abs_rhs.low, quotient, remainder); } + + return is_neg ? -remainder : remainder; } + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) + + return static_cast(static_cast(lhs) % static_cast(rhs)); + + #else + + int128_t remainder {}; + detail::knuth_div(abs_lhs, abs_rhs, remainder); return is_neg ? -remainder : remainder; #endif } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator%(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return static_cast(lhs) % rhs; } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator%(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return lhs % static_cast(rhs); } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return static_cast(static_cast(lhs) % rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs % static_cast(rhs)); -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #elif defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) @@ -3345,46 +2533,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) % rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const int128_t lhs, const detail::builtin_u128 rhs) noexcept -{ - return lhs % static_cast(rhs); -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const detail::builtin_u128 lhs, const int128_t rhs) noexcept -{ - return static_cast(lhs) % rhs; -} - -#else // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const int128_t, const T) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const T, const int128_t) noexcept -{ - static_assert(detail::is_signed_integer_v, "Sign Compare Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator%=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); - #endif - - *this = *this % rhs; + *this = static_cast(*this % rhs); return *this; } @@ -3399,7 +2554,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::opera template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator%=(const Integer rhs) noexcept { - *this = *this % rhs; + *this = static_cast(*this % rhs); return *this; } diff --git a/include/boost/safe_numbers/detail/int128/detail/mini_from_chars.hpp b/include/boost/safe_numbers/detail/int128/detail/mini_from_chars.hpp index 072f622..822c8ca 100644 --- a/include/boost/safe_numbers/detail/int128/detail/mini_from_chars.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/mini_from_chars.hpp @@ -23,7 +23,7 @@ namespace detail { namespace impl { -#if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) +#if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) BOOST_SAFE_NUMBERS_DETAIL_INT128_INLINE_CONSTEXPR unsigned char uchar_values[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -50,7 +50,7 @@ static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 25 // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FORCE_INLINE constexpr auto digit_from_char(char val) noexcept -> unsigned char { - #if defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA) + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) constexpr unsigned char uchar_values[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -140,11 +140,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int from_chars_integer_im const std::ptrdiff_t nc = last - next; // For bases 2..10 the first digits10 characters always fit in the unsigned - // target type without overflow, so the per-iteration check is unnecessary - // there: 10^digits10 <= 2^bits, and any base <= 10 packs no more value per - // digit than base 10. For bases above 10 the safe window is shorter than - // digits10 (e.g. only ~24 digits in base 36 fit in 128 bits), so the check - // must run on every iteration. + // For bases above 10, the safe window is shorter, so we must check with each iteration const std::ptrdiff_t nd { base <= 10 ? static_cast(std::numeric_limits::digits10) @@ -190,7 +186,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int from_chars_integer_im } // Return the parsed value, adding the sign back if applicable - // If we have overflowed then we do not return the result + // If we have overflowed, then we do not return the result if (overflowed) { return EDOM; @@ -208,7 +204,18 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int from_chars_integer_im // This value will be negative to differentiate from errno values // since they are in the range of acceptable distances + + // This cast is useless on 32-bit platforms + #if defined(__GNUC__) && !defined(__clang__) + # pragma GCC diagnostic push + # pragma GCC diagnostic ignored "-Wuseless-cast" + #endif + return static_cast(first - next); + + #if defined(__GNUC__) && !defined(__clang__) + # pragma GCC diagnostic pop + #endif } } // namespace impl diff --git a/include/boost/safe_numbers/detail/int128/detail/mini_to_chars.hpp b/include/boost/safe_numbers/detail/int128/detail/mini_to_chars.hpp index 65bd4c5..2cf5c0f 100644 --- a/include/boost/safe_numbers/detail/int128/detail/mini_to_chars.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/mini_to_chars.hpp @@ -12,7 +12,11 @@ namespace boost { namespace int128 { namespace detail { -#if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) +// A 128-bit integer needs up to 128 binary digits (base 2); allow for a leading sign and a +// null terminator so mini_to_chars is safe for every supported base (2, 8, 10, 16). +constexpr std::size_t mini_to_chars_buffer_size = 130; + +#if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) BOOST_SAFE_NUMBERS_DETAIL_INT128_INLINE_CONSTEXPR char lower_case_digit_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -30,9 +34,9 @@ static_assert(sizeof(upper_case_digit_table) == sizeof(char) * 16, "10 numbers, #endif // !__NVCC__ -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char (&buffer)[64], uint128_t v, const int base, const bool uppercase) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char (&buffer)[mini_to_chars_buffer_size], uint128_t v, const int base, const bool uppercase) noexcept { - #if defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA) + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) constexpr char lower_case_digit_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' @@ -44,7 +48,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char }; #endif - char* last {buffer + 64U}; + char* last {buffer + sizeof(buffer)}; *--last = '\0'; if (v == 0U) @@ -97,7 +101,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char return last; } -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char (&buffer)[64], const int128_t v, const int base, const bool uppercase) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char (&buffer)[mini_to_chars_buffer_size], const int128_t v, const int base, const bool uppercase) noexcept { char* p {nullptr}; diff --git a/include/boost/safe_numbers/detail/int128/detail/traits.hpp b/include/boost/safe_numbers/detail/int128/detail/traits.hpp index ebde18e..a681dd7 100644 --- a/include/boost/safe_numbers/detail/int128/detail/traits.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/traits.hpp @@ -71,10 +71,12 @@ using evaluation_type_t = std::conditional_t, bool> = true #define BOOST_SAFE_NUMBERS_DETAIL_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT typename UnsignedInteger, std::enable_if_t, bool> = true #define BOOST_SAFE_NUMBERS_DETAIL_INT128_DEFAULTED_INTEGER_CONCEPT typename Integer, std::enable_if_t, bool> = true +#define BOOST_SAFE_NUMBERS_DETAIL_INT128_DEFAULTED_FLOATING_POINT_CONCEPT typename Float, std::enable_if_t::value, bool> = true #define BOOST_SAFE_NUMBERS_DETAIL_INT128_SIGNED_INTEGER_CONCEPT typename SignedInteger, std::enable_if_t, bool> #define BOOST_SAFE_NUMBERS_DETAIL_INT128_UNSIGNED_INTEGER_CONCEPT typename UnsignedInteger, std::enable_if_t, bool> #define BOOST_SAFE_NUMBERS_DETAIL_INT128_INTEGER_CONCEPT typename Integer, std::enable_if_t, bool> +#define BOOST_SAFE_NUMBERS_DETAIL_INT128_FLOATING_POINT_CONCEPT typename Float, std::enable_if_t::value, bool> #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) diff --git a/include/boost/safe_numbers/detail/int128/detail/uint128_imp.hpp b/include/boost/safe_numbers/detail/int128/detail/uint128_imp.hpp index f02f42e..2840762 100644 --- a/include/boost/safe_numbers/detail/int128/detail/uint128_imp.hpp +++ b/include/boost/safe_numbers/detail/int128/detail/uint128_imp.hpp @@ -57,8 +57,7 @@ uint128_t constexpr uint128_t& operator=(uint128_t&&) noexcept = default; // Requires a conversion file to be implemented - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr uint128_t(const int128_t& v) noexcept; - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator int128_t() const noexcept; + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const int128_t& v) noexcept; // Construct from integral types #if BOOST_SAFE_NUMBERS_DETAIL_INT128_ENDIAN_LITTLE_BYTE @@ -93,13 +92,13 @@ uint128_t template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const UnsignedInteger v) noexcept : high {}, low {static_cast(v)} {} - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const detail::builtin_i128 v) noexcept : + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t(const detail::builtin_i128 v) noexcept : high {static_cast(static_cast(v) >> 64U)}, low {static_cast(v)} {} - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const detail::builtin_u128 v) noexcept : + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t(const detail::builtin_u128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v)} {} @@ -107,32 +106,36 @@ uint128_t #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ENDIAN_LITTLE_BYTE + // Construct from floating-point types + template + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(Float f) noexcept; + // Integer conversion operators BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator bool() const noexcept {return low || high; } template - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator SignedInteger() const noexcept { return static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator SignedInteger() const noexcept { return static_cast(low); } template - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 // Conversion to float // This is basically the same as ldexp(static_cast(high), 64) + static_cast(low), // but can be constexpr at C++11 instead of C++26 - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator float() const noexcept; - BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE explicit constexpr operator double() const noexcept; + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator float() const noexcept; + BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr operator double() const noexcept; - // long doubles do not exist on device - #if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) - explicit constexpr operator long double() const noexcept; + // long doubles do not exist on the CUDA or SYCL (spir64) device + #if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) + constexpr operator long double() const noexcept; #endif // Compound OR @@ -299,7 +302,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::operator doubl return static_cast(high) * detail::offset_value_v + static_cast(low); } -#if !(defined(__CUDACC__) && defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_ENABLE_CUDA)) +#if !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_GPU_SUPPORT) constexpr uint128_t::operator long double() const noexcept { @@ -308,6 +311,41 @@ constexpr uint128_t::operator long double() const noexcept #endif // __NVCC__ +//===================================== +// Float Construction +//===================================== + +// Inverse of operator(Float): decompose f into (high, low) by dividing by 2^64. +// NaN/negative -> 0 +// overflow -> UINT128_MAX. +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::uint128_t(Float f) noexcept +{ + constexpr Float two_32 {static_cast(UINT64_C(1) << 32)}; + constexpr Float two_64 {two_32 * two_32}; + + // !(f >= 0) catches both NaN and negative values without using + if (!(f >= Float{0})) + { + return; + } + + // Overflow test: f >= 2^128 iff f / 2^64 >= 2^64. Comparing scaled values + // avoids materializing 2^128 as a Float, which overflows to +infinity for + // `float` and is therefore not constant-evaluable on older compilers. + const Float scaled {f / two_64}; + if (scaled >= two_64) + { + high = UINT64_MAX; + low = UINT64_MAX; + return; + } + + high = static_cast(scaled); + const Float remainder {f - static_cast(high) * two_64}; + low = static_cast(remainder); +} + //===================================== // Unary Operators //===================================== @@ -347,35 +385,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs >= 0 && lhs.high == UINT64_C(0) && lhs.low == static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t rhs_u {rhs}; + return lhs.high == rhs_u.high && lhs.low == rhs_u.low; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs >= 0 && rhs.high == UINT64_C(0) && rhs.low == static_cast(lhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t lhs_u {lhs}; + return lhs_u.high == rhs.high && lhs_u.low == rhs.low; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -424,8 +442,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs == static_cast(rhs); @@ -436,24 +452,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) == rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs == static_cast(rhs); @@ -483,35 +481,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs < 0 || lhs.high != UINT64_C(0) || lhs.low != static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t rhs_u {rhs}; + return lhs.high != rhs_u.high || lhs.low != rhs_u.low; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs < 0 || rhs.high != UINT64_C(0) || rhs.low != static_cast(lhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t lhs_u {lhs}; + return lhs_u.high != rhs.high || lhs_u.low != rhs.low; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -560,7 +538,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -572,23 +549,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) != rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { @@ -609,35 +569,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs > 0 && lhs.high == UINT64_C(0) && lhs.low < static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t rhs_u {rhs}; + return lhs.high == rhs_u.high ? lhs.low < rhs_u.low : lhs.high < rhs_u.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs < 0 || rhs.high > UINT64_C(0) || static_cast(lhs) < rhs.low; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t lhs_u {lhs}; + return lhs_u.high == rhs.high ? lhs_u.low < rhs.low : lhs_u.high < rhs.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -716,7 +656,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -728,23 +667,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) < rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { @@ -765,35 +687,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs >= 0 && lhs.high == UINT64_C(0) && lhs.low <= static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t rhs_u {rhs}; + return lhs.high == rhs_u.high ? lhs.low <= rhs_u.low : lhs.high < rhs_u.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs < 0 || rhs.high > UINT64_C(0) || static_cast(lhs) <= rhs.low; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t lhs_u {lhs}; + return lhs_u.high == rhs.high ? lhs_u.low <= rhs.low : lhs_u.high < rhs.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -871,7 +773,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -893,23 +794,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) <= rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 @@ -920,35 +804,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BU BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs < 0 || lhs.high > UINT64_C(0) || lhs.low > static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t rhs_u {rhs}; + return lhs.high == rhs_u.high ? lhs.low > rhs_u.low : lhs.high > rhs_u.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs > 0 && rhs.high == UINT64_C(0) && static_cast(lhs) > rhs.low; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t lhs_u {lhs}; + return lhs_u.high == rhs.high ? lhs_u.low > rhs.low : lhs_u.high > rhs.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -1026,7 +890,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -1048,23 +911,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) > rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 @@ -1075,35 +921,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BU BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return rhs < 0 || lhs.high > UINT64_C(0) || lhs.low >= static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t rhs_u {rhs}; + return lhs.high == rhs_u.high ? lhs.low >= rhs_u.low : lhs.high > rhs_u.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - - return lhs >= 0 && rhs.high == UINT64_C(0) && static_cast(lhs) >= rhs.low; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif + const uint128_t lhs_u {lhs}; + return lhs_u.high == rhs.high ? lhs_u.low >= rhs.low : lhs_u.high > rhs.high; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -1191,7 +1017,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) >= rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { @@ -1203,23 +1028,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) >= rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - return true; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 @@ -1282,8 +1090,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering oper BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - if (lhs < rhs) { return std::strong_ordering::less; @@ -1296,22 +1102,11 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering oper { return std::strong_ordering::greater; } - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return std::strong_ordering::less; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE - if (lhs < rhs) { return std::strong_ordering::less; @@ -1324,15 +1119,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering oper { return std::strong_ordering::greater; } - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); - static_cast(lhs); - static_cast(rhs); - return std::strong_ordering::less; - - #endif } #endif @@ -1353,35 +1139,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {lhs.high | (rhs < 0 ? ~UINT64_C(0) : UINT64_C(0)), lhs.low | static_cast(rhs)}; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {rhs.high | (lhs < 0 ? ~UINT64_C(0) : UINT64_C(0)), rhs.low | static_cast(lhs)}; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -1401,44 +1165,26 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return {lhs.high | rhs.high, lhs.low | rhs.low}; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator|(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs | static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator|(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) | rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator|(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs | static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator|(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) | rhs; } @@ -1448,10 +1194,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator|=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this | rhs; return *this; } @@ -1466,10 +1208,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator|=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this | rhs; return *this; } @@ -1483,47 +1221,25 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operat BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {lhs.high & (rhs < 0 ? ~UINT64_C(0) : UINT64_C(0)), lhs.low & static_cast(rhs)}; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {rhs.high & (lhs < 0 ? ~UINT64_C(0) : UINT64_C(0)), rhs.low & static_cast(lhs)}; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const UnsignedInteger rhs) noexcept { - return {lhs.high, lhs.low & static_cast(rhs)}; + return {UINT64_C(0), lhs.low & static_cast(rhs)}; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const UnsignedInteger lhs, const uint128_t rhs) noexcept { - return {rhs.high, rhs.low & static_cast(lhs)}; + return {UINT64_C(0), rhs.low & static_cast(lhs)}; } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const uint128_t rhs) noexcept @@ -1531,44 +1247,26 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return {lhs.high & rhs.high, lhs.low & rhs.low}; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator&(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs & static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator&(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) & rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator&(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs & static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator&(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) & rhs; } @@ -1578,10 +1276,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator&=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this & rhs; return *this; } @@ -1597,10 +1291,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator&=(Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this & rhs; return *this; } @@ -1615,35 +1305,13 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operat BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {lhs.high ^ (rhs < 0 ? ~UINT64_C(0) : UINT64_C(0)), lhs.low ^ static_cast(rhs)}; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return {rhs.high ^ (lhs < 0 ? ~UINT64_C(0) : UINT64_C(0)), rhs.low ^ static_cast(lhs)}; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -1663,44 +1331,26 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return {lhs.high ^ rhs.high, lhs.low ^ rhs.low}; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator^(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs ^ static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator^(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) ^ rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator^(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs ^ static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator^(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) ^ rhs; } @@ -1710,10 +1360,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator^=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this ^ rhs; return *this; } @@ -1729,10 +1375,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator^=(Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this ^ rhs; return *this; } @@ -1891,9 +1533,9 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return lhs << rhs.low; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator<<(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_u128 operator<<(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { constexpr auto bit_width {sizeof(detail::builtin_u128 ) * 8}; @@ -1901,11 +1543,10 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE { return 0; } - - return lhs << rhs.low; + return lhs << static_cast(rhs.low); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator<<(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_i128 operator<<(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { constexpr auto bit_width {sizeof(detail::builtin_u128) * 8}; @@ -1914,7 +1555,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return 0; } - return lhs << rhs.low; + return lhs << static_cast(rhs.low); } #endif @@ -2114,9 +1755,9 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return lhs >> rhs.low; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator>>(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_u128 operator>>(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { constexpr auto bit_width = sizeof(detail::builtin_u128) * 8; @@ -2125,10 +1766,10 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return 0; } - return lhs >> rhs.low; + return lhs >> static_cast(rhs.low); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator>>(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR detail::builtin_i128 operator>>(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { constexpr auto bit_width = sizeof(detail::builtin_i128) * 8; @@ -2137,7 +1778,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return 0; } - return lhs >> rhs.low; + return lhs >> static_cast(rhs.low); } #endif @@ -2348,37 +1989,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return rhs < 0 ? impl::default_sub(lhs, -static_cast(rhs)) : impl::default_add(lhs, static_cast(rhs)); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return lhs < 0 ? impl::default_sub(rhs, -static_cast(lhs)) : impl::default_add(rhs, static_cast(lhs)); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } #ifdef _MSC_VER @@ -2404,7 +2023,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -2416,23 +2034,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return impl::default_add(static_cast(lhs), rhs); } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { @@ -2449,10 +2050,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator+=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this + rhs; return *this; } @@ -2468,10 +2065,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator+=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this + rhs; return *this; } @@ -2491,37 +2084,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operat BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return rhs < 0 ? impl::default_add(lhs, -static_cast(rhs)) : impl::default_sub(lhs, static_cast(rhs)); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - return lhs < 0 ? impl::default_sub(-rhs, -static_cast(lhs)) : impl::default_add(-rhs, static_cast(lhs)); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } #ifdef _MSC_VER @@ -2547,7 +2118,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -2559,23 +2129,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) - rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { @@ -2592,10 +2145,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator-=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this - rhs; return *this; } @@ -2611,10 +2160,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator-=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this - rhs; return *this; } @@ -2726,11 +2271,9 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO # endif - #elif (defined(__s390x__) || defined(__s390x__)) && defined(__GNUC__) - # define BOOST_SAFE_NUMBERS_DETAIL_INT128_HIDE_MUL - - return static_cast(static_cast(lhs) * static_cast(rhs)); - + // s390x intentionally falls through to the synthetic low_word_mul below. Casting to builtin_u128 + // makes GCC reconstruct the value through a vector-unit stack round-trip that is several times + // slower, and the memcpy path is unsafe for the narrow (scalar rhs) overloads on big-endian. #elif ((defined(_M_AMD64) && !defined(__GNUC__)) || defined(_M_ARM64)) && !defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_NO_CONSTEVAL_DETECTION) if (!BOOST_SAFE_NUMBERS_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) @@ -2743,18 +2286,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO // We need to hide this if we use a non-const eval method above to avoid a litany of cross-platform warnings #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_HIDE_MUL - constexpr std::size_t rhs_words_needed {std::is_same::value ? 1 : - std::is_same::value ? 2 : - std::is_same::value ? 4 : 0}; - - static_assert(rhs_words_needed != 0, "Must be 32, 64 or 128 bit unsigned integer"); - - std::uint32_t lhs_words[4] {}; - std::uint32_t rhs_words[rhs_words_needed] {}; - to_words(lhs, lhs_words); - to_words(rhs, rhs_words); - - return knuth_multiply(lhs_words, rhs_words); + return low_word_mul(lhs, rhs); #else #undef BOOST_SAFE_NUMBERS_DETAIL_INT128_HIDE_MUL @@ -2775,45 +2307,23 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_FO BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; const auto abs_rhs {rhs < 0 ? -static_cast(rhs) : static_cast(rhs)}; const auto res {detail::default_mul(lhs, abs_rhs)}; return rhs < 0 ? -res : res; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; const auto abs_lhs {lhs < 0 ? -static_cast(lhs) : static_cast(lhs)}; const auto res {detail::default_mul(rhs, abs_lhs)}; return lhs < 0 ? -res : res; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template @@ -2837,50 +2347,38 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return detail::default_mul(lhs, rhs); } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 +#if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) || defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_MSVC_INT128) -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator*(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { - const auto abs_rhs {rhs < 0 ? -static_cast(rhs) : static_cast(rhs)}; - const auto res {lhs * abs_rhs}; + const detail::builtin_u128 rhs_bits {static_cast(rhs)}; + const bool rhs_negative {static_cast(static_cast(rhs_bits >> static_cast(64U))) < 0}; + const uint128_t rhs_u {rhs_bits}; + const uint128_t abs_rhs {rhs_negative ? -rhs_u : rhs_u}; + const uint128_t res {lhs * abs_rhs}; - return rhs < 0 ? -res : res; + return rhs_negative ? -res : res; } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator*(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { - const auto abs_lhs {lhs < 0 ? -static_cast(lhs) : static_cast(lhs)}; - const auto res {abs_lhs * rhs}; + const detail::builtin_u128 lhs_bits {static_cast(lhs)}; + const bool lhs_negative {static_cast(static_cast(lhs_bits >> static_cast(64U))) < 0}; + const uint128_t lhs_u {lhs_bits}; + const uint128_t abs_lhs {lhs_negative ? -lhs_u : lhs_u}; + const uint128_t res {abs_lhs * rhs}; - return lhs < 0 ? -res : res; + return lhs_negative ? -res : res; } -#else -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator*(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs * static_cast(rhs); } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator*(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) * rhs; } @@ -2890,10 +2388,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator*=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this * rhs; return *this; } @@ -2909,10 +2403,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator*=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this * rhs; return *this; } @@ -2941,37 +2431,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; return rhs < 0 ? lhs / static_cast(rhs) : lhs / static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; return lhs < 0 ? static_cast(lhs) / rhs : static_cast(lhs) / rhs; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } template @@ -3025,31 +2493,30 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const { return {0, 0}; } - #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) && !defined(__s390__) && !defined(__s390x__) - else - { - return static_cast(static_cast(lhs) / static_cast(rhs)); - } - #else - else if (rhs.high != 0U) - { - return detail::knuth_div(lhs, rhs); - } - else + + // A divisor that fits in 64 bits is handled by the hardware-accelerated narrow path. This + // beats the native 128/128 divide for this common case on every platform (it avoids the + // out-of-line __udivti3 call on GCC/Clang and uses divq / _udiv128 directly where present). + if (rhs.high == 0U) { if (lhs.high == 0U) { return {0, lhs.low / rhs.low}; } - else - { - uint128_t quotient {}; - detail::one_word_div(lhs, rhs.low, quotient); - - return quotient; - } + uint128_t quotient {}; + detail::one_word_div(lhs, rhs.low, quotient); + return quotient; } + + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) && !defined(__s390__) && !defined(__s390x__) + + return static_cast(static_cast(lhs) / static_cast(rhs)); + + #else + + return detail::knuth_div(lhs, rhs); + #endif } @@ -3065,7 +2532,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) / rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -3077,33 +2543,12 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) / rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator/=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this / rhs; return *this; } @@ -3119,10 +2564,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator/=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - *this = *this / rhs; return *this; } @@ -3151,37 +2592,15 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const uint128_t lhs, const SignedInteger rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; return rhs < 0 ? lhs % static_cast(rhs) : lhs % static_cast(rhs); - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const SignedInteger lhs, const uint128_t rhs) noexcept { - #ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - using eval_type = detail::evaluation_type_t; return lhs < 0 ? static_cast(lhs) % rhs : static_cast(lhs) % rhs; - - #else - - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - static_cast(lhs); - static_cast(rhs); - return true; - - #endif } template @@ -3232,38 +2651,36 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const { return {0, 0}; } - else if (rhs > lhs) + if (rhs > lhs) { return lhs; } - #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) && !defined(__s390__) && !defined(__s390x__) - else - { - return static_cast(static_cast(lhs) % static_cast(rhs)); - } - #else - else if (rhs.high != 0U) - { - uint128_t remainder {}; - detail::knuth_div(lhs, rhs, remainder); - return remainder; - } - else + + // A divisor that fits in 64 bits is handled by the hardware-accelerated narrow path, which + // beats the native 128/128 divide for this common case on every platform. + if (rhs.high == 0U) { if (lhs.high == 0U) { return {0, lhs.low % rhs.low}; } - else - { - uint128_t quotient {}; - uint128_t remainder {}; - - detail::one_word_div(lhs, rhs.low, quotient, remainder); - return remainder; - } + uint128_t quotient {}; + uint128_t remainder {}; + detail::one_word_div(lhs, rhs.low, quotient, remainder); + return remainder; } + + #if defined(BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128) && !defined(__s390__) && !defined(__s390x__) + + return static_cast(static_cast(lhs) % static_cast(rhs)); + + #else + + uint128_t remainder {}; + detail::knuth_div(lhs, rhs, remainder); + return remainder; + #endif } @@ -3279,7 +2696,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) % rhs; } -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { @@ -3291,33 +2707,12 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return static_cast(lhs) % rhs; } -#else - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t, const T) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template ::value, bool> = true> -BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const T, const uint128_t) noexcept -{ - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - return {0, 0}; -} - -#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION #endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_HAS_INT128 template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator%=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); - #endif - *this = *this % rhs; return *this; } @@ -3333,10 +2728,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::ope template BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator%=(const Integer rhs) noexcept { - #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); - #endif - * this = *this % rhs; return *this; } diff --git a/include/boost/safe_numbers/detail/int128/fmt_format.hpp b/include/boost/safe_numbers/detail/int128/fmt_format.hpp index c02b8ce..b567907 100644 --- a/include/boost/safe_numbers/detail/int128/fmt_format.hpp +++ b/include/boost/safe_numbers/detail/int128/fmt_format.hpp @@ -58,8 +58,7 @@ constexpr auto parse_impl(ParseContext& ctx) int padding_digits = 0; auto sign = sign_option::negative; bool prefix = false; - bool write_as_character = false; - bool character_debug_format = false; + bool zero_pad = false; char fill_char = ' '; auto align = alignment::none; @@ -139,14 +138,14 @@ constexpr auto parse_impl(ParseContext& ctx) ++it; } - // Character presentation type - if (it != ctx.end() && (*it == '?' || *it == 'c')) + // Zero-pad flag (std::format places '0' before the width) + if (it != ctx.end() && *it == '0') { - character_debug_format = *it == '?'; + zero_pad = true; ++it; } - // Check for a padding character + // Parse the width while (it != ctx.end() && *it >= '0' && *it <= '9') { padding_digits = padding_digits * 10 + (*it - '0'); @@ -166,10 +165,6 @@ constexpr auto parse_impl(ParseContext& ctx) is_upper = true; break; - case 'c': - write_as_character = true; - break; - case 'o': base = 8; break; @@ -198,7 +193,7 @@ constexpr auto parse_impl(ParseContext& ctx) BOOST_SAFE_NUMBERS_DETAIL_INT128_THROW_EXCEPTION(std::logic_error("Expected '}' in format string")); // LCOV_EXCL_LINE } - return std::make_tuple(base, padding_digits, sign, is_upper, prefix, write_as_character, character_debug_format, fill_char, align, it); + return std::make_tuple(base, padding_digits, sign, is_upper, prefix, zero_pad, fill_char, align, it); } template @@ -218,8 +213,7 @@ struct formatter sign_option sign; bool is_upper; bool prefix; - bool write_as_character; - bool character_debug_format; + bool zero_pad; char fill_char; alignment align; @@ -228,8 +222,7 @@ struct formatter sign {sign_option::negative}, is_upper {false}, prefix {false}, - write_as_character {false}, - character_debug_format {false}, + zero_pad {false}, fill_char {' '}, align {alignment::none} {} @@ -243,18 +236,17 @@ struct formatter sign = std::get<2>(res); is_upper = std::get<3>(res); prefix = std::get<4>(res); - write_as_character = std::get<5>(res); - character_debug_format = std::get<6>(res); - fill_char = std::get<7>(res); - align = std::get<8>(res); + zero_pad = std::get<5>(res); + fill_char = std::get<6>(res); + align = std::get<7>(res); - return std::get<9>(res); + return std::get<8>(res); } template auto format(T v, FormatContext& ctx) const { - char buffer[64]; + char buffer[detail::mini_to_chars_buffer_size]; bool isneg {false}; boost::int128::uint128_t abs_v {}; @@ -311,9 +303,9 @@ struct formatter sign_len = 1; } - // Zero-padding only applies when no explicit alignment is set - // Account for prefix and sign in the padding calculation - if (align == alignment::none && padding_digits > 0) + // Zero-padding applies only with the '0' flag and no explicit alignment. + // Account for prefix and sign in the padding calculation. + if (zero_pad && align == alignment::none && padding_digits > 0) { auto target_digit_width {static_cast(padding_digits)}; if (target_digit_width > prefix_len + sign_len) @@ -410,11 +402,15 @@ struct formatter s.erase(0, s.find_first_not_of('\0')); s.erase(s.find_last_not_of('\0') + 1); - // Apply alignment if specified - if (align != alignment::none && s.size() < static_cast(padding_digits)) + // Apply alignment. An explicit alignment uses fill_char; with no explicit + // alignment and no zero-padding, integer types default to right alignment + // with the fill character (matching std::format). + if (s.size() < static_cast(padding_digits) && + (align != alignment::none || !zero_pad)) { auto fill_count = static_cast(padding_digits) - s.size(); - switch (align) + const auto effective_align = (align == alignment::none) ? alignment::right : align; + switch (effective_align) { case alignment::left: s.append(fill_count, fill_char); diff --git a/include/boost/safe_numbers/detail/int128/format.hpp b/include/boost/safe_numbers/detail/int128/format.hpp index 6aaa9d8..4111df8 100644 --- a/include/boost/safe_numbers/detail/int128/format.hpp +++ b/include/boost/safe_numbers/detail/int128/format.hpp @@ -42,8 +42,7 @@ constexpr auto parse_impl(ParseContext& ctx) int padding_digits = 0; auto sign = sign_option::negative; bool prefix = false; - bool write_as_character = false; - bool character_debug_format = false; + bool zero_pad = false; char fill_char = ' '; auto align = alignment::none; @@ -123,14 +122,14 @@ constexpr auto parse_impl(ParseContext& ctx) ++it; } - // Character presentation type - if (it != ctx.end() && (*it == '?' || *it == 'c')) + // Zero-pad flag (std::format places '0' before the width) + if (it != ctx.end() && *it == '0') { - character_debug_format = *it == '?'; + zero_pad = true; ++it; } - // Check for a padding character + // Parse the width while (it != ctx.end() && *it >= '0' && *it <= '9') { padding_digits = padding_digits * 10 + (*it - '0'); @@ -150,10 +149,6 @@ constexpr auto parse_impl(ParseContext& ctx) is_upper = true; break; - case 'c': - write_as_character = true; - break; - case 'o': base = 8; break; @@ -180,7 +175,7 @@ constexpr auto parse_impl(ParseContext& ctx) BOOST_SAFE_NUMBERS_DETAIL_INT128_THROW_EXCEPTION(std::format_error("Expected '}' in format string")); // LCOV_EXCL_LINE } - return std::make_tuple(base, padding_digits, sign, is_upper, prefix, write_as_character, character_debug_format, fill_char, align, it); + return std::make_tuple(base, padding_digits, sign, is_upper, prefix, zero_pad, fill_char, align, it); } template @@ -207,8 +202,7 @@ struct formatter boost::int128::detail::sign_option sign; bool is_upper; bool prefix; - bool write_as_character; - bool character_debug_format; + bool zero_pad; char fill_char; boost::int128::detail::alignment align; @@ -217,8 +211,7 @@ struct formatter sign {boost::int128::detail::sign_option::negative}, is_upper {false}, prefix {false}, - write_as_character {false}, - character_debug_format {false}, + zero_pad {false}, fill_char {' '}, align {boost::int128::detail::alignment::none} {} @@ -232,18 +225,17 @@ struct formatter sign = std::get<2>(res); is_upper = std::get<3>(res); prefix = std::get<4>(res); - write_as_character = std::get<5>(res); - character_debug_format = std::get<6>(res); - fill_char = std::get<7>(res); - align = std::get<8>(res); + zero_pad = std::get<5>(res); + fill_char = std::get<6>(res); + align = std::get<7>(res); - return std::get<9>(res); + return std::get<8>(res); } template auto format(T v, FormatContext& ctx) const { - char buffer[64]; + char buffer[boost::int128::detail::mini_to_chars_buffer_size]; bool isneg {false}; boost::int128::uint128_t abs_v {}; @@ -300,9 +292,9 @@ struct formatter sign_len = 1; } - // Zero-padding only applies when no explicit alignment is set - // Account for prefix and sign in the padding calculation - if (align == boost::int128::detail::alignment::none && padding_digits > 0) + // Zero-padding applies only with the '0' flag and no explicit alignment. + // Account for prefix and sign in the padding calculation. + if (zero_pad && align == boost::int128::detail::alignment::none && padding_digits > 0) { auto target_digit_width {static_cast(padding_digits)}; if (target_digit_width > prefix_len + sign_len) @@ -399,11 +391,17 @@ struct formatter s.erase(0, s.find_first_not_of('\0')); s.erase(s.find_last_not_of('\0') + 1); - // Apply alignment if specified - if (align != boost::int128::detail::alignment::none && s.size() < static_cast(padding_digits)) + // Apply alignment. An explicit alignment uses fill_char; with no explicit + // alignment and no zero-padding, integer types default to right alignment + // with the fill character (matching std::format). + if (s.size() < static_cast(padding_digits) && + (align != boost::int128::detail::alignment::none || !zero_pad)) { auto fill_count = static_cast(padding_digits) - s.size(); - switch (align) + const auto effective_align = (align == boost::int128::detail::alignment::none) + ? boost::int128::detail::alignment::right + : align; + switch (effective_align) { case boost::int128::detail::alignment::left: s.append(fill_count, fill_char); diff --git a/include/boost/safe_numbers/detail/int128/iostream.hpp b/include/boost/safe_numbers/detail/int128/iostream.hpp index 13c98d9..4d91db9 100644 --- a/include/boost/safe_numbers/detail/int128/iostream.hpp +++ b/include/boost/safe_numbers/detail/int128/iostream.hpp @@ -103,7 +103,7 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template & os, const LibIntegerType& v) -> std::enable_if_t, std::basic_ostream&> { - char buffer[64U] {}; + char buffer[detail::mini_to_chars_buffer_size] {}; const auto flags {os.flags()}; int base {10}; diff --git a/include/boost/safe_numbers/detail/int128/literals.hpp b/include/boost/safe_numbers/detail/int128/literals.hpp index 2a401b9..7490f7b 100644 --- a/include/boost/safe_numbers/detail/int128/literals.hpp +++ b/include/boost/safe_numbers/detail/int128/literals.hpp @@ -43,16 +43,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DE return result; } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_u128(unsigned long long v) noexcept -{ - return uint128_t{v}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_U128(unsigned long long v) noexcept -{ - return uint128_t{v}; -} - BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(const char* str) noexcept { int128_t result {}; @@ -67,16 +57,6 @@ BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_I128 return result; } -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(unsigned long long v) noexcept -{ - return int128_t{v}; -} - -BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(unsigned long long v) noexcept -{ - return int128_t{v}; -} - BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(const char* str, std::size_t len) noexcept { int128_t result {}; diff --git a/include/boost/safe_numbers/detail/int128/numeric.hpp b/include/boost/safe_numbers/detail/int128/numeric.hpp index 63e5aff..78b1b63 100644 --- a/include/boost/safe_numbers/detail/int128/numeric.hpp +++ b/include/boost/safe_numbers/detail/int128/numeric.hpp @@ -11,6 +11,7 @@ #ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILD_MODULE #include +#include #endif diff --git a/include/boost/safe_numbers/detail/int128/string.hpp b/include/boost/safe_numbers/detail/int128/string.hpp index 7d46c7b..5eadbb8 100644 --- a/include/boost/safe_numbers/detail/int128/string.hpp +++ b/include/boost/safe_numbers/detail/int128/string.hpp @@ -20,9 +20,9 @@ namespace int128 { template auto to_string(const T& value) -> std::enable_if_t<(std::is_same::value || std::is_same::value), std::string> { - char buffer[64]; + char buffer[detail::mini_to_chars_buffer_size]; const auto last {detail::mini_to_chars(buffer, value, 10, false)}; - return std::string{last, buffer + sizeof(buffer)}; + return std::string{last, buffer + sizeof(buffer) - 1}; } } // namespace int128 diff --git a/include/boost/safe_numbers/detail/int128/utilities.hpp b/include/boost/safe_numbers/detail/int128/utilities.hpp new file mode 100644 index 0000000..dc8456c --- /dev/null +++ b/include/boost/safe_numbers/detail/int128/utilities.hpp @@ -0,0 +1,438 @@ +// Copyright 2026 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_UTILITIES_HPP +#define BOOST_SAFE_NUMBERS_DETAIL_INT128_UTILITIES_HPP + +#include +#include +#include + +#ifndef BOOST_SAFE_NUMBERS_DETAIL_INT128_BUILD_MODULE + +#include +#include +#include + +#endif + +namespace boost { +namespace int128 { + +namespace detail { + +// Modular addition for 128-bit operands assuming 0 <= a, b < m +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t addmod(const uint128_t a, const uint128_t b, const uint128_t m) noexcept +{ + const uint128_t s {a + b}; + + if (s < a || s >= m) + { + return s - m; + } + + return s; +} + +// Modular multiplication via shift-and-add for the full 128-bit modulus case +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t mulmod_shift(uint128_t a, uint128_t b, const uint128_t m) noexcept +{ + uint128_t result {0}; + + while (b != 0U) + { + if (static_cast(b.low & 1U)) + { + result = addmod(result, a, m); + } + + a = addmod(a, a, m); + b >>= 1; + } + + return result; +} + +// Modular multiplication when the modulus fits in 64 bits +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr std::uint64_t mulmod_word(const std::uint64_t a, const std::uint64_t b, const std::uint64_t m) noexcept +{ + return ((uint128_t{a} * uint128_t{b}) % uint128_t{m}).low; +} + +} // namespace detail + +// Computes (base ^ exp) mod m using fast modular exponentiation with +// optimizations specific to the boost::int128 library types +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t powm(uint128_t base, uint128_t exp, const uint128_t m) noexcept +{ + if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(m == 0U)) + { + return uint128_t{0}; + } + + if (m == 1U) + { + return uint128_t{0}; + } + + if (exp == 0U) + { + return uint128_t{1}; + } + + base %= m; + + if (base == 0U) + { + return uint128_t{0}; + } + + // Power-of-two modulus: reduction is just a bitmask. + if (has_single_bit(m)) + { + const uint128_t mask {m - 1U}; + uint128_t result {1}; + + while (exp != 0U) + { + if (static_cast(exp.low & 1U)) + { + result = (result * base) & mask; + } + + base = (base * base) & mask; + exp >>= 1; + } + + return result; + } + + // Modulus fits in 64 bits: stay in 64-bit lanes. + if (m.high == 0U) + { + const auto mm {m.low}; + std::uint64_t result {1}; + auto b {base.low}; + + while (exp != 0U) + { + if (static_cast(exp.low & 1U)) + { + result = detail::mulmod_word(result, b, mm); + } + + b = detail::mulmod_word(b, b, mm); + exp >>= 1; + } + + return uint128_t{result}; + } + + // General 128-bit modulus: shift-and-add for each squaring keeps every + // intermediate strictly below m without needing a 256-bit product. + uint128_t result {1}; + + while (exp != 0U) + { + if (static_cast(exp.low & 1U)) + { + result = detail::mulmod_shift(result, base, m); + } + + base = detail::mulmod_shift(base, base, m); + exp >>= 1; + } + + return result; +} + +// Signed overload. Returns the non-negative residue in [0, m) +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t powm(const int128_t base, const int128_t exp, const int128_t m) noexcept +{ + if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(m <= 0 || exp < 0)) + { + return int128_t{0}; + } + + const uint128_t um {static_cast(m)}; + + uint128_t ub {}; + + if (base.high < 0) + { + const uint128_t magnitude {static_cast(abs(base))}; + const uint128_t r {magnitude % um}; + ub = r == 0U ? uint128_t{0} : static_cast(um - r); + } + else + { + ub = static_cast(base) % um; + } + + return static_cast(powm(ub, static_cast(exp), um)); +} + +// Computes base^exp using exponentiation by squaring. The result is reduced +// modulo 2^128, mirroring the wrap-around behavior of operator*. +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t ipow(uint128_t base, std::uint64_t exp) noexcept +{ + uint128_t result {1}; + + while (exp != 0U) + { + if (static_cast(exp & 1U)) + { + result *= base; + } + + exp >>= 1; + + if (exp != 0U) + { + base *= base; + } + } + + return result; +} + +// Signed overload. Wraps modulo 2^128 on overflow, matching operator*. +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t ipow(int128_t base, std::uint64_t exp) noexcept +{ + int128_t result {1}; + + while (exp != 0U) + { + if (static_cast(exp & 1U)) + { + result *= base; + } + + exp >>= 1; + + if (exp != 0U) + { + base *= base; + } + } + + return result; +} + +// Integer square root: returns floor(sqrt(n)). +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t isqrt(const uint128_t n) noexcept +{ + if (n < 2U) + { + return n; + } + + // 2^ceil(bit_width(n)/2) is the smallest power of two whose square exceeds n. + uint128_t x {uint128_t{1} << ((bit_width(n) + 1) / 2)}; + + while (true) + { + const uint128_t y {(x + n / x) >> 1}; + + if (y >= x) + { + return x; + } + + x = y; + } +} + +// Signed overload. Negative inputs are documented to return 0. +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr int128_t isqrt(const int128_t n) noexcept +{ + if (BOOST_SAFE_NUMBERS_DETAIL_INT128_UNLIKELY(n < 0)) + { + return int128_t{0}; + } + + return static_cast(isqrt(static_cast(n))); +} + +namespace detail { + +// The C23 checked integer macros accept any integer type for their operands +// except bool, plain char, enumerated types, and bit-precise (_BitInt) types. +template +struct valid_checked_type : std::integral_constant::value && + !std::is_same::value && + !std::is_same::value> {}; + +template <> +struct valid_checked_type : std::true_type {}; + +template <> +struct valid_checked_type : std::true_type {}; + +// Widen an integer operand to its 128-bit two's complement bit pattern, returned as a uint128_t +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr uint128_t ckd_widen(const T value) noexcept +{ + BOOST_SAFE_NUMBERS_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) + { + return static_cast(static_cast(value)); + } + else + { + return static_cast(value); + } +} + +// Sign and magnitude of an operand together with its 128-bit two's complement +// image. magnitude is the absolute value; negative records the sign. +struct ckd_operand +{ + uint128_t raw; + uint128_t magnitude; + bool negative; +}; + +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr ckd_operand ckd_decompose(const T value) noexcept +{ + const uint128_t raw {ckd_widen(value)}; + const bool negative {std::numeric_limits::is_signed && ((raw >> 127) != 0U)}; + return ckd_operand{raw, negative ? uint128_t{0} - raw : raw, negative}; +} + +// Exact signed sum of two operands given as (magnitude, sign). carry marks a +// 129th bit, which no 128-bit or narrower target can represent. +struct ckd_sum_result +{ + uint128_t magnitude; + bool negative; + bool carry; +}; + +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr ckd_sum_result ckd_signed_sum(const uint128_t a_magnitude, const bool a_negative, + const uint128_t b_magnitude, const bool b_negative) noexcept +{ + if (a_negative == b_negative) + { + // Equal signs: magnitudes add and may overflow into a 129th bit. + const uint128_t magnitude {a_magnitude + b_magnitude}; + return ckd_sum_result{magnitude, a_negative, magnitude < a_magnitude}; + } + + // Opposite signs: the smaller magnitude is subtracted and never carries. + if (a_magnitude >= b_magnitude) + { + return ckd_sum_result{a_magnitude - b_magnitude, a_negative, false}; + } + + return ckd_sum_result{b_magnitude - a_magnitude, b_negative, false}; +} + +// Whether a result of the given sign and magnitude fits in T1. exceeds_width +// forces overflow when the true magnitude does not even fit in 128 bits. +template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool ckd_overflows(const uint128_t magnitude, const bool negative, const bool exceeds_width) noexcept +{ + if (exceeds_width) + { + return true; + } + + const uint128_t max_magnitude {static_cast((std::numeric_limits::max)())}; + + if (negative) + { + const uint128_t min_magnitude {std::numeric_limits::is_signed ? max_magnitude + uint128_t{1} : uint128_t{0}}; + return magnitude > min_magnitude; + } + + return magnitude > max_magnitude; +} + +} // namespace detail + +// Checked addition following the C23 ckd_add contract. +// +// Computes a + b as if both operands were represented in a signed integer +// type of infinite range and then converts that exact result to the type +// pointed to by result. *result always receives the exact result wrapped +// around to the width of *result. Returns false when *result represents the +// exact mathematical sum, and true when the sum did not fit and wrap-around +// occurred. +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool ckd_add(T1* result, const T2 a, const T3 b) noexcept +{ + static_assert(detail::valid_checked_type::value && + detail::valid_checked_type::value && + detail::valid_checked_type::value, + "ckd_add operands must be integer types other than bool and plain char."); + + const auto op_a {detail::ckd_decompose(a)}; + const auto op_b {detail::ckd_decompose(b)}; + + // The modular sum of the widened images is the exact sum mod 2^128, which + // is all the wrapped result needs for any target no wider than 128 bits. + *result = static_cast(op_a.raw + op_b.raw); + + const auto sum {detail::ckd_signed_sum(op_a.magnitude, op_a.negative, op_b.magnitude, op_b.negative)}; + return detail::ckd_overflows(sum.magnitude, sum.negative, sum.carry); +} + +// Checked subtraction following the C23 ckd_sub contract. +// +// Behaves as ckd_add for a - b: *result receives the exact difference wrapped +// to its width, and the return value reports whether that difference did not +// fit. +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool ckd_sub(T1* result, const T2 a, const T3 b) noexcept +{ + static_assert(detail::valid_checked_type::value && + detail::valid_checked_type::value && + detail::valid_checked_type::value, + "ckd_sub operands must be integer types other than bool and plain char."); + + const auto op_a {detail::ckd_decompose(a)}; + const auto op_b {detail::ckd_decompose(b)}; + + *result = static_cast(op_a.raw - op_b.raw); + + // a - b is a + (-b): negating b flips its sign while keeping its magnitude. + const auto difference {detail::ckd_signed_sum(op_a.magnitude, op_a.negative, op_b.magnitude, !op_b.negative)}; + return detail::ckd_overflows(difference.magnitude, difference.negative, difference.carry); +} + +// Checked multiplication following the C23 ckd_mul contract. +// +// Computes a * b as if both operands had infinite range, stores the result +// wrapped to the width of *result, and returns true when the exact product did +// not fit. +BOOST_SAFE_NUMBERS_DETAIL_INT128_EXPORT template +BOOST_SAFE_NUMBERS_DETAIL_INT128_HOST_DEVICE constexpr bool ckd_mul(T1* result, const T2 a, const T3 b) noexcept +{ + static_assert(detail::valid_checked_type::value && + detail::valid_checked_type::value && + detail::valid_checked_type::value, + "ckd_mul operands must be integer types other than bool and plain char."); + + const auto op_a {detail::ckd_decompose(a)}; + const auto op_b {detail::ckd_decompose(b)}; + + *result = static_cast(op_a.raw * op_b.raw); + + // The product magnitude needs more than 128 bits exactly when it exceeds + // UINT128_MAX. Dividing the maximum by one magnitude tests that without + // forming a 256-bit product. + const bool exceeds_width {op_a.magnitude != 0U && + op_b.magnitude > ((std::numeric_limits::max)() / op_a.magnitude)}; + + const uint128_t product_magnitude {op_a.magnitude * op_b.magnitude}; + const bool product_negative {op_a.negative != op_b.negative}; + + return detail::ckd_overflows(product_magnitude, product_negative, exceeds_width); +} + +} // namespace int128 +} // namespace boost + +#endif // BOOST_SAFE_NUMBERS_DETAIL_INT128_UTILITIES_HPP diff --git a/test/benchmarks/benchmark_boost.cpp b/test/benchmarks/benchmark_boost.cpp index 24139fa..3f2ccc8 100644 --- a/test/benchmarks/benchmark_boost.cpp +++ b/test/benchmarks/benchmark_boost.cpp @@ -3,9 +3,6 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wold-style-cast" @@ -46,9 +43,6 @@ # pragma warning(disable : 4702) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - // Even with the pragma above for -Wundef, GCC-11 and GCC-12 still fail // This is a workaround to at least define BOOST_CLANG to a fail value for safe_numerics #if defined(__GNUC__) && __GNUC__ == 11 || __GNUC__ == 12 diff --git a/test/benchmarks/benchmark_signed_operations.cpp b/test/benchmarks/benchmark_signed_operations.cpp index d273e82..3995c53 100644 --- a/test/benchmarks/benchmark_signed_operations.cpp +++ b/test/benchmarks/benchmark_signed_operations.cpp @@ -2,9 +2,6 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/benchmarks/benchmark_unsigned_operations.cpp b/test/benchmarks/benchmark_unsigned_operations.cpp index 9aaee9c..b366c0b 100644 --- a/test/benchmarks/benchmark_unsigned_operations.cpp +++ b/test/benchmarks/benchmark_unsigned_operations.cpp @@ -2,9 +2,6 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_bit.cpp b/test/test_bit.cpp index da6d635..75c66ca 100644 --- a/test/test_bit.cpp +++ b/test/test_bit.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_cuda_i128_add.cu b/test/test_cuda_i128_add.cu index 55d3cd6..ca3393a 100644 --- a/test/test_cuda_i128_add.cu +++ b/test/test_cuda_i128_add.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_i128_div.cu b/test/test_cuda_i128_div.cu index 279b63a..885dfe2 100644 --- a/test/test_cuda_i128_div.cu +++ b/test/test_cuda_i128_div.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_i128_mod.cu b/test/test_cuda_i128_mod.cu index 4245d64..86248f3 100644 --- a/test/test_cuda_i128_mod.cu +++ b/test/test_cuda_i128_mod.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_i128_mul.cu b/test/test_cuda_i128_mul.cu index 555ae6f..d64b1d5 100644 --- a/test/test_cuda_i128_mul.cu +++ b/test/test_cuda_i128_mul.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_i128_sub.cu b/test/test_cuda_i128_sub.cu index 0ffea4d..c6c4a61 100644 --- a/test/test_cuda_i128_sub.cu +++ b/test/test_cuda_i128_sub.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_abs_diff.cu b/test/test_cuda_u128_abs_diff.cu index 7605b63..1fa37dd 100644 --- a/test/test_cuda_u128_abs_diff.cu +++ b/test/test_cuda_u128_abs_diff.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_add.cu b/test/test_cuda_u128_add.cu index 7baeb0b..251d15e 100644 --- a/test/test_cuda_u128_add.cu +++ b/test/test_cuda_u128_add.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_bit_ceil.cu b/test/test_cuda_u128_bit_ceil.cu index b846323..5cfbcd2 100644 --- a/test/test_cuda_u128_bit_ceil.cu +++ b/test/test_cuda_u128_bit_ceil.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_bit_floor.cu b/test/test_cuda_u128_bit_floor.cu index bdb4c9b..2cd917b 100644 --- a/test/test_cuda_u128_bit_floor.cu +++ b/test/test_cuda_u128_bit_floor.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_bit_width.cu b/test/test_cuda_u128_bit_width.cu index 65ab0d7..93a1574 100644 --- a/test/test_cuda_u128_bit_width.cu +++ b/test/test_cuda_u128_bit_width.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_bitswap.cu b/test/test_cuda_u128_bitswap.cu index 3a5e457..fee52ba 100644 --- a/test/test_cuda_u128_bitswap.cu +++ b/test/test_cuda_u128_bitswap.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_byteswap.cu b/test/test_cuda_u128_byteswap.cu index 94cafd7..8722bbf 100644 --- a/test/test_cuda_u128_byteswap.cu +++ b/test/test_cuda_u128_byteswap.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_charconv.cu b/test/test_cuda_u128_charconv.cu index e9b15e2..4dc7a5e 100644 --- a/test/test_cuda_u128_charconv.cu +++ b/test/test_cuda_u128_charconv.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_charconv_all_bases.cu b/test/test_cuda_u128_charconv_all_bases.cu index a9615b0..d5f06a5 100644 --- a/test/test_cuda_u128_charconv_all_bases.cu +++ b/test/test_cuda_u128_charconv_all_bases.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_countl_one.cu b/test/test_cuda_u128_countl_one.cu index 9642b51..a5ba398 100644 --- a/test/test_cuda_u128_countl_one.cu +++ b/test/test_cuda_u128_countl_one.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_countl_zero.cu b/test/test_cuda_u128_countl_zero.cu index a8c89d6..f579b8a 100644 --- a/test/test_cuda_u128_countl_zero.cu +++ b/test/test_cuda_u128_countl_zero.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_countr_one.cu b/test/test_cuda_u128_countr_one.cu index 43ff539..2f937cf 100644 --- a/test/test_cuda_u128_countr_one.cu +++ b/test/test_cuda_u128_countr_one.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_countr_zero.cu b/test/test_cuda_u128_countr_zero.cu index 9505062..3a703e7 100644 --- a/test/test_cuda_u128_countr_zero.cu +++ b/test/test_cuda_u128_countr_zero.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_div.cu b/test/test_cuda_u128_div.cu index ffa36ab..58959c4 100644 --- a/test/test_cuda_u128_div.cu +++ b/test/test_cuda_u128_div.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_div_ceil.cu b/test/test_cuda_u128_div_ceil.cu index ac886c1..7687866 100644 --- a/test/test_cuda_u128_div_ceil.cu +++ b/test/test_cuda_u128_div_ceil.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_from_be.cu b/test/test_cuda_u128_from_be.cu index 11cd7d7..a906677 100644 --- a/test/test_cuda_u128_from_be.cu +++ b/test/test_cuda_u128_from_be.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_from_le.cu b/test/test_cuda_u128_from_le.cu index 723918e..54e61e2 100644 --- a/test/test_cuda_u128_from_le.cu +++ b/test/test_cuda_u128_from_le.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_gcd.cu b/test/test_cuda_u128_gcd.cu index 65ef405..45123ac 100644 --- a/test/test_cuda_u128_gcd.cu +++ b/test/test_cuda_u128_gcd.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_has_single_bit.cu b/test/test_cuda_u128_has_single_bit.cu index 4b8b145..3f4c2ba 100644 --- a/test/test_cuda_u128_has_single_bit.cu +++ b/test/test_cuda_u128_has_single_bit.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_ilog.cu b/test/test_cuda_u128_ilog.cu index d4771eb..88b6741 100644 --- a/test/test_cuda_u128_ilog.cu +++ b/test/test_cuda_u128_ilog.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_ilog10.cu b/test/test_cuda_u128_ilog10.cu index 4f94e0e..2296c6e 100644 --- a/test/test_cuda_u128_ilog10.cu +++ b/test/test_cuda_u128_ilog10.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_ilog2.cu b/test/test_cuda_u128_ilog2.cu index 7787148..873423b 100644 --- a/test/test_cuda_u128_ilog2.cu +++ b/test/test_cuda_u128_ilog2.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_ipow.cu b/test/test_cuda_u128_ipow.cu index 55d6596..3e4225a 100644 --- a/test/test_cuda_u128_ipow.cu +++ b/test/test_cuda_u128_ipow.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_is_power_10.cu b/test/test_cuda_u128_is_power_10.cu index 738aa95..94e8ec1 100644 --- a/test/test_cuda_u128_is_power_10.cu +++ b/test/test_cuda_u128_is_power_10.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_is_power_2.cu b/test/test_cuda_u128_is_power_2.cu index 69f4208..6337c96 100644 --- a/test/test_cuda_u128_is_power_2.cu +++ b/test/test_cuda_u128_is_power_2.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_isqrt.cu b/test/test_cuda_u128_isqrt.cu index 0a14a7a..6c9ed6f 100644 --- a/test/test_cuda_u128_isqrt.cu +++ b/test/test_cuda_u128_isqrt.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_lcm.cu b/test/test_cuda_u128_lcm.cu index 83410a6..9e10fd6 100644 --- a/test/test_cuda_u128_lcm.cu +++ b/test/test_cuda_u128_lcm.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_midpoint.cu b/test/test_cuda_u128_midpoint.cu index 055d8fd..7c33fd9 100644 --- a/test/test_cuda_u128_midpoint.cu +++ b/test/test_cuda_u128_midpoint.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_mod.cu b/test/test_cuda_u128_mod.cu index 607bd72..cbb2a6f 100644 --- a/test/test_cuda_u128_mod.cu +++ b/test/test_cuda_u128_mod.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_mul.cu b/test/test_cuda_u128_mul.cu index 3b29f5f..c74ea05 100644 --- a/test/test_cuda_u128_mul.cu +++ b/test/test_cuda_u128_mul.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_next_multiple_of.cu b/test/test_cuda_u128_next_multiple_of.cu index c59ee19..790bde6 100644 --- a/test/test_cuda_u128_next_multiple_of.cu +++ b/test/test_cuda_u128_next_multiple_of.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_popcount.cu b/test/test_cuda_u128_popcount.cu index fc095d7..8967452 100644 --- a/test/test_cuda_u128_popcount.cu +++ b/test/test_cuda_u128_popcount.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_remove_trailing_zeros.cu b/test/test_cuda_u128_remove_trailing_zeros.cu index c155bac..fa803f5 100644 --- a/test/test_cuda_u128_remove_trailing_zeros.cu +++ b/test/test_cuda_u128_remove_trailing_zeros.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_rotl.cu b/test/test_cuda_u128_rotl.cu index 90781ee..37447f0 100644 --- a/test/test_cuda_u128_rotl.cu +++ b/test/test_cuda_u128_rotl.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_rotr.cu b/test/test_cuda_u128_rotr.cu index bb8d68c..6683a7a 100644 --- a/test/test_cuda_u128_rotr.cu +++ b/test/test_cuda_u128_rotr.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_sub.cu b/test/test_cuda_u128_sub.cu index a214c9a..a2f50a9 100644 --- a/test/test_cuda_u128_sub.cu +++ b/test/test_cuda_u128_sub.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_to_be.cu b/test/test_cuda_u128_to_be.cu index 9f45d24..8fb1328 100644 --- a/test/test_cuda_u128_to_be.cu +++ b/test/test_cuda_u128_to_be.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_cuda_u128_to_le.cu b/test/test_cuda_u128_to_le.cu index 2548a7b..9aa25ae 100644 --- a/test/test_cuda_u128_to_le.cu +++ b/test/test_cuda_u128_to_le.cu @@ -3,9 +3,6 @@ // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_INT128_ALLOW_SIGN_CONVERSION -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #include #include diff --git a/test/test_signed_addition.cpp b/test/test_signed_addition.cpp index 5a5758e..3912452 100644 --- a/test/test_signed_addition.cpp +++ b/test/test_signed_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_bounded_charconv.cpp b/test/test_signed_bounded_charconv.cpp index fa1b772..cdc3936 100644 --- a/test/test_signed_bounded_charconv.cpp +++ b/test/test_signed_bounded_charconv.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_charconv.cpp b/test/test_signed_charconv.cpp index 2093274..d28dc68 100644 --- a/test/test_signed_charconv.cpp +++ b/test/test_signed_charconv.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_checked_addition.cpp b/test/test_signed_checked_addition.cpp index 52ff876..948bee1 100644 --- a/test/test_signed_checked_addition.cpp +++ b/test/test_signed_checked_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_checked_division.cpp b/test/test_signed_checked_division.cpp index 50d0f42..342d62e 100644 --- a/test/test_signed_checked_division.cpp +++ b/test/test_signed_checked_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_checked_mod.cpp b/test/test_signed_checked_mod.cpp index 498babb..8672fcd 100644 --- a/test/test_signed_checked_mod.cpp +++ b/test/test_signed_checked_mod.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_checked_multiplication.cpp b/test/test_signed_checked_multiplication.cpp index 9010310..99b69f1 100644 --- a/test/test_signed_checked_multiplication.cpp +++ b/test/test_signed_checked_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_checked_subtraction.cpp b/test/test_signed_checked_subtraction.cpp index 9192296..5785910 100644 --- a/test/test_signed_checked_subtraction.cpp +++ b/test/test_signed_checked_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_comparisons.cpp b/test/test_signed_comparisons.cpp index 8798469..6404e66 100644 --- a/test/test_signed_comparisons.cpp +++ b/test/test_signed_comparisons.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_construction.cpp b/test/test_signed_construction.cpp index e399f50..c8a6e85 100644 --- a/test/test_signed_construction.cpp +++ b/test/test_signed_construction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ @@ -102,4 +99,4 @@ int main() test(); return boost::report_errors(); -} \ No newline at end of file +} diff --git a/test/test_signed_division.cpp b/test/test_signed_division.cpp index 1912b92..1725977 100644 --- a/test/test_signed_division.cpp +++ b/test/test_signed_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_modulo.cpp b/test/test_signed_modulo.cpp index 7ac32d2..088dcbb 100644 --- a/test/test_signed_modulo.cpp +++ b/test/test_signed_modulo.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_multiplication.cpp b/test/test_signed_multiplication.cpp index 4158173..8616b74 100644 --- a/test/test_signed_multiplication.cpp +++ b/test/test_signed_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_overflowing_addition.cpp b/test/test_signed_overflowing_addition.cpp index 10aa5cf..1647754 100644 --- a/test/test_signed_overflowing_addition.cpp +++ b/test/test_signed_overflowing_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_overflowing_division.cpp b/test/test_signed_overflowing_division.cpp index afaace3..1710ce9 100644 --- a/test/test_signed_overflowing_division.cpp +++ b/test/test_signed_overflowing_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_overflowing_mod.cpp b/test/test_signed_overflowing_mod.cpp index 9dec31d..d28505d 100644 --- a/test/test_signed_overflowing_mod.cpp +++ b/test/test_signed_overflowing_mod.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_overflowing_multiplication.cpp b/test/test_signed_overflowing_multiplication.cpp index bc227e7..c6622e7 100644 --- a/test/test_signed_overflowing_multiplication.cpp +++ b/test/test_signed_overflowing_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_overflowing_subtraction.cpp b/test/test_signed_overflowing_subtraction.cpp index 24b8a88..2d21a58 100644 --- a/test/test_signed_overflowing_subtraction.cpp +++ b/test/test_signed_overflowing_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_saturating_addition.cpp b/test/test_signed_saturating_addition.cpp index fe5734a..5bb67ce 100644 --- a/test/test_signed_saturating_addition.cpp +++ b/test/test_signed_saturating_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_saturating_division.cpp b/test/test_signed_saturating_division.cpp index 299f6ee..030ae9f 100644 --- a/test/test_signed_saturating_division.cpp +++ b/test/test_signed_saturating_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_saturating_mod.cpp b/test/test_signed_saturating_mod.cpp index e000e40..2377f4c 100644 --- a/test/test_signed_saturating_mod.cpp +++ b/test/test_signed_saturating_mod.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_saturating_multiplication.cpp b/test/test_signed_saturating_multiplication.cpp index 6391883..5541cbf 100644 --- a/test/test_signed_saturating_multiplication.cpp +++ b/test/test_signed_saturating_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_saturating_subtraction.cpp b/test/test_signed_saturating_subtraction.cpp index b455c3c..0e08a14 100644 --- a/test/test_signed_saturating_subtraction.cpp +++ b/test/test_signed_saturating_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_signed_subtraction.cpp b/test/test_signed_subtraction.cpp index 6ec1207..71af8d1 100644 --- a/test/test_signed_subtraction.cpp +++ b/test/test_signed_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_addition.cpp b/test/test_unsigned_addition.cpp index d2db53c..f6c6a0e 100644 --- a/test/test_unsigned_addition.cpp +++ b/test/test_unsigned_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_bitwise_ops.cpp b/test/test_unsigned_bitwise_ops.cpp index 5b79845..2d7d2f0 100644 --- a/test/test_unsigned_bitwise_ops.cpp +++ b/test/test_unsigned_bitwise_ops.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_bounded_charconv.cpp b/test/test_unsigned_bounded_charconv.cpp index 0597141..4672ff7 100644 --- a/test/test_unsigned_bounded_charconv.cpp +++ b/test/test_unsigned_bounded_charconv.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_charconv.cpp b/test/test_unsigned_charconv.cpp index f73b4b6..7c6606d 100644 --- a/test/test_unsigned_charconv.cpp +++ b/test/test_unsigned_charconv.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_checked_addition.cpp b/test/test_unsigned_checked_addition.cpp index 7a28c5f..d4f9ea2 100644 --- a/test/test_unsigned_checked_addition.cpp +++ b/test/test_unsigned_checked_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_checked_division.cpp b/test/test_unsigned_checked_division.cpp index 760a46e..db68c11 100644 --- a/test/test_unsigned_checked_division.cpp +++ b/test/test_unsigned_checked_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_checked_mod.cpp b/test/test_unsigned_checked_mod.cpp index 4624db7..8ef71bc 100644 --- a/test/test_unsigned_checked_mod.cpp +++ b/test/test_unsigned_checked_mod.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_checked_multiplication.cpp b/test/test_unsigned_checked_multiplication.cpp index 3137c7f..60a2a2d 100644 --- a/test/test_unsigned_checked_multiplication.cpp +++ b/test/test_unsigned_checked_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_checked_subtraction.cpp b/test/test_unsigned_checked_subtraction.cpp index 0986f0c..a7b45a0 100644 --- a/test/test_unsigned_checked_subtraction.cpp +++ b/test/test_unsigned_checked_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ @@ -137,7 +134,6 @@ void test_checked_subtraction() } } - int main() { test_valid_subtraction(); diff --git a/test/test_unsigned_comparisons.cpp b/test/test_unsigned_comparisons.cpp index 7eb8da9..6f5552e 100644 --- a/test/test_unsigned_comparisons.cpp +++ b/test/test_unsigned_comparisons.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_construction.cpp b/test/test_unsigned_construction.cpp index 31f191a..59a759b 100644 --- a/test/test_unsigned_construction.cpp +++ b/test/test_unsigned_construction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_division.cpp b/test/test_unsigned_division.cpp index 2870b13..16c57c0 100644 --- a/test/test_unsigned_division.cpp +++ b/test/test_unsigned_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_modulo.cpp b/test/test_unsigned_modulo.cpp index 1a22c97..d70384a 100644 --- a/test/test_unsigned_modulo.cpp +++ b/test/test_unsigned_modulo.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_multiplication.cpp b/test/test_unsigned_multiplication.cpp index e2cf807..31ce5ef 100644 --- a/test/test_unsigned_multiplication.cpp +++ b/test/test_unsigned_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_overflowing_addition.cpp b/test/test_unsigned_overflowing_addition.cpp index 4ff2c4b..608bc59 100644 --- a/test/test_unsigned_overflowing_addition.cpp +++ b/test/test_unsigned_overflowing_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_overflowing_division.cpp b/test/test_unsigned_overflowing_division.cpp index 1695615..a5fec33 100644 --- a/test/test_unsigned_overflowing_division.cpp +++ b/test/test_unsigned_overflowing_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_overflowing_mod.cpp b/test/test_unsigned_overflowing_mod.cpp index def266f..4724289 100644 --- a/test/test_unsigned_overflowing_mod.cpp +++ b/test/test_unsigned_overflowing_mod.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_overflowing_multiplication.cpp b/test/test_unsigned_overflowing_multiplication.cpp index 5d739c6..fae969a 100644 --- a/test/test_unsigned_overflowing_multiplication.cpp +++ b/test/test_unsigned_overflowing_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_overflowing_subtraction.cpp b/test/test_unsigned_overflowing_subtraction.cpp index cb573b2..a002add 100644 --- a/test/test_unsigned_overflowing_subtraction.cpp +++ b/test/test_unsigned_overflowing_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ @@ -139,7 +136,6 @@ void test_saturating_subtraction() } } - int main() { test_valid_subtraction(); diff --git a/test/test_unsigned_random.cpp b/test/test_unsigned_random.cpp index 44e7c36..ca97bb3 100644 --- a/test/test_unsigned_random.cpp +++ b/test/test_unsigned_random.cpp @@ -9,10 +9,6 @@ #include #include -#ifdef BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION -# error "Should not be defined for the user" -#endif - using namespace boost::safe_numbers; static std::mt19937_64 rng{42}; diff --git a/test/test_unsigned_saturating_addition.cpp b/test/test_unsigned_saturating_addition.cpp index e500d12..17cf8aa 100644 --- a/test/test_unsigned_saturating_addition.cpp +++ b/test/test_unsigned_saturating_addition.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_saturating_division.cpp b/test/test_unsigned_saturating_division.cpp index ca183df..28ba8d9 100644 --- a/test/test_unsigned_saturating_division.cpp +++ b/test/test_unsigned_saturating_division.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_saturating_mod.cpp b/test/test_unsigned_saturating_mod.cpp index 67211a6..44b970d 100644 --- a/test/test_unsigned_saturating_mod.cpp +++ b/test/test_unsigned_saturating_mod.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_saturating_multiplication.cpp b/test/test_unsigned_saturating_multiplication.cpp index 02bcbde..3174303 100644 --- a/test/test_unsigned_saturating_multiplication.cpp +++ b/test/test_unsigned_saturating_multiplication.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ diff --git a/test/test_unsigned_saturating_subtraction.cpp b/test/test_unsigned_saturating_subtraction.cpp index 7e5fb47..947ad36 100644 --- a/test/test_unsigned_saturating_subtraction.cpp +++ b/test/test_unsigned_saturating_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__ @@ -135,7 +132,6 @@ void test_saturating_subtraction() } } - int main() { test_valid_subtraction(); diff --git a/test/test_unsigned_subtraction.cpp b/test/test_unsigned_subtraction.cpp index eb4469a..65046fb 100644 --- a/test/test_unsigned_subtraction.cpp +++ b/test/test_unsigned_subtraction.cpp @@ -36,9 +36,6 @@ # pragma warning(disable : 4309) #endif -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_COMPARE -#define BOOST_SAFE_NUMBERS_DETAIL_INT128_ALLOW_SIGN_CONVERSION - #include #ifdef __clang__