GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/impl/format.ipp
Date: 2025-12-23 16:57:39
Exec Total Coverage
Lines: 72 72 100.0%
Functions: 7 7 100.0%
Branches: 27 28 96.4%

Line Branch Exec Source
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
2/2
✓ Branch 0 taken 2475 times.
✓ Branch 1 taken 1138 times.
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
2/2
✓ Branch 0 taken 1988 times.
✓ Branch 1 taken 1138 times.
3126 while( v >= 1000 )
77 {
78 1988 p -= 4;
79 1988 format_four_digits( p, v % 10000 );
80 1988 v /= 10000;
81 }
82
83
2/2
✓ Branch 0 taken 862 times.
✓ Branch 1 taken 276 times.
1138 if( v >= 10 )
84 {
85 862 p -= 2;
86 862 format_two_digits( p, v % 100 );
87 862 v /= 100;
88 }
89
90
2/2
✓ Branch 0 taken 405 times.
✓ Branch 1 taken 733 times.
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
2/2
✓ Branch 0 taken 2746 times.
✓ Branch 1 taken 442 times.
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
2/2
✓ Branch 1 taken 495 times.
✓ Branch 2 taken 15 times.
510 if( bits.is_finite(exponent_bits) )
126 {
127 bool is_negative;
128
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 340 times.
495 if(( is_negative = s.is_negative() ))
129 {
130 155 *dest = '-';
131 155 ++dest;
132 }
133
134
2/2
✓ Branch 1 taken 444 times.
✓ Branch 2 taken 51 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 444 times.
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
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 if( allow_infinity_and_nan )
155 {
156
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
6 if( s.has_all_zero_significand_bits() )
157 {
158
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
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
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
9 if( s.has_all_zero_significand_bits() )
175 {
176
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
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
197