LCOV - code coverage report
Current view: top level - json/detail/ryu/detail - d2s.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 42 42
Test Date: 2026-02-13 18:42:28 Functions: 100.0 % 7 7

            Line data    Source code
       1              : // Copyright 2018 Ulf Adams
       2              : //
       3              : // The contents of this file may be used under the terms of the Apache License,
       4              : // Version 2.0.
       5              : //
       6              : //    (See accompanying file LICENSE-Apache or copy at
       7              : //     http://www.apache.org/licenses/LICENSE-2.0)
       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              : /*
      19              :     This is a derivative work
      20              : */
      21              : 
      22              : #ifndef BOOST_JSON_DETAIL_RYU_DETAIL_D2S_HPP
      23              : #define BOOST_JSON_DETAIL_RYU_DETAIL_D2S_HPP
      24              : 
      25              : #include <boost/json/detail/config.hpp>
      26              : #include <boost/json/detail/ryu/detail/common.hpp>
      27              : 
      28              : // Only include the full table if we're not optimizing for size.
      29              : #if !defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
      30              : #include <boost/json/detail/ryu/detail/d2s_full_table.hpp>
      31              : #endif
      32              : #if defined(BOOST_JSON_RYU_HAS_UINT128)
      33              : typedef __uint128_t uint128_t;
      34              : #else
      35              : #include <boost/json/detail/ryu/detail/d2s_intrinsics.hpp>
      36              : #endif
      37              : 
      38              : namespace boost {
      39              : namespace json {
      40              : namespace detail {
      41              : 
      42              : namespace ryu {
      43              : namespace detail {
      44              : 
      45              : constexpr int DOUBLE_POW5_INV_BITCOUNT = 122;
      46              : constexpr int DOUBLE_POW5_BITCOUNT = 121;
      47              : 
      48              : #if defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
      49              : 
      50              : constexpr int POW5_TABLE_SIZE = 26;
      51              : 
      52              : inline
      53              : std::uint64_t const
      54         1186 : (&DOUBLE_POW5_TABLE() noexcept)[POW5_TABLE_SIZE]
      55              : {
      56              :     static constexpr std::uint64_t arr[26] = {
      57              :     1ull, 5ull, 25ull, 125ull, 625ull, 3125ull, 15625ull, 78125ull, 390625ull,
      58              :     1953125ull, 9765625ull, 48828125ull, 244140625ull, 1220703125ull, 6103515625ull,
      59              :     30517578125ull, 152587890625ull, 762939453125ull, 3814697265625ull,
      60              :     19073486328125ull, 95367431640625ull, 476837158203125ull,
      61              :     2384185791015625ull, 11920928955078125ull, 59604644775390625ull,
      62              :     298023223876953125ull //, 1490116119384765625ull
      63              :     };
      64         1186 :     return arr;
      65              : }
      66              : 
      67              : inline
      68              : std::uint64_t const
      69          652 : (&DOUBLE_POW5_SPLIT2() noexcept)[13][2]
      70              : {
      71              :     static constexpr std::uint64_t arr[13][2] = {
      72              :     {                    0u,  72057594037927936u },
      73              :     { 10376293541461622784u,  93132257461547851u },
      74              :     { 15052517733678820785u, 120370621524202240u },
      75              :     {  6258995034005762182u,  77787690973264271u },
      76              :     { 14893927168346708332u, 100538234169297439u },
      77              :     {  4272820386026678563u, 129942622070561240u },
      78              :     {  7330497575943398595u,  83973451344588609u },
      79              :     { 18377130505971182927u, 108533142064701048u },
      80              :     { 10038208235822497557u, 140275798336537794u },
      81              :     {  7017903361312433648u,  90651109995611182u },
      82              :     {  6366496589810271835u, 117163813585596168u },
      83              :     {  9264989777501460624u,  75715339914673581u },
      84              :     { 17074144231291089770u,  97859783203563123u }};
      85          652 :     return arr;
      86              : }
      87              : 
      88              : // Unfortunately, the results are sometimes off by one. We use an additional
      89              : // lookup table to store those cases and adjust the result.
      90              : inline
      91              : std::uint32_t const
      92          626 : (&POW5_OFFSETS() noexcept)[13]
      93              : {
      94              :     static constexpr std::uint32_t arr[13] = {
      95              :         0x00000000, 0x00000000, 0x00000000, 0x033c55be, 0x03db77d8, 0x0265ffb2,
      96              :         0x00000800, 0x01a8ff56, 0x00000000, 0x0037a200, 0x00004000, 0x03fffffc,
      97              :         0x00003ffe};
      98          626 :     return arr;
      99              : }
     100              : 
     101              : inline
     102              : std::uint64_t const
     103          584 : (&DOUBLE_POW5_INV_SPLIT2() noexcept)[13][2]
     104              : {
     105              :     static constexpr std::uint64_t arr[13][2] = {
     106              :     {                    1u, 288230376151711744u },
     107              :     {  7661987648932456967u, 223007451985306231u },
     108              :     { 12652048002903177473u, 172543658669764094u },
     109              :     {  5522544058086115566u, 266998379490113760u },
     110              :     {  3181575136763469022u, 206579990246952687u },
     111              :     {  4551508647133041040u, 159833525776178802u },
     112              :     {  1116074521063664381u, 247330401473104534u },
     113              :     { 17400360011128145022u, 191362629322552438u },
     114              :     {  9297997190148906106u, 148059663038321393u },
     115              :     { 11720143854957885429u, 229111231347799689u },
     116              :     { 15401709288678291155u, 177266229209635622u },
     117              :     {  3003071137298187333u, 274306203439684434u },
     118              :     { 17516772882021341108u, 212234145163966538u }};
     119          584 :     return arr;
     120              : }
     121              : 
     122              : inline
     123              : std::uint32_t const
     124          560 : (&POW5_INV_OFFSETS() noexcept)[20]
     125              : {
     126              :     static constexpr std::uint32_t arr[20] = {
     127              :     0x51505404, 0x55054514, 0x45555545, 0x05511411, 0x00505010, 0x00000004,
     128              :     0x00000000, 0x00000000, 0x55555040, 0x00505051, 0x00050040, 0x55554000,
     129              :     0x51659559, 0x00001000, 0x15000010, 0x55455555, 0x41404051, 0x00001010,
     130              :     0x00000014, 0x00000000};
     131          560 :     return arr;
     132              : }
     133              : 
     134              : #if defined(BOOST_JSON_RYU_HAS_UINT128)
     135              : 
     136              : // Computes 5^i in the form required by Ryu, and stores it in the given pointer.
     137              : inline
     138              : void
     139          652 : double_computePow5(
     140              :     const std::uint32_t i,
     141              :     std::uint64_t* const result)
     142              : {
     143          652 :     const std::uint32_t base = i / POW5_TABLE_SIZE;
     144          652 :     const std::uint32_t base2 = base * POW5_TABLE_SIZE;
     145          652 :     const std::uint32_t offset = i - base2;
     146          652 :     const std::uint64_t* const mul = DOUBLE_POW5_SPLIT2()[base];
     147          652 :     if (offset == 0)
     148              :     {
     149           26 :         result[0] = mul[0];
     150           26 :         result[1] = mul[1];
     151           26 :         return;
     152              :     }
     153          626 :     const std::uint64_t m = DOUBLE_POW5_TABLE()[offset];
     154          626 :     const uint128_t b0 = ((uint128_t)m) * mul[0];
     155          626 :     const uint128_t b2 = ((uint128_t)m) * mul[1];
     156          626 :     const std::uint32_t delta = pow5bits(i) - pow5bits(base2);
     157          626 :     const uint128_t shiftedSum = (b0 >> delta) + (b2 << (64 - delta)) + ((POW5_OFFSETS()[base] >> offset) & 1);
     158          626 :     result[0] = (std::uint64_t)shiftedSum;
     159          626 :     result[1] = (std::uint64_t)(shiftedSum >> 64);
     160              : }
     161              : 
     162              : // Computes 5^-i in the form required by Ryu, and stores it in the given pointer.
     163              : inline
     164              : void
     165          584 : double_computeInvPow5(
     166              :     const std::uint32_t i,
     167              :     std::uint64_t* const result)
     168              : {
     169          584 :     const std::uint32_t base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE;
     170          584 :     const std::uint32_t base2 = base * POW5_TABLE_SIZE;
     171          584 :     const std::uint32_t offset = base2 - i;
     172          584 :     const std::uint64_t* const mul = DOUBLE_POW5_INV_SPLIT2()[base]; // 1/5^base2
     173          584 :     if (offset == 0)
     174              :     {
     175           24 :         result[0] = mul[0];
     176           24 :         result[1] = mul[1];
     177           24 :         return;
     178              :     }
     179          560 :     const std::uint64_t m = DOUBLE_POW5_TABLE()[offset]; // 5^offset
     180          560 :     const uint128_t b0 = ((uint128_t)m) * (mul[0] - 1);
     181          560 :     const uint128_t b2 = ((uint128_t)m) * mul[1]; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
     182          560 :     const std::uint32_t delta = pow5bits(base2) - pow5bits(i);
     183              :     const uint128_t shiftedSum =
     184          560 :         ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((POW5_INV_OFFSETS()[i / 16] >> ((i % 16) << 1)) & 3);
     185          560 :     result[0] = (std::uint64_t)shiftedSum;
     186          560 :     result[1] = (std::uint64_t)(shiftedSum >> 64);
     187              : }
     188              : 
     189              : #else // defined(BOOST_JSON_RYU_HAS_UINT128)
     190              : 
     191              : // Computes 5^i in the form required by Ryu, and stores it in the given pointer.
     192              : inline
     193              : void
     194              : double_computePow5(
     195              :     const std::uint32_t i,
     196              :     std::uint64_t* const result)
     197              : {
     198              :     const std::uint32_t base = i / POW5_TABLE_SIZE;
     199              :     const std::uint32_t base2 = base * POW5_TABLE_SIZE;
     200              :     const std::uint32_t offset = i - base2;
     201              :     const std::uint64_t* const mul = DOUBLE_POW5_SPLIT2()[base];
     202              :     if (offset == 0)
     203              :     {
     204              :         result[0] = mul[0];
     205              :         result[1] = mul[1];
     206              :         return;
     207              :     }
     208              :     std::uint64_t const m = DOUBLE_POW5_TABLE()[offset];
     209              :     std::uint64_t high1;
     210              :     std::uint64_t const low1 = umul128(m, mul[1], &high1);
     211              :     std::uint64_t high0;
     212              :     std::uint64_t const low0 = umul128(m, mul[0], &high0);
     213              :     std::uint64_t const sum = high0 + low1;
     214              :     if (sum < high0)
     215              :         ++high1; // overflow into high1
     216              :     // high1 | sum | low0
     217              :     std::uint32_t const delta = pow5bits(i) - pow5bits(base2);
     218              :     result[0] = shiftright128(low0, sum, delta) + ((POW5_OFFSETS()[base] >> offset) & 1);
     219              :     result[1] = shiftright128(sum, high1, delta);
     220              : }
     221              : 
     222              : // Computes 5^-i in the form required by Ryu, and stores it in the given pointer.
     223              : inline
     224              : void
     225              : double_computeInvPow5(
     226              :     const std::uint32_t i,
     227              :     std::uint64_t* const result)
     228              : {
     229              :     const std::uint32_t base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE;
     230              :     const std::uint32_t base2 = base * POW5_TABLE_SIZE;
     231              :     const std::uint32_t offset = base2 - i;
     232              :     const std::uint64_t* const mul = DOUBLE_POW5_INV_SPLIT2()[base]; // 1/5^base2
     233              :     if (offset == 0)
     234              :     {
     235              :         result[0] = mul[0];
     236              :         result[1] = mul[1];
     237              :         return;
     238              :     }
     239              :     std::uint64_t const m = DOUBLE_POW5_TABLE()[offset];
     240              :     std::uint64_t high1;
     241              :     std::uint64_t const low1 = umul128(m, mul[1], &high1);
     242              :     std::uint64_t high0;
     243              :     std::uint64_t const low0 = umul128(m, mul[0] - 1, &high0);
     244              :     std::uint64_t const sum = high0 + low1;
     245              :     if (sum < high0)
     246              :         ++high1; // overflow into high1
     247              :     // high1 | sum | low0
     248              :     std::uint32_t const delta = pow5bits(base2) - pow5bits(i);
     249              :     result[0] = shiftright128(low0, sum, delta) + 1 + ((POW5_INV_OFFSETS()[i / 16] >> ((i % 16) << 1)) & 3);
     250              :     result[1] = shiftright128(sum, high1, delta);
     251              : }
     252              : 
     253              : #endif // defined(BOOST_JSON_RYU_HAS_UINT128)
     254              : 
     255              : #endif // defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
     256              : 
     257              : } // detail
     258              : } // ryu
     259              : 
     260              : } // detail
     261              : } // namespace json
     262              : } // namespace boost
     263              : 
     264              : #endif
        

Generated by: LCOV version 2.3