106c3fb27SDimitry Andric // -*- C++ -*-
206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
306c3fb27SDimitry Andric //
406c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
506c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
606c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
706c3fb27SDimitry Andric //
806c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
906c3fb27SDimitry Andric 
1006c3fb27SDimitry Andric #ifndef _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
1106c3fb27SDimitry Andric #define _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include <__algorithm/copy_n.h>
1406c3fb27SDimitry Andric #include <__charconv/from_chars_result.h>
1506c3fb27SDimitry Andric #include <__charconv/traits.h>
1606c3fb27SDimitry Andric #include <__config>
1706c3fb27SDimitry Andric #include <__memory/addressof.h>
1806c3fb27SDimitry Andric #include <__system_error/errc.h>
1906c3fb27SDimitry Andric #include <__type_traits/enable_if.h>
2006c3fb27SDimitry Andric #include <__type_traits/integral_constant.h>
2106c3fb27SDimitry Andric #include <__type_traits/is_integral.h>
2206c3fb27SDimitry Andric #include <__type_traits/is_unsigned.h>
2306c3fb27SDimitry Andric #include <__type_traits/make_unsigned.h>
2406c3fb27SDimitry Andric #include <limits>
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2706c3fb27SDimitry Andric #  pragma GCC system_header
2806c3fb27SDimitry Andric #endif
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS
3106c3fb27SDimitry Andric #include <__undef_macros>
3206c3fb27SDimitry Andric 
3306c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
3406c3fb27SDimitry Andric 
3506c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 17
3606c3fb27SDimitry Andric 
3706c3fb27SDimitry Andric from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete;
3806c3fb27SDimitry Andric 
3906c3fb27SDimitry Andric template <typename _It, typename _Tp, typename _Fn, typename... _Ts>
4006c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__sign_combinator(_It __first,_It __last,_Tp & __value,_Fn __f,_Ts...__args)4106c3fb27SDimitry Andric __sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) {
4206c3fb27SDimitry Andric   using __tl = numeric_limits<_Tp>;
4306c3fb27SDimitry Andric   decltype(std::__to_unsigned_like(__value)) __x;
4406c3fb27SDimitry Andric 
4506c3fb27SDimitry Andric   bool __neg = (__first != __last && *__first == '-');
4606c3fb27SDimitry Andric   auto __r   = __f(__neg ? __first + 1 : __first, __last, __x, __args...);
4706c3fb27SDimitry Andric   switch (__r.ec) {
4806c3fb27SDimitry Andric   case errc::invalid_argument:
4906c3fb27SDimitry Andric     return {__first, __r.ec};
5006c3fb27SDimitry Andric   case errc::result_out_of_range:
5106c3fb27SDimitry Andric     return __r;
5206c3fb27SDimitry Andric   default:
5306c3fb27SDimitry Andric     break;
5406c3fb27SDimitry Andric   }
5506c3fb27SDimitry Andric 
5606c3fb27SDimitry Andric   if (__neg) {
5706c3fb27SDimitry Andric     if (__x <= std::__complement(std::__to_unsigned_like(__tl::min()))) {
5806c3fb27SDimitry Andric       __x = std::__complement(__x);
5906c3fb27SDimitry Andric       std::copy_n(std::addressof(__x), 1, std::addressof(__value));
6006c3fb27SDimitry Andric       return __r;
6106c3fb27SDimitry Andric     }
6206c3fb27SDimitry Andric   } else {
6306c3fb27SDimitry Andric     if (__x <= std::__to_unsigned_like(__tl::max())) {
6406c3fb27SDimitry Andric       __value = __x;
6506c3fb27SDimitry Andric       return __r;
6606c3fb27SDimitry Andric     }
6706c3fb27SDimitry Andric   }
6806c3fb27SDimitry Andric 
6906c3fb27SDimitry Andric   return {__r.ptr, errc::result_out_of_range};
7006c3fb27SDimitry Andric }
7106c3fb27SDimitry Andric 
7206c3fb27SDimitry Andric template <typename _Tp>
__in_pattern(_Tp __c)7306c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __in_pattern(_Tp __c) {
7406c3fb27SDimitry Andric   return '0' <= __c && __c <= '9';
7506c3fb27SDimitry Andric }
7606c3fb27SDimitry Andric 
7706c3fb27SDimitry Andric struct _LIBCPP_HIDDEN __in_pattern_result {
7806c3fb27SDimitry Andric   bool __ok;
7906c3fb27SDimitry Andric   int __val;
8006c3fb27SDimitry Andric 
8106c3fb27SDimitry Andric   explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; }
8206c3fb27SDimitry Andric };
8306c3fb27SDimitry Andric 
8406c3fb27SDimitry Andric template <typename _Tp>
__in_pattern(_Tp __c,int __base)8506c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result __in_pattern(_Tp __c, int __base) {
8606c3fb27SDimitry Andric   if (__base <= 10)
8706c3fb27SDimitry Andric     return {'0' <= __c && __c < '0' + __base, __c - '0'};
8806c3fb27SDimitry Andric   else if (std::__in_pattern(__c))
8906c3fb27SDimitry Andric     return {true, __c - '0'};
9006c3fb27SDimitry Andric   else if ('a' <= __c && __c < 'a' + __base - 10)
9106c3fb27SDimitry Andric     return {true, __c - 'a' + 10};
9206c3fb27SDimitry Andric   else
9306c3fb27SDimitry Andric     return {'A' <= __c && __c < 'A' + __base - 10, __c - 'A' + 10};
9406c3fb27SDimitry Andric }
9506c3fb27SDimitry Andric 
9606c3fb27SDimitry Andric template <typename _It, typename _Tp, typename _Fn, typename... _Ts>
9706c3fb27SDimitry Andric 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)9806c3fb27SDimitry Andric __subject_seq_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) {
9906c3fb27SDimitry Andric   auto __find_non_zero = [](_It __firstit, _It __lastit) {
10006c3fb27SDimitry Andric     for (; __firstit != __lastit; ++__firstit)
10106c3fb27SDimitry Andric       if (*__firstit != '0')
10206c3fb27SDimitry Andric         break;
10306c3fb27SDimitry Andric     return __firstit;
10406c3fb27SDimitry Andric   };
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric   auto __p = __find_non_zero(__first, __last);
10706c3fb27SDimitry Andric   if (__p == __last || !std::__in_pattern(*__p, __args...)) {
10806c3fb27SDimitry Andric     if (__p == __first)
10906c3fb27SDimitry Andric       return {__first, errc::invalid_argument};
11006c3fb27SDimitry Andric     else {
11106c3fb27SDimitry Andric       __value = 0;
11206c3fb27SDimitry Andric       return {__p, {}};
11306c3fb27SDimitry Andric     }
11406c3fb27SDimitry Andric   }
11506c3fb27SDimitry Andric 
11606c3fb27SDimitry Andric   auto __r = __f(__p, __last, __value, __args...);
11706c3fb27SDimitry Andric   if (__r.ec == errc::result_out_of_range) {
11806c3fb27SDimitry Andric     for (; __r.ptr != __last; ++__r.ptr) {
11906c3fb27SDimitry Andric       if (!std::__in_pattern(*__r.ptr, __args...))
12006c3fb27SDimitry Andric         break;
12106c3fb27SDimitry Andric     }
12206c3fb27SDimitry Andric   }
12306c3fb27SDimitry Andric 
12406c3fb27SDimitry Andric   return __r;
12506c3fb27SDimitry Andric }
12606c3fb27SDimitry Andric 
127*5f757f3fSDimitry Andric template <typename _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>
12806c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars_atoi(const char * __first,const char * __last,_Tp & __value)12906c3fb27SDimitry Andric __from_chars_atoi(const char* __first, const char* __last, _Tp& __value) {
13006c3fb27SDimitry Andric   using __tx          = __itoa::__traits<_Tp>;
13106c3fb27SDimitry Andric   using __output_type = typename __tx::type;
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric   return std::__subject_seq_combinator(
13406c3fb27SDimitry Andric       __first, __last, __value, [](const char* __f, const char* __l, _Tp& __val) -> from_chars_result {
13506c3fb27SDimitry Andric         __output_type __a, __b;
13606c3fb27SDimitry Andric         auto __p = __tx::__read(__f, __l, __a, __b);
13706c3fb27SDimitry Andric         if (__p == __l || !std::__in_pattern(*__p)) {
13806c3fb27SDimitry Andric           __output_type __m = numeric_limits<_Tp>::max();
13906c3fb27SDimitry Andric           if (__m >= __a && __m - __a >= __b) {
14006c3fb27SDimitry Andric             __val = __a + __b;
14106c3fb27SDimitry Andric             return {__p, {}};
14206c3fb27SDimitry Andric           }
14306c3fb27SDimitry Andric         }
14406c3fb27SDimitry Andric         return {__p, errc::result_out_of_range};
14506c3fb27SDimitry Andric       });
14606c3fb27SDimitry Andric }
14706c3fb27SDimitry Andric 
148*5f757f3fSDimitry Andric template <typename _Tp, __enable_if_t<is_signed<_Tp>::value, int> = 0>
14906c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars_atoi(const char * __first,const char * __last,_Tp & __value)15006c3fb27SDimitry Andric __from_chars_atoi(const char* __first, const char* __last, _Tp& __value) {
15106c3fb27SDimitry Andric   using __t = decltype(std::__to_unsigned_like(__value));
15206c3fb27SDimitry Andric   return std::__sign_combinator(__first, __last, __value, __from_chars_atoi<__t>);
15306c3fb27SDimitry Andric }
15406c3fb27SDimitry Andric 
15506c3fb27SDimitry Andric /*
15606c3fb27SDimitry Andric // Code used to generate __from_chars_log2f_lut.
15706c3fb27SDimitry Andric #include <cmath>
15806c3fb27SDimitry Andric #include <format>
15906c3fb27SDimitry Andric #include <iostream>
16006c3fb27SDimitry Andric 
16106c3fb27SDimitry Andric int main() {
16206c3fb27SDimitry Andric   for (int i = 2; i <= 36; ++i)
16306c3fb27SDimitry Andric     std::cout << std::format("{},\n", log2f(i));
16406c3fb27SDimitry Andric }
16506c3fb27SDimitry Andric */
16606c3fb27SDimitry Andric /// log2f table for bases [2, 36].
16706c3fb27SDimitry Andric inline constexpr float __from_chars_log2f_lut[35] = {
16806c3fb27SDimitry Andric     1,         1.5849625, 2,         2.321928, 2.5849626, 2.807355, 3,        3.169925,  3.321928,
16906c3fb27SDimitry Andric     3.4594316, 3.5849626, 3.7004397, 3.807355, 3.9068906, 4,        4.087463, 4.169925,  4.2479277,
17006c3fb27SDimitry Andric     4.321928,  4.3923173, 4.4594316, 4.523562, 4.5849624, 4.643856, 4.70044,  4.7548876, 4.807355,
17106c3fb27SDimitry Andric     4.857981,  4.9068904, 4.9541965, 5,        5.044394,  5.087463, 5.129283, 5.169925};
17206c3fb27SDimitry Andric 
173*5f757f3fSDimitry Andric template <typename _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>
17406c3fb27SDimitry Andric 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)17506c3fb27SDimitry Andric __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) {
17606c3fb27SDimitry Andric   if (__base == 10)
17706c3fb27SDimitry Andric     return std::__from_chars_atoi(__first, __last, __value);
17806c3fb27SDimitry Andric 
17906c3fb27SDimitry Andric   return std::__subject_seq_combinator(
18006c3fb27SDimitry Andric       __first,
18106c3fb27SDimitry Andric       __last,
18206c3fb27SDimitry Andric       __value,
18306c3fb27SDimitry Andric       [](const char* __p, const char* __lastp, _Tp& __val, int __b) -> from_chars_result {
18406c3fb27SDimitry Andric         using __tl = numeric_limits<_Tp>;
18506c3fb27SDimitry Andric         // __base is always between 2 and 36 inclusive.
18606c3fb27SDimitry Andric         auto __digits = __tl::digits / __from_chars_log2f_lut[__b - 2];
18706c3fb27SDimitry Andric         _Tp __x = __in_pattern(*__p++, __b).__val, __y = 0;
18806c3fb27SDimitry Andric 
18906c3fb27SDimitry Andric         for (int __i = 1; __p != __lastp; ++__i, ++__p) {
19006c3fb27SDimitry Andric           if (auto __c = __in_pattern(*__p, __b)) {
19106c3fb27SDimitry Andric             if (__i < __digits - 1)
19206c3fb27SDimitry Andric               __x = __x * __b + __c.__val;
19306c3fb27SDimitry Andric             else {
19406c3fb27SDimitry Andric               if (!__itoa::__mul_overflowed(__x, __b, __x))
19506c3fb27SDimitry Andric                 ++__p;
19606c3fb27SDimitry Andric               __y = __c.__val;
19706c3fb27SDimitry Andric               break;
19806c3fb27SDimitry Andric             }
19906c3fb27SDimitry Andric           } else
20006c3fb27SDimitry Andric             break;
20106c3fb27SDimitry Andric         }
20206c3fb27SDimitry Andric 
20306c3fb27SDimitry Andric         if (__p == __lastp || !__in_pattern(*__p, __b)) {
20406c3fb27SDimitry Andric           if (__tl::max() - __x >= __y) {
20506c3fb27SDimitry Andric             __val = __x + __y;
20606c3fb27SDimitry Andric             return {__p, {}};
20706c3fb27SDimitry Andric           }
20806c3fb27SDimitry Andric         }
20906c3fb27SDimitry Andric         return {__p, errc::result_out_of_range};
21006c3fb27SDimitry Andric       },
21106c3fb27SDimitry Andric       __base);
21206c3fb27SDimitry Andric }
21306c3fb27SDimitry Andric 
214*5f757f3fSDimitry Andric template <typename _Tp, __enable_if_t<is_signed<_Tp>::value, int> = 0>
21506c3fb27SDimitry Andric 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)21606c3fb27SDimitry Andric __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) {
21706c3fb27SDimitry Andric   using __t = decltype(std::__to_unsigned_like(__value));
21806c3fb27SDimitry Andric   return std::__sign_combinator(__first, __last, __value, __from_chars_integral<__t>, __base);
21906c3fb27SDimitry Andric }
22006c3fb27SDimitry Andric 
221*5f757f3fSDimitry Andric template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
22206c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
from_chars(const char * __first,const char * __last,_Tp & __value)22306c3fb27SDimitry Andric from_chars(const char* __first, const char* __last, _Tp& __value) {
22406c3fb27SDimitry Andric   return std::__from_chars_atoi(__first, __last, __value);
22506c3fb27SDimitry Andric }
22606c3fb27SDimitry Andric 
227*5f757f3fSDimitry Andric template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>
22806c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
from_chars(const char * __first,const char * __last,_Tp & __value,int __base)22906c3fb27SDimitry Andric from_chars(const char* __first, const char* __last, _Tp& __value, int __base) {
23006c3fb27SDimitry Andric   _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base && __base <= 36, "base not in [2, 36]");
23106c3fb27SDimitry Andric   return std::__from_chars_integral(__first, __last, __value, __base);
23206c3fb27SDimitry Andric }
23306c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 17
23406c3fb27SDimitry Andric 
23506c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
23606c3fb27SDimitry Andric 
23706c3fb27SDimitry Andric _LIBCPP_POP_MACROS
23806c3fb27SDimitry Andric 
23906c3fb27SDimitry Andric #endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H
240