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>
15 #include <__charconv/from_chars_result.h>
16 #include <__charconv/traits.h>
18 #include <__memory/addressof.h>
19 #include <__system_error/errc.h>
20 #include <__type_traits/enable_if.h>
21 #include <__type_traits/integral_constant.h>
22 #include <__type_traits/is_integral.h>
23 #include <__type_traits/is_unsigned.h>
24 #include <__type_traits/make_unsigned.h>
27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28 # pragma GCC system_header
32 #include <__undef_macros>
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 #if _LIBCPP_STD_VER >= 17
38 from_chars_result
from_chars(const char*, const char*, bool, int = 10) = delete;
40 template <typename _It
, typename _Tp
, typename _Fn
, typename
... _Ts
>
41 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
42 __sign_combinator(_It __first
, _It __last
, _Tp
& __value
, _Fn __f
, _Ts
... __args
) {
43 using __tl
= numeric_limits
<_Tp
>;
44 decltype(std::__to_unsigned_like(__value
)) __x
;
46 bool __neg
= (__first
!= __last
&& *__first
== '-');
47 auto __r
= __f(__neg
? __first
+ 1 : __first
, __last
, __x
, __args
...);
49 case errc::invalid_argument
:
50 return {__first
, __r
.ec
};
51 case errc::result_out_of_range
:
58 if (__x
<= std::__complement(std::__to_unsigned_like(__tl::min()))) {
59 __x
= std::__complement(__x
);
60 std::copy_n(std::addressof(__x
), 1, std::addressof(__value
));
64 if (__x
<= std::__to_unsigned_like(__tl::max())) {
70 return {__r
.ptr
, errc::result_out_of_range
};
73 template <typename _Tp
>
74 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
bool __in_pattern(_Tp __c
) {
75 return '0' <= __c
&& __c
<= '9';
78 struct _LIBCPP_HIDDEN __in_pattern_result
{
82 explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
operator bool() const { return __ok
; }
85 template <typename _Tp
>
86 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result
__in_pattern(_Tp __c
, int __base
) {
88 return {'0' <= __c
&& __c
< '0' + __base
, __c
- '0'};
89 else if (std::__in_pattern(__c
))
90 return {true, __c
- '0'};
91 else if ('a' <= __c
&& __c
< 'a' + __base
- 10)
92 return {true, __c
- 'a' + 10};
94 return {'A' <= __c
&& __c
< 'A' + __base
- 10, __c
- 'A' + 10};
97 template <typename _It
, typename _Tp
, typename _Fn
, typename
... _Ts
>
98 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
99 __subject_seq_combinator(_It __first
, _It __last
, _Tp
& __value
, _Fn __f
, _Ts
... __args
) {
100 auto __find_non_zero
= [](_It __firstit
, _It __lastit
) {
101 for (; __firstit
!= __lastit
; ++__firstit
)
102 if (*__firstit
!= '0')
107 auto __p
= __find_non_zero(__first
, __last
);
108 if (__p
== __last
|| !std::__in_pattern(*__p
, __args
...)) {
110 return {__first
, errc::invalid_argument
};
117 auto __r
= __f(__p
, __last
, __value
, __args
...);
118 if (__r
.ec
== errc::result_out_of_range
) {
119 for (; __r
.ptr
!= __last
; ++__r
.ptr
) {
120 if (!std::__in_pattern(*__r
.ptr
, __args
...))
128 template <typename _Tp
, __enable_if_t
<is_unsigned
<_Tp
>::value
, int> = 0>
129 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
130 __from_chars_atoi(const char* __first
, const char* __last
, _Tp
& __value
) {
131 using __tx
= __itoa::__traits
<_Tp
>;
132 using __output_type
= typename
__tx::type
;
134 return std::__subject_seq_combinator(
135 __first
, __last
, __value
, [](const char* __f
, const char* __l
, _Tp
& __val
) -> from_chars_result
{
136 __output_type __a
, __b
;
137 auto __p
= __tx::__read(__f
, __l
, __a
, __b
);
138 if (__p
== __l
|| !std::__in_pattern(*__p
)) {
139 __output_type __m
= numeric_limits
<_Tp
>::max();
140 if (__m
>= __a
&& __m
- __a
>= __b
) {
145 return {__p
, errc::result_out_of_range
};
149 template <typename _Tp
, __enable_if_t
<is_signed
<_Tp
>::value
, int> = 0>
150 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
151 __from_chars_atoi(const char* __first
, const char* __last
, _Tp
& __value
) {
152 using __t
= decltype(std::__to_unsigned_like(__value
));
153 return std::__sign_combinator(__first
, __last
, __value
, __from_chars_atoi
<__t
>);
157 // Code used to generate __from_chars_log2f_lut.
163 for (int i = 2; i <= 36; ++i)
164 std::cout << std::format("{},\n", log2f(i));
167 /// log2f table for bases [2, 36].
168 inline constexpr float __from_chars_log2f_lut
[35] = {
169 1, 1.5849625, 2, 2.321928, 2.5849626, 2.807355, 3, 3.169925, 3.321928,
170 3.4594316, 3.5849626, 3.7004397, 3.807355, 3.9068906, 4, 4.087463, 4.169925, 4.2479277,
171 4.321928, 4.3923173, 4.4594316, 4.523562, 4.5849624, 4.643856, 4.70044, 4.7548876, 4.807355,
172 4.857981, 4.9068904, 4.9541965, 5, 5.044394, 5.087463, 5.129283, 5.169925};
174 template <typename _Tp
, __enable_if_t
<is_unsigned
<_Tp
>::value
, int> = 0>
175 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
176 __from_chars_integral(const char* __first
, const char* __last
, _Tp
& __value
, int __base
) {
178 return std::__from_chars_atoi(__first
, __last
, __value
);
180 return std::__subject_seq_combinator(
184 [](const char* __p
, const char* __lastp
, _Tp
& __val
, int __b
) -> from_chars_result
{
185 using __tl
= numeric_limits
<_Tp
>;
186 // __base is always between 2 and 36 inclusive.
187 auto __digits
= __tl::digits
/ __from_chars_log2f_lut
[__b
- 2];
188 _Tp __x
= __in_pattern(*__p
++, __b
).__val
, __y
= 0;
190 for (int __i
= 1; __p
!= __lastp
; ++__i
, ++__p
) {
191 if (auto __c
= __in_pattern(*__p
, __b
)) {
192 if (__i
< __digits
- 1)
193 __x
= __x
* __b
+ __c
.__val
;
195 if (!__itoa::__mul_overflowed(__x
, __b
, __x
))
204 if (__p
== __lastp
|| !__in_pattern(*__p
, __b
)) {
205 if (__tl::max() - __x
>= __y
) {
210 return {__p
, errc::result_out_of_range
};
215 template <typename _Tp
, __enable_if_t
<is_signed
<_Tp
>::value
, int> = 0>
216 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
217 __from_chars_integral(const char* __first
, const char* __last
, _Tp
& __value
, int __base
) {
218 using __t
= decltype(std::__to_unsigned_like(__value
));
219 return std::__sign_combinator(__first
, __last
, __value
, __from_chars_integral
<__t
>, __base
);
222 template <typename _Tp
, __enable_if_t
<is_integral
<_Tp
>::value
, int> = 0>
223 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
224 from_chars(const char* __first
, const char* __last
, _Tp
& __value
) {
225 return std::__from_chars_atoi(__first
, __last
, __value
);
228 template <typename _Tp
, __enable_if_t
<is_integral
<_Tp
>::value
, int> = 0>
229 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
230 from_chars(const char* __first
, const char* __last
, _Tp
& __value
, int __base
) {
231 _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base
&& __base
<= 36, "base not in [2, 36]");
232 return std::__from_chars_integral(__first
, __last
, __value
, __base
);
234 #endif // _LIBCPP_STD_VER >= 17
236 _LIBCPP_END_NAMESPACE_STD
240 #endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H