xref: /llvm-project/libcxx/include/__charconv/from_chars_integral.h (revision 37dca605c9bd41732da010ee97ed15ad9585a37d)
1f7efcacaSMark de Wever // -*- C++ -*-
2f7efcacaSMark de Wever //===----------------------------------------------------------------------===//
3f7efcacaSMark de Wever //
4f7efcacaSMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5f7efcacaSMark de Wever // See https://llvm.org/LICENSE.txt for license information.
6f7efcacaSMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7f7efcacaSMark de Wever //
8f7efcacaSMark de Wever //===----------------------------------------------------------------------===//
9f7efcacaSMark de Wever 
10f7efcacaSMark de Wever #ifndef _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
11f7efcacaSMark de Wever #define _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
12f7efcacaSMark de Wever 
13f7efcacaSMark de Wever #include <__algorithm/copy_n.h>
14*37dca605SLouis Dionne #include <__assert>
15f7efcacaSMark de Wever #include <__charconv/from_chars_result.h>
16f7efcacaSMark de Wever #include <__charconv/traits.h>
17f7efcacaSMark de Wever #include <__config>
18f7efcacaSMark de Wever #include <__memory/addressof.h>
19eb65912eSNikolas Klauser #include <__system_error/errc.h>
20f7efcacaSMark de Wever #include <__type_traits/enable_if.h>
21f7efcacaSMark de Wever #include <__type_traits/integral_constant.h>
22f7efcacaSMark de Wever #include <__type_traits/is_integral.h>
23f7efcacaSMark de Wever #include <__type_traits/is_unsigned.h>
24f7efcacaSMark de Wever #include <__type_traits/make_unsigned.h>
25f7efcacaSMark de Wever #include <limits>
26f7efcacaSMark de Wever 
27f7efcacaSMark de Wever #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28f7efcacaSMark de Wever #  pragma GCC system_header
29f7efcacaSMark de Wever #endif
30f7efcacaSMark de Wever 
31f7efcacaSMark de Wever _LIBCPP_PUSH_MACROS
32f7efcacaSMark de Wever #include <__undef_macros>
33f7efcacaSMark de Wever 
34f7efcacaSMark de Wever _LIBCPP_BEGIN_NAMESPACE_STD
35f7efcacaSMark de Wever 
36f7efcacaSMark de Wever #if _LIBCPP_STD_VER >= 17
37f7efcacaSMark de Wever 
38f7efcacaSMark de Wever from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete;
39f7efcacaSMark de Wever 
40f7efcacaSMark de Wever template <typename _It, typename _Tp, typename _Fn, typename... _Ts>
41f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__sign_combinator(_It __first,_It __last,_Tp & __value,_Fn __f,_Ts...__args)42866fbb87SMark de Wever __sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) {
43f7efcacaSMark de Wever   using __tl = numeric_limits<_Tp>;
44f7efcacaSMark de Wever   decltype(std::__to_unsigned_like(__value)) __x;
45f7efcacaSMark de Wever 
46f7efcacaSMark de Wever   bool __neg = (__first != __last && *__first == '-');
47f7efcacaSMark de Wever   auto __r   = __f(__neg ? __first + 1 : __first, __last, __x, __args...);
48866fbb87SMark de Wever   switch (__r.ec) {
49f7efcacaSMark de Wever   case errc::invalid_argument:
50f7efcacaSMark de Wever     return {__first, __r.ec};
51f7efcacaSMark de Wever   case errc::result_out_of_range:
52f7efcacaSMark de Wever     return __r;
53f7efcacaSMark de Wever   default:
54f7efcacaSMark de Wever     break;
55f7efcacaSMark de Wever   }
56f7efcacaSMark de Wever 
57866fbb87SMark de Wever   if (__neg) {
58866fbb87SMark de Wever     if (__x <= std::__complement(std::__to_unsigned_like(__tl::min()))) {
59f7efcacaSMark de Wever       __x = std::__complement(__x);
60f7efcacaSMark de Wever       std::copy_n(std::addressof(__x), 1, std::addressof(__value));
61f7efcacaSMark de Wever       return __r;
62f7efcacaSMark de Wever     }
63866fbb87SMark de Wever   } else {
64866fbb87SMark de Wever     if (__x <= std::__to_unsigned_like(__tl::max())) {
65f7efcacaSMark de Wever       __value = __x;
66f7efcacaSMark de Wever       return __r;
67f7efcacaSMark de Wever     }
68f7efcacaSMark de Wever   }
69f7efcacaSMark de Wever 
70f7efcacaSMark de Wever   return {__r.ptr, errc::result_out_of_range};
71f7efcacaSMark de Wever }
72f7efcacaSMark de Wever 
73f7efcacaSMark de Wever template <typename _Tp>
__in_pattern(_Tp __c)74866fbb87SMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __in_pattern(_Tp __c) {
75f7efcacaSMark de Wever   return '0' <= __c && __c <= '9';
76f7efcacaSMark de Wever }
77f7efcacaSMark de Wever 
78866fbb87SMark de Wever struct _LIBCPP_HIDDEN __in_pattern_result {
79f7efcacaSMark de Wever   bool __ok;
80f7efcacaSMark de Wever   int __val;
81f7efcacaSMark de Wever 
82f7efcacaSMark de Wever   explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; }
83f7efcacaSMark de Wever };
84f7efcacaSMark de Wever 
85f7efcacaSMark de Wever template <typename _Tp>
__in_pattern(_Tp __c,int __base)86866fbb87SMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result __in_pattern(_Tp __c, int __base) {
87f7efcacaSMark de Wever   if (__base <= 10)
88f7efcacaSMark de Wever     return {'0' <= __c && __c < '0' + __base, __c - '0'};
89f7efcacaSMark de Wever   else if (std::__in_pattern(__c))
90f7efcacaSMark de Wever     return {true, __c - '0'};
91f7efcacaSMark de Wever   else if ('a' <= __c && __c < 'a' + __base - 10)
92f7efcacaSMark de Wever     return {true, __c - 'a' + 10};
93f7efcacaSMark de Wever   else
94f7efcacaSMark de Wever     return {'A' <= __c && __c < 'A' + __base - 10, __c - 'A' + 10};
95f7efcacaSMark de Wever }
96f7efcacaSMark de Wever 
97f7efcacaSMark de Wever template <typename _It, typename _Tp, typename _Fn, typename... _Ts>
98f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__subject_seq_combinator(_It __first,_It __last,_Tp & __value,_Fn __f,_Ts...__args)99866fbb87SMark de Wever __subject_seq_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) {
100f7efcacaSMark de Wever   auto __find_non_zero = [](_It __firstit, _It __lastit) {
101f7efcacaSMark de Wever     for (; __firstit != __lastit; ++__firstit)
102f7efcacaSMark de Wever       if (*__firstit != '0')
103f7efcacaSMark de Wever         break;
104f7efcacaSMark de Wever     return __firstit;
105f7efcacaSMark de Wever   };
106f7efcacaSMark de Wever 
107f7efcacaSMark de Wever   auto __p = __find_non_zero(__first, __last);
108866fbb87SMark de Wever   if (__p == __last || !std::__in_pattern(*__p, __args...)) {
109f7efcacaSMark de Wever     if (__p == __first)
110f7efcacaSMark de Wever       return {__first, errc::invalid_argument};
111866fbb87SMark de Wever     else {
112f7efcacaSMark de Wever       __value = 0;
113f7efcacaSMark de Wever       return {__p, {}};
114f7efcacaSMark de Wever     }
115f7efcacaSMark de Wever   }
116f7efcacaSMark de Wever 
117f7efcacaSMark de Wever   auto __r = __f(__p, __last, __value, __args...);
118866fbb87SMark de Wever   if (__r.ec == errc::result_out_of_range) {
119866fbb87SMark de Wever     for (; __r.ptr != __last; ++__r.ptr) {
120f7efcacaSMark de Wever       if (!std::__in_pattern(*__r.ptr, __args...))
121f7efcacaSMark de Wever         break;
122f7efcacaSMark de Wever     }
123f7efcacaSMark de Wever   }
124f7efcacaSMark de Wever 
125f7efcacaSMark de Wever   return __r;
126f7efcacaSMark de Wever }
127f7efcacaSMark de Wever 
1286256ccfdSNikolas Klauser template <typename _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>
129f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars_atoi(const char * __first,const char * __last,_Tp & __value)130866fbb87SMark de Wever __from_chars_atoi(const char* __first, const char* __last, _Tp& __value) {
131f7efcacaSMark de Wever   using __tx          = __itoa::__traits<_Tp>;
132f7efcacaSMark de Wever   using __output_type = typename __tx::type;
133f7efcacaSMark de Wever 
134f7efcacaSMark de Wever   return std::__subject_seq_combinator(
135866fbb87SMark de Wever       __first, __last, __value, [](const char* __f, const char* __l, _Tp& __val) -> from_chars_result {
136f7efcacaSMark de Wever         __output_type __a, __b;
137f7efcacaSMark de Wever         auto __p = __tx::__read(__f, __l, __a, __b);
138866fbb87SMark de Wever         if (__p == __l || !std::__in_pattern(*__p)) {
139f7efcacaSMark de Wever           __output_type __m = numeric_limits<_Tp>::max();
140866fbb87SMark de Wever           if (__m >= __a && __m - __a >= __b) {
141f7efcacaSMark de Wever             __val = __a + __b;
142f7efcacaSMark de Wever             return {__p, {}};
143f7efcacaSMark de Wever           }
144f7efcacaSMark de Wever         }
145f7efcacaSMark de Wever         return {__p, errc::result_out_of_range};
146f7efcacaSMark de Wever       });
147f7efcacaSMark de Wever }
148f7efcacaSMark de Wever 
1496256ccfdSNikolas Klauser template <typename _Tp, __enable_if_t<is_signed<_Tp>::value, int> = 0>
150f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars_atoi(const char * __first,const char * __last,_Tp & __value)151866fbb87SMark de Wever __from_chars_atoi(const char* __first, const char* __last, _Tp& __value) {
152f7efcacaSMark de Wever   using __t = decltype(std::__to_unsigned_like(__value));
153f7efcacaSMark de Wever   return std::__sign_combinator(__first, __last, __value, __from_chars_atoi<__t>);
154f7efcacaSMark de Wever }
155f7efcacaSMark de Wever 
156f7efcacaSMark de Wever /*
157f7efcacaSMark de Wever // Code used to generate __from_chars_log2f_lut.
158f7efcacaSMark de Wever #include <cmath>
159f7efcacaSMark de Wever #include <format>
160866fbb87SMark de Wever #include <iostream>
161f7efcacaSMark de Wever 
162f7efcacaSMark de Wever int main() {
163f7efcacaSMark de Wever   for (int i = 2; i <= 36; ++i)
164f7efcacaSMark de Wever     std::cout << std::format("{},\n", log2f(i));
165f7efcacaSMark de Wever }
166f7efcacaSMark de Wever */
167f7efcacaSMark de Wever /// log2f table for bases [2, 36].
168f7efcacaSMark de Wever inline constexpr float __from_chars_log2f_lut[35] = {
169f7efcacaSMark de Wever     1,         1.5849625, 2,         2.321928, 2.5849626, 2.807355, 3,        3.169925,  3.321928,
170f7efcacaSMark de Wever     3.4594316, 3.5849626, 3.7004397, 3.807355, 3.9068906, 4,        4.087463, 4.169925,  4.2479277,
171f7efcacaSMark de Wever     4.321928,  4.3923173, 4.4594316, 4.523562, 4.5849624, 4.643856, 4.70044,  4.7548876, 4.807355,
172f7efcacaSMark de Wever     4.857981,  4.9068904, 4.9541965, 5,        5.044394,  5.087463, 5.129283, 5.169925};
173f7efcacaSMark de Wever 
1746256ccfdSNikolas Klauser template <typename _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>
175f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars_integral(const char * __first,const char * __last,_Tp & __value,int __base)176866fbb87SMark de Wever __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) {
177f7efcacaSMark de Wever   if (__base == 10)
178f7efcacaSMark de Wever     return std::__from_chars_atoi(__first, __last, __value);
179f7efcacaSMark de Wever 
180f7efcacaSMark de Wever   return std::__subject_seq_combinator(
181866fbb87SMark de Wever       __first,
182866fbb87SMark de Wever       __last,
183866fbb87SMark de Wever       __value,
184866fbb87SMark de Wever       [](const char* __p, const char* __lastp, _Tp& __val, int __b) -> from_chars_result {
185f7efcacaSMark de Wever         using __tl = numeric_limits<_Tp>;
186f7efcacaSMark de Wever         // __base is always between 2 and 36 inclusive.
187f7efcacaSMark de Wever         auto __digits = __tl::digits / __from_chars_log2f_lut[__b - 2];
188f7efcacaSMark de Wever         _Tp __x = __in_pattern(*__p++, __b).__val, __y = 0;
189f7efcacaSMark de Wever 
190866fbb87SMark de Wever         for (int __i = 1; __p != __lastp; ++__i, ++__p) {
191866fbb87SMark de Wever           if (auto __c = __in_pattern(*__p, __b)) {
192f7efcacaSMark de Wever             if (__i < __digits - 1)
193f7efcacaSMark de Wever               __x = __x * __b + __c.__val;
194866fbb87SMark de Wever             else {
195f7efcacaSMark de Wever               if (!__itoa::__mul_overflowed(__x, __b, __x))
196f7efcacaSMark de Wever                 ++__p;
197f7efcacaSMark de Wever               __y = __c.__val;
198f7efcacaSMark de Wever               break;
199f7efcacaSMark de Wever             }
200866fbb87SMark de Wever           } else
201f7efcacaSMark de Wever             break;
202f7efcacaSMark de Wever         }
203f7efcacaSMark de Wever 
204866fbb87SMark de Wever         if (__p == __lastp || !__in_pattern(*__p, __b)) {
205866fbb87SMark de Wever           if (__tl::max() - __x >= __y) {
206f7efcacaSMark de Wever             __val = __x + __y;
207f7efcacaSMark de Wever             return {__p, {}};
208f7efcacaSMark de Wever           }
209f7efcacaSMark de Wever         }
210f7efcacaSMark de Wever         return {__p, errc::result_out_of_range};
211f7efcacaSMark de Wever       },
212f7efcacaSMark de Wever       __base);
213f7efcacaSMark de Wever }
214f7efcacaSMark de Wever 
2156256ccfdSNikolas Klauser template <typename _Tp, __enable_if_t<is_signed<_Tp>::value, int> = 0>
216f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars_integral(const char * __first,const char * __last,_Tp & __value,int __base)217866fbb87SMark de Wever __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) {
218f7efcacaSMark de Wever   using __t = decltype(std::__to_unsigned_like(__value));
219866fbb87SMark de Wever   return std::__sign_combinator(__first, __last, __value, __from_chars_integral<__t>, __base);
220f7efcacaSMark de Wever }
221f7efcacaSMark de Wever 
2226256ccfdSNikolas Klauser template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
223f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
from_chars(const char * __first,const char * __last,_Tp & __value)224866fbb87SMark de Wever from_chars(const char* __first, const char* __last, _Tp& __value) {
225f7efcacaSMark de Wever   return std::__from_chars_atoi(__first, __last, __value);
226f7efcacaSMark de Wever }
227f7efcacaSMark de Wever 
2286256ccfdSNikolas Klauser template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
229f7efcacaSMark de Wever inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
from_chars(const char * __first,const char * __last,_Tp & __value,int __base)230866fbb87SMark de Wever from_chars(const char* __first, const char* __last, _Tp& __value, int __base) {
231cd0ad421Svarconst   _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base && __base <= 36, "base not in [2, 36]");
232f7efcacaSMark de Wever   return std::__from_chars_integral(__first, __last, __value, __base);
233f7efcacaSMark de Wever }
234f7efcacaSMark de Wever #endif // _LIBCPP_STD_VER >= 17
235f7efcacaSMark de Wever 
236f7efcacaSMark de Wever _LIBCPP_END_NAMESPACE_STD
237f7efcacaSMark de Wever 
238f7efcacaSMark de Wever _LIBCPP_POP_MACROS
239f7efcacaSMark de Wever 
240f7efcacaSMark de Wever #endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
241