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