1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 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 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H 11 #define _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H 12 13 #include <__algorithm/copy_n.h> 14 #include <__charconv/from_chars_result.h> 15 #include <__charconv/traits.h> 16 #include <__config> 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> 24 #include <limits> 25 26 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 27 # pragma GCC system_header 28 #endif 29 30 _LIBCPP_PUSH_MACROS 31 #include <__undef_macros> 32 33 _LIBCPP_BEGIN_NAMESPACE_STD 34 35 #if _LIBCPP_STD_VER >= 17 36 37 from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete; 38 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; 44 45 bool __neg = (__first != __last && *__first == '-'); 46 auto __r = __f(__neg ? __first + 1 : __first, __last, __x, __args...); 47 switch (__r.ec) { 48 case errc::invalid_argument: 49 return {__first, __r.ec}; 50 case errc::result_out_of_range: 51 return __r; 52 default: 53 break; 54 } 55 56 if (__neg) { 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)); 60 return __r; 61 } 62 } else { 63 if (__x <= std::__to_unsigned_like(__tl::max())) { 64 __value = __x; 65 return __r; 66 } 67 } 68 69 return {__r.ptr, errc::result_out_of_range}; 70 } 71 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'; 75 } 76 77 struct _LIBCPP_HIDDEN __in_pattern_result { 78 bool __ok; 79 int __val; 80 81 explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; } 82 }; 83 84 template <typename _Tp> 85 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result __in_pattern(_Tp __c, int __base) { 86 if (__base <= 10) 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}; 92 else 93 return {'A' <= __c && __c < 'A' + __base - 10, __c - 'A' + 10}; 94 } 95 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') 102 break; 103 return __firstit; 104 }; 105 106 auto __p = __find_non_zero(__first, __last); 107 if (__p == __last || !std::__in_pattern(*__p, __args...)) { 108 if (__p == __first) 109 return {__first, errc::invalid_argument}; 110 else { 111 __value = 0; 112 return {__p, {}}; 113 } 114 } 115 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...)) 120 break; 121 } 122 } 123 124 return __r; 125 } 126 127 template <typename _Tp, typename enable_if<is_unsigned<_Tp>::value, int>::type = 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; 132 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) { 140 __val = __a + __b; 141 return {__p, {}}; 142 } 143 } 144 return {__p, errc::result_out_of_range}; 145 }); 146 } 147 148 template <typename _Tp, typename enable_if<is_signed<_Tp>::value, int>::type = 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>); 153 } 154 155 /* 156 // Code used to generate __from_chars_log2f_lut. 157 #include <cmath> 158 #include <format> 159 #include <iostream> 160 161 int main() { 162 for (int i = 2; i <= 36; ++i) 163 std::cout << std::format("{},\n", log2f(i)); 164 } 165 */ 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}; 172 173 template <typename _Tp, typename enable_if<is_unsigned<_Tp>::value, int>::type = 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) { 176 if (__base == 10) 177 return std::__from_chars_atoi(__first, __last, __value); 178 179 return std::__subject_seq_combinator( 180 __first, 181 __last, 182 __value, 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; 188 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; 193 else { 194 if (!__itoa::__mul_overflowed(__x, __b, __x)) 195 ++__p; 196 __y = __c.__val; 197 break; 198 } 199 } else 200 break; 201 } 202 203 if (__p == __lastp || !__in_pattern(*__p, __b)) { 204 if (__tl::max() - __x >= __y) { 205 __val = __x + __y; 206 return {__p, {}}; 207 } 208 } 209 return {__p, errc::result_out_of_range}; 210 }, 211 __base); 212 } 213 214 template <typename _Tp, typename enable_if<is_signed<_Tp>::value, int>::type = 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); 219 } 220 221 template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 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); 225 } 226 227 template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 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); 232 } 233 #endif // _LIBCPP_STD_VER >= 17 234 235 _LIBCPP_END_NAMESPACE_STD 236 237 _LIBCPP_POP_MACROS 238 239 #endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H 240