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