diff --git a/include/boost/charconv/detail/dragonbox.hpp b/include/boost/charconv/detail/dragonbox.hpp index b1725c7..ecece09 100644 --- a/include/boost/charconv/detail/dragonbox.hpp +++ b/include/boost/charconv/detail/dragonbox.hpp @@ -25,63 +25,12 @@ #include #include #include +#include #include +#include #include -// Suppress additional buffer overrun check. -// I have no idea why MSVC thinks some functions here are vulnerable to the buffer overrun -// attacks. No, they aren't. -#if defined(__GNUC__) || defined(__clang__) - #define JKJ_SAFEBUFFERS - #define JKJ_FORCEINLINE inline __attribute__((always_inline)) -#elif defined(_MSC_VER) - #define JKJ_SAFEBUFFERS __declspec(safebuffers) - #define JKJ_FORCEINLINE __forceinline -#else - #define JKJ_SAFEBUFFERS - #define JKJ_FORCEINLINE inline -#endif - -#if defined(__has_builtin) - #define JKJ_DRAGONBOX_HAS_BUILTIN(x) __has_builtin(x) -#else - #define JKJ_DRAGONBOX_HAS_BUILTIN(x) false -#endif - -#if defined(_MSC_VER) - #include -#endif - namespace jkj::dragonbox { - namespace detail { - template - constexpr std::size_t - physical_bits = sizeof(T) * std::numeric_limits::digits; - - template - constexpr std::size_t value_bits = - std::numeric_limits, T>>::digits; - } - - // These classes expose encoding specs of IEEE-754-like floating-point formats. - // Currently available formats are IEEE754-binary32 & IEEE754-binary64. - - struct ieee754_binary32 { - static constexpr int significand_bits = 23; - static constexpr int exponent_bits = 8; - static constexpr int min_exponent = -126; - static constexpr int max_exponent = 127; - static constexpr int exponent_bias = -127; - static constexpr int decimal_digits = 9; - }; - struct ieee754_binary64 { - static constexpr int significand_bits = 52; - static constexpr int exponent_bits = 11; - static constexpr int min_exponent = -1022; - static constexpr int max_exponent = 1023; - static constexpr int exponent_bias = -1023; - static constexpr int decimal_digits = 17; - }; // A floating-point traits class defines ways to interpret a bit pattern of given size as an // encoding of floating-point number. This is a default implementation of such a traits class, @@ -93,7 +42,7 @@ namespace jkj::dragonbox { // I don't know if there is a truly reliable way of detecting // IEEE-754 binary32/binary64 formats; I just did my best here. static_assert(std::numeric_limits::is_iec559 && std::numeric_limits::radix == 2 && - (detail::physical_bits == 32 || detail::physical_bits == 64), + (boost::charconv::detail::physical_bits::value == 32 || boost::charconv::detail::physical_bits::value == 64), "default_ieee754_traits only works for 32-bits or 64-bits types " "supporting binary32 or binary64 formats!"); @@ -102,16 +51,16 @@ namespace jkj::dragonbox { // Refers to the format specification class. using format = - std::conditional_t == 32, ieee754_binary32, ieee754_binary64>; + std::conditional_t::value == 32, boost::charconv::detail::ieee754_binary32, boost::charconv::detail::ieee754_binary64>; // Defines an unsigned integer type that is large enough to carry a variable of type T. // Most of the operations will be done on this integer type. using carrier_uint = - std::conditional_t == 32, std::uint32_t, std::uint64_t>; + std::conditional_t::value == 32, std::uint32_t, std::uint64_t>; static_assert(sizeof(carrier_uint) == sizeof(T)); // Number of bits in the above unsigned integer type. - static constexpr int carrier_bits = int(detail::physical_bits); + static constexpr int carrier_bits = int(boost::charconv::detail::physical_bits::value); // Convert from carrier_uint into the original type. // Depending on the floating-point encoding format, this operation might not be possible for @@ -136,7 +85,7 @@ namespace jkj::dragonbox { static constexpr unsigned int extract_exponent_bits(carrier_uint u) noexcept { constexpr int significand_bits = format::significand_bits; constexpr int exponent_bits = format::exponent_bits; - static_assert(detail::value_bits > exponent_bits); + static_assert(boost::charconv::detail::value_bits::value > exponent_bits); constexpr auto exponent_bits_mask = (static_cast(1) << exponent_bits) - 1; return static_cast(u >> significand_bits) & exponent_bits_mask; @@ -316,85 +265,6 @@ namespace jkj::dragonbox { }; namespace detail { - - //////////////////////////////////////////////////////////////////////////////////////// - // Utilities for fast/constexpr log computation. - //////////////////////////////////////////////////////////////////////////////////////// - - namespace log { - static_assert((-1 >> 1) == -1, "right-shift for signed integers must be arithmetic"); - - // Compute floor(e * c - s). - enum class multiply : std::uint32_t {}; - enum class subtract : std::uint32_t {}; - enum class shift : std::size_t {}; - enum class min_exponent : std::int32_t {}; - enum class max_exponent : std::int32_t {}; - - template - constexpr int compute(int e) noexcept { - assert(std::int32_t(e_min) <= e && e <= std::int32_t(e_max)); - return int((std::int32_t(e) * std::int32_t(m) - std::int32_t(f)) >> std::size_t(k)); - } - - // For constexpr computation. - // Returns -1 when n = 0. - template - constexpr int floor_log2(UInt n) noexcept { - int count = -1; - while (n != 0) { - ++count; - n >>= 1; - } - return count; - } - - static constexpr int floor_log10_pow2_min_exponent = -2620; - static constexpr int floor_log10_pow2_max_exponent = 2620; - constexpr int floor_log10_pow2(int e) noexcept { - using namespace log; - return compute(e); - } - - static constexpr int floor_log2_pow10_min_exponent = -1233; - static constexpr int floor_log2_pow10_max_exponent = 1233; - constexpr int floor_log2_pow10(int e) noexcept { - using namespace log; - return compute(e); - } - - static constexpr int floor_log10_pow2_minus_log10_4_over_3_min_exponent = -2985; - static constexpr int floor_log10_pow2_minus_log10_4_over_3_max_exponent = 2936; - constexpr int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept { - using namespace log; - return compute(e); - } - - static constexpr int floor_log5_pow2_min_exponent = -1831; - static constexpr int floor_log5_pow2_max_exponent = 1831; - constexpr int floor_log5_pow2(int e) noexcept { - using namespace log; - return compute(e); - } - - static constexpr int floor_log5_pow2_minus_log5_3_min_exponent = -3543; - static constexpr int floor_log5_pow2_minus_log5_3_max_exponent = 2427; - constexpr int floor_log5_pow2_minus_log5_3(int e) noexcept { - using namespace log; - return compute(e); - } - } - //////////////////////////////////////////////////////////////////////////////////////// // Utilities for fast divisibility tests. //////////////////////////////////////////////////////////////////////////////////////// @@ -422,7 +292,7 @@ namespace jkj::dragonbox { template constexpr bool check_divisibility_and_divide_by_pow10(std::uint32_t& n) noexcept { // Make sure the computation for max_n does not overflow. - static_assert(N + 1 <= log::floor_log10_pow2(31)); + static_assert(N + 1 <= boost::charconv::detail::log::floor_log10_pow2(31)); assert(n <= boost::charconv::detail::compute_power(std::uint32_t(10), N + 1)); using info = divide_by_pow10_info; @@ -440,7 +310,7 @@ namespace jkj::dragonbox { template constexpr std::uint32_t small_division_by_pow10(std::uint32_t n) noexcept { // Make sure the computation for max_n does not overflow. - static_assert(N + 1 <= log::floor_log10_pow2(31)); + static_assert(N + 1 <= boost::charconv::detail::log::floor_log10_pow2(31)); assert(n <= boost::charconv::detail::compute_power(std::uint32_t(10), N + 1)); return (n * divide_by_pow10_info::magic_number) >> @@ -534,7 +404,7 @@ namespace jkj::dragonbox { struct cache_holder; template <> - struct cache_holder { + struct cache_holder { using cache_entry_type = std::uint64_t; static constexpr int cache_bits = 64; static constexpr int min_k = -31; @@ -563,7 +433,7 @@ namespace jkj::dragonbox { }; template <> - struct cache_holder { + struct cache_holder { using cache_entry_type = boost::charconv::detail::uint128; static constexpr int cache_bits = 128; static constexpr int min_k = -292; @@ -885,7 +755,7 @@ namespace jkj::dragonbox { struct compressed_cache_detail { static constexpr int compression_ratio = 27; static constexpr std::size_t compressed_table_size = - (cache_holder::max_k - cache_holder::min_k + + (cache_holder::max_k - cache_holder::min_k + compression_ratio) / compression_ratio; @@ -895,7 +765,7 @@ namespace jkj::dragonbox { static constexpr cache_holder_t cache = [] { cache_holder_t res{}; for (std::size_t i = 0; i < compressed_table_size; ++i) { - res.table[i] = cache_holder::cache[i * compression_ratio]; + res.table[i] = cache_holder::cache[i * compression_ratio]; } return res; }(); @@ -971,7 +841,7 @@ namespace jkj::dragonbox { static constexpr bool report_trailing_zeros = false; template - JKJ_FORCEINLINE static constexpr void + BOOST_FORCEINLINE static constexpr void on_trailing_zeros(ReturnType& r) noexcept { r.exponent += Impl::remove_trailing_zeros(r.significand); } @@ -1047,17 +917,17 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::closed; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(nearest_to_even{}); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept { return f(s.has_even_significand_bits()); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } @@ -1069,17 +939,17 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::open; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(nearest_to_odd{}); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept { return f(!s.has_even_significand_bits()); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } @@ -1091,17 +961,17 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::asymmetric_boundary; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(nearest_toward_plus_infinity{}); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept { return f(!s.is_negative()); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits s, Func&& f) noexcept { return f(!s.is_negative()); } @@ -1113,17 +983,17 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::asymmetric_boundary; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(nearest_toward_minus_infinity{}); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept { return f(s.is_negative()); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits s, Func&& f) noexcept { return f(s.is_negative()); } @@ -1135,17 +1005,17 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::right_closed_left_open; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(nearest_toward_zero{}); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } @@ -1157,17 +1027,17 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::left_closed_right_open; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(nearest_away_from_zero{}); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } @@ -1180,12 +1050,12 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::closed; template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } @@ -1196,12 +1066,12 @@ namespace jkj::dragonbox { using shorter_interval_type = interval_type::open; template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } template - JKJ_FORCEINLINE static constexpr auto + BOOST_FORCEINLINE static constexpr auto invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept { return f(); } @@ -1211,7 +1081,7 @@ namespace jkj::dragonbox { struct nearest_to_even_static_boundary : base { using decimal_to_binary_rounding_policy = nearest_to_even_static_boundary; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits s, + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits s, Func&& f) noexcept { if (s.has_even_significand_bits()) { return f(detail::nearest_always_closed{}); @@ -1224,7 +1094,7 @@ namespace jkj::dragonbox { struct nearest_to_odd_static_boundary : base { using decimal_to_binary_rounding_policy = nearest_to_odd_static_boundary; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits s, + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits s, Func&& f) noexcept { if (s.has_even_significand_bits()) { return f(detail::nearest_always_open{}); @@ -1238,7 +1108,7 @@ namespace jkj::dragonbox { using decimal_to_binary_rounding_policy = nearest_toward_plus_infinity_static_boundary; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits s, + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits s, Func&& f) noexcept { if (s.is_negative()) { return f(nearest_toward_zero{}); @@ -1252,7 +1122,7 @@ namespace jkj::dragonbox { using decimal_to_binary_rounding_policy = nearest_toward_minus_infinity_static_boundary; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits s, + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits s, Func&& f) noexcept { if (s.is_negative()) { return f(nearest_away_from_zero{}); @@ -1275,7 +1145,7 @@ namespace jkj::dragonbox { struct toward_plus_infinity : base { using decimal_to_binary_rounding_policy = toward_plus_infinity; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits s, + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits s, Func&& f) noexcept { if (s.is_negative()) { return f(detail::left_closed_directed{}); @@ -1288,7 +1158,7 @@ namespace jkj::dragonbox { struct toward_minus_infinity : base { using decimal_to_binary_rounding_policy = toward_minus_infinity; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits s, + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits s, Func&& f) noexcept { if (s.is_negative()) { return f(detail::right_closed_directed{}); @@ -1301,14 +1171,14 @@ namespace jkj::dragonbox { struct toward_zero : base { using decimal_to_binary_rounding_policy = toward_zero; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(detail::left_closed_directed{}); } }; struct away_from_zero : base { using decimal_to_binary_rounding_policy = away_from_zero; template - JKJ_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { + BOOST_FORCEINLINE static auto delegate(SignedSignificandBits, Func&& f) noexcept { return f(detail::right_closed_directed{}); } }; @@ -1396,7 +1266,7 @@ namespace jkj::dragonbox { assert(k >= cache_holder::min_k && k <= cache_holder::max_k); - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { // Compute the base index. auto const cache_index = int(std::uint32_t(k - cache_holder::min_k) / @@ -1415,8 +1285,8 @@ namespace jkj::dragonbox { } else { // Compute the required amount of bit-shift. - auto const alpha = log::floor_log2_pow10(kb + offset) - - log::floor_log2_pow10(kb) - offset; + auto const alpha = boost::charconv::detail::log::floor_log2_pow10(kb + offset) - + boost::charconv::detail::log::floor_log2_pow10(kb) - offset; assert(alpha > 0 && alpha < 64); // Try to recover the real cache. @@ -1534,15 +1404,15 @@ namespace jkj::dragonbox { using format::exponent_bias; using format::decimal_digits; - static constexpr int kappa = std::is_same_v ? 1 : 2; + static constexpr int kappa = std::is_same_v ? 1 : 2; static_assert(kappa >= 1); - static_assert(carrier_bits >= significand_bits + 2 + log::floor_log2_pow10(kappa + 1)); + static_assert(carrier_bits >= significand_bits + 2 + boost::charconv::detail::log::floor_log2_pow10(kappa + 1)); static constexpr int min_k = [] { - constexpr auto a = -log::floor_log10_pow2_minus_log10_4_over_3( + constexpr auto a = -boost::charconv::detail::log::floor_log10_pow2_minus_log10_4_over_3( int(max_exponent - significand_bits)); constexpr auto b = - -log::floor_log10_pow2(int(max_exponent - significand_bits)) + kappa; + -boost::charconv::detail::log::floor_log10_pow2(int(max_exponent - significand_bits)) + kappa; return a < b ? a : b; }(); static_assert(min_k >= cache_holder::min_k); @@ -1550,10 +1420,10 @@ namespace jkj::dragonbox { static constexpr int max_k = [] { // We do invoke shorter_interval_case for exponent == min_exponent case, // so we should not add 1 here. - constexpr auto a = -log::floor_log10_pow2_minus_log10_4_over_3( + constexpr auto a = -boost::charconv::detail::log::floor_log10_pow2_minus_log10_4_over_3( int(min_exponent - significand_bits /*+ 1*/)); constexpr auto b = - -log::floor_log10_pow2(int(min_exponent - significand_bits)) + kappa; + -boost::charconv::detail::log::floor_log10_pow2(int(min_exponent - significand_bits)) + kappa; return a > b ? a : b; }(); static_assert(max_k <= cache_holder::max_k); @@ -1564,7 +1434,7 @@ namespace jkj::dragonbox { static constexpr int case_shorter_interval_left_endpoint_lower_threshold = 2; static constexpr int case_shorter_interval_left_endpoint_upper_threshold = 2 + - log::floor_log2( + boost::charconv::detail::log::floor_log2( boost::charconv::detail::compute_power (10, boost::charconv::detail::count_factors<5>((carrier_uint(1) << (significand_bits + 2)) - 1) + 1) / 3); @@ -1572,14 +1442,14 @@ namespace jkj::dragonbox { static constexpr int case_shorter_interval_right_endpoint_lower_threshold = 0; static constexpr int case_shorter_interval_right_endpoint_upper_threshold = 2 + - log::floor_log2( + boost::charconv::detail::log::floor_log2( boost::charconv::detail::compute_power(10, boost::charconv::detail::count_factors<5>((carrier_uint(1) << (significand_bits + 1)) + 1) + 1) / 3); static constexpr int shorter_interval_tie_lower_threshold = - -log::floor_log5_pow2_minus_log5_3(significand_bits + 4) - 2 - significand_bits; + -boost::charconv::detail::log::floor_log5_pow2_minus_log5_3(significand_bits + 4) - 2 - significand_bits; static constexpr int shorter_interval_tie_upper_threshold = - -log::floor_log5_pow2(significand_bits + 2) - 2 - significand_bits; + -boost::charconv::detail::log::floor_log5_pow2(significand_bits + 2) - 2 - significand_bits; struct compute_mul_result { carrier_uint result; @@ -1595,7 +1465,7 @@ namespace jkj::dragonbox { template - JKJ_SAFEBUFFERS static ReturnType + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_nearest_normal(carrier_uint const two_fc, int const exponent, AdditionalArgs... additional_args) noexcept { ////////////////////////////////////////////////////////////////////// @@ -1606,9 +1476,9 @@ namespace jkj::dragonbox { IntervalType interval_type{additional_args...}; // Compute k and beta. - int const minus_k = log::floor_log10_pow2(exponent) - kappa; + int const minus_k = boost::charconv::detail::log::floor_log10_pow2(exponent) - kappa; auto const cache = CachePolicy::template get_cache(-minus_k); - int const beta = exponent + log::floor_log2_pow10(-minus_k); + int const beta = exponent + boost::charconv::detail::log::floor_log2_pow10(-minus_k); // Compute zi and deltai. // 10^kappa <= deltai < 10^(kappa + 1) @@ -1747,15 +1617,15 @@ namespace jkj::dragonbox { template - JKJ_SAFEBUFFERS static ReturnType + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_nearest_shorter(int const exponent, AdditionalArgs... additional_args) noexcept { ReturnType ret_value; IntervalType interval_type{additional_args...}; // Compute k and beta. - int const minus_k = log::floor_log10_pow2_minus_log10_4_over_3(exponent); - int const beta = exponent + log::floor_log2_pow10(-minus_k); + int const minus_k = boost::charconv::detail::log::floor_log10_pow2_minus_log10_4_over_3(exponent); + int const beta = exponent + boost::charconv::detail::log::floor_log2_pow10(-minus_k); // Compute xi and zi. auto const cache = CachePolicy::template get_cache(-minus_k); @@ -1804,7 +1674,7 @@ namespace jkj::dragonbox { } template - JKJ_SAFEBUFFERS static ReturnType + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_left_closed_directed(carrier_uint const two_fc, int exponent) noexcept { ////////////////////////////////////////////////////////////////////// // Step 1: Schubfach multiplier calculation @@ -1813,9 +1683,9 @@ namespace jkj::dragonbox { ReturnType ret_value; // Compute k and beta. - int const minus_k = log::floor_log10_pow2(exponent) - kappa; + int const minus_k = boost::charconv::detail::log::floor_log10_pow2(exponent) - kappa; auto const cache = CachePolicy::template get_cache(-minus_k); - int const beta = exponent + log::floor_log2_pow10(-minus_k); + int const beta = exponent + boost::charconv::detail::log::floor_log2_pow10(-minus_k); // Compute xi and deltai. // 10^kappa <= deltai < 10^(kappa + 1) @@ -1828,7 +1698,7 @@ namespace jkj::dragonbox { // and 29711844 * 2^-81 // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17 // for binary32. - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { if (exponent <= -80) { is_x_integer = false; } @@ -1893,7 +1763,7 @@ namespace jkj::dragonbox { } template - JKJ_SAFEBUFFERS static ReturnType + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_right_closed_directed(carrier_uint const two_fc, int const exponent, bool shorter_interval) noexcept { ////////////////////////////////////////////////////////////////////// @@ -1904,9 +1774,9 @@ namespace jkj::dragonbox { // Compute k and beta. int const minus_k = - log::floor_log10_pow2(exponent - (shorter_interval ? 1 : 0)) - kappa; + boost::charconv::detail::log::floor_log10_pow2(exponent - (shorter_interval ? 1 : 0)) - kappa; auto const cache = CachePolicy::template get_cache(-minus_k); - int const beta = exponent + log::floor_log2_pow10(-minus_k); + int const beta = exponent + boost::charconv::detail::log::floor_log2_pow10(-minus_k); // Compute zi and deltai. // 10^kappa <= deltai < 10^(kappa + 1) @@ -1959,10 +1829,10 @@ namespace jkj::dragonbox { } // Remove trailing zeros from n and return the number of zeros removed. - JKJ_FORCEINLINE static int remove_trailing_zeros(carrier_uint& n) noexcept { + BOOST_FORCEINLINE static int remove_trailing_zeros(carrier_uint& n) noexcept { assert(n != 0); - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { constexpr auto mod_inv_5 = std::uint32_t(0xcccc'cccd); constexpr auto mod_inv_25 = mod_inv_5 * mod_inv_5; @@ -1986,7 +1856,7 @@ namespace jkj::dragonbox { return s; } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); // Divide by 10^8 and reduce to 32-bits if divisible. // Since ret_value.significand <= (2^53 * 1000 - 1) / 1000 < 10^16, @@ -2053,12 +1923,12 @@ namespace jkj::dragonbox { static compute_mul_result compute_mul(carrier_uint u, cache_entry_type const& cache) noexcept { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { auto r = boost::charconv::detail::umul96_upper64(u, cache); return {carrier_uint(r >> 32), carrier_uint(r) == 0}; } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); auto r = boost::charconv::detail::umul192_upper128(u, cache); return {r.high, r.low == 0}; } @@ -2066,11 +1936,11 @@ namespace jkj::dragonbox { static constexpr std::uint32_t compute_delta(cache_entry_type const& cache, int beta) noexcept { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { return std::uint32_t(cache >> (cache_bits - 1 - beta)); } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); return std::uint32_t(cache.high >> (carrier_bits - 1 - beta)); } } @@ -2081,12 +1951,12 @@ namespace jkj::dragonbox { assert(beta >= 1); assert(beta < 64); - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { auto r = boost::charconv::detail::umul96_lower64(two_f, cache); return {((r >> (64 - beta)) & 1) != 0, std::uint32_t(r >> (32 - beta)) == 0}; } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); auto r = boost::charconv::detail::umul192_lower128(two_f, cache); return {((r.high >> (64 - beta)) & 1) != 0, ((r.high << beta) | (r.low >> (64 - beta))) == 0}; @@ -2096,12 +1966,12 @@ namespace jkj::dragonbox { static constexpr carrier_uint compute_left_endpoint_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { return carrier_uint((cache - (cache >> (significand_bits + 2))) >> (cache_bits - significand_bits - 1 - beta)); } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); return (cache.high - (cache.high >> (significand_bits + 2))) >> (carrier_bits - significand_bits - 1 - beta); } @@ -2110,12 +1980,12 @@ namespace jkj::dragonbox { static constexpr carrier_uint compute_right_endpoint_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { return carrier_uint((cache + (cache >> (significand_bits + 1))) >> (cache_bits - significand_bits - 1 - beta)); } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); return (cache.high + (cache.high >> (significand_bits + 1))) >> (carrier_bits - significand_bits - 1 - beta); } @@ -2124,12 +1994,12 @@ namespace jkj::dragonbox { static constexpr carrier_uint compute_round_up_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { return (carrier_uint(cache >> (cache_bits - significand_bits - 2 - beta)) + 1) / 2; } else { - static_assert(std::is_same_v); + static_assert(std::is_same_v); return ((cache.high >> (carrier_bits - significand_bits - 2 - beta)) + 1) / 2; } } @@ -2308,7 +2178,7 @@ namespace jkj::dragonbox { //////////////////////////////////////////////////////////////////////////////////////// template , class... Policies> - JKJ_FORCEINLINE JKJ_SAFEBUFFERS auto + BOOST_FORCEINLINE BOOST_CHARCONV_SAFEBUFFERS auto to_decimal(signed_significand_bits signed_significand_bits, unsigned int exponent_bits, Policies... policies) noexcept { // Build policy holder type. @@ -2367,8 +2237,8 @@ namespace jkj::dragonbox { // Hence, shorter_interval_case will return 2.225'073'858'507'201'4 * // 10^-308. This is indeed of the shortest length, and it is the unique one // closest to the true value among valid representations of the same length. - static_assert(std::is_same_v || - std::is_same_v); + static_assert(std::is_same_v || + std::is_same_v); if (two_fc == 0) { return decltype(interval_type_provider)::invoke_shorter_interval_case( @@ -2449,7 +2319,7 @@ namespace jkj::dragonbox { } template , class... Policies> - JKJ_FORCEINLINE JKJ_SAFEBUFFERS auto to_decimal(Float x, Policies... policies) noexcept { + BOOST_FORCEINLINE BOOST_CHARCONV_SAFEBUFFERS auto to_decimal(Float x, Policies... policies) noexcept { auto const br = float_bits(x); auto const exponent_bits = br.extract_exponent_bits(); auto const s = br.remove_exponent_bits(exponent_bits); @@ -2534,7 +2404,7 @@ namespace jkj::dragonbox { // Maximum required buffer size (excluding null-terminator) template inline constexpr std::size_t max_output_string_length = - std::is_same_v + std::is_same_v ? // sign(1) + significand(9) + decimal_point(1) + exp_marker(1) + exp_sign(1) + exp(2) (1 + 9 + 1 + 1 + 1 + 2) @@ -2544,15 +2414,6 @@ namespace jkj::dragonbox { (1 + 17 + 1 + 1 + 1 + 3); } - -#if defined(__GNUC__) || defined(__clang__) - #define JKJ_FORCEINLINE inline __attribute__((always_inline)) -#elif defined(_MSC_VER) - #define JKJ_FORCEINLINE __forceinline -#else - #define JKJ_FORCEINLINE inline -#endif - namespace jkj::dragonbox { namespace to_chars_detail { // These "//"'s are to prevent clang-format to ruin this nice alignment. @@ -2634,7 +2495,7 @@ namespace jkj::dragonbox { // floor(10^2 * ((10^4 * y) mod 2^32) / 2^32) = 67. // See https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ for more explanation. - JKJ_FORCEINLINE static void print_9_digits(std::uint32_t s32, int& exponent, + BOOST_FORCEINLINE static void print_9_digits(std::uint32_t s32, int& exponent, char*& buffer) noexcept { // -- IEEE-754 binary32 // Since we do not cut trailing zeros in advance, s32 must be of 6~9 digits @@ -3050,8 +2911,4 @@ namespace jkj::dragonbox { } } -#undef JKJ_FORCEINLINE -#undef JKJ_SAFEBUFFERS -#undef JKJ_DRAGONBOX_HAS_BUILTIN - -#endif \ No newline at end of file +#endif