diff --git a/include/boost/decimal/detail/int128/bit.hpp b/include/boost/decimal/detail/int128/bit.hpp index cbf3e1882..4ad05a62e 100644 --- a/include/boost/decimal/detail/int128/bit.hpp +++ b/include/boost/decimal/detail/int128/bit.hpp @@ -5,69 +5,69 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_BIT_HPP #define BOOST_DECIMAL_DETAIL_INT128_BIT_HPP -#include "int128.hpp" -#include "detail/config.hpp" -#include "detail/clz.hpp" -#include "detail/ctz.hpp" +#include +#include +#include +#include namespace boost { namespace int128 { -constexpr bool has_single_bit(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool has_single_bit(const uint128_t x) noexcept { return x && !(x & (x - 1U)); } -constexpr int countl_zero(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_zero(const uint128_t x) noexcept { return x.high == 0 ? 64 + detail::countl_zero(x.low) : detail::countl_zero(x.high); } -constexpr int countl_one(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_one(const uint128_t x) noexcept { return countl_zero(~x); } -constexpr int bit_width(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int bit_width(const uint128_t x) noexcept { return x ? 128 - countl_zero(x) : 0; } -constexpr uint128_t bit_ceil(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t bit_ceil(const uint128_t x) noexcept { return x <= 1U ? static_cast(1) : static_cast(1) << bit_width(x - 1U); } -constexpr uint128_t bit_floor(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t bit_floor(const uint128_t x) noexcept { return x > 0U ? static_cast(1) << (bit_width(x) - 1U) : static_cast(0); } -constexpr int countr_zero(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_zero(const uint128_t x) noexcept { return x.low == 0 ? 64 + detail::countr_zero(x.high) : detail::countr_zero(x.low); } -constexpr int countr_one(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_one(const uint128_t x) noexcept { return countr_zero(~x); } -constexpr uint128_t rotl(const uint128_t x, const int s) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t rotl(const uint128_t x, const int s) noexcept { constexpr auto mask {127U}; return x << (static_cast(s) & mask) | x >> (static_cast(-s) & mask); } -constexpr uint128_t rotr(const uint128_t x, const int s) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t rotr(const uint128_t x, const int s) noexcept { constexpr auto mask {127U}; return x >> (static_cast(s) & mask) | x << (static_cast(-s) & mask); } -#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) +#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) -constexpr int popcount(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept { return __builtin_popcountll(x.high) + __builtin_popcountll(x.low); } @@ -76,7 +76,7 @@ constexpr int popcount(const uint128_t x) noexcept namespace impl { -constexpr int popcount_impl(std::uint64_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount_impl(std::uint64_t x) noexcept { x = x - ((x >> 1U) & UINT64_C(0x5555555555555555)); x = (x & UINT64_C(0x3333333333333333)) + ((x >> 2U) & UINT64_C(0x3333333333333333)); @@ -89,7 +89,7 @@ constexpr int popcount_impl(std::uint64_t x) noexcept #if defined(_M_AMD64) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) -constexpr int popcount(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) { @@ -111,7 +111,7 @@ constexpr int popcount(const uint128_t x) noexcept #elif defined(_M_IX86) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) -constexpr int popcount(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) { @@ -139,18 +139,18 @@ constexpr int popcount(const uint128_t x) noexcept } } -#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) +#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_popcountll) || (defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) -constexpr int popcount(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int popcount(const uint128_t x) noexcept { return impl::popcount_impl(x.high) + impl::popcount_impl(x.low); } #endif -#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) +#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) -constexpr uint128_t byteswap(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap(const uint128_t x) noexcept { return {__builtin_bswap64(x.low), __builtin_bswap64(x.high)}; } @@ -159,14 +159,14 @@ constexpr uint128_t byteswap(const uint128_t x) noexcept namespace impl { -constexpr std::uint64_t byteswap_impl(const std::uint64_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::uint64_t byteswap_impl(const std::uint64_t x) noexcept { const auto step32 {x << 32U | x >> 32U}; const auto step16 {(step32 & UINT64_C(0x0000FFFF0000FFFF)) << 16U | (step32 & UINT64_C(0xFFFF0000FFFF0000)) >> 16U}; return (step16 & UINT64_C(0x00FF00FF00FF00FF)) << 8U | (step16 & UINT64_C(0xFF00FF00FF00FF00)) >> 8U; } -constexpr uint128_t byteswap_impl(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap_impl(const uint128_t x) noexcept { return {byteswap_impl(x.low), byteswap_impl(x.high)}; } @@ -175,7 +175,7 @@ constexpr uint128_t byteswap_impl(const uint128_t x) noexcept #if defined(_MSC_VER) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) -constexpr uint128_t byteswap(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap(const uint128_t x) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) { @@ -187,9 +187,9 @@ constexpr uint128_t byteswap(const uint128_t x) noexcept } } -#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) +#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_bswap64) || (defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) -constexpr uint128_t byteswap(const uint128_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t byteswap(const uint128_t x) noexcept { return impl::byteswap_impl(x); } diff --git a/include/boost/decimal/detail/int128/charconv.hpp b/include/boost/decimal/detail/int128/charconv.hpp new file mode 100644 index 000000000..c50e9abf4 --- /dev/null +++ b/include/boost/decimal/detail/int128/charconv.hpp @@ -0,0 +1,245 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// This header injects additional functionality into the Boost.Charconv namespace +// If this library is accepted into boost this functionality could be moved their + +#ifndef BOOST_DECIMAL_DETAIL_INT128_CHARCONV_HPP +#define BOOST_DECIMAL_DETAIL_INT128_CHARCONV_HPP + +#if __has_include() + +// Define for the user automatically, +// otherwise we'll have an ever-increasing number of these required as we go down the dependency chain +#if defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) && !defined(BOOST_CHARCONV_ENABLE_CUDA) +# define BOOST_CHARCONV_ENABLE_CUDA +#endif + +#include +#include +#include +#include + +namespace boost { +namespace charconv { + +namespace detail { + +template <> +struct is_signed { static constexpr bool value = false; }; + +template <> +struct is_signed { static constexpr bool value = true; }; + +template <> +struct make_unsigned { using type = int128::uint128_t; }; + +template <> +struct make_unsigned { using type = int128::uint128_t; }; + +template <> +struct make_signed { using type = int128::int128_t; }; + +template <> +struct make_signed { using type = int128::int128_t; }; + +#if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + +template <> +__host__ __device__ constexpr int128::uint128_t get_max_value() +{ + return std::numeric_limits::max(); +} + +template <> +__host__ __device__ constexpr int128::int128_t get_max_value() +{ + return std::numeric_limits::max(); +} + +#endif // __NVCC__ + +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR int128::uint128_t int128_pow10[39] = +{ + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x1)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xa)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x64)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x3e8)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x2710)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x186a0)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xf4240)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x989680)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x5f5e100)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x3b9aca00)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x2540be400)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x174876e800)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xe8d4a51000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x9184e72a000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x5af3107a4000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x38d7ea4c68000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x2386f26fc10000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x16345785d8a0000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xde0b6b3a7640000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x8ac7230489e80000)}, + int128::uint128_t{UINT64_C(0x5), UINT64_C(0x6bc75e2d63100000)}, + int128::uint128_t{UINT64_C(0x36), UINT64_C(0x35c9adc5dea00000)}, + int128::uint128_t{UINT64_C(0x21e), UINT64_C(0x19e0c9bab2400000)}, + int128::uint128_t{UINT64_C(0x152d), UINT64_C(0x2c7e14af6800000)}, + int128::uint128_t{UINT64_C(0xd3c2), UINT64_C(0x1bcecceda1000000)}, + int128::uint128_t{UINT64_C(0x84595), UINT64_C(0x161401484a000000)}, + int128::uint128_t{UINT64_C(0x52b7d2), UINT64_C(0xdcc80cd2e4000000)}, + int128::uint128_t{UINT64_C(0x33b2e3c), UINT64_C(0x9fd0803ce8000000)}, + int128::uint128_t{UINT64_C(0x204fce5e), UINT64_C(0x3e25026110000000)}, + int128::uint128_t{UINT64_C(0x1431e0fae), UINT64_C(0x6d7217caa0000000)}, + int128::uint128_t{UINT64_C(0xc9f2c9cd0), UINT64_C(0x4674edea40000000)}, + int128::uint128_t{UINT64_C(0x7e37be2022), UINT64_C(0xc0914b2680000000)}, + int128::uint128_t{UINT64_C(0x4ee2d6d415b), UINT64_C(0x85acef8100000000)}, + int128::uint128_t{UINT64_C(0x314dc6448d93), UINT64_C(0x38c15b0a00000000)}, + int128::uint128_t{UINT64_C(0x1ed09bead87c0), UINT64_C(0x378d8e6400000000)}, + int128::uint128_t{UINT64_C(0x13426172c74d82), UINT64_C(0x2b878fe800000000)}, + int128::uint128_t{UINT64_C(0xc097ce7bc90715), UINT64_C(0xb34b9f1000000000)}, + int128::uint128_t{UINT64_C(0x785ee10d5da46d9), UINT64_C(0xf436a000000000)}, + int128::uint128_t{UINT64_C(0x4b3b4ca85a86c47a), UINT64_C(0x98a224000000000)} +}; + +#endif // __NVCC__ + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int num_digits(const int128::uint128_t& x) noexcept +{ + #if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + + constexpr int128::uint128_t int128_pow10[39] = + { + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x1)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xa)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x64)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x3e8)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x2710)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x186a0)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xf4240)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x989680)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x5f5e100)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x3b9aca00)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x2540be400)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x174876e800)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xe8d4a51000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x9184e72a000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x5af3107a4000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x38d7ea4c68000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x2386f26fc10000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x16345785d8a0000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0xde0b6b3a7640000)}, + int128::uint128_t{UINT64_C(0x0), UINT64_C(0x8ac7230489e80000)}, + int128::uint128_t{UINT64_C(0x5), UINT64_C(0x6bc75e2d63100000)}, + int128::uint128_t{UINT64_C(0x36), UINT64_C(0x35c9adc5dea00000)}, + int128::uint128_t{UINT64_C(0x21e), UINT64_C(0x19e0c9bab2400000)}, + int128::uint128_t{UINT64_C(0x152d), UINT64_C(0x2c7e14af6800000)}, + int128::uint128_t{UINT64_C(0xd3c2), UINT64_C(0x1bcecceda1000000)}, + int128::uint128_t{UINT64_C(0x84595), UINT64_C(0x161401484a000000)}, + int128::uint128_t{UINT64_C(0x52b7d2), UINT64_C(0xdcc80cd2e4000000)}, + int128::uint128_t{UINT64_C(0x33b2e3c), UINT64_C(0x9fd0803ce8000000)}, + int128::uint128_t{UINT64_C(0x204fce5e), UINT64_C(0x3e25026110000000)}, + int128::uint128_t{UINT64_C(0x1431e0fae), UINT64_C(0x6d7217caa0000000)}, + int128::uint128_t{UINT64_C(0xc9f2c9cd0), UINT64_C(0x4674edea40000000)}, + int128::uint128_t{UINT64_C(0x7e37be2022), UINT64_C(0xc0914b2680000000)}, + int128::uint128_t{UINT64_C(0x4ee2d6d415b), UINT64_C(0x85acef8100000000)}, + int128::uint128_t{UINT64_C(0x314dc6448d93), UINT64_C(0x38c15b0a00000000)}, + int128::uint128_t{UINT64_C(0x1ed09bead87c0), UINT64_C(0x378d8e6400000000)}, + int128::uint128_t{UINT64_C(0x13426172c74d82), UINT64_C(0x2b878fe800000000)}, + int128::uint128_t{UINT64_C(0xc097ce7bc90715), UINT64_C(0xb34b9f1000000000)}, + int128::uint128_t{UINT64_C(0x785ee10d5da46d9), UINT64_C(0xf436a000000000)}, + int128::uint128_t{UINT64_C(0x4b3b4ca85a86c47a), UINT64_C(0x98a224000000000)} + }; + + #endif // __NVCC__ + + if (x.high == UINT64_C(0)) + { + return num_digits(x.low); + } + + // Use the most significant bit position to approximate log10 + // log10(x) ~= log2(x) / log2(10) ~= log2(x) / 3.32 + + const auto msb {64 + (63 - int128::detail::countl_zero(x.high))}; + + // Approximate log10 + const auto estimated_digits {(msb * 1000) / 3322 + 1}; + + if (estimated_digits < 39 && x >= int128_pow10[static_cast(estimated_digits)]) + { + return estimated_digits + 1; + } + + // Estimated digits can't be less than 20 digits (65-bits minimum) + if (x < int128_pow10[estimated_digits - 1]) + { + return estimated_digits - 1; + } + + return estimated_digits; +} + +} // namespace detail + +BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + + if (base == 10) + { + return detail::to_chars_128integer_impl(first, last, value); + } + + #endif // __NVCC__ + + return detail::to_chars_integer_impl(first, last, value, base); +} + +BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + + if (base == 10) + { + return detail::to_chars_128integer_impl(first, last, value); + } + + #endif // __NVCC__ + + return detail::to_chars_integer_impl(first, last, value, base); +} + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, int128::uint128_t& value, const int base = 10) noexcept +{ + return detail::from_chars_integer_impl(first, last, value, base); +} + +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(core::string_view sv, int128::uint128_t& value, const int base = 10) noexcept +{ + return detail::from_chars_integer_impl(sv.data(), sv.data() + sv.size(), value, base); +} + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, int128::int128_t& value, const int base = 10) noexcept +{ + return detail::from_chars_integer_impl(first, last, value, base); +} + +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(core::string_view sv, int128::int128_t& value, int base = 10) noexcept +{ + return detail::from_chars_integer_impl(sv.data(), sv.data() + sv.size(), value, base); +} + +} // namespace charconv +} // namespace boost + +#else + +#error "This header requires Boost.Charconv to be present" + +#endif // __has_include() + +#endif // BOOST_DECIMAL_DETAIL_INT128_CHARCONV_HPP diff --git a/include/boost/decimal/detail/int128/climits.hpp b/include/boost/decimal/detail/int128/climits.hpp new file mode 100644 index 000000000..607e0dade --- /dev/null +++ b/include/boost/decimal/detail/int128/climits.hpp @@ -0,0 +1,17 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_INT128_CLIMITS_HPP +#define BOOST_DECIMAL_DETAIL_INT128_CLIMITS_HPP + +#include +#include +#include + +#define BOOST_DECIMAL_DETAIL_INT128_UINT128_MAX boost::int128::uint128_t{UINT64_MAX, UINT64_MAX} + +#define BOOST_DECIMAL_DETAIL_INT128_INT128_MIN boost::int128::int128_t{INT64_MIN, 0} +#define BOOST_DECIMAL_DETAIL_INT128_INT128_MAX boost::int128::int128_t{INT64_MAX, UINT64_MAX} + +#endif // BOOST_DECIMAL_DETAIL_INT128_CLIMITS_HPP diff --git a/include/boost/decimal/detail/int128/cstdlib.hpp b/include/boost/decimal/detail/int128/cstdlib.hpp index 00de6f2f8..439006034 100644 --- a/include/boost/decimal/detail/int128/cstdlib.hpp +++ b/include/boost/decimal/detail/int128/cstdlib.hpp @@ -5,24 +5,24 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_CSTDLIB_HPP #define BOOST_DECIMAL_DETAIL_INT128_CSTDLIB_HPP -#include "int128.hpp" +#include namespace boost { namespace int128 { -struct u128div_t +BOOST_DECIMAL_DETAIL_INT128_EXPORT struct u128div_t { uint128_t quot; uint128_t rem; }; -struct i128div_t +BOOST_DECIMAL_DETAIL_INT128_EXPORT struct i128div_t { int128_t quot; int128_t rem; }; -constexpr u128div_t div(const uint128_t x, const uint128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr u128div_t div(const uint128_t x, const uint128_t y) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(x == 0U || y == 0U)) { @@ -54,7 +54,7 @@ constexpr u128div_t div(const uint128_t x, const uint128_t y) noexcept } } -constexpr i128div_t div(const int128_t x, const int128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr i128div_t div(const int128_t x, const int128_t y) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(x == 0 || y == 0)) { @@ -81,11 +81,7 @@ constexpr i128div_t div(const int128_t x, const int128_t y) noexcept const auto unsigned_res {div(abs_lhs, abs_rhs)}; const auto negative_quot {(x.high < 0) != (y.high < 0)}; - #if defined(_MSC_VER) && !defined(__GNUC__) const auto negative_rem {x.high < 0}; - #else - const auto negative_rem {(x.high < 0) != (y.high < 0)}; - #endif i128div_t res {static_cast(unsigned_res.quot), static_cast(unsigned_res.rem)}; diff --git a/include/boost/decimal/detail/int128/detail/clz.hpp b/include/boost/decimal/detail/int128/detail/clz.hpp index 61d609702..690aa997a 100644 --- a/include/boost/decimal/detail/int128/detail/clz.hpp +++ b/include/boost/decimal/detail/int128/detail/clz.hpp @@ -5,18 +5,25 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_CLZ_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_CLZ_HPP -#include "config.hpp" +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { namespace detail { namespace impl { +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + // See: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE int index64[64] = { +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR int index64[64] = { 0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61, 54, 58, 35, 52, 50, 42, 21, 44, @@ -27,8 +34,25 @@ BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE int index64[64] = { 13, 18, 8, 12, 7, 6, 5, 63 }; -constexpr int bit_scan_reverse(std::uint64_t bb) noexcept +#endif + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int bit_scan_reverse(std::uint64_t bb) noexcept { + #if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + + constexpr int index64[64] = { + 0, 47, 1, 56, 48, 27, 2, 60, + 57, 49, 41, 37, 28, 16, 3, 61, + 54, 58, 35, 52, 50, 42, 21, 44, + 38, 32, 29, 23, 17, 11, 4, 62, + 46, 55, 26, 59, 40, 36, 15, 53, + 34, 51, 20, 43, 31, 22, 10, 45, + 25, 39, 14, 33, 19, 30, 9, 24, + 13, 18, 8, 12, 7, 6, 5, 63 + }; + + #endif + constexpr auto debruijn64 {UINT64_C(0x03f79d71b4cb0a89)}; BOOST_DECIMAL_DETAIL_INT128_ASSUME(bb != 0); // LCOV_EXCL_LINE @@ -43,7 +67,9 @@ constexpr int bit_scan_reverse(std::uint64_t bb) noexcept return index64[(bb * debruijn64) >> 58]; } -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE int countl_mod37[37] = { +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR int countl_mod37[37] = { 32, 31, 6, 30, 9, 5, 0, 29, 16, 8, 2, 4, 21, 0, 19, 28, 25, 15, 0, 7, 10, 1, 17, 3, @@ -51,8 +77,22 @@ BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE int countl_mod37[37] = { 27, 12, 24, 13, 14, 0 }; -constexpr int backup_countl_impl(std::uint32_t x) noexcept +#endif + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int backup_countl_impl(std::uint32_t x) noexcept { + #if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + + constexpr int countl_mod37[37] = { + 32, 31, 6, 30, 9, 5, 0, 29, + 16, 8, 2, 4, 21, 0, 19, 28, + 25, 15, 0, 7, 10, 1, 17, 3, + 22, 20, 26, 0, 11, 18, 23, + 27, 12, 24, 13, 14, 0 + }; + + #endif + x |= x >> 1; x |= x >> 2; x |= x >> 4; @@ -62,7 +102,7 @@ constexpr int backup_countl_impl(std::uint32_t x) noexcept return countl_mod37[x % 37]; } -#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_clz) +#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_clz) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) constexpr int countl_impl(unsigned int x) noexcept { @@ -79,7 +119,7 @@ constexpr int countl_impl(unsigned long long x) noexcept return x ? __builtin_clzll(x) : std::numeric_limits::digits; } -#elif (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) +#elif (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) constexpr int countl_impl(std::uint32_t x) noexcept { @@ -146,7 +186,7 @@ constexpr int countl_impl(std::uint32_t x) noexcept } } -constexpr int countl_impl(std::uint64_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_impl(std::uint64_t x) noexcept { return x ? bit_scan_reverse(static_cast(x)) ^ 63 : std::numeric_limits::digits; } @@ -154,12 +194,12 @@ constexpr int countl_impl(std::uint64_t x) noexcept #else template -constexpr int countl_impl(T x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_impl(T x) noexcept { return x ? bit_scan_reverse(static_cast(x)) ^ 63 : std::numeric_limits::digits; } -constexpr int countl_impl(std::uint32_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_impl(std::uint32_t x) noexcept { return backup_countl_impl(x); } @@ -170,7 +210,7 @@ constexpr int countl_impl(std::uint32_t x) noexcept } // namespace impl template -constexpr int countl_zero(T x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countl_zero(T x) noexcept { static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, "Can only count with unsigned integers"); diff --git a/include/boost/decimal/detail/int128/detail/common_div.hpp b/include/boost/decimal/detail/int128/detail/common_div.hpp index 8249ceeaa..263ecd02c 100644 --- a/include/boost/decimal/detail/int128/detail/common_div.hpp +++ b/include/boost/decimal/detail/int128/detail/common_div.hpp @@ -5,11 +5,16 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_COMMON_DIV_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_COMMON_DIV_HPP -#include "config.hpp" -#include "clz.hpp" +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { namespace detail { @@ -20,7 +25,7 @@ namespace detail { #endif template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void half_word_div(const T& lhs, const std::uint32_t rhs, T& quotient, T& remainder) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void half_word_div(const T& lhs, const std::uint32_t rhs, T& quotient, T& remainder) noexcept { using high_word_type = decltype(T{}.high); @@ -49,11 +54,13 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void half_word_div(const T& l } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void half_word_div(const T& lhs, const std::uint32_t rhs, T& quotient) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void half_word_div(const T& lhs, const std::uint32_t rhs, T& quotient) noexcept { + using high_word_type = decltype(T{}.high); + BOOST_DECIMAL_DETAIL_INT128_ASSUME(rhs != 0); // LCOV_EXCL_LINE - quotient.high = lhs.high / rhs; + quotient.high = static_cast(static_cast(lhs.high) / rhs); auto remainder {((static_cast(lhs.high) % rhs) << 32) | (lhs.low >> 32)}; quotient.low = (remainder / rhs) << 32; remainder = ((remainder % rhs) << 32) | (lhs.low & UINT32_MAX); @@ -68,7 +75,7 @@ namespace impl { #endif template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t (&vn)[4], const std::uint32_t (&v)[v_size], +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t (&vn)[4], const std::uint32_t (&v)[v_size], const bool needs_shift, const int s, const int complement_s, const std::integral_constant&) noexcept { vn[1] = needs_shift ? ((v[1] << s) | (v[0] >> complement_s)) : v[1]; @@ -76,7 +83,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t ( } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t (&vn)[4], const std::uint32_t (&v)[v_size], +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t (&vn)[4], const std::uint32_t (&v)[v_size], const bool needs_shift, const int s, const int complement_s, const std::integral_constant&) noexcept { vn[3] = needs_shift ? ((v[3] << s) | (v[2] >> complement_s)) : v[3]; @@ -86,7 +93,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t ( } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t (&vn)[8], const std::uint32_t (&v)[v_size], +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t (&vn)[8], const std::uint32_t (&v)[v_size], const bool needs_shift, const int s, const int complement_s, const std::integral_constant&) noexcept { vn[7] = needs_shift ? ((v[7] << s) | (v[6] >> complement_s)) : v[7]; @@ -100,7 +107,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_v(std::uint32_t ( } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_u(std::uint32_t (&un)[un_size], const std::uint32_t (&u)[u_size], +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_u(std::uint32_t (&un)[un_size], const std::uint32_t (&u)[u_size], const bool needs_shift, const int s, const int complement_s, const std::integral_constant&) noexcept { un[4] = needs_shift ? (u[3] >> complement_s) : 0; @@ -111,7 +118,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_u(std::uint32_t ( } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_u(std::uint32_t (&un)[un_size], const std::uint32_t (&u)[u_size], +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_u(std::uint32_t (&un)[un_size], const std::uint32_t (&u)[u_size], const bool needs_shift, const int s, const int complement_s, const std::integral_constant&) noexcept { un[8] = needs_shift ? (u[7] >> complement_s) : 0; @@ -128,7 +135,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void unpack_u(std::uint32_t ( // See: The Art of Computer Programming Volume 2 (Semi-numerical algorithms) section 4.3.1 // Algorithm D: Division of Non-negative integers template -constexpr void knuth_divide(std::uint32_t (&u)[u_size], const std::size_t m, +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr void knuth_divide(std::uint32_t (&u)[u_size], const std::size_t m, const std::uint32_t (&v)[v_size], const std::size_t n, std::uint32_t (&q)[q_size]) noexcept { @@ -235,7 +242,7 @@ constexpr void knuth_divide(std::uint32_t (&u)[u_size], const std::size_t m, #endif template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const T& x, std::uint32_t (&words)[4]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const T& x, std::uint32_t (&words)[4]) noexcept { #if !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_ENDIAN_BIG_BYTE if (!BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) @@ -251,6 +258,8 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const T& words[3] = static_cast(static_cast(x.high) >> 32); // LCOV_EXCL_LINE } + BOOST_DECIMAL_DETAIL_INT128_ASSERT_MSG(x != static_cast(0), "Division by 0"); + std::size_t word_count {4}; while (words[word_count - 1U] == 0U) { @@ -260,7 +269,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const T& return word_count; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const std::uint64_t x, std::uint32_t (&words)[2]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const std::uint64_t x, std::uint32_t (&words)[2]) noexcept { #if !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_ENDIAN_BIG_BYTE if (!BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) @@ -277,7 +286,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const st return x > UINT32_MAX ? 2 : 1; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const std::uint32_t x, std::uint32_t (&words)[1]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const std::uint32_t x, std::uint32_t (&words)[1]) noexcept { words[0] = x; @@ -285,7 +294,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr std::size_t to_words(const st } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T from_words(const std::uint32_t (&words)[4]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T from_words(const std::uint32_t (&words)[4]) noexcept { using high_word_type = decltype(T{}.high); @@ -298,7 +307,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T from_words(const std::uint3 #if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 template -constexpr T div_mod_msvc(T dividend, T divisor, T& remainder) +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr T div_mod_msvc(T dividend, T divisor, T& remainder) { using high_word_type = decltype(T{}.high); @@ -425,7 +434,7 @@ constexpr T div_mod_msvc(T dividend, T divisor, T& remainder) // In the division case it is a waste of cycles template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint64_t rhs, T& quotient) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) @@ -461,7 +470,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lh } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint64_t rhs, T& quotient, T& remainder) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) @@ -500,13 +509,13 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lh } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint32_t rhs, T& quotient, T& remainder) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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); } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lhs, const std::uint32_t rhs, T& quotient) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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); } @@ -518,7 +527,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void one_word_div(const T& lh #endif template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend, const T& divisor) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend, const T& divisor) noexcept { BOOST_DECIMAL_DETAIL_INT128_ASSUME(divisor != static_cast(0)); @@ -539,8 +548,8 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend 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)}; + const auto m{ impl::to_words(dividend, u) }; + const auto n{ impl::to_words(divisor, v) }; impl::knuth_divide(u, m, v, n, q); @@ -549,10 +558,10 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend, const T& divisor, T& remainder) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend, const T& divisor, T& remainder) noexcept { BOOST_DECIMAL_DETAIL_INT128_ASSUME(divisor != static_cast(0)); - + #if defined(_M_AMD64) && !defined(__GNUC__) && !defined(__clang__) && _MSC_VER >= 1920 BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR(!std::numeric_limits::is_signed) @@ -570,8 +579,8 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr T knuth_div(const T& dividend 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)}; + const auto m{ impl::to_words(dividend, u) }; + const auto n{ impl::to_words(divisor, v) }; impl::knuth_divide(u, m, v, n, q); diff --git a/include/boost/decimal/detail/int128/detail/common_mul.hpp b/include/boost/decimal/detail/int128/detail/common_mul.hpp index 0f8a70bb6..5aeac3b55 100644 --- a/include/boost/decimal/detail/int128/detail/common_mul.hpp +++ b/include/boost/decimal/detail/int128/detail/common_mul.hpp @@ -5,10 +5,15 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_COMMON_MUL_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_COMMON_MUL_HPP -#include "config.hpp" +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { namespace detail { @@ -16,7 +21,7 @@ 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_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr ReturnType knuth_multiply(const std::uint32_t (&u)[u_size], +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr ReturnType knuth_multiply(const std::uint32_t (&u)[u_size], const std::uint32_t (&v)[v_size]) noexcept { using high_word_type = decltype(ReturnType{}.high); @@ -54,13 +59,13 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr ReturnType knuth_multiply(con } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const T& x, std::uint32_t (&words)[4]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const T& x, std::uint32_t (&words)[4]) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION if (!BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) { - std::memcpy(words, &x, sizeof(T)); + std::memcpy(&words, &x, sizeof(T)); return; } @@ -73,13 +78,13 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const T& x, std } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint64_t x, std::uint32_t (&words)[2]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint64_t x, std::uint32_t (&words)[2]) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION if (!BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x)) { - std::memcpy(words, &x, sizeof(std::uint64_t)); + std::memcpy(&words, &x, sizeof(std::uint64_t)); return; } @@ -89,7 +94,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint words[1] = static_cast(x >> 32); // LCOV_EXCL_LINE } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint32_t x, std::uint32_t (&words)[1]) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr void to_words(const std::uint32_t x, std::uint32_t (&words)[1]) noexcept { words[0] = x; } diff --git a/include/boost/decimal/detail/int128/detail/config.hpp b/include/boost/decimal/detail/int128/detail/config.hpp index 140b304dd..6118b06be 100644 --- a/include/boost/decimal/detail/int128/detail/config.hpp +++ b/include/boost/decimal/detail/int128/detail/config.hpp @@ -39,7 +39,9 @@ using builtin_u128 = unsigned __int128; #elif __has_include(<__msvc_int128.hpp>) && _MSVC_LANG >= 202002L +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE #include <__msvc_int128.hpp> +#endif #define BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 @@ -100,9 +102,9 @@ using builtin_u128 = std::_Unsigned128; # define BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_IS_CONSTANT_EVALUATED #endif -#if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_IS_CONSTANT_EVALUATED) +#if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_IS_CONSTANT_EVALUATED) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) # define BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x) std::is_constant_evaluated() -#elif defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_IS_CONSTANT_EVALUATED) +#elif defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_IS_CONSTANT_EVALUATED) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) # define BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x) __builtin_is_constant_evaluated() #else # define BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(x) false @@ -126,8 +128,10 @@ using builtin_u128 = std::_Unsigned128; #ifdef __x86_64__ +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE # include # include +#endif # ifdef __ADX__ # define BOOST_DECIMAL_DETAIL_INT128_ADD_CARRY _addcarryx_u64 @@ -139,7 +143,9 @@ using builtin_u128 = std::_Unsigned128; #elif defined(_M_AMD64) +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE # include +#endif # ifdef __ADX__ # define BOOST_DECIMAL_DETAIL_INT128_ADD_CARRY _addcarryx_u64 @@ -151,11 +157,15 @@ using builtin_u128 = std::_Unsigned128; #elif defined(__i386__) +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE # include +#endif #elif defined(_M_IX86) +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE # include +#endif #endif // Platform macros @@ -173,7 +183,9 @@ using builtin_u128 = std::_Unsigned128; # define BOOST_DECIMAL_DETAIL_INT128_HAS_IF_CONSTEXPR #endif // if constexpr detection +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE #include +#endif #define BOOST_DECIMAL_DETAIL_INT128_ASSERT(x) assert(x) #define BOOST_DECIMAL_DETAIL_INT128_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) @@ -230,4 +242,53 @@ using builtin_u128 = std::_Unsigned128; # define BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE std::abort() #endif +#ifdef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE +# define BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR inline constexpr +# define BOOST_DECIMAL_DETAIL_INT128_EXPORT export +#else +# define BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR static constexpr +# define BOOST_DECIMAL_DETAIL_INT128_EXPORT +#endif + +// Detect if we can throw or not +// First check if the user said no explicitly +// Then check if it's been disabled elsewhere + +#ifdef BOOST_DECIMAL_DETAIL_INT128_DISABLE_EXCEPTIONS + +# define BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(expr) + +#else + +# ifdef _MSC_VER +# ifdef _CPPUNWIND +# define BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(expr) throw expr; +# else +# define BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(expr) +# define BOOST_DECIMAL_DETAIL_INT128_DISABLE_EXCEPTIONS +# endif +# else +# ifdef __EXCEPTIONS +# define BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(expr) throw expr; +# else +# define BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(expr) +# define BOOST_DECIMAL_DETAIL_INT128_DISABLE_EXCEPTIONS +# endif +#endif + +#endif // Exceptions + +#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L && __has_include() +# define BOOST_DECIMAL_DETAIL_INT128_HAS_SPACESHIP_OPERATOR +# ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE +# include +# endif +#endif + +#if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) +# define BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE __host__ __device__ +#else +# define BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE +#endif + #endif // BOOST_DECIMAL_DETAIL_INT128_DETAIL_CONFIG_HPP diff --git a/include/boost/decimal/detail/int128/detail/constants.hpp b/include/boost/decimal/detail/int128/detail/constants.hpp index 9e2024d4a..7299ed16f 100644 --- a/include/boost/decimal/detail/int128/detail/constants.hpp +++ b/include/boost/decimal/detail/int128/detail/constants.hpp @@ -5,17 +5,21 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_CONSTANTS_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_CONSTANTS_HPP +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { namespace detail { -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE std::uint64_t low_word_mask {(std::numeric_limits::max)()}; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR std::uint64_t low_word_mask {(std::numeric_limits::max)()}; template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE T offset_value_v = static_cast((std::numeric_limits::max)()); +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR T offset_value_v = static_cast((std::numeric_limits::max)()); } // namespace detail } // namespace int128 diff --git a/include/boost/decimal/detail/int128/detail/conversions.hpp b/include/boost/decimal/detail/int128/detail/conversions.hpp index c9d45528a..db2f2df8f 100644 --- a/include/boost/decimal/detail/int128/detail/conversions.hpp +++ b/include/boost/decimal/detail/int128/detail/conversions.hpp @@ -5,8 +5,8 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_CONVERSIONS_HPP #define BOOST_DECIMAL_DETAIL_INT128_CONVERSIONS_HPP -#include "int128_imp.hpp" -#include "uint128_imp.hpp" +#include +#include namespace boost { namespace int128 { @@ -20,68 +20,249 @@ struct valid_overload }; template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_valid_overload_v = valid_overload::value; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_valid_overload_v = valid_overload::value; } // namespace detail #if BOOST_DECIMAL_DETAIL_INT128_ENDIAN_LITTLE_BYTE -constexpr int128_t::int128_t(const uint128_t& v) noexcept : low {v.low}, high {static_cast(v.high)} {} +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t::int128_t(const uint128_t& v) noexcept : low {v.low}, high {static_cast(v.high)} {} -constexpr uint128_t::uint128_t(const int128_t& v) noexcept : low {v.low}, high {static_cast(v.high)} {} +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::uint128_t(const int128_t& v) noexcept : low {v.low}, high {static_cast(v.high)} {} #else -constexpr int128_t::int128_t(const uint128_t& v) noexcept : high {static_cast(v.high)}, low {v.low} {} +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t::int128_t(const uint128_t& v) noexcept : high {static_cast(v.high)}, low {v.low} {} -constexpr uint128_t::uint128_t(const int128_t& v) noexcept : high {static_cast(v.high)}, low {v.low} {} +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::uint128_t(const int128_t& v) noexcept : high {static_cast(v.high)}, low {v.low} {} #endif // BOOST_DECIMAL_DETAIL_INT128_ENDIAN_LITTLE_BYTE +//===================================== +// Conversion Operators +//===================================== + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t::operator uint128_t() const noexcept +{ + return uint128_t{static_cast(this->high), static_cast(this->low)}; +} + +BOOST_DECIMAL_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 //===================================== +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif + template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr bool operator==(T, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_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_DECIMAL_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 } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr bool operator!=(T, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_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_DECIMAL_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 } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr bool operator<(T, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_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_DECIMAL_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 false; + } + + return lhs < static_cast(rhs); + } + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr bool operator<=(T, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_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_DECIMAL_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 false; + } + + return lhs <= static_cast(rhs); + } + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr bool operator>(T, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_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_DECIMAL_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 true; + } + + return lhs > static_cast(rhs); + } + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr bool operator>=(T, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_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_DECIMAL_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 true; + } + + return lhs >= static_cast(rhs); + } + + #endif } //===================================== @@ -89,40 +270,89 @@ constexpr bool operator>=(T, U) noexcept //===================================== template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr T operator+(T lhs, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION + static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - return lhs; + static_cast(rhs); + return static_cast(lhs); + + #else + + return static_cast(lhs) + static_cast(rhs); + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr T operator-(T lhs, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION + static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - return lhs; + static_cast(rhs); + return static_cast(lhs); + + #else + + return static_cast(lhs) - static_cast(rhs); + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr T operator*(T lhs, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION + static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - return lhs; + static_cast(rhs); + return static_cast(lhs); + + #else + + return static_cast(lhs) * static_cast(rhs); + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr T operator/(T lhs, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION + static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - return lhs; + static_cast(rhs); + return static_cast(lhs); + + #else + + return static_cast(lhs) / static_cast(rhs); + + #endif } template && detail::is_valid_overload_v && !std::is_same::value, bool> = true> -constexpr T operator%(T lhs, U) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const T lhs, const U rhs) noexcept { + #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION + static_assert(std::is_same::value, "Sign Conversion Error, cast one type to the other for this operation"); - return lhs; + static_cast(rhs); + return static_cast(lhs); + + #else + + return static_cast(lhs) % static_cast(rhs); + + #endif } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace int128 } // namespace boost diff --git a/include/boost/decimal/detail/int128/detail/ctz.hpp b/include/boost/decimal/detail/int128/detail/ctz.hpp index 84c74a160..f05baf027 100644 --- a/include/boost/decimal/detail/int128/detail/ctz.hpp +++ b/include/boost/decimal/detail/int128/detail/ctz.hpp @@ -5,17 +5,22 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_CTZ_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_CTZ_HPP -#include "config.hpp" +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { namespace detail { namespace impl { -#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) +#if BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) constexpr int countr_impl(unsigned int x) noexcept { @@ -34,7 +39,9 @@ constexpr int countr_impl(unsigned long long x) noexcept #endif -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE int countr_mod37[37] = { +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR int countr_mod37[37] = { 32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, @@ -42,6 +49,8 @@ BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE int countr_mod37[37] = { 5, 20, 8, 19, 18 }; +#endif + #if defined(_MSC_VER) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) #pragma warning(push) @@ -70,15 +79,27 @@ constexpr int countr_impl(std::uint32_t x) noexcept #pragma warning(pop) -#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) +#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) || (defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #endif -constexpr int countr_impl(std::uint32_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_impl(std::uint32_t x) noexcept { + #if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + + constexpr int countr_mod37[37] = { + 32, 0, 1, 26, 2, 23, 27, 0, + 3, 16, 24, 30, 28, 11, 0, 13, + 4, 7, 17, 0, 25, 22, 31, 15, + 29, 10, 12, 6, 0, 21, 14, 9, + 5, 20, 8, 19, 18 + }; + + #endif + return countr_mod37[(-x & x) % 37]; } @@ -88,7 +109,7 @@ constexpr int countr_impl(std::uint32_t x) noexcept #endif -#if (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) +#if (defined(_M_AMD64) || defined(_M_ARM64)) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) constexpr int countr_impl(std::uint64_t x) noexcept { @@ -111,9 +132,9 @@ constexpr int countr_impl(std::uint64_t x) noexcept } } -#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) +#elif !BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN(__builtin_ctz) || (defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) -constexpr int countr_impl(std::uint64_t x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_impl(std::uint64_t x) noexcept { return static_cast(x) != 0 ? countr_impl(static_cast(x)) : countr_impl(static_cast(x >> 32)) + 32; @@ -124,7 +145,7 @@ constexpr int countr_impl(std::uint64_t x) noexcept } // namespace impl template -constexpr int countr_zero(T x) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int countr_zero(T x) noexcept { static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, "Can only count with unsigned integers"); diff --git a/include/boost/decimal/detail/int128/detail/fwd.hpp b/include/boost/decimal/detail/int128/detail/fwd.hpp index e451eb6cf..5ae031a20 100644 --- a/include/boost/decimal/detail/int128/detail/fwd.hpp +++ b/include/boost/decimal/detail/int128/detail/fwd.hpp @@ -5,11 +5,13 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_FWD_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_FWD_HPP +#include + namespace boost { namespace int128 { -struct uint128_t; -struct int128_t; +BOOST_DECIMAL_DETAIL_INT128_EXPORT struct uint128_t; +BOOST_DECIMAL_DETAIL_INT128_EXPORT struct int128_t; } // namespace int128 } // namespace boost diff --git a/include/boost/decimal/detail/int128/detail/int128_imp.hpp b/include/boost/decimal/detail/int128/detail/int128_imp.hpp index 3c1796fca..dd053e398 100644 --- a/include/boost/decimal/detail/int128/detail/int128_imp.hpp +++ b/include/boost/decimal/detail/int128/detail/int128_imp.hpp @@ -5,24 +5,27 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_INT128_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_INT128_HPP -#include "fwd.hpp" -#include "config.hpp" -#include "traits.hpp" -#include "constants.hpp" -#include "clz.hpp" -#include "common_mul.hpp" -#include "common_div.hpp" +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { struct - #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) + #if (defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128)) && !defined(_M_IX86) alignas(alignof(detail::builtin_i128)) - #else - alignas(16) #endif int128_t { @@ -52,205 +55,210 @@ int128_t constexpr int128_t& operator=(const int128_t&) noexcept = default; constexpr int128_t& operator=(int128_t&&) noexcept = default; - // Requires conversion file to be implemented - constexpr int128_t(const uint128_t& v) noexcept; + // Requires a conversion file to be implemented + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr int128_t(const uint128_t& v) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator uint128_t() const noexcept; // Construct from integral types #if BOOST_DECIMAL_DETAIL_INT128_ENDIAN_LITTLE_BYTE - constexpr int128_t(const std::int64_t hi, const std::uint64_t lo) noexcept : low{lo}, high{hi} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const std::int64_t hi, const std::uint64_t lo) noexcept : low{lo}, high{hi} {} template - constexpr int128_t(const SignedInteger v) noexcept : low {static_cast(v)}, high {v < 0 ? -1 : 0} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const SignedInteger v) noexcept : low {static_cast(v)}, high {v < 0 ? -1 : 0} {} template - constexpr int128_t(const UnsignedInteger v) noexcept : low {static_cast(v)}, high {} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const UnsignedInteger v) noexcept : low {static_cast(v)}, high {} {} #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t(const detail::builtin_i128 v) noexcept : low {static_cast(v & static_cast(detail::low_word_mask))}, high {static_cast(v >> static_cast(64U))} {} - BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t(const detail::builtin_u128 v) noexcept : low {static_cast(v & static_cast(detail::low_word_mask))}, high {static_cast(v >> static_cast(64U))} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t(const detail::builtin_i128 v) noexcept : low {static_cast(v & static_cast(detail::low_word_mask))}, high {static_cast(v >> static_cast(64U))} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t(const detail::builtin_u128 v) noexcept : low {static_cast(v & static_cast(detail::low_word_mask))}, high {static_cast(v >> static_cast(64U))} {} #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 #else // Big endian - constexpr int128_t(const std::int64_t hi, const std::uint64_t lo) noexcept : high{hi}, low{lo} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const std::int64_t hi, const std::uint64_t lo) noexcept : high{hi}, low{lo} {} template - constexpr int128_t(const SignedInteger v) noexcept : high{v < 0 ? -1 : 0}, low{static_cast(v)} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const SignedInteger v) noexcept : high{v < 0 ? -1 : 0}, low{static_cast(v)} {} template - constexpr int128_t(const UnsignedInteger v) noexcept : high {}, low {static_cast(v)} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t(const UnsignedInteger v) noexcept : high {}, low {static_cast(v)} {} #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 - constexpr int128_t(const detail::builtin_i128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v & detail::low_word_mask)} {} - constexpr int128_t(const detail::builtin_u128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v & detail::low_word_mask)} {} + BOOST_DECIMAL_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_DECIMAL_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)} {} #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 #endif // BOOST_DECIMAL_DETAIL_INT128_ENDIAN_LITTLE_BYTE // Integer Conversion operators - constexpr operator bool() const noexcept { return low || high; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator bool() const noexcept { return low || high; } template - explicit constexpr operator SignedInteger() const noexcept { return static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator SignedInteger() const noexcept { return static_cast(low); } template - explicit constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) - explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } - explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } #endif // BOOST_DECIMAL_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 - explicit constexpr operator float() const noexcept; - explicit constexpr operator double() const noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator float() const noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator double() const noexcept; + + // Long double does not exist on device + #if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) explicit constexpr operator long double() const noexcept; + #endif // Compound Or template - constexpr int128_t& operator|=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator|=(Integer rhs) noexcept; - constexpr int128_t& operator|=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator|=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator|=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator|=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound And template - constexpr int128_t& operator&=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator&=(Integer rhs) noexcept; - constexpr int128_t& operator&=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator&=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator&=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator&=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound XOR template - constexpr int128_t& operator^=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator^=(Integer rhs) noexcept; - constexpr int128_t& operator^=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator^=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator^=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator^=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Left Shift template - constexpr int128_t& operator<<=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator<<=(Integer rhs) noexcept; - constexpr int128_t& operator<<=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator<<=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator<<=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator<<=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Right Shift template - constexpr int128_t& operator>>=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator>>=(Integer rhs) noexcept; - constexpr int128_t& operator>>=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator>>=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator>>=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator>>=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Prefix and postfix increment - constexpr int128_t& operator++() noexcept; - constexpr int128_t& operator++(int) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator++() noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator++(int) noexcept; // Prefix and postfix decrment - constexpr int128_t& operator--() noexcept; - constexpr int128_t& operator--(int) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator--() noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator--(int) noexcept; // Compound Addition template - constexpr int128_t& operator+=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator+=(Integer rhs) noexcept; - constexpr int128_t& operator+=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator+=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator+=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator+=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Subtraction template - constexpr int128_t& operator-=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator-=(Integer rhs) noexcept; - constexpr int128_t& operator-=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator-=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator-=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator-=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Multiplication template - constexpr int128_t& operator*=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator*=(Integer rhs) noexcept; - constexpr int128_t& operator*=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator*=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator*=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator*=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Division template - constexpr int128_t& operator/=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator/=(Integer rhs) noexcept; - constexpr int128_t& operator/=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator/=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator/=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator/=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Modulo template - constexpr int128_t& operator%=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator%=(Integer rhs) noexcept; - constexpr int128_t& operator%=(int128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& operator%=(int128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline int128_t& operator%=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& operator%=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 }; @@ -259,7 +267,7 @@ int128_t // Absolute Value function //===================================== -constexpr int128_t abs(int128_t value) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t abs(int128_t value) noexcept { if (value.high < 0) { @@ -279,33 +287,37 @@ constexpr int128_t abs(int128_t value) noexcept // by 0xFFFFFFFF in order to generally replicate what ldexp is doing in the constexpr context. // We also avoid pulling in for the __float128 case where we would need ldexpq -constexpr int128_t::operator float() const noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t::operator float() const noexcept { return static_cast(high) * detail::offset_value_v + static_cast(low); } -constexpr int128_t::operator double() const noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t::operator double() const noexcept { return static_cast(high) * detail::offset_value_v + static_cast(low); } +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + constexpr int128_t::operator long double() const noexcept { return static_cast(high) * detail::offset_value_v + static_cast(low); } +#endif + //===================================== // Unary Operators //===================================== -constexpr int128_t operator+(const int128_t value) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const int128_t value) noexcept { return value; } -constexpr int128_t operator-(const int128_t value) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const int128_t value) noexcept { - return (value.low == 0) ? int128_t{-value.high, 0} : + return (value.low == 0) ? int128_t{static_cast(0ULL - static_cast(value.high)), 0} : int128_t{~value.high, ~value.low + 1}; } @@ -313,12 +325,12 @@ constexpr int128_t operator-(const int128_t value) noexcept // Equality Operators //===================================== -constexpr bool operator==(const int128_t lhs, const bool rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const int128_t lhs, const bool rhs) noexcept { return lhs.high == 0 && lhs.low == static_cast(rhs); } -constexpr bool operator==(const bool lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const bool lhs, const int128_t rhs) noexcept { return rhs.high == 0 && rhs.low == static_cast(lhs); } @@ -333,7 +345,7 @@ constexpr bool operator==(const bool lhs, const int128_t rhs) noexcept # pragma GCC diagnostic ignored "-Wsign-compare" #endif -constexpr bool operator==(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const int128_t lhs, const int128_t rhs) noexcept { // x64 and ARM64 like the values in opposite directions @@ -348,20 +360,20 @@ constexpr bool operator==(const int128_t lhs, const int128_t rhs) noexcept #endif } -template -constexpr bool operator==(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const int128_t lhs, const SignedInteger rhs) noexcept { return lhs.high == (rhs < 0 ? -1 : 0) && lhs.low == static_cast(rhs); } -template -constexpr bool operator==(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const SignedInteger lhs, const int128_t rhs) noexcept { return rhs.high == (lhs < 0 ? -1 : 0) && rhs.low == static_cast(lhs); } -template -constexpr bool operator==(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -377,8 +389,8 @@ constexpr bool operator==(const int128_t lhs, const UnsignedInteger rhs) noexcep #endif } -template -constexpr bool operator==(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -396,39 +408,39 @@ constexpr bool operator==(const UnsignedInteger lhs, const int128_t rhs) noexcep #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs == static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) == rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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 -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const int128_t, const T) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const int128_t) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; @@ -442,7 +454,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const int // Inequality Operators //===================================== -constexpr bool operator!=(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const int128_t lhs, const int128_t rhs) noexcept { // x64 and ARM64 like the values in opposite directions @@ -474,30 +486,30 @@ constexpr bool operator!=(const int128_t lhs, const int128_t rhs) noexcept #endif } -constexpr bool operator!=(const int128_t lhs, const bool rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const int128_t lhs, const bool rhs) noexcept { return lhs.high != 0 || lhs.low != static_cast(rhs); } -constexpr bool operator!=(const bool lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const bool lhs, const int128_t rhs) noexcept { return rhs.high != 0 || rhs.low != static_cast(lhs); } -template -constexpr bool operator!=(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const int128_t lhs, const SignedInteger rhs) noexcept { return lhs.high != (rhs < 0 ? -1 : 0) || lhs.low != static_cast(rhs); } -template -constexpr bool operator!=(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const SignedInteger lhs, const int128_t rhs) noexcept { return rhs.high != (lhs < 0 ? -1 : 0) || rhs.low != static_cast(lhs); } -template -constexpr bool operator!=(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -513,8 +525,8 @@ constexpr bool operator!=(const int128_t lhs, const UnsignedInteger rhs) noexcep #endif } -template -constexpr bool operator!=(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -532,39 +544,39 @@ constexpr bool operator!=(const UnsignedInteger lhs, const int128_t rhs) noexcep #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs != static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) != rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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 -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const int128_t, const T) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const int128_t) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; @@ -578,7 +590,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const int // Less than Operators //===================================== -constexpr bool operator<(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const int128_t lhs, const int128_t rhs) noexcept { // On ARM macs only with the clang compiler is casting to __int128 uniformly better (and seemingly cost free) #if defined(__aarch64__) && defined(__APPLE__) && defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -609,8 +621,8 @@ constexpr bool operator<(const int128_t lhs, const int128_t rhs) noexcept #endif } -template -constexpr bool operator<(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -626,8 +638,8 @@ constexpr bool operator<(const int128_t lhs, const UnsignedInteger rhs) noexcept #endif } -template -constexpr bool operator<(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -643,8 +655,8 @@ constexpr bool operator<(const UnsignedInteger lhs, const int128_t rhs) noexcept #endif } -template -constexpr bool operator<(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const int128_t lhs, const SignedInteger rhs) noexcept { if (lhs.high < 0) { @@ -659,8 +671,8 @@ constexpr bool operator<(const int128_t lhs, const SignedInteger rhs) noexcept return lhs.low < static_cast(rhs); } -template -constexpr bool operator<(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const SignedInteger lhs, const int128_t rhs) noexcept { if (rhs.high < 0) { @@ -678,39 +690,39 @@ constexpr bool operator<(const SignedInteger lhs, const int128_t rhs) noexcept #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs < static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) < rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const int128_t, const T) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const int128_t) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; @@ -724,7 +736,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const int1 // Greater than Operators //===================================== -constexpr bool operator>(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const int128_t lhs, const int128_t rhs) noexcept { // On ARM macs only with the clang compiler is casting to __int128 uniformly better (and seemingly cost free) #if defined(__aarch64__) && defined(__APPLE__) && defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -755,20 +767,20 @@ constexpr bool operator>(const int128_t lhs, const int128_t rhs) noexcept #endif } -template -constexpr bool operator>(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const int128_t lhs, const SignedInteger rhs) noexcept { return !(lhs < rhs) && !(lhs == rhs); } -template -constexpr bool operator>(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const SignedInteger lhs, const int128_t rhs) noexcept { return !(lhs < rhs) && !(lhs == rhs); } -template -constexpr bool operator>(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -784,8 +796,8 @@ constexpr bool operator>(const int128_t lhs, const UnsignedInteger rhs) noexcept #endif } -template -constexpr bool operator>(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -803,39 +815,39 @@ constexpr bool operator>(const UnsignedInteger lhs, const int128_t rhs) noexcept #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs > static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) > rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const int128_t, const T) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const int128_t) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; @@ -849,7 +861,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const int1 // Less Equal Operators //===================================== -constexpr bool operator<=(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const int128_t lhs, const int128_t rhs) noexcept { // On ARM macs only with the clang compiler is casting to __int128 uniformly better (and seemingly cost free) #if defined(__aarch64__) && defined(__APPLE__) && defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -880,20 +892,20 @@ constexpr bool operator<=(const int128_t lhs, const int128_t rhs) noexcept #endif } -template -constexpr bool operator<=(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const int128_t lhs, const SignedInteger rhs) noexcept { return !(lhs > rhs); } -template -constexpr bool operator<=(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const SignedInteger lhs, const int128_t rhs) noexcept { return !(lhs > rhs); } -template -constexpr bool operator<=(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -909,8 +921,8 @@ constexpr bool operator<=(const int128_t lhs, const UnsignedInteger rhs) noexcep #endif } -template -constexpr bool operator<=(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -928,39 +940,39 @@ constexpr bool operator<=(const UnsignedInteger lhs, const int128_t rhs) noexcep #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs <= static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) <= rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const int128_t, const T) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const int128_t) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; @@ -974,7 +986,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const int // Greater Equal Operators //===================================== -constexpr bool operator>=(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const int128_t lhs, const int128_t rhs) noexcept { // On ARM macs only with the clang compiler is casting to __int128 uniformly better (and seemingly cost free) #if defined(__aarch64__) && defined(__APPLE__) && defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -1005,20 +1017,20 @@ constexpr bool operator>=(const int128_t lhs, const int128_t rhs) noexcept #endif } -template -constexpr bool operator>=(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const int128_t lhs, const SignedInteger rhs) noexcept { return !(lhs < rhs); } -template -constexpr bool operator>=(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const SignedInteger lhs, const int128_t rhs) noexcept { return !(lhs < rhs); } -template -constexpr bool operator>=(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -1034,8 +1046,8 @@ constexpr bool operator>=(const int128_t lhs, const UnsignedInteger rhs) noexcep #endif } -template -constexpr bool operator>=(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -1053,39 +1065,39 @@ constexpr bool operator>=(const UnsignedInteger lhs, const int128_t rhs) noexcep #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs >= static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) >= rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const int128_t, const T) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const int128_t) noexcept { static_assert(detail::is_signed_integer_v, "Sign Compare Error"); return true; @@ -1095,11 +1107,125 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const int #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 +//===================================== +// Spaceship Operator +//===================================== + +#ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_SPACESHIP_OPERATOR + +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const int128_t lhs, const int128_t rhs) noexcept +{ + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + return std::strong_ordering::greater; + } +} + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const int128_t lhs, const SignedInteger rhs) noexcept +{ + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + return std::strong_ordering::greater; + } +} + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const SignedInteger lhs, const int128_t rhs) noexcept +{ + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + return std::strong_ordering::greater; + } +} + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const int128_t lhs, const UnsignedInteger rhs) noexcept +{ + #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE + + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + 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_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const UnsignedInteger lhs, const int128_t rhs) noexcept +{ + #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE + + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + 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 + //===================================== // Not Operator //===================================== -constexpr int128_t operator~(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator~(const int128_t rhs) noexcept { return {~rhs.high, ~rhs.low}; } @@ -1108,25 +1234,25 @@ constexpr int128_t operator~(const int128_t rhs) noexcept // Or Operator //===================================== -constexpr int128_t operator|(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const int128_t rhs) noexcept { return {lhs.high | rhs.high, lhs.low | rhs.low}; } -template -constexpr int128_t operator|(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const SignedInteger rhs) noexcept { return {lhs.high | (rhs < 0 ? -1 : 0), lhs.low | static_cast(rhs)}; } -template -constexpr int128_t operator|(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const SignedInteger lhs, const int128_t rhs) noexcept { return {rhs.high | (lhs < 0 ? -1 : 0), static_cast(lhs) | rhs.low}; } -template -constexpr int128_t operator|(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1142,8 +1268,8 @@ constexpr int128_t operator|(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator|(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1161,39 +1287,39 @@ constexpr int128_t operator|(const UnsignedInteger lhs, const int128_t rhs) noex #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 -constexpr int128_t operator|(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs | static_cast(rhs); } -constexpr int128_t operator|(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator|(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator|(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs | static_cast(rhs); } -constexpr int128_t operator|(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -constexpr int128_t operator|(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr int128_t operator|(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -1208,7 +1334,7 @@ constexpr int128_t operator|(const T, const int128_t) noexcept //===================================== template -constexpr int128_t& int128_t::operator|=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator|=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -1218,7 +1344,7 @@ constexpr int128_t& int128_t::operator|=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator|=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator|=(const int128_t rhs) noexcept { *this = *this | rhs; return *this; @@ -1227,7 +1353,7 @@ constexpr int128_t& int128_t::operator|=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator|=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator|=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1243,25 +1369,25 @@ inline int128_t& int128_t::operator|=(const Integer rhs) noexcept // And Operator //===================================== -constexpr int128_t operator&(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const int128_t rhs) noexcept { return {lhs.high & rhs.high, lhs.low & rhs.low}; } -template -constexpr int128_t operator&(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const SignedInteger rhs) noexcept { return {lhs.high & (rhs < 0 ? -1 : 0), lhs.low & static_cast(rhs)}; } -template -constexpr int128_t operator&(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const SignedInteger lhs, const int128_t rhs) noexcept { return {rhs.high & (lhs < 0 ? -1 : 0), static_cast(lhs) & rhs.low}; } -template -constexpr int128_t operator&(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1277,8 +1403,8 @@ constexpr int128_t operator&(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator&(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1296,39 +1422,39 @@ constexpr int128_t operator&(const UnsignedInteger lhs, const int128_t rhs) noex #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 -constexpr int128_t operator&(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs & static_cast(rhs); } -constexpr int128_t operator&(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator&(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator&(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs & static_cast(rhs); } -constexpr int128_t operator&(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -constexpr int128_t operator&(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr int128_t operator&(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -1341,7 +1467,7 @@ constexpr int128_t operator&(const T, const int128_t) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator&=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator&=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1358,7 +1484,7 @@ inline int128_t& int128_t::operator&=(const Integer rhs) noexcept //===================================== template -constexpr int128_t& int128_t::operator&=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator&=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -1368,7 +1494,7 @@ constexpr int128_t& int128_t::operator&=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator&=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator&=(const int128_t rhs) noexcept { *this = *this & rhs; return *this; @@ -1378,25 +1504,25 @@ constexpr int128_t& int128_t::operator&=(const int128_t rhs) noexcept // XOR Operator //===================================== -constexpr int128_t operator^(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const int128_t rhs) noexcept { return {lhs.high ^ rhs.high, lhs.low ^ rhs.low}; } -template -constexpr int128_t operator^(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const SignedInteger rhs) noexcept { return {lhs.high ^ (rhs < 0 ? -1 : 0), lhs.low ^ static_cast(rhs)}; } -template -constexpr int128_t operator^(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const SignedInteger lhs, const int128_t rhs) noexcept { return {rhs.high ^ (lhs < 0 ? -1 : 0), static_cast(lhs) ^ rhs.low}; } -template -constexpr int128_t operator^(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1412,8 +1538,8 @@ constexpr int128_t operator^(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator^(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1424,46 +1550,46 @@ constexpr int128_t operator^(const UnsignedInteger lhs, const int128_t rhs) noex static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); static_cast(lhs); static_cast(rhs); - return true; + return int128_t{}; #endif } #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 -constexpr int128_t operator^(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs ^ static_cast(rhs); } -constexpr int128_t operator^(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator^(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator^(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs ^ static_cast(rhs); } -constexpr int128_t operator^(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -constexpr int128_t operator^(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr int128_t operator^(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -1478,7 +1604,7 @@ constexpr int128_t operator^(const T, const int128_t) noexcept //===================================== template -constexpr int128_t& int128_t::operator^=(Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator^=(Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -1488,7 +1614,7 @@ constexpr int128_t& int128_t::operator^=(Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator^=(int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator^=(int128_t rhs) noexcept { *this = *this ^ rhs; return *this; @@ -1497,7 +1623,7 @@ constexpr int128_t& int128_t::operator^=(int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator^=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator^=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1516,11 +1642,23 @@ inline int128_t& int128_t::operator^=(const Integer rhs) noexcept namespace detail { template -constexpr int128_t default_ls_impl(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t default_ls_impl(const int128_t lhs, const Integer rhs) noexcept { - if (rhs < 0 || rhs >= 128) + static_assert(std::is_integral::value, "Only builtin types allowed"); + + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (rhs < 0 || rhs >= 128) + { + return {0, 0}; + } + } + else + { + if (rhs >= 128) + { + return {0, 0}; + } } if (rhs == 0) @@ -1549,11 +1687,21 @@ constexpr int128_t default_ls_impl(const int128_t lhs, const Integer rhs) noexce } template -int128_t intrinsic_ls_impl(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE int128_t intrinsic_ls_impl(const int128_t lhs, const Integer rhs) noexcept { - if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + { + return {0, 0}; + } + } + else + { + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128)) + { + return {0, 0}; + } } #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 @@ -1628,8 +1776,8 @@ int128_t intrinsic_ls_impl(const int128_t lhs, const Integer rhs) noexcept } // namespace detail -template -constexpr int128_t operator<<(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator<<(const int128_t lhs, const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION @@ -1649,10 +1797,21 @@ constexpr int128_t operator<<(const int128_t lhs, const Integer rhs) noexcept #endif } -template && (sizeof(Integer) * 8 > 16), bool> = true> -constexpr Integer operator<<(const Integer lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator<<(const int128_t lhs, const int128_t rhs) noexcept { - constexpr auto bit_width {sizeof(Integer) * 8}; + if (rhs.high != 0 || rhs.low >= 128) + { + return 0; + } + + return lhs << rhs.low; +} + +#ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 + +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator<<(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +{ + constexpr auto bit_width {sizeof(detail::builtin_u128) * 8}; if (rhs.high != 0 || rhs.low >= bit_width) { @@ -1662,8 +1821,22 @@ constexpr Integer operator<<(const Integer lhs, const int128_t rhs) noexcept return lhs << rhs.low; } -template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> -constexpr int operator<<(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator<<(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +{ + constexpr auto bit_width {sizeof(detail::builtin_i128) * 8}; + + if (rhs.high != 0 || rhs.low >= bit_width) + { + return 0; + } + + return lhs << rhs.low; +} + +#endif + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int operator<<(const SignedInteger lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(SignedInteger) * 8}; @@ -1675,8 +1848,8 @@ constexpr int operator<<(const SignedInteger lhs, const int128_t rhs) noexcept return static_cast(lhs) << rhs.low; } -template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> -constexpr unsigned operator<<(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr unsigned operator<<(const UnsignedInteger lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(UnsignedInteger) * 8}; @@ -1694,13 +1867,13 @@ constexpr unsigned operator<<(const UnsignedInteger lhs, const int128_t rhs) noe #endif // _MSC_VER template -constexpr int128_t& int128_t::operator<<=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator<<=(const Integer rhs) noexcept { *this = *this << rhs; return *this; } -constexpr int128_t& int128_t::operator<<=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator<<=(const int128_t rhs) noexcept { *this = *this << rhs; return *this; @@ -1709,7 +1882,7 @@ constexpr int128_t& int128_t::operator<<=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator<<=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator<<=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1732,11 +1905,21 @@ inline int128_t& int128_t::operator<<=(const Integer rhs) noexcept namespace detail { template -constexpr int128_t default_rs_impl(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t default_rs_impl(const int128_t lhs, const Integer rhs) noexcept { - if (rhs >= 128 || rhs < 0 ) + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return lhs.high < 0 ? int128_t{-1, UINT64_MAX} : int128_t{0, 0}; + if (rhs >= 128 || rhs < 0) + { + return lhs.high < 0 ? int128_t{-1, UINT64_MAX} : int128_t{0, 0}; + } + } + else + { + if (rhs >= 128) + { + return lhs.high < 0 ? int128_t{-1, UINT64_MAX} : int128_t{0, 0}; + } } if (rhs == 0) @@ -1761,11 +1944,21 @@ constexpr int128_t default_rs_impl(const int128_t lhs, const Integer rhs) noexce } template -int128_t intrinsic_rs_impl(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE int128_t intrinsic_rs_impl(const int128_t lhs, const Integer rhs) noexcept { - if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (rhs >= 128 || rhs < 0) + { + return lhs.high < 0 ? int128_t{-1, UINT64_MAX} : int128_t{0, 0}; + } + } + else + { + if (rhs >= 128) + { + return lhs.high < 0 ? int128_t{-1, UINT64_MAX} : int128_t{0, 0}; + } } #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 @@ -1837,8 +2030,8 @@ int128_t intrinsic_rs_impl(const int128_t lhs, const Integer rhs) noexcept } // namespace detail -template -constexpr int128_t operator>>(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator>>(const int128_t lhs, const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION @@ -1858,10 +2051,21 @@ constexpr int128_t operator>>(const int128_t lhs, const Integer rhs) noexcept #endif } -template && (sizeof(Integer) * 8 > 16), bool> = true> -constexpr Integer operator>>(const Integer lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator>>(const int128_t lhs, const int128_t rhs) noexcept +{ + if (rhs.high != 0 || rhs.low >= 128) + { + return 0; + } + + return lhs >> rhs.low; +} + +#ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 + +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator>>(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { - constexpr auto bit_width {sizeof(Integer) * 8}; + constexpr auto bit_width {sizeof(detail::builtin_u128) * 8}; if (rhs.high != 0 || rhs.low >= bit_width) { @@ -1871,8 +2075,22 @@ constexpr Integer operator>>(const Integer lhs, const int128_t rhs) noexcept return lhs >> rhs.low; } -template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> -constexpr int operator>>(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator>>(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +{ + constexpr auto bit_width {sizeof(detail::builtin_i128) * 8}; + + if (rhs.high != 0 || rhs.low >= bit_width) + { + return 0; + } + + return lhs >> rhs.low; +} + +#endif + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int operator>>(const SignedInteger lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(SignedInteger) * 8}; @@ -1884,8 +2102,8 @@ constexpr int operator>>(const SignedInteger lhs, const int128_t rhs) noexcept return static_cast(lhs) >> rhs.low; } -template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> -constexpr unsigned operator>>(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr unsigned operator>>(const UnsignedInteger lhs, const int128_t rhs) noexcept { constexpr auto bit_width {sizeof(UnsignedInteger) * 8}; @@ -1903,13 +2121,13 @@ constexpr unsigned operator>>(const UnsignedInteger lhs, const int128_t rhs) noe #endif // _MSC_VER template -constexpr int128_t& int128_t::operator>>=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator>>=(const Integer rhs) noexcept { *this = *this >> rhs; return *this; } -constexpr int128_t& int128_t::operator>>=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator>>=(const int128_t rhs) noexcept { *this = *this >> rhs; return *this; @@ -1918,7 +2136,7 @@ constexpr int128_t& int128_t::operator>>=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator>>=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator>>=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1938,7 +2156,7 @@ inline int128_t& int128_t::operator>>=(const Integer rhs) noexcept // Increment Operators //===================================== -constexpr int128_t& int128_t::operator++() noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator++() noexcept { if (++low == UINT64_C(0)) { @@ -1948,21 +2166,18 @@ constexpr int128_t& int128_t::operator++() noexcept return *this; } -constexpr int128_t& int128_t::operator++(int) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t int128_t::operator++(int) noexcept { - if (++low == UINT64_C(0)) - { - ++high; - } - - return *this; + const auto temp {*this}; + ++(*this); + return temp; } //===================================== // Decrement Operators //===================================== -constexpr int128_t& int128_t::operator--() noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator--() noexcept { if (low-- == UINT64_C(0)) { @@ -1972,14 +2187,11 @@ constexpr int128_t& int128_t::operator--() noexcept return *this; } -constexpr int128_t& int128_t::operator--(int) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t int128_t::operator--(int) noexcept { - if (low-- == UINT64_C(0)) - { - --high; - } - - return *this; + const auto temp {*this}; + --(*this); + return temp; } //===================================== @@ -1988,7 +2200,7 @@ constexpr int128_t& int128_t::operator--(int) noexcept namespace detail { -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_add(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_add(const int128_t lhs, const int128_t rhs) noexcept { const auto new_low {lhs.low + rhs.low}; const auto new_high {static_cast(lhs.high) + @@ -1998,7 +2210,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_add(const in return int128_t{static_cast(new_high), new_low}; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const int128_t lhs, const int128_t rhs) noexcept { #if (defined(__x86_64__) || (defined(__aarch64__) && !defined(__APPLE__))) && !defined(_WIN32) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -2013,33 +2225,6 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const in return int128_t{static_cast(result_high), result_low}; - #elif defined(__aarch64__) && !defined(__APPLE__) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) && defined(__GNUC__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) - - if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) - { - return library_add(lhs, rhs); - } - else - { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wclass-memaccess" - - detail::builtin_i128 builtin_lhs {}; - detail::builtin_i128 builtin_rhs {}; - - std::memcpy(&builtin_lhs, &lhs, sizeof(builtin_i128)); - std::memcpy(&builtin_rhs, &rhs, sizeof(builtin_i128)); - - auto builtin_res {builtin_lhs + builtin_rhs}; - - int128_t result {}; - std::memcpy(&result, &builtin_res, sizeof(int128_t)); - - return result; - - #pragma GCC diagnostic pop - } - #elif defined(_M_AMD64) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) @@ -2063,7 +2248,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const in } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const int128_t lhs, const Integer rhs) noexcept { const auto new_low {lhs.low + rhs}; const auto new_high {static_cast(lhs.high) + static_cast(new_low < lhs.low)}; @@ -2071,7 +2256,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_add(const in return int128_t{static_cast(new_high), new_low}; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_sub(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_sub(const int128_t lhs, const int128_t rhs) noexcept { const auto new_low {lhs.low - rhs.low}; const auto new_high {static_cast(lhs.high) - static_cast(rhs.high) - static_cast(lhs.low < rhs.low)}; @@ -2079,9 +2264,9 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_sub(const in return int128_t{static_cast(new_high), new_low}; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const int128_t lhs, const int128_t rhs) noexcept { - #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_SUB_OVERFLOW) && (!defined(__aarch64__) || defined(__APPLE__) || !defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128)) + #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_SUB_OVERFLOW) && (!defined(__aarch64__) || defined(__APPLE__) || !defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128)) && !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) // __builtin_sub_overflow is marked constexpr so we don't need if consteval handling std::uint64_t result_low {}; @@ -2089,7 +2274,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const in return int128_t{static_cast(result_high), result_low}; - #elif defined(__aarch64__) && !defined(__APPLE__) && !defined(BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION) + #elif defined(__aarch64__) && !defined(__APPLE__) return static_cast(static_cast(lhs) - static_cast(rhs)); @@ -2116,7 +2301,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const in } template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const int128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const int128_t lhs, const Integer rhs) noexcept { const auto new_low {lhs.low - rhs}; const auto new_high {static_cast(lhs.high) - static_cast(new_low > lhs.low)}; @@ -2129,22 +2314,22 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_sub(const in // doing addition via subtraction is >10% faster in the benchmarks #if defined(__s390__) || defined(__s390x__) -constexpr int128_t operator+(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const int128_t lhs, const int128_t rhs) noexcept { return detail::default_sub(lhs, -rhs); } #else -constexpr int128_t operator+(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const int128_t lhs, const int128_t rhs) noexcept { return detail::default_add(lhs, rhs); } #endif -template -constexpr int128_t operator+(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2160,8 +2345,8 @@ constexpr int128_t operator+(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator+(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2177,14 +2362,14 @@ constexpr int128_t operator+(const UnsignedInteger lhs, const int128_t rhs) noex #endif } -template -constexpr int128_t operator+(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const int128_t lhs, const SignedInteger rhs) noexcept { return rhs > 0 ? detail::default_add(lhs, rhs) : detail::default_sub(lhs, -rhs); } -template -constexpr int128_t operator+(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator+(const SignedInteger lhs, const int128_t rhs) noexcept { return lhs > 0 ? detail::default_add(rhs, lhs) : detail::default_sub(rhs, -lhs); } @@ -2193,27 +2378,27 @@ constexpr int128_t operator+(const SignedInteger lhs, const int128_t rhs) noexce #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2221,12 +2406,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const T, const #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return detail::default_add(lhs, static_cast(rhs)); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return detail::default_add(rhs, static_cast(lhs)); } @@ -2234,7 +2419,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::b #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr int128_t& int128_t::operator+=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator+=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -2244,7 +2429,7 @@ constexpr int128_t& int128_t::operator+=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator+=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator+=(const int128_t rhs) noexcept { *this = *this + rhs; return *this; @@ -2253,7 +2438,7 @@ constexpr int128_t& int128_t::operator+=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator+=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator+=(const Integer rhs) noexcept { *this = *this + rhs; return *this; @@ -2265,13 +2450,13 @@ inline int128_t& int128_t::operator+=(const Integer rhs) noexcept // Subtraction Operators //===================================== -constexpr int128_t operator-(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const int128_t lhs, const int128_t rhs) noexcept { return detail::default_sub(lhs, rhs); } -template -constexpr int128_t operator-(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2287,8 +2472,8 @@ constexpr int128_t operator-(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator-(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2304,14 +2489,14 @@ constexpr int128_t operator-(const UnsignedInteger lhs, const int128_t rhs) noex #endif } -template -constexpr int128_t operator-(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const int128_t lhs, const SignedInteger rhs) noexcept { return detail::default_sub(lhs, static_cast(rhs)); } -template -constexpr int128_t operator-(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator-(const SignedInteger lhs, const int128_t rhs) noexcept { return detail::default_sub(static_cast(lhs), rhs); } @@ -2320,27 +2505,27 @@ constexpr int128_t operator-(const SignedInteger lhs, const int128_t rhs) noexce #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs - static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const detail::builtin_u128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) - rhs; } #else // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2348,12 +2533,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const T, const #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs - static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) - rhs; } @@ -2361,7 +2546,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR int128_t operator-(const detail::b #endif template -constexpr int128_t& int128_t::operator-=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator-=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -2371,7 +2556,7 @@ constexpr int128_t& int128_t::operator-=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator-=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator-=(const int128_t rhs) noexcept { *this = *this - rhs; return *this; @@ -2380,7 +2565,7 @@ constexpr int128_t& int128_t::operator-=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator-=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator-=(const Integer rhs) noexcept { *this = *this - rhs; return *this; @@ -2394,12 +2579,12 @@ inline int128_t& int128_t::operator-=(const Integer rhs) noexcept namespace detail { -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t signed_shift_left_32(const std::uint64_t low) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_mul(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2412,7 +2597,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t library_mul(const in return result; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const int128_t lhs, const std::uint64_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2435,7 +2620,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const in return {high_res, low_res}; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const int128_t lhs, const std::uint32_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2449,7 +2634,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const in #if defined(_M_AMD64) && !defined(__GNUC__) -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE int128_t msvc_amd64_mul(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE int128_t msvc_amd64_mul(const int128_t lhs, const int128_t rhs) noexcept { int128_t result {}; result.low = _umul128(lhs.low, rhs.low, reinterpret_cast(&result.high)); @@ -2461,7 +2646,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE int128_t msvc_amd64_mul(const int128_t #endif -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const int128_t lhs, const int128_t rhs) noexcept { #if ((defined(__aarch64__) && defined(__APPLE__)) || defined(__x86_64__) || defined(__PPC__) || defined(__powerpc__)) && defined(__GNUC__) && !defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -2544,13 +2729,13 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr int128_t default_mul(const in } // namespace detail -constexpr int128_t operator*(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const int128_t rhs) noexcept { return detail::default_mul(lhs, rhs); } -template -constexpr int128_t operator*(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2567,8 +2752,8 @@ constexpr int128_t operator*(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator*(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2590,15 +2775,15 @@ constexpr int128_t operator*(const UnsignedInteger lhs, const int128_t rhs) noex # pragma warning(disable : 4146) // Unary minus applied to unsigned #endif -template -constexpr int128_t operator*(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const SignedInteger rhs) noexcept { return rhs < 0 ? -detail::default_mul(lhs, -static_cast(rhs)) : detail::default_mul(lhs, static_cast(rhs)); } -template -constexpr int128_t operator*(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const SignedInteger lhs, const int128_t rhs) noexcept { return lhs < 0 ? -detail::default_mul(rhs, -static_cast(lhs)) : detail::default_mul(rhs, static_cast(lhs)); @@ -2612,27 +2797,27 @@ constexpr int128_t operator*(const SignedInteger lhs, const int128_t rhs) noexce #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator*(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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); } -constexpr int128_t operator*(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -constexpr int128_t operator*(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr int128_t operator*(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -2640,12 +2825,12 @@ constexpr int128_t operator*(const T, const int128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator*(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return detail::default_mul(lhs, static_cast(rhs)); } -constexpr int128_t operator*(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator*(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return detail::default_mul(rhs, static_cast(lhs)); } @@ -2653,7 +2838,7 @@ constexpr int128_t operator*(const detail::builtin_i128 lhs, const int128_t rhs) #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr int128_t& int128_t::operator*=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator*=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -2663,7 +2848,7 @@ constexpr int128_t& int128_t::operator*=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator*=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator*=(const int128_t rhs) noexcept { *this = *this * rhs; return *this; @@ -2672,7 +2857,7 @@ constexpr int128_t& int128_t::operator*=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator*=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator*=(const Integer rhs) noexcept { *this = *this * rhs; return *this; @@ -2689,25 +2874,25 @@ inline int128_t& int128_t::operator*=(const Integer rhs) noexcept # pragma clang diagnostic ignored "-Wassume" #endif -constexpr int128_t operator/(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const int128_t rhs) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs == 0)) { return {0, 0}; } + constexpr int128_t min_val {INT64_MIN, 0}; const auto abs_lhs {abs(lhs)}; const auto abs_rhs {abs(rhs)}; - if (abs_lhs < abs_rhs) + if (lhs != min_val && abs_lhs < abs_rhs) { return {0,0}; } #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) - else - { - return static_cast(static_cast(lhs) / static_cast(rhs)); - } + + return static_cast(static_cast(lhs) / static_cast(rhs)); + #else int128_t quotient {}; @@ -2733,8 +2918,8 @@ constexpr int128_t operator/(const int128_t lhs, const int128_t rhs) noexcept #endif } -template -constexpr int128_t operator/(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2761,8 +2946,8 @@ constexpr int128_t operator/(const int128_t lhs, const UnsignedInteger rhs) noex #endif } -template -constexpr int128_t operator/(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2779,7 +2964,8 @@ constexpr int128_t operator/(const UnsignedInteger lhs, const int128_t rhs) noex { auto abs_rhs {abs(rhs)}; const auto res {static_cast(lhs) / abs_rhs.low}; - return int128_t{rhs.high, res}; + const int128_t result {0, res}; + return rhs < 0 ? -result : result; } #else @@ -2792,8 +2978,8 @@ constexpr int128_t operator/(const UnsignedInteger lhs, const int128_t rhs) noex #endif } -template -constexpr int128_t operator/(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const SignedInteger rhs) noexcept { using eval_type = detail::evaluation_type_t; @@ -2804,16 +2990,23 @@ constexpr int128_t operator/(const int128_t lhs, const SignedInteger rhs) noexce int128_t quotient {}; + constexpr int128_t min_val {INT64_MIN, 0}; const auto negative_res {static_cast((lhs.high < 0) ^ (rhs < 0))}; const auto abs_rhs {rhs < 0 ? -rhs : rhs}; const auto abs_lhs {abs(lhs)}; + + if (lhs != min_val && abs_lhs < abs_rhs) + { + return {0, 0}; + } + detail::one_word_div(abs_lhs, static_cast(abs_rhs), quotient); return negative_res ? -quotient : quotient; } -template -constexpr int128_t operator/(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const SignedInteger lhs, const int128_t rhs) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs == 0)) { @@ -2839,27 +3032,27 @@ constexpr int128_t operator/(const SignedInteger lhs, const int128_t rhs) noexce #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator/(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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); } -constexpr int128_t operator/(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -constexpr int128_t operator/(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr int128_t operator/(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -2867,12 +3060,12 @@ constexpr int128_t operator/(const T, const int128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return static_cast(static_cast(lhs) / rhs); } -constexpr int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs / static_cast(rhs)); } @@ -2881,27 +3074,27 @@ constexpr int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -inline int128_t operator/(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs / static_cast(rhs); } -inline int128_t operator/(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -inline int128_t operator/(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -inline int128_t operator/(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -2909,12 +3102,12 @@ inline int128_t operator/(const T, const int128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -inline int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs / static_cast(rhs); } -inline int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) / rhs; } @@ -2922,7 +3115,7 @@ inline int128_t operator/(const detail::builtin_i128 lhs, const int128_t rhs) no #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr int128_t& int128_t::operator/=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator/=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -2932,7 +3125,7 @@ constexpr int128_t& int128_t::operator/=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator/=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator/=(const int128_t rhs) noexcept { *this = *this / rhs; return *this; @@ -2941,7 +3134,7 @@ constexpr int128_t& int128_t::operator/=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator/=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator/=(const Integer rhs) noexcept { *this = *this / rhs; return *this; @@ -2959,22 +3152,22 @@ inline int128_t& int128_t::operator/=(const Integer rhs) noexcept // Modulo Operator //===================================== -template -constexpr int128_t operator%(int128_t lhs, UnsignedInteger rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(int128_t lhs, UnsignedInteger rhs) noexcept; -template -constexpr int128_t operator%(UnsignedInteger lhs, int128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(UnsignedInteger lhs, int128_t rhs) noexcept; -template -constexpr int128_t operator%(int128_t lhs, SignedInteger rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(int128_t lhs, SignedInteger rhs) noexcept; -template -constexpr int128_t operator%(SignedInteger lhs, int128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(SignedInteger lhs, int128_t rhs) noexcept; -constexpr int128_t operator%(int128_t lhs, int128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(int128_t lhs, int128_t rhs) noexcept; template -constexpr int128_t operator%(const int128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const UnsignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -3005,7 +3198,7 @@ constexpr int128_t operator%(const int128_t lhs, const UnsignedInteger rhs) noex } template -constexpr int128_t operator%(const UnsignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const UnsignedInteger lhs, const int128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -3023,9 +3216,9 @@ constexpr int128_t operator%(const UnsignedInteger lhs, const int128_t rhs) noex return lhs; } - const int128_t remainder {0, static_cast(lhs) % rhs.low}; + const int128_t remainder {0, static_cast(lhs) % abs_rhs.low}; - return rhs < 0 ? -remainder : remainder; + return remainder; #else @@ -3038,28 +3231,29 @@ constexpr int128_t operator%(const UnsignedInteger lhs, const int128_t rhs) noex } template -constexpr int128_t operator%(const int128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const SignedInteger rhs) noexcept { return lhs % static_cast(rhs); } template -constexpr int128_t operator%(const SignedInteger lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const SignedInteger lhs, const int128_t rhs) noexcept { return static_cast(lhs) % rhs; } -constexpr int128_t operator%(const int128_t lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const int128_t rhs) noexcept { if (rhs == 0) { return {0, 0}; } + constexpr int128_t min_val {INT64_MIN, 0}; const auto abs_lhs {abs(lhs)}; const auto abs_rhs {abs(rhs)}; - if (abs_rhs > abs_lhs) + if (lhs != min_val && rhs != min_val && abs_rhs > abs_lhs) { return lhs; } @@ -3070,11 +3264,7 @@ constexpr int128_t operator%(const int128_t lhs, const int128_t rhs) noexcept } #else - #if defined(_MSC_VER) && !defined(__GNUC__) const auto is_neg{lhs < 0}; - #else - const auto is_neg {(lhs < 0) != (rhs < 0)}; - #endif int128_t remainder {}; @@ -3103,39 +3293,39 @@ constexpr int128_t operator%(const int128_t lhs, const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 -constexpr int128_t operator%(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return static_cast(lhs) % rhs; } -constexpr int128_t operator%(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator%(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return lhs % static_cast(rhs); } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr int128_t operator%(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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); } -constexpr int128_t operator%(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -constexpr int128_t operator%(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr int128_t operator%(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -3145,39 +3335,39 @@ constexpr int128_t operator%(const T, const int128_t) noexcept #elif defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -inline int128_t operator%(const int128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const int128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs % static_cast(rhs); } -inline int128_t operator%(const detail::builtin_i128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const detail::builtin_i128 lhs, const int128_t rhs) noexcept { return static_cast(lhs) % rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -inline int128_t operator%(const int128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t operator%(const int128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs % static_cast(rhs); } -inline int128_t operator%(const detail::builtin_u128 lhs, const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_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_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -template ::value, bool> = true> -inline int128_t operator%(const int128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -inline int128_t operator%(const T, const int128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -3188,7 +3378,7 @@ inline int128_t operator%(const T, const int128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr int128_t& int128_t::operator%=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator%=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_signed_integer_v, "Sign Conversion Error"); @@ -3198,7 +3388,7 @@ constexpr int128_t& int128_t::operator%=(const Integer rhs) noexcept return *this; } -constexpr int128_t& int128_t::operator%=(const int128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t& int128_t::operator%=(const int128_t rhs) noexcept { *this = *this % rhs; return *this; @@ -3207,7 +3397,7 @@ constexpr int128_t& int128_t::operator%=(const int128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline int128_t& int128_t::operator%=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline int128_t& int128_t::operator%=(const Integer rhs) noexcept { *this = *this % rhs; return *this; @@ -3265,15 +3455,15 @@ class numeric_limits_impl_i128 static constexpr bool tinyness_before = false; // Member functions - static constexpr auto (min) () -> boost::int128::int128_t { return {INT64_MIN, 0}; } - static constexpr auto lowest () -> boost::int128::int128_t { return {INT64_MIN, 0}; } - static constexpr auto (max) () -> boost::int128::int128_t { return {INT64_MAX, UINT64_MAX}; } - static constexpr auto epsilon () -> boost::int128::int128_t { return {0, 0}; } - static constexpr auto round_error () -> boost::int128::int128_t { return {0, 0}; } - static constexpr auto infinity () -> boost::int128::int128_t { return {0, 0}; } - static constexpr auto quiet_NaN () -> boost::int128::int128_t { return {0, 0}; } - static constexpr auto signaling_NaN() -> boost::int128::int128_t { return {0, 0}; } - static constexpr auto denorm_min () -> boost::int128::int128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto (min) () -> boost::int128::int128_t { return {INT64_MIN, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto lowest () -> boost::int128::int128_t { return {INT64_MIN, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto (max) () -> boost::int128::int128_t { return {INT64_MAX, UINT64_MAX}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto epsilon () -> boost::int128::int128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto round_error () -> boost::int128::int128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto infinity () -> boost::int128::int128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto quiet_NaN () -> boost::int128::int128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto signaling_NaN() -> boost::int128::int128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto denorm_min () -> boost::int128::int128_t { return {0, 0}; } }; #if !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L diff --git a/include/boost/decimal/detail/int128/detail/mini_from_chars.hpp b/include/boost/decimal/detail/int128/detail/mini_from_chars.hpp index ffb92a9a5..55b83bf33 100644 --- a/include/boost/decimal/detail/int128/detail/mini_from_chars.hpp +++ b/include/boost/decimal/detail/int128/detail/mini_from_chars.hpp @@ -6,18 +6,26 @@ #ifndef MINI_FROM_CHARS_HPP #define MINI_FROM_CHARS_HPP -#include "uint128_imp.hpp" -#include "int128_imp.hpp" +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include #include +#endif + namespace boost { namespace int128 { namespace detail { namespace impl { -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE unsigned char uchar_values[] = + +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR unsigned char uchar_values[] = {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -37,14 +45,40 @@ BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE unsigned char uchar_values[] = static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char"); +#endif // __NVCC__ + // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr auto digit_from_char(char val) noexcept -> unsigned char +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr auto digit_from_char(char val) noexcept -> unsigned char { + #if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + + constexpr unsigned char uchar_values[] = + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + + static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char"); + + #endif // __NVCC__ + return uchar_values[static_cast(val)]; } template -constexpr int from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept { if (first >= last) { @@ -71,8 +105,8 @@ constexpr int from_chars_integer_impl(const char* first, const char* last, Integ ++next; } - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); + overflow_value = static_cast((std::numeric_limits::max)()); + max_digit = static_cast((std::numeric_limits::max)()); if (is_negative) { @@ -165,16 +199,27 @@ constexpr int from_chars_integer_impl(const char* first, const char* last, Integ } } - return 0; + // This value will be negative to differentiate from errno values + // since they are in the range of acceptable distances + #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 -constexpr int from_chars(const char* first, const char* last, uint128_t& value, int base = 10) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int from_chars(const char* first, const char* last, uint128_t& value, int base = 10) noexcept { return impl::from_chars_integer_impl(first, last, value, base); } -constexpr int from_chars(const char* first, const char* last, int128_t& value, int base = 10) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int from_chars(const char* first, const char* last, int128_t& value, int base = 10) noexcept { return impl::from_chars_integer_impl(first, last, value, base); } diff --git a/include/boost/decimal/detail/int128/detail/mini_to_chars.hpp b/include/boost/decimal/detail/int128/detail/mini_to_chars.hpp index 76659d8c2..e931e0628 100644 --- a/include/boost/decimal/detail/int128/detail/mini_to_chars.hpp +++ b/include/boost/decimal/detail/int128/detail/mini_to_chars.hpp @@ -6,29 +6,44 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_MINI_TO_CHARS_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_MINI_TO_CHARS_HPP -#include "uint128_imp.hpp" -#include "int128_imp.hpp" +#include namespace boost { namespace int128 { namespace detail { -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE char lower_case_digit_table[] = { +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR char lower_case_digit_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; static_assert(sizeof(lower_case_digit_table) == sizeof(char) * 16, "10 numbers, and 6 letters"); -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE char upper_case_digit_table[] = { +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR char upper_case_digit_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static_assert(sizeof(upper_case_digit_table) == sizeof(char) * 16, "10 numbers, and 6 letters"); -constexpr char* mini_to_chars(char (&buffer)[64], uint128_t v, const int base, const bool uppercase) noexcept +#endif // !__NVCC__ + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char (&buffer)[64], uint128_t v, const int base, const bool uppercase) noexcept { + #if defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA) + constexpr char lower_case_digit_table[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + }; + + constexpr char upper_case_digit_table[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' + }; + #endif + char* last {buffer + 64U}; *--last = '\0'; @@ -42,6 +57,14 @@ constexpr char* mini_to_chars(char (&buffer)[64], uint128_t v, const int base, c switch (base) { + case 2: + while (v != 0U) + { + *--last = v.low & 1U ? '1' : '0'; + v >>= 1U; + } + break; + case 8: while (v != 0U) { @@ -74,7 +97,7 @@ constexpr char* mini_to_chars(char (&buffer)[64], uint128_t v, const int base, c return last; } -constexpr char* mini_to_chars(char (&buffer)[64], const int128_t v, const int base, const bool uppercase) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr char* mini_to_chars(char (&buffer)[64], const int128_t v, const int base, const bool uppercase) noexcept { char* p {nullptr}; diff --git a/include/boost/decimal/detail/int128/detail/traits.hpp b/include/boost/decimal/detail/int128/detail/traits.hpp index f7a35044a..971c5dbc7 100644 --- a/include/boost/decimal/detail/int128/detail/traits.hpp +++ b/include/boost/decimal/detail/int128/detail/traits.hpp @@ -5,10 +5,15 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_TRAITS_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_TRAITS_HPP -#include "config.hpp" +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include +#endif + namespace boost { namespace int128 { namespace detail { @@ -25,7 +30,7 @@ struct signed_integer }; template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_signed_integer_v = signed_integer::value; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_signed_integer_v = signed_integer::value; template struct unsigned_integer @@ -39,10 +44,10 @@ struct unsigned_integer }; template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_unsigned_integer_v = unsigned_integer::value; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_unsigned_integer_v = unsigned_integer::value; template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_any_integer_v = signed_integer::value || unsigned_integer::value; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_any_integer_v = signed_integer::value || unsigned_integer::value; // Decides if we can use a u32 or u64 implementation for some operations diff --git a/include/boost/decimal/detail/int128/detail/uint128_imp.hpp b/include/boost/decimal/detail/int128/detail/uint128_imp.hpp index c1c2a6469..8e1a26d57 100644 --- a/include/boost/decimal/detail/int128/detail/uint128_imp.hpp +++ b/include/boost/decimal/detail/int128/detail/uint128_imp.hpp @@ -5,25 +5,28 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_UINT128_IMP_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_UINT128_IMP_HPP -#include "fwd.hpp" -#include "config.hpp" -#include "traits.hpp" -#include "constants.hpp" -#include "clz.hpp" -#include "common_mul.hpp" -#include "common_div.hpp" +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include #include +#endif + namespace boost { namespace int128 { -struct - #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 +BOOST_DECIMAL_DETAIL_INT128_EXPORT struct + #if (defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128)) && !defined(_M_IX86) alignas(alignof(detail::builtin_u128)) - #else - alignas(16) #endif uint128_t { @@ -53,27 +56,28 @@ uint128_t constexpr uint128_t& operator=(const uint128_t&) noexcept = default; constexpr uint128_t& operator=(uint128_t&&) noexcept = default; - // Requires conversion file to be implemented - constexpr uint128_t(const int128_t& v) noexcept; + // Requires a conversion file to be implemented + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr uint128_t(const int128_t& v) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator int128_t() const noexcept; // Construct from integral types #if BOOST_DECIMAL_DETAIL_INT128_ENDIAN_LITTLE_BYTE - constexpr uint128_t(const std::uint64_t hi, const std::uint64_t lo) noexcept : low {lo}, high {hi} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const std::uint64_t hi, const std::uint64_t lo) noexcept : low {lo}, high {hi} {} template - constexpr uint128_t(const SignedInteger v) noexcept : low {static_cast(v)}, high {v < 0 ? UINT64_MAX : UINT64_C(0)} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const SignedInteger v) noexcept : low {static_cast(v)}, high {v < 0 ? UINT64_MAX : UINT64_C(0)} {} template - constexpr uint128_t(const UnsignedInteger v) noexcept : low {static_cast(v)}, high {} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const UnsignedInteger v) noexcept : low {static_cast(v)}, high {} {} #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) - BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t(const detail::builtin_i128 v) noexcept : + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t(const detail::builtin_i128 v) noexcept : low {static_cast(v)}, high {static_cast(static_cast(v) >> static_cast(64U))} {} - BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t(const detail::builtin_u128 v) noexcept : + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t(const detail::builtin_u128 v) noexcept : low {static_cast(v)}, high {static_cast(v >> static_cast(64U))} {} @@ -81,21 +85,21 @@ uint128_t #else // Big endian - constexpr uint128_t(const std::uint64_t hi, const std::uint64_t lo) noexcept : high {hi}, low {lo} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const std::uint64_t hi, const std::uint64_t lo) noexcept : high {hi}, low {lo} {} template - constexpr uint128_t(const SignedInteger v) noexcept : high {v < 0 ? UINT64_MAX : UINT64_C(0)}, low {static_cast(v)} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const SignedInteger v) noexcept : high {v < 0 ? UINT64_MAX : UINT64_C(0)}, low {static_cast(v)} {} template - constexpr uint128_t(const UnsignedInteger v) noexcept : high {}, low {static_cast(v)} {} + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const UnsignedInteger v) noexcept : high {}, low {static_cast(v)} {} #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 - constexpr uint128_t(const detail::builtin_i128 v) noexcept : + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const detail::builtin_i128 v) noexcept : high {static_cast(static_cast(v) >> 64U)}, low {static_cast(v)} {} - constexpr uint128_t(const detail::builtin_u128 v) noexcept : + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t(const detail::builtin_u128 v) noexcept : high {static_cast(v >> 64U)}, low {static_cast(v)} {} @@ -104,161 +108,165 @@ uint128_t #endif // BOOST_DECIMAL_DETAIL_INT128_ENDIAN_LITTLE_BYTE // Integer conversion operators - constexpr operator bool() const noexcept {return low || high; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator bool() const noexcept {return low || high; } template - explicit constexpr operator SignedInteger() const noexcept { return static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator SignedInteger() const noexcept { return static_cast(low); } template - explicit constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator UnsignedInteger() const noexcept { return static_cast(low); } #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) - explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_i128() const noexcept { return static_cast(static_cast(high) << static_cast(64)) | static_cast(low); } - explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR operator detail::builtin_u128() const noexcept { return (static_cast(high) << static_cast(64)) | static_cast(low); } #endif // BOOST_DECIMAL_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 - explicit constexpr operator float() const noexcept; - explicit constexpr operator double() const noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator float() const noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE explicit constexpr operator double() const noexcept; + + // long doubles do not exist on device + #if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) explicit constexpr operator long double() const noexcept; + #endif // Compound OR template - constexpr uint128_t& operator|=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator|=(Integer rhs) noexcept; - constexpr uint128_t& operator|=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator|=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator|=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator|=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound AND template - constexpr uint128_t& operator&=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator&=(Integer rhs) noexcept; - constexpr uint128_t& operator&=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator&=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator&=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator&=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound XOR template - constexpr uint128_t& operator^=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator^=(Integer rhs) noexcept; - constexpr uint128_t& operator^=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator^=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator^=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator^=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Left Shift template - constexpr uint128_t& operator<<=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator<<=(Integer rhs) noexcept; - constexpr uint128_t& operator<<=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator<<=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator<<=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator<<=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Right Shift template - constexpr uint128_t& operator>>=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator>>=(Integer rhs) noexcept; - constexpr uint128_t& operator>>=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator>>=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator>>=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator>>=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 - constexpr uint128_t& operator++() noexcept; - constexpr uint128_t& operator++(int) noexcept; - constexpr uint128_t& operator--() noexcept; - constexpr uint128_t& operator--(int) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator++() noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator++(int) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator--() noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator--(int) noexcept; // Compound Addition template - constexpr uint128_t& operator+=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator+=(Integer rhs) noexcept; - constexpr uint128_t& operator+=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator+=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator+=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator+=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Subtraction template - constexpr uint128_t& operator-=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator-=(Integer rhs) noexcept; - constexpr uint128_t& operator-=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator-=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator-=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator-=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Multiplication template - constexpr uint128_t& operator*=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator*=(Integer rhs) noexcept; - constexpr uint128_t& operator*=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator*=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator*=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator*=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound Division template - constexpr uint128_t& operator/=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator/=(Integer rhs) noexcept; - constexpr uint128_t& operator/=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator/=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator/=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator/=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 // Compound modulo template - constexpr uint128_t& operator%=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator%=(Integer rhs) noexcept; - constexpr uint128_t& operator%=(uint128_t rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& operator%=(uint128_t rhs) noexcept; #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template - inline uint128_t& operator%=(Integer rhs) noexcept; + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& operator%=(Integer rhs) noexcept; #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 }; @@ -267,7 +275,7 @@ uint128_t // Absolute Value function //===================================== -constexpr uint128_t abs(const uint128_t value) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t abs(const uint128_t value) noexcept { return value; } @@ -281,31 +289,35 @@ constexpr uint128_t abs(const uint128_t value) noexcept // by 0xFFFFFFFF in order to generally replicate what ldexp is doing in the constexpr context. // We also avoid pulling in for the __float128 case where we would need ldexpq -constexpr uint128_t::operator float() const noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::operator float() const noexcept { return static_cast(high) * detail::offset_value_v + static_cast(low); } -constexpr uint128_t::operator double() const noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t::operator double() const noexcept { return static_cast(high) * detail::offset_value_v + static_cast(low); } +#if !(defined(__CUDACC__) && defined(BOOST_DECIMAL_DETAIL_INT128_ENABLE_CUDA)) + constexpr uint128_t::operator long double() const noexcept { return static_cast(high) * detail::offset_value_v + static_cast(low); } +#endif // __NVCC__ + //===================================== // Unary Operators //===================================== -constexpr uint128_t operator+(const uint128_t value) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const uint128_t value) noexcept { return value; } -constexpr uint128_t operator-(const uint128_t value) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const uint128_t value) noexcept { return {~value.high + static_cast(value.low == UINT64_C(0)), ~value.low + UINT64_C(1)}; } @@ -314,12 +326,12 @@ constexpr uint128_t operator-(const uint128_t value) noexcept // Equality Operators //===================================== -constexpr bool operator==(const uint128_t lhs, const bool rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const uint128_t lhs, const bool rhs) noexcept { return lhs.high == UINT64_C(0) && lhs.low == static_cast(rhs); } -constexpr bool operator==(const bool lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const bool lhs, const uint128_t rhs) noexcept { return rhs.high == UINT64_C(0) && rhs.low == static_cast(lhs); } @@ -332,8 +344,8 @@ constexpr bool operator==(const bool lhs, const uint128_t rhs) noexcept # pragma GCC diagnostic ignored "-Wsign-conversion" #endif -template -constexpr bool operator==(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -349,8 +361,8 @@ constexpr bool operator==(const uint128_t lhs, const SignedInteger rhs) noexcept #endif } -template -constexpr bool operator==(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -366,22 +378,20 @@ constexpr bool operator==(const SignedInteger lhs, const uint128_t rhs) noexcept #endif } -template -constexpr bool operator==(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return lhs.high == UINT64_C(0) && lhs.low == static_cast(rhs); } -template -constexpr bool operator==(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return rhs.high == UINT64_C(0) && rhs.low == static_cast(lhs); } -constexpr bool operator==(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator==(const uint128_t lhs, const uint128_t rhs) noexcept { - // Intel and ARM like the values in opposite directions - #if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_AMD64) return lhs.low == rhs.low && lhs.high == rhs.high; @@ -398,8 +408,8 @@ constexpr bool operator==(const uint128_t lhs, const uint128_t rhs) noexcept } else { - __m128i a = _mm_load_si128(reinterpret_cast(&lhs)); - __m128i b = _mm_load_si128(reinterpret_cast(&rhs)); + __m128i a = _mm_loadu_si128(reinterpret_cast(&lhs)); + __m128i b = _mm_loadu_si128(reinterpret_cast(&rhs)); __m128i cmp = _mm_cmpeq_epi32(a, b); return _mm_movemask_ps(_mm_castsi128_ps(cmp)) == 0xF; @@ -416,27 +426,27 @@ constexpr bool operator==(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs == static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) == rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t, const T) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const uint128_t) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; @@ -444,12 +454,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const T, const uin #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs == static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) == rhs; } @@ -460,18 +470,18 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator==(const detail::buil // Inequality Operators //===================================== -constexpr bool operator!=(const uint128_t lhs, const bool rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const uint128_t lhs, const bool rhs) noexcept { return lhs.high != UINT64_C(0) || lhs.low != static_cast(rhs); } -constexpr bool operator!=(const bool lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const bool lhs, const uint128_t rhs) noexcept { return rhs.high != UINT64_C(0) || rhs.low != static_cast(lhs); } -template -constexpr bool operator!=(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -487,8 +497,8 @@ constexpr bool operator!=(const uint128_t lhs, const SignedInteger rhs) noexcept #endif } -template -constexpr bool operator!=(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -504,19 +514,19 @@ constexpr bool operator!=(const SignedInteger lhs, const uint128_t rhs) noexcept #endif } -template -constexpr bool operator!=(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return lhs.high != UINT64_C(0) || lhs.low != static_cast(rhs); } -template -constexpr bool operator!=(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return rhs.high != UINT64_C(0) || rhs.low != static_cast(lhs); } -constexpr bool operator!=(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator!=(const uint128_t lhs, const uint128_t rhs) noexcept { #if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_AMD64) @@ -534,8 +544,8 @@ constexpr bool operator!=(const uint128_t lhs, const uint128_t rhs) noexcept } else { - __m128i a = _mm_load_si128(reinterpret_cast(&lhs)); - __m128i b = _mm_load_si128(reinterpret_cast(&rhs)); + __m128i a = _mm_loadu_si128(reinterpret_cast(&lhs)); + __m128i b = _mm_loadu_si128(reinterpret_cast(&rhs)); __m128i cmp = _mm_cmpeq_epi32(a, b); return _mm_movemask_ps(_mm_castsi128_ps(cmp)) != 0xF; @@ -552,27 +562,27 @@ constexpr bool operator!=(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs != static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) != rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t, const T) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const uint128_t) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; @@ -580,12 +590,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const T, const uin #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs != static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) != rhs; } @@ -596,8 +606,8 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator!=(const detail::buil // Less than Operators //===================================== -template -constexpr bool operator<(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -613,8 +623,8 @@ constexpr bool operator<(const uint128_t lhs, const SignedInteger rhs) noexcept #endif } -template -constexpr bool operator<(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -630,19 +640,19 @@ constexpr bool operator<(const SignedInteger lhs, const uint128_t rhs) noexcept #endif } -template -constexpr bool operator<(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return lhs.high == UINT64_C(0) && lhs.low < static_cast(rhs); } -template -constexpr bool operator<(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return rhs.high > UINT64_C(0) || static_cast(lhs) < rhs.low; } -constexpr bool operator<(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<(const uint128_t lhs, const uint128_t rhs) noexcept { // On ARM macs only with the clang compiler is casting to unsigned __int128 uniformly better (and seemingly cost free) #if defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -708,27 +718,27 @@ constexpr bool operator<(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs < static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) < rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t, const T) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const uint128_t) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; @@ -736,12 +746,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const T, const uint #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs < static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) < rhs; } @@ -752,8 +762,8 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<(const detail::built // Less Equal Operators //===================================== -template -constexpr bool operator<=(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -769,8 +779,8 @@ constexpr bool operator<=(const uint128_t lhs, const SignedInteger rhs) noexcept #endif } -template -constexpr bool operator<=(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -786,19 +796,19 @@ constexpr bool operator<=(const SignedInteger lhs, const uint128_t rhs) noexcept #endif } -template -constexpr bool operator<=(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return lhs.high == UINT64_C(0) && lhs.low <= static_cast(rhs); } -template -constexpr bool operator<=(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return rhs.high > UINT64_C(0) || static_cast(lhs) <= rhs.low; } -constexpr bool operator<=(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator<=(const uint128_t lhs, const uint128_t rhs) noexcept { #if defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -863,37 +873,37 @@ constexpr bool operator<=(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs <= static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) <= rhs; } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs <= static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) <= rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const uint128_t, const T) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const uint128_t) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; @@ -907,8 +917,8 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator<=(const T, const uin // Greater Than Operators //===================================== -template -constexpr bool operator>(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -924,8 +934,8 @@ constexpr bool operator>(const uint128_t lhs, const SignedInteger rhs) noexcept #endif } -template -constexpr bool operator>(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -941,19 +951,19 @@ constexpr bool operator>(const SignedInteger lhs, const uint128_t rhs) noexcept #endif } -template -constexpr bool operator>(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return lhs.high > UINT64_C(0) || lhs.low > static_cast(rhs); } -template -constexpr bool operator>(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return rhs.high == UINT64_C(0) && static_cast(lhs) > rhs.low; } -constexpr bool operator>(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>(const uint128_t lhs, const uint128_t rhs) noexcept { #if defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -1018,37 +1028,37 @@ constexpr bool operator>(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs > static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) > rhs; } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs > static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) > rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const uint128_t, const T) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const uint128_t) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; @@ -1062,8 +1072,8 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>(const T, const uint // Greater-equal Operators //===================================== -template -constexpr bool operator>=(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -1079,8 +1089,8 @@ constexpr bool operator>=(const uint128_t lhs, const SignedInteger rhs) noexcept #endif } -template -constexpr bool operator>=(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE @@ -1096,19 +1106,19 @@ constexpr bool operator>=(const SignedInteger lhs, const uint128_t rhs) noexcept #endif } -template -constexpr bool operator>=(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return lhs.high > UINT64_C(0) || lhs.low >= static_cast(rhs); } -template -constexpr bool operator>=(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return rhs.high == UINT64_C(0) && static_cast(lhs) >= rhs.low; } -constexpr bool operator>=(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr bool operator>=(const uint128_t lhs, const uint128_t rhs) noexcept { #if defined(__clang__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -1171,39 +1181,39 @@ constexpr bool operator>=(const uint128_t lhs, const uint128_t rhs) noexcept #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs >= static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) >= rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs >= static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) >= rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const uint128_t, const T) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const uint128_t) noexcept { static_assert(detail::is_unsigned_integer_v, "Sign Compare Error"); return true; @@ -1213,11 +1223,125 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR bool operator>=(const T, const uin #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 +//===================================== +// Spaceship Operator +//===================================== + +#ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_SPACESHIP_OPERATOR + +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const uint128_t lhs, const uint128_t rhs) noexcept +{ + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + return std::strong_ordering::greater; + } +} + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const uint128_t lhs, const UnsignedInteger rhs) noexcept +{ + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + return std::strong_ordering::greater; + } +} + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const UnsignedInteger lhs, const uint128_t rhs) noexcept +{ + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + return std::strong_ordering::greater; + } +} + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const SignedInteger lhs, const uint128_t rhs) noexcept +{ + #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE + + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + 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_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::strong_ordering operator<=>(const uint128_t lhs, const SignedInteger rhs) noexcept +{ + #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_COMPARE + + if (lhs < rhs) + { + return std::strong_ordering::less; + } + else if (lhs == rhs) + { + return std::strong_ordering::equivalent; + } + else + { + 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 + //===================================== // Not Operator //===================================== -constexpr uint128_t operator~(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator~(const uint128_t rhs) noexcept { return {~rhs.high, ~rhs.low}; } @@ -1226,8 +1350,8 @@ constexpr uint128_t operator~(const uint128_t rhs) noexcept // OR Operator //===================================== -template -constexpr uint128_t operator|(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1243,8 +1367,8 @@ constexpr uint128_t operator|(const uint128_t lhs, const SignedInteger rhs) noex #endif } -template -constexpr uint128_t operator|(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1260,19 +1384,19 @@ constexpr uint128_t operator|(const SignedInteger lhs, const uint128_t rhs) noex #endif } -template -constexpr uint128_t operator|(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return {lhs.high, lhs.low | static_cast(rhs)}; } -template -constexpr uint128_t operator|(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return {rhs.high, rhs.low | static_cast(lhs)}; } -constexpr uint128_t operator|(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const uint128_t rhs) noexcept { return {lhs.high | rhs.high, lhs.low | rhs.low}; } @@ -1281,27 +1405,27 @@ constexpr uint128_t operator|(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator|(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs | static_cast(rhs); } -constexpr uint128_t operator|(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) | rhs; } #else -template ::value, bool> = true> -constexpr uint128_t operator|(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr uint128_t operator|(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -1309,12 +1433,12 @@ constexpr uint128_t operator|(const T, const uint128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator|(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs | static_cast(rhs); } -constexpr uint128_t operator|(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator|(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) | rhs; } @@ -1322,7 +1446,7 @@ constexpr uint128_t operator|(const detail::builtin_u128 lhs, const uint128_t rh #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator|=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator|=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -1331,8 +1455,7 @@ constexpr uint128_t& uint128_t::operator|=(const Integer rhs) noexcept *this = *this | rhs; return *this; } - -constexpr uint128_t& uint128_t::operator|=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator|=(const uint128_t rhs) noexcept { *this = *this | rhs; return *this; @@ -1341,7 +1464,7 @@ constexpr uint128_t& uint128_t::operator|=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator|=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator|=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1357,8 +1480,8 @@ inline uint128_t& uint128_t::operator|=(const Integer rhs) noexcept // AND Operator //===================================== -template -constexpr uint128_t operator&(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1375,7 +1498,7 @@ constexpr uint128_t operator&(const uint128_t lhs, const SignedInteger rhs) noex } template -constexpr uint128_t operator&(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1391,19 +1514,19 @@ constexpr uint128_t operator&(const SignedInteger lhs, const uint128_t rhs) noex #endif } -template -constexpr uint128_t operator&(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return {lhs.high, lhs.low & static_cast(rhs)}; } -template -constexpr uint128_t operator&(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return {rhs.high, rhs.low & static_cast(lhs)}; } -constexpr uint128_t operator&(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const uint128_t rhs) noexcept { return {lhs.high & rhs.high, lhs.low & rhs.low}; } @@ -1412,27 +1535,27 @@ constexpr uint128_t operator&(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator&(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs & static_cast(rhs); } -constexpr uint128_t operator&(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) & rhs; } #else -template ::value, bool> = true> -constexpr uint128_t operator&(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr uint128_t operator&(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -1440,12 +1563,12 @@ constexpr uint128_t operator&(const T, const uint128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator&(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs & static_cast(rhs); } -constexpr uint128_t operator&(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator&(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) & rhs; } @@ -1453,7 +1576,7 @@ constexpr uint128_t operator&(const detail::builtin_u128 lhs, const uint128_t rh #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator&=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator&=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -1463,7 +1586,7 @@ constexpr uint128_t& uint128_t::operator&=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator&=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator&=(const uint128_t rhs) noexcept { *this = *this & rhs; return *this; @@ -1472,7 +1595,7 @@ constexpr uint128_t& uint128_t::operator&=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator&=(Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator&=(Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1489,8 +1612,8 @@ inline uint128_t& uint128_t::operator&=(Integer rhs) noexcept // XOR Operator //===================================== -template -constexpr uint128_t operator^(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1506,8 +1629,8 @@ constexpr uint128_t operator^(const uint128_t lhs, const SignedInteger rhs) noex #endif } -template -constexpr uint128_t operator^(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -1523,19 +1646,19 @@ constexpr uint128_t operator^(const SignedInteger lhs, const uint128_t rhs) noex #endif } -template -constexpr uint128_t operator^(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return {lhs.high, lhs.low ^ static_cast(rhs)}; } -template -constexpr uint128_t operator^(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return {rhs.high, rhs.low ^ static_cast(lhs)}; } -constexpr uint128_t operator^(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const uint128_t rhs) noexcept { return {lhs.high ^ rhs.high, lhs.low ^ rhs.low}; } @@ -1544,27 +1667,27 @@ constexpr uint128_t operator^(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator^(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs ^ static_cast(rhs); } -constexpr uint128_t operator^(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) ^ rhs; } #else -template ::value, bool> = true> -constexpr uint128_t operator^(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr uint128_t operator^(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -1572,12 +1695,12 @@ constexpr uint128_t operator^(const T, const uint128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator^(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs ^ static_cast(rhs); } -constexpr uint128_t operator^(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator^(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) ^ rhs; } @@ -1585,7 +1708,7 @@ constexpr uint128_t operator^(const detail::builtin_u128 lhs, const uint128_t rh #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator^=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator^=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -1595,7 +1718,7 @@ constexpr uint128_t& uint128_t::operator^=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator^=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator^=(const uint128_t rhs) noexcept { *this = *this ^ rhs; return *this; @@ -1604,7 +1727,7 @@ constexpr uint128_t& uint128_t::operator^=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator^=(Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator^=(Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -1623,11 +1746,23 @@ inline uint128_t& uint128_t::operator^=(Integer rhs) noexcept namespace detail { template -constexpr uint128_t default_ls_impl(const uint128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t default_ls_impl(const uint128_t lhs, const Integer rhs) noexcept { - if (rhs < 0 || rhs >= 128) + static_assert(std::is_integral::value, "Needs to be a builtin type"); + + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (rhs < 0 || rhs >= 128) + { + return {0, 0}; + } + } + else + { + if (rhs >= 128) + { + return {0, 0}; + } } if (rhs == 0) @@ -1652,12 +1787,23 @@ constexpr uint128_t default_ls_impl(const uint128_t lhs, const Integer rhs) noex } template -uint128_t intrinsic_ls_impl(const uint128_t lhs, const T rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE uint128_t intrinsic_ls_impl(const uint128_t lhs, const T rhs) noexcept { - if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + { + return {0, 0}; + } + } + else + { + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128)) + { + return {0, 0}; + } } + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs == 0)) { return lhs; @@ -1712,8 +1858,8 @@ uint128_t intrinsic_ls_impl(const uint128_t lhs, const T rhs) noexcept } // namespace detail -template -constexpr uint128_t operator<<(const uint128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator<<(const uint128_t lhs, const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION @@ -1735,10 +1881,21 @@ constexpr uint128_t operator<<(const uint128_t lhs, const Integer rhs) noexcept // A number of different overloads to ensure that we return the same type as the builtins would -template ::value && (sizeof(Integer) * 8 > 16), bool> = true> -constexpr Integer operator<<(const Integer lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator<<(const uint128_t lhs, const uint128_t rhs) noexcept +{ + if (rhs.high > UINT64_C(0) || rhs.low >= UINT64_C(128)) + { + return uint128_t{0}; + } + + return lhs << rhs.low; +} + +#ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 + +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator<<(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { - constexpr auto bit_width {sizeof(Integer) * 8}; + constexpr auto bit_width {sizeof(detail::builtin_u128 ) * 8}; if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { @@ -1748,60 +1905,54 @@ constexpr Integer operator<<(const Integer lhs, const uint128_t rhs) noexcept return lhs << rhs.low; } -template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> -constexpr int operator<<(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator<<(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { - constexpr auto bit_width {sizeof(SignedInteger) * 8}; + constexpr auto bit_width {sizeof(detail::builtin_u128) * 8}; if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { return 0; } - return static_cast(lhs) << rhs.low; + return lhs << rhs.low; } -template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> -constexpr unsigned int operator<<(const UnsignedInteger lhs, const uint128_t rhs) noexcept +#endif + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int operator<<(const SignedInteger lhs, const uint128_t rhs) noexcept { - constexpr auto bit_width {sizeof(UnsignedInteger) * 8}; + constexpr auto bit_width {sizeof(SignedInteger) * 8}; if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { return 0; } - return static_cast(lhs) << rhs.low; + return static_cast(lhs) << rhs.low; } -constexpr uint128_t operator<<(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr unsigned int operator<<(const UnsignedInteger lhs, const uint128_t rhs) noexcept { - #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION + constexpr auto bit_width {sizeof(UnsignedInteger) * 8}; - if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) - { - return detail::default_ls_impl(lhs, rhs.low); // LCOV_EXCL_LINE - } - else + if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { - return detail::intrinsic_ls_impl(lhs, rhs.low); + return 0; } - #else - - return detail::default_ls_impl(lhs, rhs.low); - - #endif + return static_cast(lhs) << rhs.low; } template -constexpr uint128_t& uint128_t::operator<<=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator<<=(const Integer rhs) noexcept { *this = *this << rhs; return *this; } -constexpr uint128_t& uint128_t::operator<<=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator<<=(const uint128_t rhs) noexcept { *this = *this << rhs; return *this; @@ -1810,7 +1961,7 @@ constexpr uint128_t& uint128_t::operator<<=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator<<=(Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator<<=(Integer rhs) noexcept { *this = *this << rhs; return *this; @@ -1825,11 +1976,21 @@ inline uint128_t& uint128_t::operator<<=(Integer rhs) noexcept namespace detail { template -constexpr uint128_t default_rs_impl(const uint128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t default_rs_impl(const uint128_t lhs, const Integer rhs) noexcept { - if (rhs < 0 || rhs >= 128) + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (rhs < 0 || rhs >= 128) + { + return {0, 0}; + } + } + else + { + if (rhs >= 128) + { + return {0, 0}; + } } if (rhs == 0) @@ -1854,12 +2015,23 @@ constexpr uint128_t default_rs_impl(const uint128_t lhs, const Integer rhs) noex } template -uint128_t intrinsic_rs_impl(const uint128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE uint128_t intrinsic_rs_impl(const uint128_t lhs, const Integer rhs) noexcept { - if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::numeric_limits::is_signed) { - return {0, 0}; + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128 || rhs < 0)) + { + return {0, 0}; + } + } + else + { + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs >= 128)) + { + return {0, 0}; + } } + if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs == 0)) { return lhs; @@ -1911,8 +2083,8 @@ uint128_t intrinsic_rs_impl(const uint128_t lhs, const Integer rhs) noexcept } // namespace detail -template ::value, bool> = true> -constexpr uint128_t operator>>(const uint128_t lhs, const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator>>(const uint128_t lhs, const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION @@ -1932,78 +2104,78 @@ constexpr uint128_t operator>>(const uint128_t lhs, const Integer rhs) noexcept #endif } -template ::value && (sizeof(Integer) * 8 > 16), bool> = true> -constexpr Integer operator>>(const Integer lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator>>(const uint128_t lhs, const uint128_t rhs) noexcept { - constexpr auto bit_width = sizeof(Integer) * 8; - - if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) + if (rhs.high > UINT64_C(0) || rhs.low >= UINT64_C(128)) { - return 0; + return uint128_t{0}; } return lhs >> rhs.low; } -template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> -constexpr int operator>>(const SignedInteger lhs, const uint128_t rhs) noexcept +#ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 + +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_u128 operator>>(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { - constexpr auto bit_width = sizeof(SignedInteger) * 8; + constexpr auto bit_width = sizeof(detail::builtin_u128) * 8; if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { return 0; } - return static_cast(lhs) >> rhs.low; + return lhs >> rhs.low; } -template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> -constexpr unsigned operator>>(UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr detail::builtin_i128 operator>>(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { - constexpr auto bit_width = sizeof(UnsignedInteger) * 8; + constexpr auto bit_width = sizeof(detail::builtin_i128) * 8; if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { return 0; } - return static_cast(lhs) >> rhs.low; + return lhs >> rhs.low; } -constexpr uint128_t operator>>(const uint128_t lhs, const uint128_t rhs) noexcept +#endif + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(SignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int operator>>(const SignedInteger lhs, const uint128_t rhs) noexcept { - if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs.high != 0U)) + constexpr auto bit_width = sizeof(SignedInteger) * 8; + + if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { - return {0, 0}; + return 0; } - #ifndef BOOST_DECIMAL_DETAIL_INT128_NO_CONSTEVAL_DETECTION + return static_cast(lhs) >> rhs.low; +} - if (BOOST_DECIMAL_DETAIL_INT128_IS_CONSTANT_EVALUATED(lhs)) - { - return detail::default_rs_impl(lhs, rhs.low); // LCOV_EXCL_LINE - } - else +BOOST_DECIMAL_DETAIL_INT128_EXPORT template && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr unsigned operator>>(UnsignedInteger lhs, const uint128_t rhs) noexcept +{ + constexpr auto bit_width = sizeof(UnsignedInteger) * 8; + + if (rhs.high > UINT64_C(0) || rhs.low >= bit_width) { - return detail::intrinsic_rs_impl(lhs, rhs.low); + return 0; } - #else - - return detail::default_rs_impl(lhs, rhs.low); - - #endif + return static_cast(lhs) >> rhs.low; } template -constexpr uint128_t& uint128_t::operator>>=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator>>=(const Integer rhs) noexcept { *this = *this >> rhs; return *this; } -constexpr uint128_t& uint128_t::operator>>=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator>>=(const uint128_t rhs) noexcept { *this = *this >> rhs; return *this; @@ -2012,7 +2184,7 @@ constexpr uint128_t& uint128_t::operator>>=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator>>=(Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator>>=(Integer rhs) noexcept { *this = *this >> rhs; return *this; @@ -2024,7 +2196,7 @@ inline uint128_t& uint128_t::operator>>=(Integer rhs) noexcept // Increment Operator //===================================== -constexpr uint128_t& uint128_t::operator++() noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator++() noexcept { if (++low == UINT64_C(0)) { @@ -2034,16 +2206,18 @@ constexpr uint128_t& uint128_t::operator++() noexcept return *this; } -constexpr uint128_t& uint128_t::operator++(int) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t uint128_t::operator++(int) noexcept { - return ++(*this); + const auto temp {*this}; + ++(*this); + return temp; } //===================================== // Decrement Operator //===================================== -constexpr uint128_t& uint128_t::operator--() noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator--() noexcept { if (--low == UINT64_MAX) { @@ -2053,9 +2227,11 @@ constexpr uint128_t& uint128_t::operator--() noexcept return *this; } -constexpr uint128_t& uint128_t::operator--(int) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t uint128_t::operator--(int) noexcept { - return --(*this); + const auto temp {*this}; + --(*this); + return temp; } //===================================== @@ -2064,7 +2240,7 @@ constexpr uint128_t& uint128_t::operator--(int) noexcept namespace impl { -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_add(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_add(const uint128_t lhs, const uint128_t rhs) noexcept { #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_ADD_OVERFLOW) && (defined(__i386__) || (defined(__aarch64__) && !defined(__APPLE__)) || defined(__arm__) || (defined(__s390__) || defined(__s390x__))) @@ -2087,7 +2263,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_add(const u #endif } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_add(const uint128_t lhs, const std::uint64_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_add(const uint128_t lhs, const std::uint64_t rhs) noexcept { #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_ADD_OVERFLOW) && (defined(__i386__) || (defined(__aarch64__) && !defined(__APPLE__)) || defined(__arm__) || (defined(__s390__) || defined(__s390x__))) @@ -2110,7 +2286,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_add(const u #endif } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_sub(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_sub(const uint128_t lhs, const uint128_t rhs) noexcept { #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_SUB_OVERFLOW) && (defined(__i386__) || defined(__arm__) || (defined(__s390__) || defined(__s390x__))) @@ -2138,7 +2314,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_sub(const u #endif } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_sub(const uint128_t lhs, const std::uint64_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_sub(const uint128_t lhs, const std::uint64_t rhs) noexcept { #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_BUILTIN_SUB_OVERFLOW) && (defined(__i386__) || (defined(__aarch64__) && !defined(__APPLE__)) || defined(__arm__) || (defined(__s390__) || defined(__s390x__))) @@ -2169,8 +2345,8 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_sub(const u # pragma warning(disable : 4146) #endif -template -constexpr uint128_t operator+(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2187,8 +2363,8 @@ constexpr uint128_t operator+(const uint128_t lhs, const SignedInteger rhs) noex #endif } -template -constexpr uint128_t operator+(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2209,19 +2385,19 @@ constexpr uint128_t operator+(const SignedInteger lhs, const uint128_t rhs) noex # pragma warning(pop) #endif -template -constexpr uint128_t operator+(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return impl::default_add(lhs, static_cast(rhs)); } -template -constexpr uint128_t operator+(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return impl::default_add(rhs, static_cast(lhs)); } -constexpr uint128_t operator+(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator+(const uint128_t lhs, const uint128_t rhs) noexcept { return impl::default_add(lhs, rhs); } @@ -2230,27 +2406,27 @@ constexpr uint128_t operator+(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return impl::default_add(lhs, static_cast(rhs)); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return impl::default_add(static_cast(lhs), rhs); } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2258,12 +2434,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const T, const #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return impl::default_add(lhs, static_cast(rhs)); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return impl::default_add(static_cast(lhs), rhs); } @@ -2271,7 +2447,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator+(const detail:: #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator+=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator+=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -2281,7 +2457,7 @@ constexpr uint128_t& uint128_t::operator+=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator+=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator+=(const uint128_t rhs) noexcept { *this = *this + rhs; return *this; @@ -2290,7 +2466,7 @@ constexpr uint128_t& uint128_t::operator+=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator+=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator+=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -2312,8 +2488,8 @@ inline uint128_t& uint128_t::operator+=(const Integer rhs) noexcept # pragma warning(disable : 4146) #endif -template -constexpr uint128_t operator-(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2330,8 +2506,8 @@ constexpr uint128_t operator-(const uint128_t lhs, const SignedInteger rhs) noex #endif } -template -constexpr uint128_t operator-(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2352,19 +2528,19 @@ constexpr uint128_t operator-(const SignedInteger lhs, const uint128_t rhs) noex # pragma warning(pop) #endif -template -constexpr uint128_t operator-(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return impl::default_sub(lhs, static_cast(rhs)); } -template -constexpr uint128_t operator-(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return impl::default_add(-rhs, static_cast(lhs)); } -constexpr uint128_t operator-(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator-(const uint128_t lhs, const uint128_t rhs) noexcept { return impl::default_sub(lhs, rhs); } @@ -2373,27 +2549,27 @@ constexpr uint128_t operator-(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs - static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) - rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2401,12 +2577,12 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const T, const #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs - static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) - rhs; } @@ -2414,7 +2590,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator-(const detail:: #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator-=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator-=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -2424,7 +2600,7 @@ constexpr uint128_t& uint128_t::operator-=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator-=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator-=(const uint128_t rhs) noexcept { *this = *this - rhs; return *this; @@ -2433,7 +2609,7 @@ constexpr uint128_t& uint128_t::operator-=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator-=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator-=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -2458,7 +2634,7 @@ namespace detail { #if defined(_M_AMD64) && !defined(__GNUC__) -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const uint128_t rhs) noexcept { uint128_t result {}; result.low = _umul128(lhs.low, rhs.low, &result.high); @@ -2468,7 +2644,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, return result; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint64_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint64_t rhs) noexcept { uint128_t result {}; result.low = _umul128(lhs.low, rhs, &result.high); @@ -2477,7 +2653,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, return result; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint32_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint32_t rhs) noexcept { uint128_t result {}; result.low = _umul128(lhs.low, static_cast(rhs), &result.high); @@ -2488,7 +2664,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, #elif defined(_M_ARM64) -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const uint128_t rhs) noexcept { const auto low_low{lhs.low * rhs.low}; const auto high_low_low{__umulh(lhs.low, rhs.low)}; @@ -2501,7 +2677,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, return {high, low_low}; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint64_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint64_t rhs) noexcept { const auto low{lhs.low * rhs}; const auto high{__umulh(lhs.low, rhs) + (lhs.high * rhs)}; @@ -2509,7 +2685,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, return {high, low}; } -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint32_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, const std::uint32_t rhs) noexcept { const auto low{lhs.low * rhs}; const auto high{__umulh(lhs.low, static_cast(rhs)) + (lhs.high * rhs)}; @@ -2520,7 +2696,7 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE uint128_t msvc_mul(const uint128_t lhs, #endif // MSVC implementations template -BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_mul(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_mul(const uint128_t lhs, const UnsignedInteger rhs) noexcept { #if (defined(__aarch64__) || defined(__x86_64__) || defined(__PPC__) || defined(__powerpc__)) && defined(__GNUC__) && defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) @@ -2596,8 +2772,8 @@ BOOST_DECIMAL_DETAIL_INT128_FORCE_INLINE constexpr uint128_t default_mul(const u # pragma warning(disable : 4146) #endif -template -constexpr uint128_t operator*(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2618,8 +2794,8 @@ constexpr uint128_t operator*(const uint128_t lhs, const SignedInteger rhs) noex #endif } -template -constexpr uint128_t operator*(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2640,8 +2816,8 @@ constexpr uint128_t operator*(const SignedInteger lhs, const uint128_t rhs) noex #endif } -template -constexpr uint128_t operator*(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const UnsignedInteger rhs) noexcept { return detail::default_mul(lhs, static_cast(rhs)); } @@ -2650,13 +2826,13 @@ constexpr uint128_t operator*(const uint128_t lhs, const UnsignedInteger rhs) no # pragma warning(pop) #endif -template -constexpr uint128_t operator*(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const UnsignedInteger lhs, const uint128_t rhs) noexcept { return detail::default_mul(rhs, static_cast(lhs)); } -constexpr uint128_t operator*(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const uint128_t rhs) noexcept { return detail::default_mul(lhs, rhs); } @@ -2665,7 +2841,7 @@ constexpr uint128_t operator*(const uint128_t lhs, const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator*(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE 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}; @@ -2673,7 +2849,7 @@ constexpr uint128_t operator*(const uint128_t lhs, const detail::builtin_i128 rh return rhs < 0 ? -res : res; } -constexpr uint128_t operator*(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE 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}; @@ -2683,15 +2859,15 @@ constexpr uint128_t operator*(const detail::builtin_i128 lhs, const uint128_t rh #else -template ::value, bool> = true> -constexpr uint128_t operator*(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; } -template ::value, bool> = true> -constexpr uint128_t operator*(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_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}; @@ -2699,12 +2875,12 @@ constexpr uint128_t operator*(const T, const uint128_t) noexcept #endif // BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -constexpr uint128_t operator*(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs * static_cast(rhs); } -constexpr uint128_t operator*(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator*(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) * rhs; } @@ -2712,7 +2888,7 @@ constexpr uint128_t operator*(const detail::builtin_u128 lhs, const uint128_t rh #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator*=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator*=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -2722,7 +2898,7 @@ constexpr uint128_t& uint128_t::operator*=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator*=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator*=(const uint128_t rhs) noexcept { *this = *this * rhs; return *this; @@ -2731,7 +2907,7 @@ constexpr uint128_t& uint128_t::operator*=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator*=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator*=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -2748,22 +2924,22 @@ inline uint128_t& uint128_t::operator*=(const Integer rhs) noexcept //===================================== // For div we need forward declarations since we mix and match the arguments -template -constexpr uint128_t operator/(uint128_t lhs, SignedInteger rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(uint128_t lhs, SignedInteger rhs) noexcept; -template -constexpr uint128_t operator/(SignedInteger lhs, uint128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(SignedInteger lhs, uint128_t rhs) noexcept; -template -constexpr uint128_t operator/(uint128_t lhs, UnsignedInteger rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(uint128_t lhs, UnsignedInteger rhs) noexcept; -template -constexpr uint128_t operator/(UnsignedInteger lhs, uint128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(UnsignedInteger lhs, uint128_t rhs) noexcept; -constexpr uint128_t operator/(uint128_t lhs, uint128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(uint128_t lhs, uint128_t rhs) noexcept; template -constexpr uint128_t operator/(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2781,7 +2957,7 @@ constexpr uint128_t operator/(const uint128_t lhs, const SignedInteger rhs) noex } template -constexpr uint128_t operator/(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2799,7 +2975,7 @@ constexpr uint128_t operator/(const SignedInteger lhs, const uint128_t rhs) noex } template -constexpr uint128_t operator/(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const uint128_t lhs, const UnsignedInteger rhs) noexcept { using eval_type = detail::evaluation_type_t; @@ -2821,7 +2997,7 @@ constexpr uint128_t operator/(const uint128_t lhs, const UnsignedInteger rhs) no } template -constexpr uint128_t operator/(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const UnsignedInteger lhs, const uint128_t rhs) noexcept { using eval_type = detail::evaluation_type_t; @@ -2838,7 +3014,7 @@ constexpr uint128_t operator/(const UnsignedInteger lhs, const uint128_t rhs) no return {0, static_cast(lhs) / rhs.low}; } -constexpr uint128_t operator/(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator/(const uint128_t lhs, const uint128_t rhs) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs == 0U)) { @@ -2855,7 +3031,7 @@ constexpr uint128_t operator/(const uint128_t lhs, const uint128_t rhs) noexcept return static_cast(static_cast(lhs) / static_cast(rhs)); } #else - else if (rhs.high != 0) + else if (rhs.high != 0U) { return detail::knuth_div(lhs, rhs); } @@ -2879,39 +3055,39 @@ constexpr uint128_t operator/(const uint128_t lhs, const uint128_t rhs) noexcept #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs / static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) / rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs / static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) / rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -2922,7 +3098,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator/(const T, const #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator/=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator/=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -2932,7 +3108,7 @@ constexpr uint128_t& uint128_t::operator/=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator/=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator/=(const uint128_t rhs) noexcept { *this = *this / rhs; return *this; @@ -2941,7 +3117,7 @@ constexpr uint128_t& uint128_t::operator/=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator/=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator/=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -2958,22 +3134,22 @@ inline uint128_t& uint128_t::operator/=(const Integer rhs) noexcept //===================================== // For div we need forward declarations since we mix and match the arguments -template -constexpr uint128_t operator%(uint128_t lhs, SignedInteger rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(uint128_t lhs, SignedInteger rhs) noexcept; -template -constexpr uint128_t operator%(SignedInteger lhs, uint128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(SignedInteger lhs, uint128_t rhs) noexcept; -template -constexpr uint128_t operator%(uint128_t lhs, UnsignedInteger rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(uint128_t lhs, UnsignedInteger rhs) noexcept; -template -constexpr uint128_t operator%(UnsignedInteger lhs, uint128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT template +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(UnsignedInteger lhs, uint128_t rhs) noexcept; -constexpr uint128_t operator%(uint128_t lhs, uint128_t rhs) noexcept; +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(uint128_t lhs, uint128_t rhs) noexcept; template -constexpr uint128_t operator%(const uint128_t lhs, const SignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const uint128_t lhs, const SignedInteger rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -2991,7 +3167,7 @@ constexpr uint128_t operator%(const uint128_t lhs, const SignedInteger rhs) noex } template -constexpr uint128_t operator%(const SignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const SignedInteger lhs, const uint128_t rhs) noexcept { #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION @@ -3009,7 +3185,7 @@ constexpr uint128_t operator%(const SignedInteger lhs, const uint128_t rhs) noex } template -constexpr uint128_t operator%(const uint128_t lhs, const UnsignedInteger rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const uint128_t lhs, const UnsignedInteger rhs) noexcept { using eval_type = detail::evaluation_type_t; @@ -3034,7 +3210,7 @@ constexpr uint128_t operator%(const uint128_t lhs, const UnsignedInteger rhs) no } template -constexpr uint128_t operator%(const UnsignedInteger lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const UnsignedInteger lhs, const uint128_t rhs) noexcept { using eval_type = detail::evaluation_type_t; @@ -3050,7 +3226,7 @@ constexpr uint128_t operator%(const UnsignedInteger lhs, const uint128_t rhs) no return {0, static_cast(lhs) % rhs.low}; } -constexpr uint128_t operator%(const uint128_t lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator%(const uint128_t lhs, const uint128_t rhs) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(rhs == 0U)) { @@ -3066,7 +3242,7 @@ constexpr uint128_t operator%(const uint128_t lhs, const uint128_t rhs) noexcept return static_cast(static_cast(lhs) % static_cast(rhs)); } #else - else if (rhs.high != 0) + else if (rhs.high != 0U) { uint128_t remainder {}; detail::knuth_div(lhs, rhs, remainder); @@ -3093,39 +3269,39 @@ constexpr uint128_t operator%(const uint128_t lhs, const uint128_t rhs) noexcept #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t lhs, const detail::builtin_u128 rhs) noexcept { return lhs % static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const detail::builtin_u128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) % rhs; } #ifdef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t lhs, const detail::builtin_i128 rhs) noexcept { return lhs % static_cast(rhs); } -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const detail::builtin_i128 lhs, const uint128_t rhs) noexcept { return static_cast(lhs) % rhs; } #else -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const uint128_t, const T) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; } -template ::value, bool> = true> -BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const T, const uint128_t) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT template ::value, bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE BOOST_DECIMAL_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}; @@ -3136,7 +3312,7 @@ BOOST_DECIMAL_DETAIL_INT128_BUILTIN_CONSTEXPR uint128_t operator%(const T, const #endif // BOOST_DECIMAL_DETAIL_INT128_HAS_INT128 template -constexpr uint128_t& uint128_t::operator%=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator%=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(detail::is_unsigned_integer_v, "Sign Conversion Error"); @@ -3146,7 +3322,7 @@ constexpr uint128_t& uint128_t::operator%=(const Integer rhs) noexcept return *this; } -constexpr uint128_t& uint128_t::operator%=(const uint128_t rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t& uint128_t::operator%=(const uint128_t rhs) noexcept { *this = *this % rhs; return *this; @@ -3155,7 +3331,7 @@ constexpr uint128_t& uint128_t::operator%=(const uint128_t rhs) noexcept #ifdef BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128 template -inline uint128_t& uint128_t::operator%=(const Integer rhs) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE inline uint128_t& uint128_t::operator%=(const Integer rhs) noexcept { #ifndef BOOST_DECIMAL_DETAIL_INT128_ALLOW_SIGN_CONVERSION static_assert(!std::numeric_limits::is_signed, "Sign Conversion Error"); @@ -3217,15 +3393,15 @@ class numeric_limits_impl_u128 static constexpr bool tinyness_before = false; // Member functions - static constexpr auto (min) () -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto lowest () -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto (max) () -> boost::int128::uint128_t { return {UINT64_MAX, UINT64_MAX}; } - static constexpr auto epsilon () -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto round_error () -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto infinity () -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto quiet_NaN () -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto signaling_NaN() -> boost::int128::uint128_t { return {0, 0}; } - static constexpr auto denorm_min () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto (min) () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto lowest () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto (max) () -> boost::int128::uint128_t { return {UINT64_MAX, UINT64_MAX}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto epsilon () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto round_error () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto infinity () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto quiet_NaN () -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto signaling_NaN() -> boost::int128::uint128_t { return {0, 0}; } + BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE static constexpr auto denorm_min () -> boost::int128::uint128_t { return {0, 0}; } }; #if !defined(__cpp_inline_variables) || __cpp_inline_variables < 201606L diff --git a/include/boost/decimal/detail/int128/detail/utilities.hpp b/include/boost/decimal/detail/int128/detail/utilities.hpp index 00f41c2d5..e14834830 100644 --- a/include/boost/decimal/detail/int128/detail/utilities.hpp +++ b/include/boost/decimal/detail/int128/detail/utilities.hpp @@ -5,14 +5,20 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_DETAIL_UTILITIES_HPP #define BOOST_DECIMAL_DETAIL_INT128_DETAIL_UTILITIES_HPP +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include +#endif + namespace boost { namespace int128 { namespace detail { template -constexpr std::size_t strlen(const T* str) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::size_t strlen(const T* str) noexcept { std::size_t i {}; while (*str != '\0') diff --git a/include/boost/decimal/detail/int128/fmt_format.hpp b/include/boost/decimal/detail/int128/fmt_format.hpp new file mode 100644 index 000000000..44063f171 --- /dev/null +++ b/include/boost/decimal/detail/int128/fmt_format.hpp @@ -0,0 +1,460 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_INT128_FMT_FORMAT_HPP +#define BOOST_DECIMAL_DETAIL_INT128_FMT_FORMAT_HPP + +#if __has_include() && __has_include() + +#include +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +#include +#include + +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + +#define BOOST_DECIMAL_DETAIL_INT128_HAS_FMT_FORMAT + +namespace boost { +namespace int128 { +namespace fmt_detail { + +enum class sign_option +{ + plus, + negative, + space +}; + +enum class alignment +{ + none, + left, // < + right, // > + center // ^ +}; + +template +constexpr auto parse_impl(ParseContext& ctx) +{ + auto it {ctx.begin()}; + int base = 10; + bool is_upper = false; + int padding_digits = 0; + auto sign = sign_option::negative; + bool prefix = false; + bool write_as_character = false; + bool character_debug_format = false; + char fill_char = ' '; + auto align = alignment::none; + + // Parse fill and alignment: [[fill]align] + // Alignment characters are: < (left), > (right), ^ (center) + if (it != ctx.end()) + { + // Check if we have [fill]align (fill char followed by alignment) + auto next = it; + ++next; + if (next != ctx.end() && (*next == '<' || *next == '>' || *next == '^')) + { + fill_char = *it; + it = next; + switch (*it) + { + case '<': + align = alignment::left; + break; + case '>': + align = alignment::right; + break; + case '^': + align = alignment::center; + break; + default: // LCOV_EXCL_LINE + BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE; // LCOV_EXCL_LINE + } + ++it; + } + // Check if we just have align (no fill char) + else if (*it == '<' || *it == '>' || *it == '^') + { + switch (*it) + { + case '<': + align = alignment::left; + break; + case '>': + align = alignment::right; + break; + case '^': + align = alignment::center; + break; + default: // LCOV_EXCL_LINE + BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE; // LCOV_EXCL_LINE + } + ++it; + } + } + + // Handle sign or space + if (it != ctx.end()) + { + switch (*it) { + case ' ': + sign = sign_option::space; + ++it; + break; + case '+': + sign = sign_option::plus; + ++it; + break; + case '-': + sign = sign_option::negative; + ++it; + break; + default: + break; + } + } + + // Alternate form option + if (it != ctx.end() && *it == '#') + { + prefix = true; + ++it; + } + + // Character presentation type + if (it != ctx.end() && (*it == '?' || *it == 'c')) + { + character_debug_format = *it == '?'; + ++it; + } + + // Check for a padding character + while (it != ctx.end() && *it >= '0' && *it <= '9') + { + padding_digits = padding_digits * 10 + (*it - '0'); + ++it; + } + + // Integer presentation + if (it != ctx.end() && *it != '}') + { + switch (*it++) + { + case 'b': + base = 2; + break; + case 'B': + base = 2; + is_upper = true; + break; + + case 'c': + write_as_character = true; + break; + + case 'o': + base = 8; + break; + + case 'd': + base = 10; + break; + + case 'x': + base = 16; + break; + case 'X': + base = 16; + is_upper = true; + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(std::logic_error("Unsupported format specifier")); + // LCOV_EXCL_STOP + } + } + + // Verify we're at the closing brace + if (it != ctx.end() && *it != '}') + { + BOOST_DECIMAL_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); +} + +template +struct is_library_type_impl +{ + static constexpr bool value {std::is_same::value || std::is_same::value}; +}; + +template +static constexpr bool is_library_type_v = is_library_type_impl::value; + +template +struct formatter +{ + int base; + int padding_digits; + sign_option sign; + bool is_upper; + bool prefix; + bool write_as_character; + bool character_debug_format; + char fill_char; + alignment align; + + constexpr formatter() : base {10}, + padding_digits {0}, + sign {sign_option::negative}, + is_upper {false}, + prefix {false}, + write_as_character {false}, + character_debug_format {false}, + fill_char {' '}, + align {alignment::none} + {} + + constexpr auto parse(fmt::format_parse_context& ctx) + { + const auto res {boost::int128::fmt_detail::parse_impl(ctx)}; + + base = std::get<0>(res); + padding_digits = std::get<1>(res); + 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); + + return std::get<9>(res); + } + + template + auto format(T v, FormatContext& ctx) const + { + char buffer[64]; + bool isneg {false}; + boost::int128::uint128_t abs_v {}; + + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) + { + if (v < T{0}) + { + isneg = true; + // Can't negate int128_t::min(), handle specially + if (v == (std::numeric_limits::min)()) + { + abs_v = boost::int128::uint128_t{UINT64_C(0x8000000000000000), 0}; + } + else + { + abs_v = static_cast(-v); + } + } + else + { + abs_v = static_cast(v); + } + } + else + { + abs_v = static_cast(v); + } + + const auto end = detail::mini_to_chars(buffer, abs_v, base, is_upper); + std::string s(end, buffer + sizeof(buffer)); + + // Calculate prefix length that will be added later + std::size_t prefix_len {0}; + if (prefix) + { + switch (base) + { + case 2: + case 16: + prefix_len = 2; // "0b", "0B", "0x", or "0X" + break; + case 8: + prefix_len = 1; // "0" + break; + default: + break; + } + } + + // Calculate sign length that will be added later + std::size_t sign_len {0}; + if (sign == sign_option::plus || sign == sign_option::space || isneg) + { + 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) + { + auto target_digit_width {static_cast(padding_digits)}; + if (target_digit_width > prefix_len + sign_len) + { + target_digit_width -= prefix_len + sign_len; + } + else + { + target_digit_width = 0; + } + + if (s.size() - 1u < target_digit_width) + { + s.insert(s.begin(), target_digit_width - s.size() + 1u, '0'); + } + } + + if (prefix) + { + switch (base) + { + case 2: + if (is_upper) + { + s.insert(s.begin(), 'B'); + } + else + { + s.insert(s.begin(), 'b'); + } + s.insert(s.begin(), '0'); + break; + case 8: + s.insert(s.begin(), '0'); + break; + case 16: + if (is_upper) + { + s.insert(s.begin(), 'X'); + } + else + { + s.insert(s.begin(), 'x'); + } + s.insert(s.begin(), '0'); + break; + default: + // Nothing to do + break; + } + } + + // Insert our sign + switch (sign) + { + case sign_option::plus: + if (isneg) + { + s.insert(s.begin(), '-'); + } + else + { + s.insert(s.begin(), '+'); + } + break; + case sign_option::space: + if (!isneg) + { + s.insert(s.begin(), ' '); + } + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) + { + if (isneg) + { + s.insert(s.begin(), '-'); + } + } + break; + case sign_option::negative: + BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) + { + if (isneg) + { + s.insert(s.begin(), '-'); + } + } + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE; + // LCOV_EXCL_STOP + } + + 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)) + { + auto fill_count = static_cast(padding_digits) - s.size(); + switch (align) + { + case alignment::left: + s.append(fill_count, fill_char); + break; + case alignment::right: + s.insert(s.begin(), fill_count, fill_char); + break; + case alignment::center: + { + auto left_fill = fill_count / 2; + auto right_fill = fill_count - left_fill; + s.insert(s.begin(), left_fill, fill_char); + s.append(right_fill, fill_char); + break; + } + // LCOV_EXCL_START + default: + break; + // LCOV_EXCL_STOP + } + } + + return fmt::format_to(ctx.out(), "{}", s); + } +}; + +} // namespace fmt_detail +} // namespace int128 +} // namespace boost + +namespace fmt { + +template <> +struct formatter : public boost::int128::fmt_detail::formatter {}; + +template <> +struct formatter : public boost::int128::fmt_detail::formatter {}; + +} // namespace fmt + +#endif // Has format headers + +#endif // BOOST_DECIMAL_DETAIL_INT128_FMT_FORMAT_HPP diff --git a/include/boost/decimal/detail/int128/format.hpp b/include/boost/decimal/detail/int128/format.hpp new file mode 100644 index 000000000..15cd82bc2 --- /dev/null +++ b/include/boost/decimal/detail/int128/format.hpp @@ -0,0 +1,437 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_INT128_FORMAT_HPP +#define BOOST_DECIMAL_DETAIL_INT128_FORMAT_HPP + +#if __has_include() && defined(__cpp_lib_format) && __cpp_lib_format >= 201907L && !defined(BOOST_DECIMAL_DISABLE_CLIB) + +#include +#include +#include +#include +#include +#include + +#define BOOST_DECIMAL_DETAIL_INT128_HAS_FORMAT + +namespace boost::int128::detail { + +enum class sign_option +{ + plus, + negative, + space +}; + +enum class alignment +{ + none, + left, // < + right, // > + center // ^ +}; + +template +constexpr auto parse_impl(ParseContext& ctx) +{ + auto it {ctx.begin()}; + int base = 10; + bool is_upper = false; + int padding_digits = 0; + auto sign = sign_option::negative; + bool prefix = false; + bool write_as_character = false; + bool character_debug_format = false; + char fill_char = ' '; + auto align = alignment::none; + + // Parse fill and alignment: [[fill]align] + // Alignment characters are: < (left), > (right), ^ (center) + if (it != ctx.end()) + { + // Check if we have [fill]align (fill char followed by alignment) + auto next = it; + ++next; + if (next != ctx.end() && (*next == '<' || *next == '>' || *next == '^')) + { + fill_char = *it; + it = next; + switch (*it) + { + case '<': + align = alignment::left; + break; + case '>': + align = alignment::right; + break; + case '^': + align = alignment::center; + break; + default: // LCOV_EXCL_LINE + BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE; // LCOV_EXCL_LINE + } + ++it; + } + // Check if we just have align (no fill char) + else if (*it == '<' || *it == '>' || *it == '^') + { + switch (*it) + { + case '<': + align = alignment::left; + break; + case '>': + align = alignment::right; + break; + case '^': + align = alignment::center; + break; + default: // LCOV_EXCL_LINE + BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE; // LCOV_EXCL_LINE + } + ++it; + } + } + + // Handle sign or space + if (it != ctx.end()) + { + switch (*it) { + case ' ': + sign = sign_option::space; + ++it; + break; + case '+': + sign = sign_option::plus; + ++it; + break; + case '-': + sign = sign_option::negative; + ++it; + break; + default: + break; + } + } + + // Alternate form option + if (it != ctx.end() && *it == '#') + { + prefix = true; + ++it; + } + + // Character presentation type + if (it != ctx.end() && (*it == '?' || *it == 'c')) + { + character_debug_format = *it == '?'; + ++it; + } + + // Check for a padding character + while (it != ctx.end() && *it >= '0' && *it <= '9') + { + padding_digits = padding_digits * 10 + (*it - '0'); + ++it; + } + + // Integer presentation + if (it != ctx.end() && *it != '}') + { + switch (*it++) + { + case 'b': + base = 2; + break; + case 'B': + base = 2; + is_upper = true; + break; + + case 'c': + write_as_character = true; + break; + + case 'o': + base = 8; + break; + + case 'd': + base = 10; + break; + + case 'x': + base = 16; + break; + case 'X': + base = 16; + is_upper = true; + break; + default: // LCOV_EXCL_LINE + BOOST_DECIMAL_DETAIL_INT128_THROW_EXCEPTION(std::format_error("Unsupported format specifier")); // LCOV_EXCL_LINE + } + } + + // Verify we're at the closing brace + if (it != ctx.end() && *it != '}') + { + BOOST_DECIMAL_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); +} + +template +struct is_library_type_impl +{ + static constexpr bool value {std::is_same_v || std::is_same_v}; +}; + +template +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_library_type_v = is_library_type_impl::value; + +template +concept is_library_type = is_library_type_v; + +} // namespace boost::int128::detail + +namespace std { + +template +struct formatter +{ + int base; + int padding_digits; + boost::int128::detail::sign_option sign; + bool is_upper; + bool prefix; + bool write_as_character; + bool character_debug_format; + char fill_char; + boost::int128::detail::alignment align; + + constexpr formatter() : base {10}, + padding_digits {0}, + sign {boost::int128::detail::sign_option::negative}, + is_upper {false}, + prefix {false}, + write_as_character {false}, + character_debug_format {false}, + fill_char {' '}, + align {boost::int128::detail::alignment::none} + {} + + constexpr auto parse(format_parse_context& ctx) + { + const auto res {boost::int128::detail::parse_impl(ctx)}; + + base = std::get<0>(res); + padding_digits = std::get<1>(res); + 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); + + return std::get<9>(res); + } + + template + auto format(T v, FormatContext& ctx) const + { + char buffer[64]; + bool isneg {false}; + boost::int128::uint128_t abs_v {}; + + if constexpr (std::is_same_v) + { + if (v < 0) + { + isneg = true; + // Can't negate int128_t::min(), handle specially + if (v == (std::numeric_limits::min)()) + { + abs_v = boost::int128::uint128_t{UINT64_C(0x8000000000000000), 0}; + } + else + { + abs_v = static_cast(-v); + } + } + else + { + abs_v = static_cast(v); + } + } + else + { + abs_v = static_cast(v); + } + + const auto end = boost::int128::detail::mini_to_chars(buffer, abs_v, base, is_upper); + std::string s(end, buffer + sizeof(buffer)); + + // Calculate prefix length that will be added later + std::size_t prefix_len {0}; + if (prefix) + { + switch (base) + { + case 2: + case 16: + prefix_len = 2; // "0b", "0B", "0x", or "0X" + break; + case 8: + prefix_len = 1; // "0" + break; + default: + break; + } + } + + // Calculate sign length that will be added later + std::size_t sign_len {0}; + if (sign == boost::int128::detail::sign_option::plus || sign == boost::int128::detail::sign_option::space || isneg) + { + 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) + { + auto target_digit_width {static_cast(padding_digits)}; + if (target_digit_width > prefix_len + sign_len) + { + target_digit_width -= prefix_len + sign_len; + } + else + { + target_digit_width = 0; + } + + if (s.size() - 1u < target_digit_width) + { + s.insert(s.begin(), target_digit_width - s.size() + 1u, '0'); + } + } + + if (prefix) + { + switch (base) + { + case 2: + if (is_upper) + { + s.insert(s.begin(), 'B'); + } + else + { + s.insert(s.begin(), 'b'); + } + s.insert(s.begin(), '0'); + break; + case 8: + s.insert(s.begin(), '0'); + break; + case 16: + if (is_upper) + { + s.insert(s.begin(), 'X'); + } + else + { + s.insert(s.begin(), 'x'); + } + s.insert(s.begin(), '0'); + break; + default: + // Nothing to do + break; + } + } + + // Insert our sign + switch (sign) + { + case boost::int128::detail::sign_option::plus: + if (isneg) + { + s.insert(s.begin(), '-'); + } + else + { + s.insert(s.begin(), '+'); + } + break; + case boost::int128::detail::sign_option::space: + if (!isneg) + { + s.insert(s.begin(), ' '); + } + if constexpr (std::is_same_v) + { + if (isneg) + { + s.insert(s.begin(), '-'); + } + } + break; + case boost::int128::detail::sign_option::negative: + if constexpr (std::is_same_v) + { + if (isneg) + { + s.insert(s.begin(), '-'); + } + } + break; + // LCOV_EXCL_START + default: + BOOST_DECIMAL_DETAIL_INT128_UNREACHABLE; + // LCOV_EXCL_STOP + } + + 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)) + { + auto fill_count = static_cast(padding_digits) - s.size(); + switch (align) + { + case boost::int128::detail::alignment::left: + s.append(fill_count, fill_char); + break; + case boost::int128::detail::alignment::right: + s.insert(s.begin(), fill_count, fill_char); + break; + case boost::int128::detail::alignment::center: + { + auto left_fill = fill_count / 2; + auto right_fill = fill_count - left_fill; + s.insert(s.begin(), left_fill, fill_char); + s.append(right_fill, fill_char); + break; + } + // LCOV_EXCL_START + default: + break; + // LCOV_EXCL_STOP + } + } + + return std::format_to(ctx.out(), "{}", s); + } +}; + +} // namespace std + +#endif + +#endif // BOOST_DECIMAL_DETAIL_INT128_FORMAT_HPP diff --git a/include/boost/decimal/detail/int128/int128.hpp b/include/boost/decimal/detail/int128/int128.hpp index b0b20982f..6c3b3cc88 100644 --- a/include/boost/decimal/detail/int128/int128.hpp +++ b/include/boost/decimal/detail/int128/int128.hpp @@ -5,9 +5,9 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_INT128_HPP #define BOOST_DECIMAL_DETAIL_INT128_INT128_HPP -#include "detail/fwd.hpp" -#include "detail/int128_imp.hpp" -#include "detail/uint128_imp.hpp" -#include "detail/conversions.hpp" +#include +#include +#include +#include #endif // BOOST_DECIMAL_DETAIL_INT128_INT128_HPP diff --git a/include/boost/decimal/detail/int128/iostream.hpp b/include/boost/decimal/detail/int128/iostream.hpp index 8dc094a06..d3a2558c4 100644 --- a/include/boost/decimal/detail/int128/iostream.hpp +++ b/include/boost/decimal/detail/int128/iostream.hpp @@ -5,15 +5,21 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_IOSTREAM_HPP #define BOOST_DECIMAL_DETAIL_INT128_IOSTREAM_HPP -#include "int128.hpp" -#include "detail/mini_from_chars.hpp" -#include "detail/mini_to_chars.hpp" -#include "detail/utilities.hpp" +#include +#include +#include +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include #include #include #include +#endif + namespace boost { namespace int128 { @@ -26,17 +32,19 @@ struct streamable_overload }; template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_streamable_overload_v = streamable_overload::value; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_streamable_overload_v = streamable_overload::value; } // namespace detail -template +BOOST_DECIMAL_DETAIL_INT128_EXPORT template auto operator>>(std::basic_istream& is, LibIntegerType& v) -> std::enable_if_t, std::basic_istream&> { charT t_buffer[64] {}; is >> std::ws >> std::setw(63) >> t_buffer; + const auto t_buffer_len {std::char_traits::length(t_buffer)}; + char buffer[64] {}; auto buffer_start {buffer}; @@ -75,12 +83,23 @@ auto operator>>(std::basic_istream& is, LibIntegerType& v) } } - detail::from_chars(buffer_start, buffer + detail::strlen(buffer), v, base); + const auto r {detail::from_chars(buffer_start, buffer + detail::strlen(buffer), v, base)}; + + // Put back unconsumed characters + // If r is greater than 0 then an errno values has been hit + const auto consumed {static_cast(r > 0 ? 0 : -r)}; + BOOST_DECIMAL_DETAIL_INT128_ASSERT(t_buffer_len >= consumed); + const auto return_chars {static_cast(t_buffer_len - consumed)}; + + for (std::size_t i {}; i < return_chars; ++i) + { + is.putback(t_buffer[t_buffer_len - i - 1]); + } return is; } -template +BOOST_DECIMAL_DETAIL_INT128_EXPORT template auto operator<<(std::basic_ostream& os, const LibIntegerType& v) -> std::enable_if_t, std::basic_ostream&> { @@ -105,14 +124,17 @@ auto operator<<(std::basic_ostream& os, const LibIntegerType& v) auto first {detail::mini_to_chars(buffer, v, base, uppercase)}; - if (base == 8) - { - *--first = '0'; - } - else if (base == 16) + if (flags & std::ios_base::showbase) { - *--first = uppercase ? 'X' : 'x'; - *--first = '0'; + if (base == 8) + { + *--first = '0'; + } + else if (base == 16) + { + *--first = uppercase ? 'X' : 'x'; + *--first = '0'; + } } BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (!std::is_same::value) diff --git a/include/boost/decimal/detail/int128/limits.hpp b/include/boost/decimal/detail/int128/limits.hpp new file mode 100644 index 000000000..2ed8d2745 --- /dev/null +++ b/include/boost/decimal/detail/int128/limits.hpp @@ -0,0 +1,11 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_INT128_LIMITS_HPP +#define BOOST_DECIMAL_DETAIL_INT128_LIMITS_HPP + +#include +#include + +#endif // BOOST_DECIMAL_DETAIL_INT128_LIMITS_HPP diff --git a/include/boost/decimal/detail/int128/literals.hpp b/include/boost/decimal/detail/int128/literals.hpp index 99ce3a43a..d684d19d4 100644 --- a/include/boost/decimal/detail/int128/literals.hpp +++ b/include/boost/decimal/detail/int128/literals.hpp @@ -6,84 +6,85 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_LITERALS_HPP #define BOOST_DECIMAL_DETAIL_INT128_LITERALS_HPP -#include "int128.hpp" -#include "detail/mini_from_chars.hpp" -#include "detail/utilities.hpp" +#include +#include +#include +#include namespace boost { namespace int128 { namespace literals { -constexpr uint128_t operator ""_u128(const char* str) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_u128(const char* str) noexcept { uint128_t result {}; detail::from_chars(str, str + detail::strlen(str), result); return result; } -constexpr uint128_t operator ""_U128(const char* str) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_U128(const char* str) noexcept { uint128_t result {}; detail::from_chars(str, str + detail::strlen(str), result); return result; } -constexpr uint128_t operator ""_u128(const char* str, std::size_t len) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_u128(const char* str, std::size_t len) noexcept { uint128_t result {}; detail::from_chars(str, str + len, result); return result; } -constexpr uint128_t operator ""_U128(const char* str, std::size_t len) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_U128(const char* str, std::size_t len) noexcept { uint128_t result {}; detail::from_chars(str, str + len, result); return result; } -constexpr uint128_t operator ""_u128(unsigned long long v) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_u128(unsigned long long v) noexcept { return uint128_t{v}; } -constexpr uint128_t operator ""_U128(unsigned long long v) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t operator ""_U128(unsigned long long v) noexcept { return uint128_t{v}; } -constexpr int128_t operator ""_i128(const char* str) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(const char* str) noexcept { int128_t result {}; detail::from_chars(str, str + detail::strlen(str), result); return result; } -constexpr int128_t operator ""_I128(const char* str) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(const char* str) noexcept { int128_t result {}; detail::from_chars(str, str + detail::strlen(str), result); return result; } -constexpr int128_t operator ""_i128(unsigned long long v) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(unsigned long long v) noexcept { return int128_t{v}; } -constexpr int128_t operator ""_I128(unsigned long long v) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(unsigned long long v) noexcept { return int128_t{v}; } -constexpr int128_t operator ""_i128(const char* str, std::size_t len) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_i128(const char* str, std::size_t len) noexcept { int128_t result {}; detail::from_chars(str, str + len, result); return result; } -constexpr int128_t operator ""_I128(const char* str, std::size_t len) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(const char* str, std::size_t len) noexcept { int128_t result {}; detail::from_chars(str, str + len, result); diff --git a/include/boost/decimal/detail/int128/numeric.hpp b/include/boost/decimal/detail/int128/numeric.hpp index ceecb660c..0ef1637d4 100644 --- a/include/boost/decimal/detail/int128/numeric.hpp +++ b/include/boost/decimal/detail/int128/numeric.hpp @@ -5,10 +5,14 @@ #ifndef BOOST_DECIMAL_DETAIL_INT128_NUMERIC_HPP #define BOOST_DECIMAL_DETAIL_INT128_NUMERIC_HPP -#include "bit.hpp" -#include "detail/traits.hpp" +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + #include -#include + +#endif namespace boost { namespace int128 { @@ -35,20 +39,20 @@ struct reduced_integers #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_reduced_integer_v {reduced_integers::value || +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_reduced_integer_v {reduced_integers::value || std::is_same::value || std::is_same::value}; #else template -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE bool is_reduced_integer_v {reduced_integers::value}; +BOOST_DECIMAL_DETAIL_INT128_INLINE_CONSTEXPR bool is_reduced_integer_v {reduced_integers::value}; #endif // 128-bit } // namespace detail -constexpr uint128_t add_sat(const uint128_t x, const uint128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t add_sat(const uint128_t x, const uint128_t y) noexcept { const auto z {x + y}; @@ -60,7 +64,7 @@ constexpr uint128_t add_sat(const uint128_t x, const uint128_t y) noexcept return z; } -constexpr uint128_t sub_sat(const uint128_t x, const uint128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t sub_sat(const uint128_t x, const uint128_t y) noexcept { const auto z {x - y}; @@ -72,72 +76,67 @@ constexpr uint128_t sub_sat(const uint128_t x, const uint128_t y) noexcept return z; } -constexpr int128_t add_sat(int128_t x, int128_t y) noexcept; -constexpr int128_t sub_sat(int128_t x, int128_t y) noexcept; - #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4307) // Addition Overflow # pragma warning(disable : 4146) // Unary minus applied to unsigned type #endif -constexpr int128_t add_sat(const int128_t x, const int128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t add_sat(const int128_t x, const int128_t y) noexcept { - if (x >= 0 && y >= 0) - { - constexpr auto max_value {static_cast((std::numeric_limits::max)())}; - const auto big_x {static_cast(x)}; - const auto big_y {static_cast(y)}; - const auto big_res {big_x + big_y}; + // Detect overflow BEFORE the addition to avoid signed overflow UB. + // When both are non-negative: overflow iff x > max - y (subtraction safe: max - non_negative >= 0) + // When both are negative: overflow iff x < min - y (subtraction safe: min - negative > min) + // Mixed signs: overflow is impossible. - return big_res > max_value ? (std::numeric_limits::max)() : static_cast(big_res); - } - else if ((x < 0 && y > 0) || (x > 0 && y < 0)) + if (x.high >= 0 && y.high >= 0) { - return x + y; + if (x > (std::numeric_limits::max)() - y) + { + return (std::numeric_limits::max)(); + } } - else + else if (x.high < 0 && y.high < 0) { - // x < 0 and y < 0 - // Nearly the same technique as the positive values case - constexpr auto max_value {-static_cast((std::numeric_limits::min)())}; - const auto big_x {static_cast(abs(x))}; - const auto big_y {static_cast(abs(y))}; - const auto big_res {big_x + big_y}; - - return big_res > max_value ? (std::numeric_limits::min)() : -static_cast(big_res); + if (x < (std::numeric_limits::min)() - y) + { + return (std::numeric_limits::min)(); + } } + + return x + y; } -constexpr int128_t sub_sat(const int128_t x, const int128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t sub_sat(const int128_t x, const int128_t y) noexcept { - if (x <= 0 && y >= 0) - { - // Underflow case - const auto res {x - y}; - return res > x ? (std::numeric_limits::min)() : res; - } - else if (x > 0 && y < 0) - { - // Overflow Case - constexpr auto max_val {static_cast((std::numeric_limits::max)())}; - const auto big_x {static_cast(x)}; - const auto big_y {-static_cast(y)}; - const auto res {big_x + big_y}; + // Detect overflow BEFORE the subtraction to avoid signed overflow UB. + // Positive overflow: x >= 0 and y < 0 and x > max + y (safe: max + negative < max) + // Negative overflow: x < 0 and y >= 0 and x < min + y (safe: min + non_negative > min) + // Same signs: overflow is impossible. - return (res > max_val || res < big_x) ? (std::numeric_limits::max)() : static_cast(res); + if (x.high >= 0 && y.high < 0) + { + if (x > (std::numeric_limits::max)() + y) + { + return (std::numeric_limits::max)(); + } } - else + else if (x.high < 0 && y.high >= 0) { - return x - y; + if (x < (std::numeric_limits::min)() + y) + { + return (std::numeric_limits::min)(); + } } + + return x - y; } #ifdef _MSC_VER # pragma warning(pop) #endif -constexpr uint128_t mul_sat(const uint128_t x, const uint128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t mul_sat(const uint128_t x, const uint128_t y) noexcept { const auto x_bits {bit_width(x)}; const auto y_bits {bit_width(y)}; @@ -150,7 +149,7 @@ constexpr uint128_t mul_sat(const uint128_t x, const uint128_t y) noexcept return x * y; } -constexpr int128_t mul_sat(const int128_t& x, const int128_t& y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t mul_sat(const int128_t& x, const int128_t& y) noexcept { const auto x_bits {bit_width(static_cast(abs(x)))}; const auto y_bits {bit_width(static_cast(abs(y)))}; @@ -171,12 +170,12 @@ constexpr int128_t mul_sat(const int128_t& x, const int128_t& y) noexcept return res; } -constexpr uint128_t div_sat(const uint128_t x, const uint128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t div_sat(const uint128_t x, const uint128_t y) noexcept { return x / y; } -constexpr int128_t div_sat(const int128_t x, const int128_t y) noexcept +BOOST_DECIMAL_DETAIL_INT128_EXPORT BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t div_sat(const int128_t x, const int128_t y) noexcept { if (BOOST_DECIMAL_DETAIL_INT128_UNLIKELY(x == (std::numeric_limits::min)() && y == -1)) { @@ -187,12 +186,17 @@ constexpr int128_t div_sat(const int128_t x, const int128_t y) noexcept return x / y; } -template , bool> = true> -constexpr TargetType saturate_cast(const uint128_t value) noexcept +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4267) +#endif + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template , bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr TargetType saturate_cast(const uint128_t value) noexcept { BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) { - return value; + return static_cast(value); } else { @@ -205,12 +209,16 @@ constexpr TargetType saturate_cast(const uint128_t value) noexcept } } -template , bool> = true> -constexpr TargetType saturate_cast(const int128_t value) noexcept +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +BOOST_DECIMAL_DETAIL_INT128_EXPORT template , bool> = true> +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr TargetType saturate_cast(const int128_t value) noexcept { BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value) { - return value; + return static_cast(value); } #if defined(BOOST_DECIMAL_DETAIL_INT128_HAS_INT128) || defined(BOOST_DECIMAL_DETAIL_INT128_HAS_MSVC_INT128) else BOOST_DECIMAL_DETAIL_INT128_IF_CONSTEXPR (std::is_same::value || std::is_same::value) @@ -236,6 +244,185 @@ constexpr TargetType saturate_cast(const int128_t value) noexcept } } +namespace detail { + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr std::uint64_t gcd64(std::uint64_t x, std::uint64_t y) noexcept +{ + if (x == 0) + { + return y; + } + if (y == 0) + { + return x; + } + + const auto s {impl::countr_impl(x | y)}; + x >>= impl::countr_impl(x); + + do + { + y >>= impl::countr_impl(y); + if (x > y) + { + const auto temp {x}; + x = y; + y = temp; + } + + y -= x; + } while (y); + + return x << s; +} + +} // namespace detail + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t gcd(uint128_t a, uint128_t b) noexcept +{ + // Base case + if (a == 0U) + { + return b; + } + if (b == 0U) + { + return a; + } + + const auto a_zero {countr_zero(a)}; + const auto b_zero {countr_zero(b)}; + const auto shift {b_zero < a_zero ? b_zero : a_zero}; + a >>= shift; + b >>= shift; + + do + { + b >>= countr_zero(b); + + if (a > b) + { + const uint128_t temp {a}; + a = b; + b = temp; + } + + b -= a; + } while (b != 0U && (a.high | b.high) > 0U); + + // Stop doing 128-bit math as soon as we can + const auto g {detail::gcd64(a.low, b.low)}; + return uint128_t{0, g} << shift; +} + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t gcd(const int128_t a, const int128_t b) noexcept +{ + return static_cast(gcd(static_cast(abs(a)), static_cast(abs(b)))); +} + +// For unknown reasons this implementation fails for MSVC x86 only in release mode +// Directly calculating leads to the same failures, so unfortunately we have a viable, +// but very slow impl that we know works. +#if !(defined(_M_IX86) && !defined(_NDEBUG)) + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t lcm(const uint128_t a, const uint128_t b) noexcept +{ + if (a == 0U || b == 0U) + { + return static_cast(0); + } + + // Calculate GCD first + const auto g {gcd(a, b)}; + + // Compute LCM avoiding overflow: (a/gcd) * b + return (a / g) * b; +} + +#else + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t lcm(uint128_t a, uint128_t b) noexcept +{ + if (a == 0U || b == 0U) + { + return uint128_t{0}; + } + + + unsigned shift{}; + while ((a & 1U) == 0U && (b & 1U) == 0U) + { + a >>= 1U; + b >>= 1U; + shift++; + } + + // Ensure a >= b + if (a < b) + { + std::swap(a, b); + } + + uint128_t lcm{a}; + + while (lcm % b != 0U) + { + lcm += a; + } + + return lcm << shift; +} + +#endif + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t lcm(const int128_t a, const int128_t b) noexcept +{ + return static_cast(lcm(static_cast(abs(a)), static_cast(abs(b)))); +} + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr uint128_t midpoint(const uint128_t a, const uint128_t b) noexcept +{ + // Bit manipulation formula works for unsigned integers + auto mid {(a & b) + ((a ^ b) >> 1)}; + + // std::midpoint rounds towards the first parameter + if ((a ^ b) & 1U && a > b) + { + ++mid; + } + + return mid; +} + +BOOST_DECIMAL_DETAIL_INT128_HOST_DEVICE constexpr int128_t midpoint(const int128_t a, const int128_t b) noexcept +{ + // For signed integers, we use a + (b - a) / 2 or a - (a - b) / 2 + // The subtraction is done in unsigned arithmetic to handle overflow correctly + // Integer division automatically rounds toward the first argument + // + // Use direct field access for both the uint128 construction and the + // comparison to avoid NVCC host compiler issues with operator<= and + // static_cast on int128_t for large-magnitude values + + const uint128_t ua {static_cast(a.high), a.low}; + const uint128_t ub {static_cast(b.high), b.low}; + + const bool a_le_b {a.high == b.high ? a.low <= b.low : a.high < b.high}; + + if (a_le_b) + { + // diff = b - a (computed in unsigned, handles wrap-around correctly) + const auto diff {ub - ua}; + return a + static_cast(diff / 2U); + } + else + { + // diff = a - b (computed in unsigned, handles wrap-around correctly) + const auto diff {ua - ub}; + return a - static_cast(diff / 2U); + } +} + } // namespace int128 } // namespace boost diff --git a/include/boost/decimal/detail/int128/random.hpp b/include/boost/decimal/detail/int128/random.hpp new file mode 100644 index 000000000..fad18f6c8 --- /dev/null +++ b/include/boost/decimal/detail/int128/random.hpp @@ -0,0 +1,96 @@ +// Copyright 2026 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_INT128_RANDOM_HPP +#define BOOST_DECIMAL_DETAIL_INT128_RANDOM_HPP + +#include + +namespace boost { +namespace random { +namespace traits { + +template +struct make_unsigned_imp; + +template <> +struct make_unsigned_imp +{ + using type = int128::uint128_t; +}; + +template <> +struct make_unsigned_imp +{ + using type = int128::uint128_t; +}; + +template +struct make_unsigned; + +template <> +struct make_unsigned +{ + using type = int128::uint128_t; +}; + +template <> +struct make_unsigned +{ + using type = int128::int128_t; +}; + +template +struct make_unsigned_or_unbounded_imp; + +template <> +struct make_unsigned_or_unbounded_imp +{ + using type = int128::uint128_t; +}; + +template <> +struct make_unsigned_or_unbounded_imp +{ + using type = int128::uint128_t; +}; + +template +struct make_unsigned_or_unbounded; + +template <> +struct make_unsigned_or_unbounded +{ + using type = int128::uint128_t; +}; + +template <> +struct make_unsigned_or_unbounded +{ + using type = int128::uint128_t; +}; + +template +struct is_integral; + +template <> +struct is_integral : std::true_type {}; + +template <> +struct is_integral : std::true_type {}; + +template +struct is_signed; + +template <> +struct is_signed : std::false_type {}; + +template <> +struct is_signed : std::true_type {}; + +} // namespace traits +} // namespace random +} // namespace boost + +#endif // BOOST_DECIMAL_DETAIL_INT128_RANDOM_HPP diff --git a/include/boost/decimal/detail/int128/string.hpp b/include/boost/decimal/detail/int128/string.hpp new file mode 100644 index 000000000..db8adf5ed --- /dev/null +++ b/include/boost/decimal/detail/int128/string.hpp @@ -0,0 +1,31 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_INT128_STRING_HPP +#define BOOST_DECIMAL_DETAIL_INT128_STRING_HPP + +#include +#include + +#ifndef BOOST_DECIMAL_DETAIL_INT128_BUILD_MODULE + +#include + +#endif + +namespace boost { +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]; + const auto last {detail::mini_to_chars(buffer, value, 10, false)}; + return std::string{last, buffer + sizeof(buffer)}; +} + +} // namespace int128 +} // namespace boost + +#endif // BOOST_DECIMAL_DETAIL_INT128_STRING_HPP