LCOV - code coverage report
Current view: top level - json/detail/impl - format.ipp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 72 72
Test Date: 2025-12-23 16:57:37 Functions: 100.0 % 7 7

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3              : // Copyright (c) 2020 Peter Dimov (pdimov at gmail dot com),
       4              : //
       5              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7              : //
       8              : // Official repository: https://github.com/boostorg/json
       9              : //
      10              : 
      11              : #ifndef BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
      12              : #define BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
      13              : 
      14              : #include <boost/json/detail/dragonbox/dragonbox.hpp>
      15              : #include <boost/json/detail/format.hpp>
      16              : #include <cmath>
      17              : #include <cstring>
      18              : 
      19              : namespace boost {
      20              : namespace json {
      21              : namespace detail {
      22              : 
      23              : /*  Reference work:
      24              : 
      25              :     https://www.ampl.com/netlib/fp/dtoa.c
      26              :     https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
      27              :     https://kkimdev.github.io/posts/2018/06/15/IEEE-754-Floating-Point-Type-in-C++.html
      28              : */
      29              : 
      30         4838 : inline char const* digits_lut() noexcept
      31              : {
      32              :     return
      33              :         "00010203040506070809"
      34              :         "10111213141516171819"
      35              :         "20212223242526272829"
      36              :         "30313233343536373839"
      37              :         "40414243444546474849"
      38              :         "50515253545556575859"
      39              :         "60616263646566676869"
      40              :         "70717273747576777879"
      41              :         "80818283848586878889"
      42         4838 :         "90919293949596979899";
      43              : }
      44              : 
      45         1988 : inline void format_four_digits( char * dest, unsigned v )
      46              : {
      47         1988 :     std::memcpy( dest + 2, digits_lut() + (v % 100) * 2, 2 );
      48         1988 :     std::memcpy( dest    , digits_lut() + (v / 100) * 2, 2 );
      49         1988 : }
      50              : 
      51          862 : inline void format_two_digits( char * dest, unsigned v )
      52              : {
      53          862 :     std::memcpy( dest, digits_lut() + v * 2, 2 );
      54          862 : }
      55              : 
      56          405 : inline void format_digit( char * dest, unsigned v )
      57              : {
      58          405 :     *dest = static_cast<char>( v + '0' );
      59          405 : }
      60              : 
      61              : unsigned
      62         3613 : format_uint64(
      63              :     char* dest,
      64              :     std::uint64_t v) noexcept
      65              : {
      66         3613 :     if(v < 10)
      67              :     {
      68         2475 :         *dest = static_cast<char>( '0' + v );
      69         2475 :         return 1;
      70              :     }
      71              : 
      72              :     char buffer[ 24 ];
      73              : 
      74         1138 :     char * p = buffer + 24;
      75              : 
      76         3126 :     while( v >= 1000 )
      77              :     {
      78         1988 :         p -= 4;
      79         1988 :         format_four_digits( p, v % 10000 );
      80         1988 :         v /= 10000;
      81              :     }
      82              : 
      83         1138 :     if( v >= 10 )
      84              :     {
      85          862 :         p -= 2;
      86          862 :         format_two_digits( p, v % 100 );
      87          862 :         v /= 100;
      88              :     }
      89              : 
      90         1138 :     if( v )
      91              :     {
      92          405 :         p -= 1;
      93          405 :         format_digit( p, static_cast<unsigned>(v) );
      94              :     }
      95              : 
      96         1138 :     unsigned const n = static_cast<unsigned>( buffer + 24 - p );
      97         1138 :     std::memcpy( dest, p, n );
      98              : 
      99         1138 :     return n;
     100              : }
     101              : 
     102              : unsigned
     103         3188 : format_int64(
     104              :     char* dest, int64_t i) noexcept
     105              : {
     106         3188 :     std::uint64_t ui = static_cast<
     107              :         std::uint64_t>(i);
     108         3188 :     if(i >= 0)
     109         2746 :         return format_uint64(dest, ui);
     110          442 :     *dest++ = '-';
     111          442 :     ui = ~ui + 1;
     112          442 :     return 1 + format_uint64(dest, ui);
     113              : }
     114              : 
     115              : std::size_t
     116          510 : format_double(
     117              :     char* dest, double d, bool allow_infinity_and_nan) noexcept
     118              : {
     119              :     using Traits = dragonbox_float_traits<double>;
     120              : 
     121          510 :     auto const bits = dragonbox_float_bits<double, Traits>(d);
     122          510 :     auto const exponent_bits = bits.extract_exponent_bits();
     123          510 :     auto const s = bits.remove_exponent_bits(exponent_bits);
     124              : 
     125          510 :     if( bits.is_finite(exponent_bits) )
     126              :     {
     127              :         bool is_negative;
     128          495 :         if(( is_negative = s.is_negative() ))
     129              :         {
     130          155 :             *dest = '-';
     131          155 :             ++dest;
     132              :         }
     133              : 
     134          495 :         if( bits.is_nonzero() )
     135              :         {
     136          444 :             auto const decimal = to_decimal<double, Traits>(
     137              :                 s, exponent_bits);
     138          444 :             std::size_t const size = to_chars_detail::dragon_box_print_chars(
     139          444 :                 decimal.significand,
     140          444 :                 decimal.exponent,
     141              :                 dest,
     142              :                 dest + detail::max_number_chars);
     143          444 :             BOOST_ASSERT( size );
     144          444 :             return size + is_negative;
     145              :         }
     146              :         else
     147              :         {
     148           51 :             std::memcpy(dest, "0E0", 3);
     149           51 :             return 3 + is_negative;
     150              :         }
     151              :     }
     152              : 
     153              : 
     154           15 :     if( allow_infinity_and_nan )
     155              :     {
     156            6 :         if( s.has_all_zero_significand_bits() )
     157              :         {
     158            4 :             if( s.is_negative() )
     159              :             {
     160            2 :                 std::memcpy(dest, "-Infinity", 9);
     161            2 :                 return 9;
     162              :             }
     163              :             else
     164              :             {
     165            2 :                 std::memcpy(dest, "Infinity", 8);
     166            2 :                 return 8;
     167              :             }
     168              :         }
     169              : 
     170            2 :         std::memcpy(dest, "NaN", 3);
     171            2 :         return 3;
     172              :     }
     173              : 
     174            9 :     if( s.has_all_zero_significand_bits() )
     175              :     {
     176            6 :         if( s.is_negative() )
     177              :         {
     178            3 :             std::memcpy(dest, "-1e99999", 8);
     179            3 :             return 8;
     180              :         }
     181              :         else
     182              :         {
     183            3 :             std::memcpy(dest, "1e99999", 7);
     184            3 :             return 7;
     185              :         }
     186              :     }
     187              : 
     188            3 :     std::memcpy(dest, "null", 4);
     189            3 :     return 4;
     190              : }
     191              : 
     192              : } // detail
     193              : } // namespace json
     194              : } // namespace boost
     195              : 
     196              : #endif
        

Generated by: LCOV version 2.1