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