/src/boost/boost/json/detail/impl/format.ipp
Line | Count | Source |
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/ryu/ryu.hpp> |
15 | | #include <cstring> |
16 | | |
17 | | namespace boost { |
18 | | namespace json { |
19 | | namespace detail { |
20 | | |
21 | | /* Reference work: |
22 | | |
23 | | https://www.ampl.com/netlib/fp/dtoa.c |
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 |
26 | | */ |
27 | | |
28 | | inline char const* digits_lut() noexcept |
29 | 810k | { |
30 | 810k | return |
31 | 810k | "00010203040506070809" |
32 | 810k | "10111213141516171819" |
33 | 810k | "20212223242526272829" |
34 | 810k | "30313233343536373839" |
35 | 810k | "40414243444546474849" |
36 | 810k | "50515253545556575859" |
37 | 810k | "60616263646566676869" |
38 | 810k | "70717273747576777879" |
39 | 810k | "80818283848586878889" |
40 | 810k | "90919293949596979899"; |
41 | 810k | } |
42 | | |
43 | | inline void format_four_digits( char * dest, unsigned v ) |
44 | 332k | { |
45 | 332k | std::memcpy( dest + 2, digits_lut() + (v % 100) * 2, 2 ); |
46 | 332k | std::memcpy( dest , digits_lut() + (v / 100) * 2, 2 ); |
47 | 332k | } |
48 | | |
49 | | inline void format_two_digits( char * dest, unsigned v ) |
50 | 145k | { |
51 | 145k | std::memcpy( dest, digits_lut() + v * 2, 2 ); |
52 | 145k | } |
53 | | |
54 | | inline void format_digit( char * dest, unsigned v ) |
55 | 91.6k | { |
56 | 91.6k | *dest = static_cast<char>( v + '0' ); |
57 | 91.6k | } |
58 | | |
59 | | unsigned |
60 | | format_uint64( |
61 | | char* dest, |
62 | | std::uint64_t v) noexcept |
63 | 2.91M | { |
64 | 2.91M | if(v < 10) |
65 | 2.70M | { |
66 | 2.70M | *dest = static_cast<char>( '0' + v ); |
67 | 2.70M | return 1; |
68 | 2.70M | } |
69 | | |
70 | 210k | char buffer[ 24 ]; |
71 | | |
72 | 210k | char * p = buffer + 24; |
73 | | |
74 | 543k | while( v >= 1000 ) |
75 | 332k | { |
76 | 332k | p -= 4; |
77 | 332k | format_four_digits( p, v % 10000 ); |
78 | 332k | v /= 10000; |
79 | 332k | } |
80 | | |
81 | 210k | if( v >= 10 ) |
82 | 145k | { |
83 | 145k | p -= 2; |
84 | 145k | format_two_digits( p, v % 100 ); |
85 | 145k | v /= 100; |
86 | 145k | } |
87 | | |
88 | 210k | if( v ) |
89 | 91.6k | { |
90 | 91.6k | p -= 1; |
91 | 91.6k | format_digit( p, static_cast<unsigned>(v) ); |
92 | 91.6k | } |
93 | | |
94 | 210k | unsigned const n = static_cast<unsigned>( buffer + 24 - p ); |
95 | 210k | std::memcpy( dest, p, n ); |
96 | | |
97 | 210k | return n; |
98 | 2.91M | } |
99 | | |
100 | | unsigned |
101 | | format_int64( |
102 | | char* dest, int64_t i) noexcept |
103 | 2.87M | { |
104 | 2.87M | std::uint64_t ui = static_cast< |
105 | 2.87M | std::uint64_t>(i); |
106 | 2.87M | if(i >= 0) |
107 | 2.86M | return format_uint64(dest, ui); |
108 | 7.07k | *dest++ = '-'; |
109 | 7.07k | ui = ~ui + 1; |
110 | 7.07k | return 1 + format_uint64(dest, ui); |
111 | 2.87M | } |
112 | | |
113 | | unsigned |
114 | | format_double( |
115 | | char* dest, double d, bool allow_infinity_and_nan) noexcept |
116 | 5.83M | { |
117 | 5.83M | return static_cast<int>( |
118 | 5.83M | ryu::d2s_buffered_n(d, dest, allow_infinity_and_nan)); |
119 | 5.83M | } |
120 | | |
121 | | } // detail |
122 | | } // namespace json |
123 | | } // namespace boost |
124 | | |
125 | | #endif |