Coverage Report

Created: 2026-11-12 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/libs/charconv/src/to_chars.cpp
Line
Count
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 "float128_impl.hpp"
8
#include "to_chars_float_impl.hpp"
9
#include <boost/charconv/to_chars.hpp>
10
#include <boost/charconv/chars_format.hpp>
11
#include <limits>
12
#include <cstring>
13
#include <cstdio>
14
#include <cstdint>
15
#include <cmath>
16
17
namespace boost { namespace charconv { namespace detail { namespace to_chars_detail {
18
19
#ifdef BOOST_MSVC
20
# pragma warning(push)
21
# pragma warning(disable: 4127) // Conditional expression is constant (e.g. BOOST_IF_CONSTEXPR statements)
22
#endif
23
24
    // These "//"'s are to prevent clang-format to ruin this nice alignment.
25
    // Thanks to reddit user u/mcmcc:
26
    // https://www.reddit.com/r/cpp/comments/so3wx9/dragonbox_110_is_released_a_fast_floattostring/hw8z26r/?context=3
27
    static constexpr char radix_100_head_table[] = {
28
        '0', '.', '1', '.', '2', '.', '3', '.', '4', '.', //
29
        '5', '.', '6', '.', '7', '.', '8', '.', '9', '.', //
30
        '1', '.', '1', '.', '1', '.', '1', '.', '1', '.', //
31
        '1', '.', '1', '.', '1', '.', '1', '.', '1', '.', //
32
        '2', '.', '2', '.', '2', '.', '2', '.', '2', '.', //
33
        '2', '.', '2', '.', '2', '.', '2', '.', '2', '.', //
34
        '3', '.', '3', '.', '3', '.', '3', '.', '3', '.', //
35
        '3', '.', '3', '.', '3', '.', '3', '.', '3', '.', //
36
        '4', '.', '4', '.', '4', '.', '4', '.', '4', '.', //
37
        '4', '.', '4', '.', '4', '.', '4', '.', '4', '.', //
38
        '5', '.', '5', '.', '5', '.', '5', '.', '5', '.', //
39
        '5', '.', '5', '.', '5', '.', '5', '.', '5', '.', //
40
        '6', '.', '6', '.', '6', '.', '6', '.', '6', '.', //
41
        '6', '.', '6', '.', '6', '.', '6', '.', '6', '.', //
42
        '7', '.', '7', '.', '7', '.', '7', '.', '7', '.', //
43
        '7', '.', '7', '.', '7', '.', '7', '.', '7', '.', //
44
        '8', '.', '8', '.', '8', '.', '8', '.', '8', '.', //
45
        '8', '.', '8', '.', '8', '.', '8', '.', '8', '.', //
46
        '9', '.', '9', '.', '9', '.', '9', '.', '9', '.', //
47
        '9', '.', '9', '.', '9', '.', '9', '.', '9', '.'  //
48
    };
49
50
    static void print_1_digit(std::uint32_t n, char* buffer) noexcept
51
3.95k
    {
52
3.95k
        *buffer = char('0' + n);
53
3.95k
    }
54
55
    static void print_2_digits(std::uint32_t n, char* buffer) noexcept 
56
35.9M
    {
57
35.9M
        std::memcpy(buffer, radix_table + n * 2, 2);
58
35.9M
    }
59
60
    // These digit generation routines are inspired by James Anhalt's itoa algorithm:
61
    // https://github.com/jeaiii/itoa
62
    // The main idea is for given n, find y such that floor(10^k * y / 2^32) = n holds,
63
    // where k is an appropriate integer depending on the length of n.
64
    // For example, if n = 1234567, we set k = 6. In this case, we have
65
    // floor(y / 2^32) = 1,
66
    // floor(10^2 * ((10^0 * y) mod 2^32) / 2^32) = 23,
67
    // floor(10^2 * ((10^2 * y) mod 2^32) / 2^32) = 45, and
68
    // floor(10^2 * ((10^4 * y) mod 2^32) / 2^32) = 67.
69
    // See https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ for more explanation.
70
71
    BOOST_FORCEINLINE static void print_9_digits(std::uint32_t s32, int& exponent,
72
                                                char*& buffer) noexcept 
73
348k
    {
74
        // -- IEEE-754 binary32
75
        // Since we do not cut trailing zeros in advance, s32 must be of 6~9 digits
76
        // unless the original input was subnormal.
77
        // In particular, when it is of 9 digits it shouldn't have any trailing zeros.
78
        // -- IEEE-754 binary64
79
        // In this case, s32 must be of 7~9 digits unless the input is subnormal,
80
        // and it shouldn't have any trailing zeros if it is of 9 digits.
81
348k
        if (s32 >= 100000000)
82
0
        {
83
            // 9 digits.
84
            // 1441151882 = ceil(2^57 / 1'0000'0000) + 1
85
0
            auto prod = s32 * std::uint64_t(1441151882);
86
0
            prod >>= 25;
87
0
            std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2, 2);
88
89
0
            prod = std::uint32_t(prod) * std::uint64_t(100);
90
0
            print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
91
0
            prod = std::uint32_t(prod) * std::uint64_t(100);
92
0
            print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
93
0
            prod = std::uint32_t(prod) * std::uint64_t(100);
94
0
            print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
95
0
            prod = std::uint32_t(prod) * std::uint64_t(100);
96
0
            print_2_digits(std::uint32_t(prod >> 32), buffer + 8);
97
98
0
            exponent += 8;
99
0
            buffer += 10;
100
0
        }
101
348k
        else if (s32 >= 1000000) 
102
5.90k
        {
103
            // 7 or 8 digits.
104
            // 281474978 = ceil(2^48 / 100'0000) + 1
105
5.90k
            auto prod = s32 * std::uint64_t(281474978);
106
5.90k
            prod >>= 16;
107
5.90k
            const auto head_digits = std::uint32_t(prod >> 32);
108
            // If s32 is of 8 digits, increase the exponent by 7.
109
            // Otherwise, increase it by 6.
110
5.90k
            exponent += static_cast<int>(6 + unsigned(head_digits >= 10));
111
112
            // Write the first digit and the decimal point.
113
5.90k
            std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
114
            // This third character may be overwritten later, but we don't care.
115
5.90k
            buffer[2] = radix_table[head_digits * 2 + 1];
116
117
            // Remaining 6 digits are all zero?
118
5.90k
            if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 1000000)) 
119
0
            {
120
                // The number of characters actually need to be written is:
121
                //   1, if only the first digit is nonzero, which means that either s32 is of 7
122
                //   digits or it is of 8 digits but the second digit is zero, or
123
                //   3, otherwise.
124
                // Note that buffer[2] is never '0' if s32 is of 7 digits, because the input is
125
                // never zero.
126
0
                buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
127
0
            }
128
5.90k
            else 
129
5.90k
            {
130
                // At least one of the remaining 6 digits are nonzero.
131
                // After this adjustment, now the first destination becomes buffer + 2.
132
5.90k
                buffer += unsigned(head_digits >= 10);
133
134
                // Obtain the next two digits.
135
5.90k
                prod = std::uint32_t(prod) * std::uint64_t(100);
136
5.90k
                print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
137
138
                // Remaining 4 digits are all zero?
139
5.90k
                if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000)) 
140
0
                {
141
0
                    buffer += (3 + unsigned(buffer[3] > '0'));
142
0
                }
143
5.90k
                else 
144
5.90k
                {
145
                    // At least one of the remaining 4 digits are nonzero.
146
147
                    // Obtain the next two digits.
148
5.90k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
149
5.90k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
150
151
                    // Remaining 2 digits are all zero?
152
5.90k
                    if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
153
0
                    {
154
0
                        buffer += (5 + unsigned(buffer[5] > '0'));
155
0
                    }
156
5.90k
                    else 
157
5.90k
                    {
158
                        // Obtain the last two digits.
159
5.90k
                        prod = std::uint32_t(prod) * std::uint64_t(100);
160
5.90k
                        print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
161
162
5.90k
                        buffer += (7 + unsigned(buffer[7] > '0'));
163
5.90k
                    }
164
5.90k
                }
165
5.90k
            }
166
5.90k
        }
167
342k
        else if (s32 >= 10000)
168
5.80k
        {
169
            // 5 or 6 digits.
170
            // 429497 = ceil(2^32 / 1'0000)
171
5.80k
            auto prod = s32 * std::uint64_t(429497);
172
5.80k
            const auto head_digits = std::uint32_t(prod >> 32);
173
174
            // If s32 is of 6 digits, increase the exponent by 5.
175
            // Otherwise, increase it by 4.
176
5.80k
            exponent += static_cast<int>(4 + unsigned(head_digits >= 10));
177
178
            // Write the first digit and the decimal point.
179
5.80k
            std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
180
            // This third character may be overwritten later but we don't care.
181
5.80k
            buffer[2] = radix_table[head_digits * 2 + 1];
182
183
            // Remaining 4 digits are all zero?
184
5.80k
            if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000)) 
185
0
            {
186
                // The number of characters actually written is 1 or 3, similarly to the case of
187
                // 7 or 8 digits.
188
0
                buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
189
0
            }
190
5.80k
            else 
191
5.80k
            {
192
                // At least one of the remaining 4 digits are nonzero.
193
                // After this adjustment, now the first destination becomes buffer + 2.
194
5.80k
                buffer += unsigned(head_digits >= 10);
195
196
                // Obtain the next two digits.
197
5.80k
                prod = std::uint32_t(prod) * std::uint64_t(100);
198
5.80k
                print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
199
200
                // Remaining 2 digits are all zero?
201
5.80k
                if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
202
0
                {
203
0
                    buffer += (3 + unsigned(buffer[3] > '0'));
204
0
                }
205
5.80k
                else
206
5.80k
                {
207
                    // Obtain the last two digits.
208
5.80k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
209
5.80k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
210
211
5.80k
                    buffer += (5 + unsigned(buffer[5] > '0'));
212
5.80k
                }
213
5.80k
            }
214
5.80k
        }
215
337k
        else if (s32 >= 100)
216
6.00k
        {
217
            // 3 or 4 digits.
218
            // 42949673 = ceil(2^32 / 100)
219
6.00k
            auto prod = s32 * std::uint64_t(42949673);
220
6.00k
            const auto head_digits = std::uint32_t(prod >> 32);
221
222
            // If s32 is of 4 digits, increase the exponent by 3.
223
            // Otherwise, increase it by 2.
224
6.00k
            exponent += (2 + int(head_digits >= 10));
225
226
            // Write the first digit and the decimal point.
227
6.00k
            std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
228
            // This third character may be overwritten later but we don't care.
229
6.00k
            buffer[2] = radix_table[head_digits * 2 + 1];
230
231
            // Remaining 2 digits are all zero?
232
6.00k
            if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100))
233
0
            {
234
                // The number of characters actually written is 1 or 3, similarly to the case of
235
                // 7 or 8 digits.
236
0
                buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
237
0
            }
238
6.00k
            else
239
6.00k
            {
240
                // At least one of the remaining 2 digits are nonzero.
241
                // After this adjustment, now the first destination becomes buffer + 2.
242
6.00k
                buffer += unsigned(head_digits >= 10);
243
244
                // Obtain the last two digits.
245
6.00k
                prod = std::uint32_t(prod) * std::uint64_t(100);
246
6.00k
                print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
247
248
6.00k
                buffer += (3 + unsigned(buffer[3] > '0'));
249
6.00k
            }
250
6.00k
        }
251
331k
        else
252
331k
        {
253
            // 1 or 2 digits.
254
            // If s32 is of 2 digits, increase the exponent by 1.
255
331k
            exponent += int(s32 >= 10);
256
257
            // Write the first digit and the decimal point.
258
331k
            std::memcpy(buffer, radix_100_head_table + s32 * 2, 2);
259
            // This third character may be overwritten later but we don't care.
260
331k
            buffer[2] = radix_table[s32 * 2 + 1];
261
262
            // The number of characters actually written is 1 or 3, similarly to the case of
263
            // 7 or 8 digits.
264
331k
            buffer += (1 + (unsigned(s32 >= 10) & unsigned(buffer[2] > '0')) * 2);
265
331k
        }
266
348k
    }
267
268
    template <>
269
    to_chars_result dragon_box_print_chars<float, dragonbox_float_traits<float>>(std::uint32_t s32, int exponent, char* first, char* last, chars_format fmt) noexcept
270
0
    {
271
0
        auto buffer = first;
272
273
0
        const std::ptrdiff_t total_length = total_buffer_length(9, exponent, false);
274
0
        if (total_length > (last - first))
275
0
        {
276
0
            return {last, std::errc::value_too_large};
277
0
        }
278
279
        // Print significand.
280
0
        print_9_digits(s32, exponent, buffer);
281
282
        // Print exponent and return
283
0
        if (exponent < 0)
284
0
        {
285
0
            std::memcpy(buffer, "e-", 2);
286
0
            buffer += 2;
287
0
            exponent = -exponent;
288
0
        }
289
0
        else if (exponent == 0)
290
0
        {
291
0
            if (fmt == chars_format::scientific)
292
0
            {
293
0
                std::memcpy(buffer, "e+00", 4);
294
0
                buffer += 4;
295
0
            }
296
297
0
            return {buffer, std::errc()};
298
0
        }
299
0
        else 
300
0
        {
301
0
            std::memcpy(buffer, "e+", 2);
302
0
            buffer += 2;
303
0
        }
304
305
0
        print_2_digits(std::uint32_t(exponent), buffer);
306
0
        buffer += 2;
307
308
0
        return {buffer, std::errc()};
309
0
    }
310
311
    template <>
312
    to_chars_result dragon_box_print_chars<double, dragonbox_float_traits<double>>(const std::uint64_t significand, int exponent, char* first, char* last, chars_format fmt) noexcept
313
4.30M
    {
314
4.30M
        auto buffer = first;
315
316
        // Print significand by decomposing it into a 9-digit block and a 8-digit block.
317
4.30M
        std::uint32_t first_block;
318
4.30M
        std::uint32_t second_block {};
319
4.30M
        bool no_second_block;
320
321
4.30M
        if (significand >= 100000000)
322
3.95M
        {
323
3.95M
            first_block = std::uint32_t(significand / 100000000);
324
3.95M
            second_block = std::uint32_t(significand) - first_block * 100000000;
325
3.95M
            exponent += 8;
326
3.95M
            no_second_block = (second_block == 0);
327
3.95M
        }
328
348k
        else
329
348k
        {
330
348k
            first_block = std::uint32_t(significand);
331
348k
            no_second_block = true;
332
348k
        }
333
334
4.30M
        const std::ptrdiff_t total_length = total_buffer_length(no_second_block ? 9 : 17, exponent, false);;
335
4.30M
        if (total_length > (last - first))
336
0
        {
337
0
            return {last, std::errc::value_too_large};
338
0
        }
339
340
4.30M
        if (no_second_block)
341
348k
        {
342
348k
            print_9_digits(first_block, exponent, buffer);
343
348k
        }
344
3.95M
        else
345
3.95M
        {
346
            // We proceed similarly to print_9_digits(), but since we do not need to remove
347
            // trailing zeros, the procedure is a bit simpler.
348
3.95M
            if (first_block >= 100000000)
349
3.89M
            {
350
                // The input is of 17 digits, thus there should be no trailing zero at all.
351
                // The first block is of 9 digits.
352
                // 1441151882 = ceil(2^57 / 1'0000'0000) + 1
353
3.89M
                auto prod = first_block * std::uint64_t(1441151882);
354
3.89M
                prod >>= 25;
355
3.89M
                std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2, 2);
356
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
357
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
358
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
359
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
360
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
361
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
362
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
363
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 8);
364
365
                // The second block is of 8 digits.
366
                // 281474978 = ceil(2^48 / 100'0000) + 1
367
3.89M
                prod = second_block * std::uint64_t(281474978);
368
3.89M
                prod >>= 16;
369
3.89M
                prod += 1;
370
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 10);
371
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
372
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 12);
373
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
374
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 14);
375
3.89M
                prod = std::uint32_t(prod) * std::uint64_t(100);
376
3.89M
                print_2_digits(std::uint32_t(prod >> 32), buffer + 16);
377
378
3.89M
                exponent += 8;
379
3.89M
                buffer += 18;
380
3.89M
            }
381
59.2k
            else
382
59.2k
            {
383
59.2k
                if (first_block >= 1000000)
384
49.0k
                {
385
                    // 7 or 8 digits.
386
                    // 281474978 = ceil(2^48 / 100'0000) + 1
387
49.0k
                    auto prod = first_block * std::uint64_t(281474978);
388
49.0k
                    prod >>= 16;
389
49.0k
                    const auto head_digits = std::uint32_t(prod >> 32);
390
391
49.0k
                    std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
392
49.0k
                    buffer[2] = radix_table[head_digits * 2 + 1];
393
394
49.0k
                    exponent += static_cast<int>(6 + unsigned(head_digits >= 10));
395
49.0k
                    buffer += unsigned(head_digits >= 10);
396
397
                    // Print remaining 6 digits.
398
49.0k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
399
49.0k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
400
49.0k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
401
49.0k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
402
49.0k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
403
49.0k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
404
405
49.0k
                    buffer += 8;
406
49.0k
                }
407
10.1k
                else if (first_block >= 10000)
408
5.69k
                {
409
                    // 5 or 6 digits.
410
                    // 429497 = ceil(2^32 / 1'0000)
411
5.69k
                    auto prod = first_block * std::uint64_t(429497);
412
5.69k
                    const auto head_digits = std::uint32_t(prod >> 32);
413
414
5.69k
                    std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
415
5.69k
                    buffer[2] = radix_table[head_digits * 2 + 1];
416
417
5.69k
                    exponent += static_cast<int>(4 + unsigned(head_digits >= 10));
418
5.69k
                    buffer += unsigned(head_digits >= 10);
419
420
                    // Print remaining 4 digits.
421
5.69k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
422
5.69k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
423
5.69k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
424
5.69k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
425
426
5.69k
                    buffer += 6;
427
5.69k
                }
428
4.47k
                else if (first_block >= 100)
429
3.31k
                {
430
                    // 3 or 4 digits.
431
                    // 42949673 = ceil(2^32 / 100)
432
3.31k
                    auto prod = first_block * std::uint64_t(42949673);
433
3.31k
                    const auto head_digits = std::uint32_t(prod >> 32);
434
435
3.31k
                    std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2);
436
3.31k
                    buffer[2] = radix_table[head_digits * 2 + 1];
437
438
3.31k
                    exponent += static_cast<int>(2 + unsigned(head_digits >= 10));
439
3.31k
                    buffer += unsigned(head_digits >= 10);
440
441
                    // Print remaining 2 digits.
442
3.31k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
443
3.31k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
444
445
3.31k
                    buffer += 4;
446
3.31k
                }
447
1.16k
                else
448
1.16k
                {
449
                    // 1 or 2 digits.
450
1.16k
                    std::memcpy(buffer, radix_100_head_table + first_block * 2, 2);
451
1.16k
                    buffer[2] = radix_table[first_block * 2 + 1];
452
453
1.16k
                    exponent += (first_block >= 10);
454
1.16k
                    buffer += (2 + unsigned(first_block >= 10));
455
1.16k
                }
456
457
                // Next, print the second block.
458
                // The second block is of 8 digits, but we may have trailing zeros.
459
                // 281474978 = ceil(2^48 / 100'0000) + 1
460
59.2k
                auto prod = second_block * std::uint64_t(281474978);
461
59.2k
                prod >>= 16;
462
59.2k
                prod += 1;
463
59.2k
                print_2_digits(std::uint32_t(prod >> 32), buffer);
464
465
                // Remaining 6 digits are all zero?
466
59.2k
                if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 1000000))
467
0
                {
468
0
                    buffer += (1 + unsigned(buffer[1] > '0'));
469
0
                }
470
59.2k
                else
471
59.2k
                {
472
                    // Obtain the next two digits.
473
59.2k
                    prod = std::uint32_t(prod) * std::uint64_t(100);
474
59.2k
                    print_2_digits(std::uint32_t(prod >> 32), buffer + 2);
475
476
                    // Remaining 4 digits are all zero?
477
59.2k
                    if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000)) 
478
0
                    {
479
0
                        buffer += (3 + unsigned(buffer[3] > '0'));
480
0
                    }
481
59.2k
                    else
482
59.2k
                    {
483
                        // Obtain the next two digits.
484
59.2k
                        prod = std::uint32_t(prod) * std::uint64_t(100);
485
59.2k
                        print_2_digits(std::uint32_t(prod >> 32), buffer + 4);
486
487
                        // Remaining 2 digits are all zero?
488
59.2k
                        if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100)) 
489
0
                        {
490
0
                            buffer += (5 + unsigned(buffer[5] > '0'));
491
0
                        }
492
59.2k
                        else 
493
59.2k
                        {
494
                            // Obtain the last two digits.
495
59.2k
                            prod = std::uint32_t(prod) * std::uint64_t(100);
496
59.2k
                            print_2_digits(std::uint32_t(prod >> 32), buffer + 6);
497
59.2k
                            buffer += (7 + unsigned(buffer[7] > '0'));
498
59.2k
                        }
499
59.2k
                    }
500
59.2k
                }
501
59.2k
            }
502
3.95M
        }
503
4.30M
        if (exponent < 0)
504
61.7k
        {
505
61.7k
            std::memcpy(buffer, "e-", 2);
506
61.7k
            buffer += 2;
507
61.7k
            exponent = -exponent;
508
61.7k
        }
509
4.24M
        else if (exponent == 0)
510
6.14k
        {
511
6.14k
            if (fmt == chars_format::scientific)
512
6.14k
            {
513
6.14k
                std::memcpy(buffer, "e+00", 4);
514
6.14k
                buffer += 4;
515
6.14k
            }
516
517
6.14k
            return {buffer, std::errc()};
518
6.14k
        }
519
4.23M
        else
520
4.23M
        {
521
4.23M
            std::memcpy(buffer, "e+", 2);
522
4.23M
            buffer += 2;
523
4.23M
        }
524
525
4.29M
        if (exponent >= 100) 
526
3.95k
        {
527
            // d1 = exponent / 10; d2 = exponent % 10;
528
            // 6554 = ceil(2^16 / 10)
529
3.95k
            auto prod = std::uint32_t(exponent) * std::uint32_t(6554);
530
3.95k
            auto d1 = prod >> 16;
531
3.95k
            prod = std::uint16_t(prod) * std::uint32_t(5); // * 10
532
3.95k
            auto d2 = prod >> 15;                          // >> 16
533
3.95k
            print_2_digits(d1, buffer);
534
3.95k
            print_1_digit(d2, buffer + 2);
535
3.95k
            buffer += 3;
536
3.95k
        }
537
4.29M
        else
538
4.29M
        {
539
4.29M
            print_2_digits(static_cast<std::uint32_t>(exponent), buffer);
540
4.29M
            buffer += 2;
541
4.29M
        }
542
543
4.29M
        return {buffer, std::errc()};
544
4.30M
    }
545
546
#ifdef BOOST_MSVC
547
# pragma warning(pop)
548
#endif
549
550
}}}} // Namespaces
551
552
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, float value,
553
                                                           boost::charconv::chars_format fmt) noexcept
554
0
{
555
0
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
556
0
}
557
558
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, float value,
559
                                                           boost::charconv::chars_format fmt, int precision) noexcept
560
0
{
561
0
    if (precision < 0)
562
0
    {
563
0
        precision = 6;
564
0
    }
565
566
0
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
567
0
}
568
569
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, double value,
570
                                                           boost::charconv::chars_format fmt) noexcept
571
4.30M
{
572
4.30M
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
573
4.30M
}
574
575
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, double value,
576
                                                           boost::charconv::chars_format fmt, int precision) noexcept
577
0
{
578
0
    if (precision < 0)
579
0
    {
580
0
        precision = 6;
581
0
    }
582
583
0
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
584
0
}
585
586
#if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC)
587
588
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
589
                                                           boost::charconv::chars_format fmt) noexcept
590
{
591
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, -1);
592
}
593
594
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
595
                                                           boost::charconv::chars_format fmt, int precision) noexcept
596
{
597
    if (precision < 0)
598
    {
599
        precision = 6;
600
    }
601
602
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision);
603
}
604
605
#elif !defined(BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE) && !defined(BOOST_CHARCONV_LDBL_IS_FLOAT128)
606
607
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
608
                                                           boost::charconv::chars_format fmt) noexcept
609
0
{
610
0
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
611
0
}
612
613
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
614
                                                           boost::charconv::chars_format fmt, int precision) noexcept
615
0
{
616
0
    if (precision < 0)
617
0
    {
618
0
        precision = 6;
619
0
    }
620
621
0
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
622
0
}
623
624
#endif
625
626
#ifdef BOOST_CHARCONV_HAS_QUADMATH
627
628
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt) noexcept
629
{
630
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
631
}
632
633
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt, int precision) noexcept
634
{
635
    if (precision < 0)
636
    {
637
        precision = 6;
638
    }
639
640
    return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
641
}
642
643
#endif
644
645
#ifdef BOOST_CHARCONV_HAS_FLOAT16
646
647
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float16_t value,
648
                                                           boost::charconv::chars_format fmt) noexcept
649
{
650
    return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, -1);
651
}
652
653
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float16_t value,
654
                                                           boost::charconv::chars_format fmt, int precision) noexcept
655
{
656
    if (precision < 0)
657
    {
658
        precision = 6;
659
        return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, precision);
660
    }
661
662
    // If the precision is specified it is better to use our exisiting methods for float
663
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision);
664
}
665
#endif
666
667
#ifdef BOOST_CHARCONV_HAS_FLOAT32
668
669
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float32_t value,
670
                                                           boost::charconv::chars_format fmt) noexcept
671
{
672
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, -1);
673
}
674
675
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float32_t value,
676
                                                           boost::charconv::chars_format fmt, int precision) noexcept
677
{
678
    static_assert(std::numeric_limits<std::float32_t>::digits == FLT_MANT_DIG &&
679
                  std::numeric_limits<std::float32_t>::min_exponent == FLT_MIN_EXP,
680
                  "float and std::float32_t are not the same layout like they should be");
681
682
    if (precision < 0)
683
    {
684
        precision = 6;
685
    }
686
687
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision);
688
}
689
#endif
690
691
#ifdef BOOST_CHARCONV_HAS_FLOAT64
692
693
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float64_t value,
694
                                                           boost::charconv::chars_format fmt) noexcept
695
{
696
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, -1);
697
}
698
699
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float64_t value,
700
                                                           boost::charconv::chars_format fmt, int precision) noexcept
701
{
702
    static_assert(std::numeric_limits<std::float64_t>::digits == DBL_MANT_DIG &&
703
                  std::numeric_limits<std::float64_t>::min_exponent == DBL_MIN_EXP,
704
                  "double and std::float64_t are not the same layout like they should be");
705
706
    if (precision < 0)
707
    {
708
        precision = 6;
709
    }
710
711
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision);
712
}
713
#endif
714
715
#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH)
716
717
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float128_t value,
718
                                                           boost::charconv::chars_format fmt) noexcept
719
{
720
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<__float128>(value), fmt, -1);
721
}
722
723
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float128_t value,
724
                                                           boost::charconv::chars_format fmt, int precision) noexcept
725
{
726
    if (precision < 0)
727
    {
728
        precision = 6;
729
    }
730
731
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<__float128>(value), fmt, precision);
732
}
733
#endif
734
735
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
736
737
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::bfloat16_t value,
738
                                                           boost::charconv::chars_format fmt) noexcept
739
{
740
    return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, -1);
741
}
742
743
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::bfloat16_t value,
744
                                                           boost::charconv::chars_format fmt, int precision) noexcept
745
{
746
    if (precision < 0)
747
    {
748
        precision = 6;
749
        return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, precision);
750
    }
751
752
    // If the precision is specified it is better to use our existing methods for float
753
    return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision);
754
}
755
#endif