xref: /freebsd/contrib/llvm-project/libcxx/include/__charconv/to_chars_integral.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H
11 #define _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H
12 
13 #include <__algorithm/copy_n.h>
14 #include <__assert>
15 #include <__bit/countl.h>
16 #include <__charconv/tables.h>
17 #include <__charconv/to_chars_base_10.h>
18 #include <__charconv/to_chars_result.h>
19 #include <__charconv/traits.h>
20 #include <__config>
21 #include <__system_error/errc.h>
22 #include <__type_traits/enable_if.h>
23 #include <__type_traits/integral_constant.h>
24 #include <__type_traits/is_same.h>
25 #include <__type_traits/make_32_64_or_128_bit.h>
26 #include <__type_traits/make_unsigned.h>
27 #include <__utility/unreachable.h>
28 #include <cstddef>
29 #include <cstdint>
30 #include <limits>
31 
32 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
33 #  pragma GCC system_header
34 #endif
35 
36 _LIBCPP_PUSH_MACROS
37 #include <__undef_macros>
38 
39 _LIBCPP_BEGIN_NAMESPACE_STD
40 
41 #if _LIBCPP_STD_VER >= 17
42 
43 to_chars_result to_chars(char*, char*, bool, int = 10) = delete;
44 
45 template <typename _Tp>
46 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
47 __to_chars_itoa(char* __first, char* __last, _Tp __value, false_type);
48 
49 template <typename _Tp>
50 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
51 __to_chars_itoa(char* __first, char* __last, _Tp __value, true_type) {
52   auto __x = std::__to_unsigned_like(__value);
53   if (__value < 0 && __first != __last) {
54     *__first++ = '-';
55     __x        = std::__complement(__x);
56   }
57 
58   return std::__to_chars_itoa(__first, __last, __x, false_type());
59 }
60 
61 template <typename _Tp>
62 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
63 __to_chars_itoa(char* __first, char* __last, _Tp __value, false_type) {
64   using __tx  = __itoa::__traits<_Tp>;
65   auto __diff = __last - __first;
66 
67   if (__tx::digits <= __diff || __tx::__width(__value) <= __diff)
68     return {__tx::__convert(__first, __value), errc(0)};
69   else
70     return {__last, errc::value_too_large};
71 }
72 
73 #  ifndef _LIBCPP_HAS_NO_INT128
74 template <>
75 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
76 __to_chars_itoa(char* __first, char* __last, __uint128_t __value, false_type) {
77   // When the value fits in 64-bits use the 64-bit code path. This reduces
78   // the number of expensive calculations on 128-bit values.
79   //
80   // NOTE the 128-bit code path requires this optimization.
81   if (__value <= numeric_limits<uint64_t>::max())
82     return __to_chars_itoa(__first, __last, static_cast<uint64_t>(__value), false_type());
83 
84   using __tx  = __itoa::__traits<__uint128_t>;
85   auto __diff = __last - __first;
86 
87   if (__tx::digits <= __diff || __tx::__width(__value) <= __diff)
88     return {__tx::__convert(__first, __value), errc(0)};
89   else
90     return {__last, errc::value_too_large};
91 }
92 #  endif
93 
94 template <class _Tp>
95 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
96 __to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type);
97 
98 template <typename _Tp>
99 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
100 __to_chars_integral(char* __first, char* __last, _Tp __value, int __base, true_type) {
101   auto __x = std::__to_unsigned_like(__value);
102   if (__value < 0 && __first != __last) {
103     *__first++ = '-';
104     __x        = std::__complement(__x);
105   }
106 
107   return std::__to_chars_integral(__first, __last, __x, __base, false_type());
108 }
109 
110 namespace __itoa {
111 
112 template <unsigned _Base>
113 struct _LIBCPP_HIDDEN __integral;
114 
115 template <>
116 struct _LIBCPP_HIDDEN __integral<2> {
117   template <typename _Tp>
118   _LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {
119     // If value == 0 still need one digit. If the value != this has no
120     // effect since the code scans for the most significant bit set. (Note
121     // that __libcpp_clz doesn't work for 0.)
122     return numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1);
123   }
124 
125   template <typename _Tp>
126   _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result
127   __to_chars(char* __first, char* __last, _Tp __value) {
128     ptrdiff_t __cap = __last - __first;
129     int __n         = __width(__value);
130     if (__n > __cap)
131       return {__last, errc::value_too_large};
132 
133     __last                   = __first + __n;
134     char* __p                = __last;
135     const unsigned __divisor = 16;
136     while (__value > __divisor) {
137       unsigned __c = __value % __divisor;
138       __value /= __divisor;
139       __p -= 4;
140       std::copy_n(&__base_2_lut[4 * __c], 4, __p);
141     }
142     do {
143       unsigned __c = __value % 2;
144       __value /= 2;
145       *--__p = "01"[__c];
146     } while (__value != 0);
147     return {__last, errc(0)};
148   }
149 };
150 
151 template <>
152 struct _LIBCPP_HIDDEN __integral<8> {
153   template <typename _Tp>
154   _LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {
155     // If value == 0 still need one digit. If the value != this has no
156     // effect since the code scans for the most significat bit set. (Note
157     // that __libcpp_clz doesn't work for 0.)
158     return ((numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1)) + 2) / 3;
159   }
160 
161   template <typename _Tp>
162   _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result
163   __to_chars(char* __first, char* __last, _Tp __value) {
164     ptrdiff_t __cap = __last - __first;
165     int __n         = __width(__value);
166     if (__n > __cap)
167       return {__last, errc::value_too_large};
168 
169     __last             = __first + __n;
170     char* __p          = __last;
171     unsigned __divisor = 64;
172     while (__value > __divisor) {
173       unsigned __c = __value % __divisor;
174       __value /= __divisor;
175       __p -= 2;
176       std::copy_n(&__base_8_lut[2 * __c], 2, __p);
177     }
178     do {
179       unsigned __c = __value % 8;
180       __value /= 8;
181       *--__p = "01234567"[__c];
182     } while (__value != 0);
183     return {__last, errc(0)};
184   }
185 };
186 
187 template <>
188 struct _LIBCPP_HIDDEN __integral<16> {
189   template <typename _Tp>
190   _LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {
191     // If value == 0 still need one digit. If the value != this has no
192     // effect since the code scans for the most significat bit set. (Note
193     // that __libcpp_clz doesn't work for 0.)
194     return (numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1) + 3) / 4;
195   }
196 
197   template <typename _Tp>
198   _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result
199   __to_chars(char* __first, char* __last, _Tp __value) {
200     ptrdiff_t __cap = __last - __first;
201     int __n         = __width(__value);
202     if (__n > __cap)
203       return {__last, errc::value_too_large};
204 
205     __last             = __first + __n;
206     char* __p          = __last;
207     unsigned __divisor = 256;
208     while (__value > __divisor) {
209       unsigned __c = __value % __divisor;
210       __value /= __divisor;
211       __p -= 2;
212       std::copy_n(&__base_16_lut[2 * __c], 2, __p);
213     }
214     if (__first != __last)
215       do {
216         unsigned __c = __value % 16;
217         __value /= 16;
218         *--__p = "0123456789abcdef"[__c];
219       } while (__value != 0);
220     return {__last, errc(0)};
221   }
222 };
223 
224 } // namespace __itoa
225 
226 template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) >= sizeof(unsigned)), int> = 0>
227 _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) {
228   return __itoa::__integral<_Base>::__width(__value);
229 }
230 
231 template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) < sizeof(unsigned)), int> = 0>
232 _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) {
233   return std::__to_chars_integral_width<_Base>(static_cast<unsigned>(__value));
234 }
235 
236 template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) >= sizeof(unsigned)), int> = 0>
237 _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
238 __to_chars_integral(char* __first, char* __last, _Tp __value) {
239   return __itoa::__integral<_Base>::__to_chars(__first, __last, __value);
240 }
241 
242 template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) < sizeof(unsigned)), int> = 0>
243 _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
244 __to_chars_integral(char* __first, char* __last, _Tp __value) {
245   return std::__to_chars_integral<_Base>(__first, __last, static_cast<unsigned>(__value));
246 }
247 
248 template <typename _Tp>
249 _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) {
250   _LIBCPP_ASSERT_INTERNAL(__value >= 0, "The function requires a non-negative value.");
251 
252   unsigned __base_2 = __base * __base;
253   unsigned __base_3 = __base_2 * __base;
254   unsigned __base_4 = __base_2 * __base_2;
255 
256   int __r = 0;
257   while (true) {
258     if (__value < __base)
259       return __r + 1;
260     if (__value < __base_2)
261       return __r + 2;
262     if (__value < __base_3)
263       return __r + 3;
264     if (__value < __base_4)
265       return __r + 4;
266 
267     __value /= __base_4;
268     __r += 4;
269   }
270 
271   __libcpp_unreachable();
272 }
273 
274 template <typename _Tp>
275 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
276 __to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type) {
277   if (__base == 10) [[likely]]
278     return std::__to_chars_itoa(__first, __last, __value, false_type());
279 
280   switch (__base) {
281   case 2:
282     return std::__to_chars_integral<2>(__first, __last, __value);
283   case 8:
284     return std::__to_chars_integral<8>(__first, __last, __value);
285   case 16:
286     return std::__to_chars_integral<16>(__first, __last, __value);
287   }
288 
289   ptrdiff_t __cap = __last - __first;
290   int __n         = std::__to_chars_integral_width(__value, __base);
291   if (__n > __cap)
292     return {__last, errc::value_too_large};
293 
294   __last    = __first + __n;
295   char* __p = __last;
296   do {
297     unsigned __c = __value % __base;
298     __value /= __base;
299     *--__p = "0123456789abcdefghijklmnopqrstuvwxyz"[__c];
300   } while (__value != 0);
301   return {__last, errc(0)};
302 }
303 
304 template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
305 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
306 to_chars(char* __first, char* __last, _Tp __value) {
307   using _Type = __make_32_64_or_128_bit_t<_Tp>;
308   static_assert(!is_same<_Type, void>::value, "unsupported integral type used in to_chars");
309   return std::__to_chars_itoa(__first, __last, static_cast<_Type>(__value), is_signed<_Tp>());
310 }
311 
312 template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
313 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
314 to_chars(char* __first, char* __last, _Tp __value, int __base) {
315   _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base && __base <= 36, "base not in [2, 36]");
316 
317   using _Type = __make_32_64_or_128_bit_t<_Tp>;
318   return std::__to_chars_integral(__first, __last, static_cast<_Type>(__value), __base, is_signed<_Tp>());
319 }
320 
321 #endif // _LIBCPP_STD_VER >= 17
322 
323 _LIBCPP_END_NAMESPACE_STD
324 
325 _LIBCPP_POP_MACROS
326 
327 #endif // _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H
328