2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
11 #define _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
13 #include <__algorithm/copy_n.h>
14 #include <__charconv/from_chars_result.h>
15 #include <__charconv/traits.h>
17 #include <__memory/addressof.h>
18 #include <__system_error/errc.h>
19 #include <__type_traits/enable_if.h>
20 #include <__type_traits/integral_constant.h>
21 #include <__type_traits/is_integral.h>
22 #include <__type_traits/is_unsigned.h>
23 #include <__type_traits/make_unsigned.h>
26 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27 # pragma GCC system_header
31 #include <__undef_macros>
33 _LIBCPP_BEGIN_NAMESPACE_STD
35 #if _LIBCPP_STD_VER >= 17
37 from_chars_result
from_chars(const char*, const char*, bool, int = 10) = delete;
39 template <typename _It
, typename _Tp
, typename _Fn
, typename
... _Ts
>
40 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
41 __sign_combinator(_It __first
, _It __last
, _Tp
& __value
, _Fn __f
, _Ts
... __args
) {
42 using __tl
= numeric_limits
<_Tp
>;
43 decltype(std::__to_unsigned_like(__value
)) __x
;
45 bool __neg
= (__first
!= __last
&& *__first
== '-');
46 auto __r
= __f(__neg
? __first
+ 1 : __first
, __last
, __x
, __args
...);
48 case errc::invalid_argument
:
49 return {__first
, __r
.ec
};
50 case errc::result_out_of_range
:
57 if (__x
<= std::__complement(std::__to_unsigned_like(__tl::min()))) {
58 __x
= std::__complement(__x
);
59 std::copy_n(std::addressof(__x
), 1, std::addressof(__value
));
63 if (__x
<= std::__to_unsigned_like(__tl::max())) {
69 return {__r
.ptr
, errc::result_out_of_range
};
72 template <typename _Tp
>
73 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
bool __in_pattern(_Tp __c
) {
74 return '0' <= __c
&& __c
<= '9';
77 struct _LIBCPP_HIDDEN __in_pattern_result
{
81 explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
operator bool() const { return __ok
; }
84 template <typename _Tp
>
85 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result
__in_pattern(_Tp __c
, int __base
) {
87 return {'0' <= __c
&& __c
< '0' + __base
, __c
- '0'};
88 else if (std::__in_pattern(__c
))
89 return {true, __c
- '0'};
90 else if ('a' <= __c
&& __c
< 'a' + __base
- 10)
91 return {true, __c
- 'a' + 10};
93 return {'A' <= __c
&& __c
< 'A' + __base
- 10, __c
- 'A' + 10};
96 template <typename _It
, typename _Tp
, typename _Fn
, typename
... _Ts
>
97 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
98 __subject_seq_combinator(_It __first
, _It __last
, _Tp
& __value
, _Fn __f
, _Ts
... __args
) {
99 auto __find_non_zero
= [](_It __firstit
, _It __lastit
) {
100 for (; __firstit
!= __lastit
; ++__firstit
)
101 if (*__firstit
!= '0')
106 auto __p
= __find_non_zero(__first
, __last
);
107 if (__p
== __last
|| !std::__in_pattern(*__p
, __args
...)) {
109 return {__first
, errc::invalid_argument
};
116 auto __r
= __f(__p
, __last
, __value
, __args
...);
117 if (__r
.ec
== errc::result_out_of_range
) {
118 for (; __r
.ptr
!= __last
; ++__r
.ptr
) {
119 if (!std::__in_pattern(*__r
.ptr
, __args
...))
127 template <typename _Tp
, __enable_if_t
<is_unsigned
<_Tp
>::value
, int> = 0>
128 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
129 __from_chars_atoi(const char* __first
, const char* __last
, _Tp
& __value
) {
130 using __tx
= __itoa::__traits
<_Tp
>;
131 using __output_type
= typename
__tx::type
;
133 return std::__subject_seq_combinator(
134 __first
, __last
, __value
, [](const char* __f
, const char* __l
, _Tp
& __val
) -> from_chars_result
{
135 __output_type __a
, __b
;
136 auto __p
= __tx::__read(__f
, __l
, __a
, __b
);
137 if (__p
== __l
|| !std::__in_pattern(*__p
)) {
138 __output_type __m
= numeric_limits
<_Tp
>::max();
139 if (__m
>= __a
&& __m
- __a
>= __b
) {
144 return {__p
, errc::result_out_of_range
};
148 template <typename _Tp
, __enable_if_t
<is_signed
<_Tp
>::value
, int> = 0>
149 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
150 __from_chars_atoi(const char* __first
, const char* __last
, _Tp
& __value
) {
151 using __t
= decltype(std::__to_unsigned_like(__value
));
152 return std::__sign_combinator(__first
, __last
, __value
, __from_chars_atoi
<__t
>);
156 // Code used to generate __from_chars_log2f_lut.
162 for (int i = 2; i <= 36; ++i)
163 std::cout << std::format("{},\n", log2f(i));
166 /// log2f table for bases [2, 36].
167 inline constexpr float __from_chars_log2f_lut
[35] = {
168 1, 1.5849625, 2, 2.321928, 2.5849626, 2.807355, 3, 3.169925, 3.321928,
169 3.4594316, 3.5849626, 3.7004397, 3.807355, 3.9068906, 4, 4.087463, 4.169925, 4.2479277,
170 4.321928, 4.3923173, 4.4594316, 4.523562, 4.5849624, 4.643856, 4.70044, 4.7548876, 4.807355,
171 4.857981, 4.9068904, 4.9541965, 5, 5.044394, 5.087463, 5.129283, 5.169925};
173 template <typename _Tp
, __enable_if_t
<is_unsigned
<_Tp
>::value
, int> = 0>
174 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
175 __from_chars_integral(const char* __first
, const char* __last
, _Tp
& __value
, int __base
) {
177 return std::__from_chars_atoi(__first
, __last
, __value
);
179 return std::__subject_seq_combinator(
183 [](const char* __p
, const char* __lastp
, _Tp
& __val
, int __b
) -> from_chars_result
{
184 using __tl
= numeric_limits
<_Tp
>;
185 // __base is always between 2 and 36 inclusive.
186 auto __digits
= __tl::digits
/ __from_chars_log2f_lut
[__b
- 2];
187 _Tp __x
= __in_pattern(*__p
++, __b
).__val
, __y
= 0;
189 for (int __i
= 1; __p
!= __lastp
; ++__i
, ++__p
) {
190 if (auto __c
= __in_pattern(*__p
, __b
)) {
191 if (__i
< __digits
- 1)
192 __x
= __x
* __b
+ __c
.__val
;
194 if (!__itoa::__mul_overflowed(__x
, __b
, __x
))
203 if (__p
== __lastp
|| !__in_pattern(*__p
, __b
)) {
204 if (__tl::max() - __x
>= __y
) {
209 return {__p
, errc::result_out_of_range
};
214 template <typename _Tp
, __enable_if_t
<is_signed
<_Tp
>::value
, int> = 0>
215 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
216 __from_chars_integral(const char* __first
, const char* __last
, _Tp
& __value
, int __base
) {
217 using __t
= decltype(std::__to_unsigned_like(__value
));
218 return std::__sign_combinator(__first
, __last
, __value
, __from_chars_integral
<__t
>, __base
);
221 template <typename _Tp
, __enable_if_t
<is_integral
<_Tp
>::value
, int> = 0>
222 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
223 from_chars(const char* __first
, const char* __last
, _Tp
& __value
) {
224 return std::__from_chars_atoi(__first
, __last
, __value
);
227 template <typename _Tp
, __enable_if_t
<is_integral
<_Tp
>::value
, int> = 0>
228 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
229 from_chars(const char* __first
, const char* __last
, _Tp
& __value
, int __base
) {
230 _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base
&& __base
<= 36, "base not in [2, 36]");
231 return std::__from_chars_integral(__first
, __last
, __value
, __base
);
233 #endif // _LIBCPP_STD_VER >= 17
235 _LIBCPP_END_NAMESPACE_STD
239 #endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H