xref: /freebsd/contrib/llvm-project/libcxx/src/charconv.cpp (revision 833a452e9f082a7982a31c21f0da437dbbe0a39d)
1 //===------------------------- charconv.cpp -------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "charconv"
10 #include <string.h>
11 
12 _LIBCPP_BEGIN_NAMESPACE_STD
13 
14 namespace __itoa
15 {
16 
17 static constexpr char cDigitsLut[200] = {
18     '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
19     '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
20     '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
21     '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
22     '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
23     '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
24     '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
25     '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
26     '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
27     '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
28     '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
29     '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
30     '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
31     '7', '9', '8', '9', '9'};
32 
33 template <typename T>
34 inline _LIBCPP_INLINE_VISIBILITY char*
35 append1(char* buffer, T i) noexcept
36 {
37     *buffer = '0' + static_cast<char>(i);
38     return buffer + 1;
39 }
40 
41 template <typename T>
42 inline _LIBCPP_INLINE_VISIBILITY char*
43 append2(char* buffer, T i) noexcept
44 {
45     memcpy(buffer, &cDigitsLut[(i)*2], 2);
46     return buffer + 2;
47 }
48 
49 template <typename T>
50 inline _LIBCPP_INLINE_VISIBILITY char*
51 append3(char* buffer, T i) noexcept
52 {
53     return append2(append1(buffer, (i) / 100), (i) % 100);
54 }
55 
56 template <typename T>
57 inline _LIBCPP_INLINE_VISIBILITY char*
58 append4(char* buffer, T i) noexcept
59 {
60     return append2(append2(buffer, (i) / 100), (i) % 100);
61 }
62 
63 template <typename T>
64 inline _LIBCPP_INLINE_VISIBILITY char*
65 append2_no_zeros(char* buffer, T v) noexcept
66 {
67     if (v < 10)
68         return append1(buffer, v);
69     else
70         return append2(buffer, v);
71 }
72 
73 template <typename T>
74 inline _LIBCPP_INLINE_VISIBILITY char*
75 append4_no_zeros(char* buffer, T v) noexcept
76 {
77     if (v < 100)
78         return append2_no_zeros(buffer, v);
79     else if (v < 1000)
80         return append3(buffer, v);
81     else
82         return append4(buffer, v);
83 }
84 
85 template <typename T>
86 inline _LIBCPP_INLINE_VISIBILITY char*
87 append8_no_zeros(char* buffer, T v) noexcept
88 {
89     if (v < 10000)
90     {
91         buffer = append4_no_zeros(buffer, v);
92     }
93     else
94     {
95         buffer = append4_no_zeros(buffer, v / 10000);
96         buffer = append4(buffer, v % 10000);
97     }
98     return buffer;
99 }
100 
101 char*
102 __u32toa(uint32_t value, char* buffer) noexcept
103 {
104     if (value < 100000000)
105     {
106         buffer = append8_no_zeros(buffer, value);
107     }
108     else
109     {
110         // value = aabbbbcccc in decimal
111         const uint32_t a = value / 100000000;  // 1 to 42
112         value %= 100000000;
113 
114         buffer = append2_no_zeros(buffer, a);
115         buffer = append4(buffer, value / 10000);
116         buffer = append4(buffer, value % 10000);
117     }
118 
119     return buffer;
120 }
121 
122 char*
123 __u64toa(uint64_t value, char* buffer) noexcept
124 {
125     if (value < 100000000)
126     {
127         uint32_t v = static_cast<uint32_t>(value);
128         buffer = append8_no_zeros(buffer, v);
129     }
130     else if (value < 10000000000000000)
131     {
132         const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
133         const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
134 
135         buffer = append8_no_zeros(buffer, v0);
136         buffer = append4(buffer, v1 / 10000);
137         buffer = append4(buffer, v1 % 10000);
138     }
139     else
140     {
141         const uint32_t a =
142             static_cast<uint32_t>(value / 10000000000000000);  // 1 to 1844
143         value %= 10000000000000000;
144 
145         buffer = append4_no_zeros(buffer, a);
146 
147         const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
148         const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
149         buffer = append4(buffer, v0 / 10000);
150         buffer = append4(buffer, v0 % 10000);
151         buffer = append4(buffer, v1 / 10000);
152         buffer = append4(buffer, v1 % 10000);
153     }
154 
155     return buffer;
156 }
157 
158 }  // namespace __itoa
159 
160 _LIBCPP_END_NAMESPACE_STD
161