LCOV - code coverage report
Current view: top level - json/detail/dragonbox - dragonbox_common.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 17 17
Test Date: 2026-02-03 18:58:32 Functions: 87.5 % 8 7

            Line data    Source code
       1              : // Copyright 2020-2022 Junekey Jeon
       2              : //
       3              : // The contents of this file may be used under the terms of
       4              : // the Apache License v2.0 with LLVM Exceptions.
       5              : //
       6              : //    (See accompanying file LICENSE-Apache or copy at
       7              : //     https://llvm.org/foundation/relicensing/LICENSE.txt)
       8              : //
       9              : // Alternatively, the contents of this file may be used under the terms of
      10              : // the Boost Software License, Version 1.0.
      11              : //    (See accompanying file LICENSE-Boost or copy at
      12              : //     https://www.boost.org/LICENSE_1_0.txt)
      13              : //
      14              : // Unless required by applicable law or agreed to in writing, this software
      15              : // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
      16              : // KIND, either express or implied.
      17              : //
      18              : // Some parts are copied from Dragonbox project.
      19              : //
      20              : // Copyright 2023 Matt Borland
      21              : // Distributed under the Boost Software License, Version 1.0.
      22              : // https://www.boost.org/LICENSE_1_0.txt
      23              : 
      24              : #ifndef BOOST_JSON_DETAIL_DRAGONBOX_DRAGONBOX_COMMON_HPP
      25              : #define BOOST_JSON_DETAIL_DRAGONBOX_DRAGONBOX_COMMON_HPP
      26              : 
      27              : #include <boost/json/detail/charconv/detail/config.hpp>
      28              : #include <boost/json/detail/dragonbox/bit_layouts.hpp>
      29              : #include <boost/json/detail/dragonbox/emulated128.hpp>
      30              : #include <boost/core/bit.hpp>
      31              : #include <type_traits>
      32              : #include <limits>
      33              : #include <cstdint>
      34              : #include <cstring>
      35              : #include <cstddef>
      36              : #include <climits>
      37              : 
      38              : namespace boost {
      39              : namespace json {
      40              : namespace detail {
      41              : 
      42              : template <typename T>
      43              : struct physical_bits
      44              : {
      45              :     static constexpr std::size_t value = sizeof(T) * CHAR_BIT;
      46              : };
      47              : 
      48              : template <typename T>
      49              : struct value_bits
      50              : {
      51              :     static constexpr std::size_t value = std::numeric_limits<typename std::enable_if<std::is_unsigned<T>::value, T>::type>::digits;
      52              : };
      53              : 
      54              : #ifdef BOOST_NO_CXX17_INLINE_VARIABLES
      55              : 
      56              : template <typename T> constexpr std::size_t physical_bits<T>::value;
      57              : template <typename T> constexpr std::size_t value_bits<T>::value;
      58              : 
      59              : #endif
      60              : 
      61              : // A floating-point traits class defines ways to interpret a bit pattern of given size as an
      62              : // encoding of floating-point number. This is a default implementation of such a traits class,
      63              : // supporting ways to interpret 32-bits into a binary32-encoded floating-point number and to
      64              : // interpret 64-bits into a binary64-encoded floating-point number. Users might specialize this
      65              : // class to change the default behavior for certain types.
      66              : template <typename T>
      67              : struct default_float_traits
      68              : {
      69              :     // I don't know if there is a truly reliable way of detecting
      70              :     // IEEE-754 binary32/binary64 formats; I just did my best here.
      71              :     static_assert(std::numeric_limits<T>::is_iec559 && std::numeric_limits<T>::radix == 2 &&
      72              :                   (detail::physical_bits<T>::value == 32 || detail::physical_bits<T>::value == 64),
      73              :                     "default_ieee754_traits only works for 32-bits or 64-bits types "
      74              :                     "supporting binary32 or binary64 formats!");
      75              : 
      76              :     // The type that is being viewed.
      77              :     using type = T;
      78              : 
      79              :     // Refers to the format specification class.
      80              :     using format =
      81              :         typename std::conditional<detail::physical_bits<T>::value == 32, detail::ieee754_binary32, detail::ieee754_binary64>::type;
      82              : 
      83              :     // Defines an unsignedeger type that is large enough to carry a variable of type T.
      84              :     // Most of the operations will be done on this integer type.
      85              :     using carrier_uint = typename std::conditional<detail::physical_bits<T>::value == 32, std::uint32_t, std::uint64_t>::type;
      86              : 
      87              :     static_assert(sizeof(carrier_uint) == sizeof(T), "carrier_uint must be T");
      88              : 
      89              :     // Number of bits in the above unsignedeger type.
      90              :     static constexpr int carrier_bits = static_cast<int>(detail::physical_bits<carrier_uint>::value);
      91              : 
      92              :     // Convert from carrier_uint into the original type.
      93              :     // Depending on the floating-point encoding format, this operation might not be possible for
      94              :     // some specific bit patterns. However, the contract is that u always denotes a
      95              :     // valid bit pattern, so this function must be assumed to be noexcept.
      96              :     static T carrier_to_float(carrier_uint u) noexcept
      97              :     {
      98              :         T x;
      99              :         std::memcpy(&x, &u, sizeof(carrier_uint));
     100              :         return x;
     101              :     }
     102              : 
     103              :     // Same as above.
     104              :     static carrier_uint float_to_carrier(T x) noexcept
     105              :     {
     106              :         carrier_uint u;
     107              :         std::memcpy(&u, &x, sizeof(carrier_uint));
     108              :         return u;
     109              :     }
     110              : 
     111              :     // Extract exponent bits from a bit pattern.
     112              :     // The result must be aligned to the LSB so that there is no additional zero paddings
     113              :     // on the right. This function does not do bias adjustment.
     114              :     static constexpr unsigned extract_exponent_bits(carrier_uint u) noexcept
     115              :     {
     116              :         return static_cast<unsigned>(u >> format::exponent_bits) & static_cast<unsigned>((1U << format::exponent_bits) - 1);
     117              :     }
     118              : 
     119              :     // Extract significand bits from a bit pattern.
     120              :     // The result must be aligned to the LSB so that there is no additional zero paddings
     121              :     // on the right. The result does not contain the implicit bit.
     122              :     static constexpr carrier_uint extract_significand_bits(carrier_uint u) noexcept
     123              :     {
     124              :         return static_cast<carrier_uint>(u & static_cast<carrier_uint>((static_cast<carrier_uint>(1) << format::significand_bits) - 1));
     125              :     }
     126              : 
     127              :     // Remove the exponent bits and extract significand bits together with the sign bit.
     128              :     static constexpr carrier_uint remove_exponent_bits(carrier_uint u, unsigned exponent_bits) noexcept
     129              :     {
     130              :         return u ^ (static_cast<carrier_uint>(exponent_bits) << format::significand_bits);
     131              :     }
     132              : 
     133              :     // Shift the obtained signed significand bits to the left by 1 to remove the sign bit.
     134              :     static constexpr carrier_uint remove_sign_bit_and_shift(carrier_uint u) noexcept
     135              :     {
     136              :         return static_cast<carrier_uint>(static_cast<carrier_uint>(u) << 1);
     137              :     }
     138              : 
     139              :     // The actual value of exponent is obtained by adding this value to the extracted exponent bits
     140              :     static constexpr int exponent_bias = 1 - (1 << (carrier_bits - format::significand_bits - 2));
     141              : 
     142              :     // Obtain the actual value of the binary exponent from the extracted exponent bits.
     143              :     static constexpr int binary_exponent(unsigned exponent_bits) noexcept
     144              :     {
     145              :         return exponent_bits == 0 ? format::min_exponent : static_cast<int>(exponent_bits) + format::exponent_bias;
     146              :     }
     147              : 
     148              :     // Obtain the actual value of the binary exponent from the extracted significand bits and
     149              :     // exponent bits.
     150              :     static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept
     151              :     {
     152              :         return exponent_bits == 0 ? significand_bits : (significand_bits | (static_cast<carrier_uint>(1) << format::significand_bits));
     153              :     }
     154              : 
     155              : 
     156              :     // Various boolean observer functions
     157              : 
     158              :     static constexpr bool is_nonzero(carrier_uint u) noexcept { return (u << 1) != 0; }
     159              : 
     160              :     static constexpr bool is_positive(carrier_uint u) noexcept
     161              :     {
     162              :         return u < static_cast<carrier_uint>(1) << (format::significand_bits + format::exponent_bits);
     163              :     }
     164              : 
     165              :     static constexpr bool is_negative(carrier_uint u) noexcept { return !is_positive(u); }
     166              : 
     167              :     static constexpr bool is_finite(unsigned exponent_bits) noexcept
     168              :     {
     169              :         //constexpr unsigned exponent_bits_all_set = (1u << format::exponent_bits) - 1;
     170              :         return exponent_bits != (1u << format::exponent_bits) - 1;
     171              :     }
     172              : 
     173              :     static constexpr bool has_all_zero_significand_bits(carrier_uint u) noexcept
     174              :     {
     175              :         return (u << 1) == 0;
     176              :     }
     177              : 
     178              :     static constexpr bool has_even_significand_bits(carrier_uint u) noexcept
     179              :     {
     180              :         return u % 2 == 0;
     181              :     }
     182              : };
     183              : 
     184              : // Convenient wrappers for floating-point traits classes.
     185              : // In order to reduce the argument passing overhead, these classes should be as simple as
     186              : // possible (e.g., no inheritance, no private non-static data member, etc.; this is an
     187              : // unfortunate fact about common ABI convention).
     188              : 
     189              : template <typename T, typename Traits = default_float_traits<T>>
     190              : struct float_bits;
     191              : 
     192              : template <typename T, typename Traits = default_float_traits<T>>
     193              : struct signed_significand_bits;
     194              : 
     195              : template <typename T, typename Traits>
     196              : struct float_bits
     197              : {
     198              :     using type = T;
     199              :     using traits_type = Traits;
     200              :     using carrier_uint = typename traits_type::carrier_uint;
     201              : 
     202              :     carrier_uint u;
     203              : 
     204              :     float_bits() = default;
     205              :     constexpr explicit float_bits(carrier_uint bit_pattern) noexcept : u{bit_pattern} {}
     206              :     constexpr explicit float_bits(T float_value) noexcept : u{traits_type::float_to_carrier(float_value)} {}
     207              : 
     208              :     constexpr T to_float() const noexcept { return traits_type::carrier_to_float(u); }
     209              : 
     210              :     // Extract exponent bits from a bit pattern.
     211              :     // The result must be aligned to the LSB so that there is no additional zero paddings
     212              :     // on the right. This function does not do bias adjustment.
     213              :     constexpr unsigned extract_exponent_bits() const noexcept
     214              :     {
     215              :         return traits_type::extract_exponent_bits(u);
     216              :     }
     217              : 
     218              :     // Extract significand bits from a bit pattern.
     219              :     // The result must be aligned to the LSB so that there is no additional zero paddings
     220              :     // on the right. The result does not contain the implicit bit.
     221              :     constexpr carrier_uint extract_significand_bits() const noexcept
     222              :     {
     223              :         return traits_type::extract_significand_bits(u);
     224              :     }
     225              : 
     226              :     // Remove the exponent bits and extract significand bits together with the sign bit.
     227              :     constexpr signed_significand_bits<type, traits_type> remove_exponent_bits(unsigned exponent_bits) const noexcept
     228              :     {
     229              :         return signed_significand_bits<type, traits_type>(traits_type::remove_exponent_bits(u, exponent_bits));
     230              :     }
     231              : 
     232              :     // Obtain the actual value of the binary exponent from the extracted exponent bits.
     233              :     static constexpr int binary_exponent(unsigned exponent_bits) noexcept
     234              :     {
     235              :         return traits_type::binary_exponent(exponent_bits);
     236              :     }
     237              : 
     238              :     constexpr int binary_exponent() const noexcept
     239              :     {
     240              :         return binary_exponent(extract_exponent_bits());
     241              :     }
     242              : 
     243              :     // Obtain the actual value of the binary exponent from the extracted significand bits and
     244              :     // exponent bits.
     245              :     static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept
     246              :     {
     247              :         return traits_type::binary_significand(significand_bits, exponent_bits);
     248              :     }
     249              : 
     250              :     constexpr carrier_uint binary_significand() const noexcept
     251              :     {
     252              :         return binary_significand(extract_significand_bits(), extract_exponent_bits());
     253              :     }
     254              : 
     255              :     constexpr bool is_nonzero() const noexcept { return traits_type::is_nonzero(u); }
     256              : 
     257              :     constexpr bool is_positive() const noexcept { return traits_type::is_positive(u); }
     258              : 
     259              :     constexpr bool is_negative() const noexcept { return traits_type::is_negative(u); }
     260              : 
     261              :     constexpr bool is_finite(unsigned exponent_bits) const noexcept { return traits_type::is_finite(exponent_bits); }
     262              : 
     263              :     constexpr bool is_finite() const noexcept { return traits_type::is_finite(extract_exponent_bits()); }
     264              : 
     265              :     constexpr bool has_even_significand_bits() const noexcept { return traits_type::has_even_significand_bits(u); }
     266              : };
     267              : 
     268              : template <typename T, typename Traits>
     269              : struct signed_significand_bits
     270              : {
     271              :     using type = T;
     272              :     using traits_type = Traits;
     273              :     using carrier_uint = typename traits_type::carrier_uint;
     274              : 
     275              :     carrier_uint u;
     276              : 
     277              :     signed_significand_bits() = default;
     278              :     constexpr explicit signed_significand_bits(carrier_uint bit_pattern) noexcept
     279              :         : u{bit_pattern} {}
     280              : 
     281              :     // Shift the obtained signed significand bits to the left by 1 to remove the sign bit.
     282              :     constexpr carrier_uint remove_sign_bit_and_shift() const noexcept
     283              :     {
     284              :         return traits_type::remove_sign_bit_and_shift(u);
     285              :     }
     286              : 
     287              :     constexpr bool is_positive() const noexcept { return traits_type::is_positive(u); }
     288              : 
     289              :     constexpr bool is_negative() const noexcept { return traits_type::is_negative(u); }
     290              : 
     291              :     constexpr bool has_all_zero_significand_bits() const noexcept
     292              :     {
     293              :         return traits_type::has_all_zero_significand_bits(u);
     294              :     }
     295              : 
     296              :     constexpr bool has_even_significand_bits() const noexcept
     297              :     {
     298              :         return traits_type::has_even_significand_bits(u);
     299              :     }
     300              : };
     301              : 
     302              : ////////////////////////////////////////////////////////////////////////////////////////
     303              : // Some simple utilities for constexpr computation.
     304              : ////////////////////////////////////////////////////////////////////////////////////////
     305              : 
     306              : template <class Int, class Int2>
     307          613 : BOOST_JSON_CXX14_CONSTEXPR Int compute_power(Int a, Int2 exp) noexcept
     308              : {
     309          613 :     BOOST_ASSERT(exp >= 0);
     310              : 
     311          613 :     Int res = 1;
     312         1839 :     while (exp > 0)
     313              :     {
     314         1226 :         if (exp % 2 != 0)
     315              :         {
     316          920 :             res *= a;
     317              :         }
     318              : 
     319         1226 :         a *= a;
     320         1226 :         exp >>= 1;
     321              :     }
     322          613 :     return res;
     323              : }
     324              : 
     325              : static constexpr std::uint64_t power_of_10[] = {
     326              :     UINT64_C(1), UINT64_C(10), UINT64_C(100), UINT64_C(1000), UINT64_C(10000),
     327              :     UINT64_C(100000), UINT64_C(1000000), UINT64_C(10000000), UINT64_C(100000000),
     328              :     UINT64_C(1000000000), UINT64_C(10000000000), UINT64_C(100000000000), UINT64_C(1000000000000),
     329              :     UINT64_C(10000000000000), UINT64_C(100000000000000), UINT64_C(1000000000000000),
     330              :     UINT64_C(10000000000000000), UINT64_C(100000000000000000), UINT64_C(1000000000000000000),
     331              :     UINT64_C(10000000000000000000)
     332              : };
     333              : 
     334              : static_assert(sizeof(power_of_10) == 20 * sizeof(std::uint64_t), "There should be the first 20 powers of 10");
     335              : 
     336              : 
     337              : template <unsigned a, typename UInt>
     338              : BOOST_JSON_CXX14_CONSTEXPR int count_factors(UInt n) noexcept
     339              : {
     340              :     int c = 0;
     341              : 
     342              :     while (n % a == 0)
     343              :     {
     344              :         n /= a;
     345              :         ++c;
     346              :     }
     347              :     return c;
     348              : }
     349              : 
     350              : ////////////////////////////////////////////////////////////////////////////////////////
     351              : // Utilities for fast/constexpr log computation.
     352              : ////////////////////////////////////////////////////////////////////////////////////////
     353              : 
     354              : namespace log  {
     355              : static_assert((-1 >> 1) == -1, "right-shift for signed integers must be arithmetic");
     356              : 
     357              : // Compute floor(e * c - s).
     358              : enum class multiply : std::uint32_t {};
     359              : enum class subtract : std::uint32_t {};
     360              : enum class shift : std::size_t {};
     361              : enum class min_exponent : std::int32_t {};
     362              : enum class max_exponent : std::int32_t {};
     363              : 
     364              : template <multiply m, subtract f, shift k, min_exponent e_min, max_exponent e_max>
     365          888 : constexpr int compute(int e) noexcept
     366              : {
     367          888 :     return static_cast<int>((std::int32_t(e) * std::int32_t(m) - std::int32_t(f)) >> std::size_t(k));
     368              : }
     369              : 
     370              : // For constexpr computation.
     371              : // Returns -1 when n = 0.
     372              : template <class UInt>
     373              : BOOST_JSON_CXX14_CONSTEXPR int floor_log2(UInt n) noexcept
     374              : {
     375              :     int count = -1;
     376              :     while (n != 0)
     377              :     {
     378              :         ++count;
     379              :         n >>= 1;
     380              :     }
     381              : 
     382              :     return count;
     383              : }
     384              : 
     385              : static constexpr int floor_log10_pow2_min_exponent = -2620;
     386              : 
     387              : static constexpr int floor_log10_pow2_max_exponent = 2620;
     388              : 
     389          306 : constexpr int floor_log10_pow2(int e) noexcept
     390              : {
     391              :     using namespace log;
     392              :     return compute<multiply(315653), subtract(0), shift(20),
     393              :                     min_exponent(floor_log10_pow2_min_exponent),
     394          306 :                     max_exponent(floor_log10_pow2_max_exponent)>(e);
     395              : }
     396              : 
     397              : static constexpr int floor_log2_pow10_min_exponent = -1233;
     398              : 
     399              : static constexpr int floor_log2_pow10_max_exponent = 1233;
     400              : 
     401          444 : constexpr int floor_log2_pow10(int e) noexcept
     402              : {
     403              :     using namespace log;
     404              :     return compute<multiply(1741647), subtract(0), shift(19),
     405              :                     min_exponent(floor_log2_pow10_min_exponent),
     406          444 :                     max_exponent(floor_log2_pow10_max_exponent)>(e);
     407              : }
     408              : 
     409              : static constexpr int floor_log10_pow2_minus_log10_4_over_3_min_exponent = -2985;
     410              : 
     411              : static constexpr int floor_log10_pow2_minus_log10_4_over_3_max_exponent = 2936;
     412              : 
     413          138 : constexpr int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept
     414              : {
     415              :     using namespace log;
     416              :     return compute<multiply(631305), subtract(261663), shift(21),
     417              :                     min_exponent(floor_log10_pow2_minus_log10_4_over_3_min_exponent),
     418          138 :                     max_exponent(floor_log10_pow2_minus_log10_4_over_3_max_exponent)>(e);
     419              : }
     420              : 
     421              : static constexpr int floor_log5_pow2_min_exponent = -1831;
     422              : 
     423              : static constexpr int floor_log5_pow2_max_exponent = 1831;
     424              : 
     425              : constexpr int floor_log5_pow2(int e) noexcept
     426              : {
     427              :     using namespace log;
     428              :     return compute<multiply(225799), subtract(0), shift(19),
     429              :                     min_exponent(floor_log5_pow2_min_exponent),
     430              :                     max_exponent(floor_log5_pow2_max_exponent)>(e);
     431              : }
     432              : 
     433              : static constexpr int floor_log5_pow2_minus_log5_3_min_exponent = -3543;
     434              : 
     435              : static constexpr int floor_log5_pow2_minus_log5_3_max_exponent = 2427;
     436              : 
     437              : constexpr int floor_log5_pow2_minus_log5_3(int e) noexcept
     438              : {
     439              :     using namespace log;
     440              :     return compute<multiply(451597), subtract(715764), shift(20),
     441              :                     min_exponent(floor_log5_pow2_minus_log5_3_min_exponent),
     442              :                     max_exponent(floor_log5_pow2_minus_log5_3_max_exponent)>(e);
     443              : }
     444              : } // Namespace log
     445              : 
     446              : } // namespace detail
     447              : } // namespace json
     448              : } // namespace boost
     449              : 
     450              : #endif // BOOST_JSON_DETAIL_DRAGONBOX_DRAGONBOX_COMMON_HPP
        

Generated by: LCOV version 2.3