GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/dragonbox/impl/to_chars.ipp
Date: 2025-12-23 16:57:39
Exec Total Coverage
Lines: 110 188 58.5%
Functions: 3 3 100.0%
Branches: 28 80 35.0%

Line Branch Exec Source
1 // Copyright 2020-2023 Junekey Jeon
2 // Copyright 2022 Peter Dimov
3 // Copyright 2023 Matt Borland
4 // Distributed under the Boost Software License, Version 1.0.
5 // https://www.boost.org/LICENSE_1_0.txt
6
7 #include <boost/json/detail/format.hpp>
8 #include <boost/json/detail/dragonbox/to_chars_integer_impl.hpp>
9 #include <limits>
10 #include <cstring>
11 #include <cstdio>
12 #include <cstdint>
13 #include <cmath>
14
15 namespace boost {
16 namespace json {
17 namespace detail {
18 namespace to_chars_detail {
19
20 #ifdef BOOST_MSVC
21 # pragma warning(push)
22 # pragma warning(disable: 4127) // Conditional expression is constant (e.g. BOOST_IF_CONSTEXPR statements)
23 #endif
24
25 // These "//"'s are to prevent clang-format to ruin this nice alignment.
26 // Thanks to reddit user u/mcmcc:
27 // https://www.reddit.com/r/cpp/comments/so3wx9/dragonbox_110_is_released_a_fast_floattostring/hw8z26r/?context=3
28 static constexpr char radix_100_head_table[] = {
29 '0', '.', '1', '.', '2', '.', '3', '.', '4', '.', //
30 '5', '.', '6', '.', '7', '.', '8', '.', '9', '.', //
31 '1', '.', '1', '.', '1', '.', '1', '.', '1', '.', //
32 '1', '.', '1', '.', '1', '.', '1', '.', '1', '.', //
33 '2', '.', '2', '.', '2', '.', '2', '.', '2', '.', //
34 '2', '.', '2', '.', '2', '.', '2', '.', '2', '.', //
35 '3', '.', '3', '.', '3', '.', '3', '.', '3', '.', //
36 '3', '.', '3', '.', '3', '.', '3', '.', '3', '.', //
37 '4', '.', '4', '.', '4', '.', '4', '.', '4', '.', //
38 '4', '.', '4', '.', '4', '.', '4', '.', '4', '.', //
39 '5', '.', '5', '.', '5', '.', '5', '.', '5', '.', //
40 '5', '.', '5', '.', '5', '.', '5', '.', '5', '.', //
41 '6', '.', '6', '.', '6', '.', '6', '.', '6', '.', //
42 '6', '.', '6', '.', '6', '.', '6', '.', '6', '.', //
43 '7', '.', '7', '.', '7', '.', '7', '.', '7', '.', //
44 '7', '.', '7', '.', '7', '.', '7', '.', '7', '.', //
45 '8', '.', '8', '.', '8', '.', '8', '.', '8', '.', //
46 '8', '.', '8', '.', '8', '.', '8', '.', '8', '.', //
47 '9', '.', '9', '.', '9', '.', '9', '.', '9', '.', //
48 '9', '.', '9', '.', '9', '.', '9', '.', '9', '.' //
49 };
50
51 22 static void print_1_digit(std::uint32_t n, char* buffer) noexcept
52 {
53 22 *buffer = char('0' + n);
54 22 }
55
56 334 static void print_2_digits(std::uint32_t n, char* buffer) noexcept
57 {
58 334 std::memcpy(buffer, radix_table + n * 2, 2);
59 334 }
60
61 // These digit generation routines are inspired by James Anhalt's itoa algorithm:
62 // https://github.com/jeaiii/itoa
63 // The main idea is for given n, find y such that floor(10^k * y / 2^32) = n holds,
64 // where k is an appropriate integer depending on the length of n.
65 // For example, if n = 1234567, we set k = 6. In this case, we have
66 // floor(y / 2^32) = 1,
67 // floor(10^2 * ((10^0 * y) mod 2^32) / 2^32) = 23,
68 // floor(10^2 * ((10^2 * y) mod 2^32) / 2^32) = 45, and
69 // floor(10^2 * ((10^4 * y) mod 2^32) / 2^32) = 67.
70 // See https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ for more explanation.
71
72 BOOST_FORCEINLINE static void print_9_digits(std::uint32_t s32, int& exponent,
73 char*& buffer) noexcept
74 {
75 // -- IEEE-754 binary32
76 // Since we do not cut trailing zeros in advance, s32 must be of 6~9 digits
77 // unless the original input was subnormal.
78 // In particular, when it is of 9 digits it shouldn't have any trailing zeros.
79 // -- IEEE-754 binary64
80 // In this case, s32 must be of 7~9 digits unless the input is subnormal,
81 // and it shouldn't have any trailing zeros if it is of 9 digits.
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
440 if (s32 >= 100000000)
83 {
84 // 9 digits.
85 // 1441151882 = ceil(2^57 / 1'0000'0000) + 1
86 auto prod = s32 * std::uint64_t(1441151882);
87 prod >>= 25;
88 std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2, 2);
89
90 prod = std::uint32_t(prod) * std::uint64_t(100);
91 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
92 prod = std::uint32_t(prod) * std::uint64_t(100);
93 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
94 prod = std::uint32_t(prod) * std::uint64_t(100);
95 print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
96 prod = std::uint32_t(prod) * std::uint64_t(100);
97 print_2_digits(std::uint32_t(prod >> 32), buffer + 8);
98
99 exponent += 8;
100 buffer += 10;
101 }
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
440 else if (s32 >= 1000000)
103 {
104 // 7 or 8 digits.
105 // 281474978 = ceil(2^48 / 100'0000) + 1
106 auto prod = s32 * std::uint64_t(281474978);
107 prod >>= 16;
108 const auto head_digits = std::uint32_t(prod >> 32);
109 // If s32 is of 8 digits, increase the exponent by 7.
110 // Otherwise, increase it by 6.
111 exponent += static_cast<int>(6 + unsigned(head_digits >= 10));
112
113 // Write the first digit and the decimal point.
114 std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
115 // This third character may be overwritten later, but we don't care.
116 buffer[2] = radix_table[head_digits * 2 + 1];
117
118 // Remaining 6 digits are all zero?
119 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 1000000))
120 {
121 // The number of characters actually need to be written is:
122 // 1, if only the first digit is nonzero, which means that either s32 is of 7
123 // digits or it is of 8 digits but the second digit is zero, or
124 // 3, otherwise.
125 // Note that buffer[2] is never '0' if s32 is of 7 digits, because the input is
126 // never zero.
127 buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
128 }
129 else
130 {
131 // At least one of the remaining 6 digits are nonzero.
132 // After this adjustment, now the first destination becomes buffer + 2.
133 buffer += unsigned(head_digits >= 10);
134
135 // Obtain the next two digits.
136 prod = std::uint32_t(prod) * std::uint64_t(100);
137 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
138
139 // Remaining 4 digits are all zero?
140 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000))
141 {
142 buffer += (3 + unsigned(buffer[3] > '0'));
143 }
144 else
145 {
146 // At least one of the remaining 4 digits are nonzero.
147
148 // Obtain the next two digits.
149 prod = std::uint32_t(prod) * std::uint64_t(100);
150 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
151
152 // Remaining 2 digits are all zero?
153 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
154 {
155 buffer += (5 + unsigned(buffer[5] > '0'));
156 }
157 else
158 {
159 // Obtain the last two digits.
160 prod = std::uint32_t(prod) * std::uint64_t(100);
161 print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
162
163 buffer += (7 + unsigned(buffer[7] > '0'));
164 }
165 }
166 }
167 }
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
440 else if (s32 >= 10000)
169 {
170 // 5 or 6 digits.
171 // 429497 = ceil(2^32 / 1'0000)
172 auto prod = s32 * std::uint64_t(429497);
173 const auto head_digits = std::uint32_t(prod >> 32);
174
175 // If s32 is of 6 digits, increase the exponent by 5.
176 // Otherwise, increase it by 4.
177 exponent += static_cast<int>(4 + unsigned(head_digits >= 10));
178
179 // Write the first digit and the decimal point.
180 std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
181 // This third character may be overwritten later but we don't care.
182 buffer[2] = radix_table[head_digits * 2 + 1];
183
184 // Remaining 4 digits are all zero?
185 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000))
186 {
187 // The number of characters actually written is 1 or 3, similarly to the case of
188 // 7 or 8 digits.
189 buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
190 }
191 else
192 {
193 // At least one of the remaining 4 digits are nonzero.
194 // After this adjustment, now the first destination becomes buffer + 2.
195 buffer += unsigned(head_digits >= 10);
196
197 // Obtain the next two digits.
198 prod = std::uint32_t(prod) * std::uint64_t(100);
199 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
200
201 // Remaining 2 digits are all zero?
202 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
203 {
204 buffer += (3 + unsigned(buffer[3] > '0'));
205 }
206 else
207 {
208 // Obtain the last two digits.
209 prod = std::uint32_t(prod) * std::uint64_t(100);
210 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
211
212 buffer += (5 + unsigned(buffer[5] > '0'));
213 }
214 }
215 }
216
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 426 times.
440 else if (s32 >= 100)
217 {
218 // 3 or 4 digits.
219 // 42949673 = ceil(2^32 / 100)
220 14 auto prod = s32 * std::uint64_t(42949673);
221 14 const auto head_digits = std::uint32_t(prod >> 32);
222
223 // If s32 is of 4 digits, increase the exponent by 3.
224 // Otherwise, increase it by 2.
225
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
14 exponent += (2 + int(head_digits >= 10));
226
227 // Write the first digit and the decimal point.
228 14 std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
229 // This third character may be overwritten later but we don't care.
230 14 buffer[2] = radix_table[head_digits * 2 + 1];
231
232 // Remaining 2 digits are all zero?
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
234 {
235 // The number of characters actually written is 1 or 3, similarly to the case of
236 // 7 or 8 digits.
237 buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
238 }
239 else
240 {
241 // At least one of the remaining 2 digits are nonzero.
242 // After this adjustment, now the first destination becomes buffer + 2.
243 14 buffer += unsigned(head_digits >= 10);
244
245 // Obtain the last two digits.
246 14 prod = std::uint32_t(prod) * std::uint64_t(100);
247 14 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
248
249
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 buffer += (3 + unsigned(buffer[3] > '0'));
250 }
251 }
252 else
253 {
254 // 1 or 2 digits.
255 // If s32 is of 2 digits, increase the exponent by 1.
256 426 exponent += int(s32 >= 10);
257
258 // Write the first digit and the decimal point.
259 426 std::memcpy(buffer, radix_100_head_table + s32 * 2, 2);
260 // This third character may be overwritten later but we don't care.
261 426 buffer[2] = radix_table[s32 * 2 + 1];
262
263 // The number of characters actually written is 1 or 3, similarly to the case of
264 // 7 or 8 digits.
265 426 buffer += (1 + (unsigned(s32 >= 10) & unsigned(buffer[2] > '0')) * 2);
266 }
267 440 }
268
269 444 std::size_t dragon_box_print_chars(const std::uint64_t significand, int exponent, char* first, char* last) noexcept
270 {
271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 444 times.
444 BOOST_ASSERT( detail::max_number_chars >= std::size_t(last - first) );
272
273 444 auto buffer = first;
274 // Print significand by decomposing it into a 9-digit block and a 8-digit block.
275 std::uint32_t first_block;
276 444 std::uint32_t second_block {};
277 bool no_second_block;
278
279
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 440 times.
444 if (significand >= 100000000)
280 {
281 4 first_block = std::uint32_t(significand / 100000000);
282 4 second_block = std::uint32_t(significand) - first_block * 100000000;
283 4 exponent += 8;
284 4 no_second_block = (second_block == 0);
285 }
286 else
287 {
288 440 first_block = std::uint32_t(significand);
289 440 no_second_block = true;
290 }
291
292
2/2
✓ Branch 0 taken 440 times.
✓ Branch 1 taken 4 times.
444 if (no_second_block)
293 {
294 print_9_digits(first_block, exponent, buffer);
295 }
296 else
297 {
298 // We proceed similarly to print_9_digits(), but since we do not need to remove
299 // trailing zeros, the procedure is a bit simpler.
300
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (first_block >= 100000000)
301 {
302 // The input is of 17 digits, thus there should be no trailing zero at all.
303 // The first block is of 9 digits.
304 // 1441151882 = ceil(2^57 / 1'0000'0000) + 1
305 1 auto prod = first_block * std::uint64_t(1441151882);
306 1 prod >>= 25;
307 1 std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2, 2);
308 1 prod = std::uint32_t(prod) * std::uint64_t(100);
309 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
310 1 prod = std::uint32_t(prod) * std::uint64_t(100);
311 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
312 1 prod = std::uint32_t(prod) * std::uint64_t(100);
313 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
314 1 prod = std::uint32_t(prod) * std::uint64_t(100);
315 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 8);
316
317 // The second block is of 8 digits.
318 // 281474978 = ceil(2^48 / 100'0000) + 1
319 1 prod = second_block * std::uint64_t(281474978);
320 1 prod >>= 16;
321 1 prod += 1;
322 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 10);
323 1 prod = std::uint32_t(prod) * std::uint64_t(100);
324 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 12);
325 1 prod = std::uint32_t(prod) * std::uint64_t(100);
326 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 14);
327 1 prod = std::uint32_t(prod) * std::uint64_t(100);
328 1 print_2_digits(std::uint32_t(prod >> 32), buffer + 16);
329
330 1 exponent += 8;
331 1 buffer += 18;
332 }
333 else
334 {
335
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (first_block >= 1000000)
336 {
337 // 7 or 8 digits.
338 // 281474978 = ceil(2^48 / 100'0000) + 1
339 3 auto prod = first_block * std::uint64_t(281474978);
340 3 prod >>= 16;
341 3 const auto head_digits = std::uint32_t(prod >> 32);
342
343 3 std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
344 3 buffer[2] = radix_table[head_digits * 2 + 1];
345
346
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 exponent += static_cast<int>(6 + unsigned(head_digits >= 10));
347 3 buffer += unsigned(head_digits >= 10);
348
349 // Print remaining 6 digits.
350 3 prod = std::uint32_t(prod) * std::uint64_t(100);
351 3 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
352 3 prod = std::uint32_t(prod) * std::uint64_t(100);
353 3 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
354 3 prod = std::uint32_t(prod) * std::uint64_t(100);
355 3 print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
356
357 3 buffer += 8;
358 }
359 else if (first_block >= 10000)
360 {
361 // 5 or 6 digits.
362 // 429497 = ceil(2^32 / 1'0000)
363 auto prod = first_block * std::uint64_t(429497);
364 const auto head_digits = std::uint32_t(prod >> 32);
365
366 std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
367 buffer[2] = radix_table[head_digits * 2 + 1];
368
369 exponent += static_cast<int>(4 + unsigned(head_digits >= 10));
370 buffer += unsigned(head_digits >= 10);
371
372 // Print remaining 4 digits.
373 prod = std::uint32_t(prod) * std::uint64_t(100);
374 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
375 prod = std::uint32_t(prod) * std::uint64_t(100);
376 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
377
378 buffer += 6;
379 }
380 else if (first_block >= 100)
381 {
382 // 3 or 4 digits.
383 // 42949673 = ceil(2^32 / 100)
384 auto prod = first_block * std::uint64_t(42949673);
385 const auto head_digits = std::uint32_t(prod >> 32);
386
387 std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
388 buffer[2] = radix_table[head_digits * 2 + 1];
389
390 exponent += static_cast<int>(2 + unsigned(head_digits >= 10));
391 buffer += unsigned(head_digits >= 10);
392
393 // Print remaining 2 digits.
394 prod = std::uint32_t(prod) * std::uint64_t(100);
395 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
396
397 buffer += 4;
398 }
399 else
400 {
401 // 1 or 2 digits.
402 std::memcpy(buffer, radix_100_head_table + first_block * 2, 2);
403 buffer[2] = radix_table[first_block * 2 + 1];
404
405 exponent += (first_block >= 10);
406 buffer += (2 + unsigned(first_block >= 10));
407 }
408
409 // Next, print the second block.
410 // The second block is of 8 digits, but we may have trailing zeros.
411 // 281474978 = ceil(2^48 / 100'0000) + 1
412 3 auto prod = second_block * std::uint64_t(281474978);
413 3 prod >>= 16;
414 3 prod += 1;
415 3 print_2_digits(std::uint32_t(prod >> 32), buffer);
416
417 // Remaining 6 digits are all zero?
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 1000000))
419 {
420 buffer += (1 + unsigned(buffer[1] > '0'));
421 }
422 else
423 {
424 // Obtain the next two digits.
425 3 prod = std::uint32_t(prod) * std::uint64_t(100);
426 3 print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
427
428 // Remaining 4 digits are all zero?
429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000))
430 {
431 buffer += (3 + unsigned(buffer[3] > '0'));
432 }
433 else
434 {
435 // Obtain the next two digits.
436 3 prod = std::uint32_t(prod) * std::uint64_t(100);
437 3 print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
438
439 // Remaining 2 digits are all zero?
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
441 {
442 buffer += (5 + unsigned(buffer[5] > '0'));
443 }
444 else
445 {
446 // Obtain the last two digits.
447 3 prod = std::uint32_t(prod) * std::uint64_t(100);
448 3 print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
449
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 buffer += (7 + unsigned(buffer[7] > '0'));
450 }
451 }
452 }
453 }
454 }
455
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 359 times.
444 if (exponent < 0)
456 {
457 85 std::memcpy(buffer, "E-", 2);
458 85 buffer += 2;
459 85 exponent = -exponent;
460 }
461
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 206 times.
359 else if (exponent == 0)
462 {
463 153 std::memcpy(buffer, "E0", 2);
464 153 return 2 + (buffer - first);
465 }
466 else
467 {
468 206 std::memcpy(buffer, "E+", 2);
469 206 buffer += 2;
470 }
471
472
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 269 times.
291 if (exponent >= 100)
473 {
474 // d1 = exponent / 10; d2 = exponent % 10;
475 // 6554 = ceil(2^16 / 10)
476 22 auto prod = std::uint32_t(exponent) * std::uint32_t(6554);
477 22 auto d1 = prod >> 16;
478 22 prod = std::uint16_t(prod) * std::uint32_t(5); // * 10
479 22 auto d2 = prod >> 15; // >> 16
480 22 print_2_digits(d1, buffer);
481 22 print_1_digit(d2, buffer + 2);
482 22 buffer += 3;
483 }
484 else
485 {
486 269 print_2_digits(static_cast<std::uint32_t>(exponent), buffer);
487 269 buffer += 2;
488 }
489
490 291 return buffer - first;
491 }
492
493 #ifdef BOOST_MSVC
494 # pragma warning(pop)
495 #endif
496
497 } // namespace to_chars_detail
498 } // namespace detail
499 } // namespace json
500 } // namespace boost
501