Line data Source code
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 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 3126 : while( v >= 1000 )
77 : {
78 1988 : p -= 4;
79 1988 : format_four_digits( p, v % 10000 );
80 1988 : v /= 10000;
81 : }
82 :
83 1138 : if( v >= 10 )
84 : {
85 862 : p -= 2;
86 862 : format_two_digits( p, v % 100 );
87 862 : v /= 100;
88 : }
89 :
90 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 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 510 : if( bits.is_finite(exponent_bits) )
126 : {
127 : bool is_negative;
128 495 : if(( is_negative = s.is_negative() ))
129 : {
130 155 : *dest = '-';
131 155 : ++dest;
132 : }
133 :
134 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 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 15 : if( allow_infinity_and_nan )
155 : {
156 6 : if( s.has_all_zero_significand_bits() )
157 : {
158 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 9 : if( s.has_all_zero_significand_bits() )
175 : {
176 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
|