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/dragonbox/dragonbox.hpp>
 
15 +
#include <boost/json/detail/format.hpp>
 
16 +
#include <cmath>
15  
#include <cstring>
17  
#include <cstring>
16  

18  

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

22  

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

24  

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

29  

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

44  

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

50  

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

55  

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

60  

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

71  

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

73  

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

75  

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

82  

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

89  

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

95  

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

98  

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

101  

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

114  

113 -
unsigned
115 +
std::size_t
114  
format_double(
116  
format_double(
115  
    char* dest, double d, bool allow_infinity_and_nan) noexcept
117  
    char* dest, double d, bool allow_infinity_and_nan) noexcept
116  
{
118  
{
117 -
    return static_cast<int>(
119 +
    using Traits = dragonbox_float_traits<double>;
118 -
        ryu::d2s_buffered_n(d, dest, allow_infinity_and_nan));
120 +

 
121 +
    auto const bits = dragonbox_float_bits<double, Traits>(d);
 
122 +
    auto const exponent_bits = bits.extract_exponent_bits();
 
123 +
    auto const s = bits.remove_exponent_bits(exponent_bits);
 
124 +

 
125 +
    if( bits.is_finite(exponent_bits) )
 
126 +
    {
 
127 +
        bool is_negative;
 
128 +
        if(( is_negative = s.is_negative() ))
 
129 +
        {
 
130 +
            *dest = '-';
 
131 +
            ++dest;
 
132 +
        }
 
133 +

 
134 +
        if( bits.is_nonzero() )
 
135 +
        {
 
136 +
            auto const decimal = to_decimal<double, Traits>(
 
137 +
                s, exponent_bits);
 
138 +
            std::size_t const size = to_chars_detail::dragon_box_print_chars(
 
139 +
                decimal.significand,
 
140 +
                decimal.exponent,
 
141 +
                dest,
 
142 +
                dest + detail::max_number_chars);
 
143 +
            BOOST_ASSERT( size );
 
144 +
            return size + is_negative;
 
145 +
        }
 
146 +
        else
 
147 +
        {
 
148 +
            std::memcpy(dest, "0E0", 3);
 
149 +
            return 3 + is_negative;
 
150 +
        }
 
151 +
    }
 
152 +

 
153 +

 
154 +
    if( allow_infinity_and_nan )
 
155 +
    {
 
156 +
        if( s.has_all_zero_significand_bits() )
 
157 +
        {
 
158 +
            if( s.is_negative() )
 
159 +
            {
 
160 +
                std::memcpy(dest, "-Infinity", 9);
 
161 +
                return 9;
 
162 +
            }
 
163 +
            else
 
164 +
            {
 
165 +
                std::memcpy(dest, "Infinity", 8);
 
166 +
                return 8;
 
167 +
            }
 
168 +
        }
 
169 +

 
170 +
        std::memcpy(dest, "NaN", 3);
 
171 +
        return 3;
 
172 +
    }
 
173 +

 
174 +
    if( s.has_all_zero_significand_bits() )
 
175 +
    {
 
176 +
        if( s.is_negative() )
 
177 +
        {
 
178 +
            std::memcpy(dest, "-1e99999", 8);
 
179 +
            return 8;
 
180 +
        }
 
181 +
        else
 
182 +
        {
 
183 +
            std::memcpy(dest, "1e99999", 7);
 
184 +
            return 7;
 
185 +
        }
 
186 +
    }
 
187 +

 
188 +
    std::memcpy(dest, "null", 4);
 
189 +
    return 4;
119  
}
190  
}
120  

191  

121  
} // detail
192  
} // detail
122  
} // namespace json
193  
} // namespace json
123  
} // namespace boost
194  
} // namespace boost
124  

195  

125  
#endif
196  
#endif