1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2020 Peter Dimov (pdimov at gmail dot com),
3  
// Copyright (c) 2020 Peter Dimov (pdimov at gmail dot com),
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/boostorg/json
8  
// Official repository: https://github.com/boostorg/json
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
11  
#ifndef BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
12  
#define BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
12  
#define BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
13  

13  

14  
#include <boost/json/detail/ryu/ryu.hpp>
14  
#include <boost/json/detail/ryu/ryu.hpp>
15  
#include <cstring>
15  
#include <cstring>
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace json {
18  
namespace json {
19  
namespace detail {
19  
namespace detail {
20  

20  

21  
/*  Reference work:
21  
/*  Reference work:
22  

22  

23  
    https://www.ampl.com/netlib/fp/dtoa.c
23  
    https://www.ampl.com/netlib/fp/dtoa.c
24  
    https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
24  
    https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
25  
    https://kkimdev.github.io/posts/2018/06/15/IEEE-754-Floating-Point-Type-in-C++.html
25  
    https://kkimdev.github.io/posts/2018/06/15/IEEE-754-Floating-Point-Type-in-C++.html
26  
*/
26  
*/
27  

27  

28  
inline char const* digits_lut() noexcept
28  
inline char const* digits_lut() noexcept
29  
{
29  
{
30  
    return
30  
    return
31  
        "00010203040506070809"
31  
        "00010203040506070809"
32  
        "10111213141516171819"
32  
        "10111213141516171819"
33  
        "20212223242526272829"
33  
        "20212223242526272829"
34  
        "30313233343536373839"
34  
        "30313233343536373839"
35  
        "40414243444546474849"
35  
        "40414243444546474849"
36  
        "50515253545556575859"
36  
        "50515253545556575859"
37  
        "60616263646566676869"
37  
        "60616263646566676869"
38  
        "70717273747576777879"
38  
        "70717273747576777879"
39  
        "80818283848586878889"
39  
        "80818283848586878889"
40  
        "90919293949596979899";
40  
        "90919293949596979899";
41  
}
41  
}
42  

42  

43  
inline void format_four_digits( char * dest, unsigned v )
43  
inline void format_four_digits( char * dest, unsigned v )
44  
{
44  
{
45  
    std::memcpy( dest + 2, digits_lut() + (v % 100) * 2, 2 );
45  
    std::memcpy( dest + 2, digits_lut() + (v % 100) * 2, 2 );
46  
    std::memcpy( dest    , digits_lut() + (v / 100) * 2, 2 );
46  
    std::memcpy( dest    , digits_lut() + (v / 100) * 2, 2 );
47  
}
47  
}
48  

48  

49  
inline void format_two_digits( char * dest, unsigned v )
49  
inline void format_two_digits( char * dest, unsigned v )
50  
{
50  
{
51  
    std::memcpy( dest, digits_lut() + v * 2, 2 );
51  
    std::memcpy( dest, digits_lut() + v * 2, 2 );
52  
}
52  
}
53  

53  

54  
inline void format_digit( char * dest, unsigned v )
54  
inline void format_digit( char * dest, unsigned v )
55  
{
55  
{
56  
    *dest = static_cast<char>( v + '0' );
56  
    *dest = static_cast<char>( v + '0' );
57  
}
57  
}
58  

58  

59  
unsigned
59  
unsigned
60  
format_uint64(
60  
format_uint64(
61  
    char* dest,
61  
    char* dest,
62  
    std::uint64_t v) noexcept
62  
    std::uint64_t v) noexcept
63  
{
63  
{
64  
    if(v < 10)
64  
    if(v < 10)
65  
    {
65  
    {
66  
        *dest = static_cast<char>( '0' + v );
66  
        *dest = static_cast<char>( '0' + v );
67  
        return 1;
67  
        return 1;
68  
    }
68  
    }
69  

69  

70  
    char buffer[ 24 ];
70  
    char buffer[ 24 ];
71  

71  

72  
    char * p = buffer + 24;
72  
    char * p = buffer + 24;
73  

73  

74  
    while( v >= 1000 )
74  
    while( v >= 1000 )
75  
    {
75  
    {
76  
        p -= 4;
76  
        p -= 4;
77  
        format_four_digits( p, v % 10000 );
77  
        format_four_digits( p, v % 10000 );
78  
        v /= 10000;
78  
        v /= 10000;
79  
    }
79  
    }
80  

80  

81  
    if( v >= 10 )
81  
    if( v >= 10 )
82  
    {
82  
    {
83  
        p -= 2;
83  
        p -= 2;
84  
        format_two_digits( p, v % 100 );
84  
        format_two_digits( p, v % 100 );
85  
        v /= 100;
85  
        v /= 100;
86  
    }
86  
    }
87  

87  

88  
    if( v )
88  
    if( v )
89  
    {
89  
    {
90  
        p -= 1;
90  
        p -= 1;
91  
        format_digit( p, static_cast<unsigned>(v) );
91  
        format_digit( p, static_cast<unsigned>(v) );
92  
    }
92  
    }
93  

93  

94  
    unsigned const n = static_cast<unsigned>( buffer + 24 - p );
94  
    unsigned const n = static_cast<unsigned>( buffer + 24 - p );
95  
    std::memcpy( dest, p, n );
95  
    std::memcpy( dest, p, n );
96  

96  

97  
    return n;
97  
    return n;
98  
}
98  
}
99  

99  

100  
unsigned
100  
unsigned
101  
format_int64(
101  
format_int64(
102  
    char* dest, int64_t i) noexcept
102  
    char* dest, int64_t i) noexcept
103  
{
103  
{
104  
    std::uint64_t ui = static_cast<
104  
    std::uint64_t ui = static_cast<
105  
        std::uint64_t>(i);
105  
        std::uint64_t>(i);
106  
    if(i >= 0)
106  
    if(i >= 0)
107  
        return format_uint64(dest, ui);
107  
        return format_uint64(dest, ui);
108  
    *dest++ = '-';
108  
    *dest++ = '-';
109  
    ui = ~ui + 1;
109  
    ui = ~ui + 1;
110  
    return 1 + format_uint64(dest, ui);
110  
    return 1 + format_uint64(dest, ui);
111  
}
111  
}
112  

112  

113  
unsigned
113  
unsigned
114  
format_double(
114  
format_double(
115  
    char* dest, double d, bool allow_infinity_and_nan) noexcept
115  
    char* dest, double d, bool allow_infinity_and_nan) noexcept
116  
{
116  
{
117  
    return static_cast<int>(
117  
    return static_cast<int>(
118  
        ryu::d2s_buffered_n(d, dest, allow_infinity_and_nan));
118  
        ryu::d2s_buffered_n(d, dest, allow_infinity_and_nan));
119  
}
119  
}
120  

120  

121  
} // detail
121  
} // detail
122  
} // namespace json
122  
} // namespace json
123  
} // namespace boost
123  
} // namespace boost
124  

124  

125  
#endif
125  
#endif