241 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H11#define _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H12 13#include <__algorithm/copy_n.h>14#include <__assert>15#include <__charconv/from_chars_result.h>16#include <__charconv/traits.h>17#include <__config>18#include <__memory/addressof.h>19#include <__system_error/errc.h>20#include <__type_traits/enable_if.h>21#include <__type_traits/is_integral.h>22#include <__type_traits/is_signed.h>23#include <__type_traits/is_unsigned.h>24#include <__type_traits/make_unsigned.h>25#include <limits>26 27#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)28# pragma GCC system_header29#endif30 31_LIBCPP_PUSH_MACROS32#include <__undef_macros>33 34_LIBCPP_BEGIN_NAMESPACE_STD35 36#if _LIBCPP_STD_VER >= 1737 38from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete;39 40template <typename _It, typename _Tp, typename _Fn, typename... _Ts>41inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result42__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;45 46 bool __neg = (__first != __last && *__first == '-');47 auto __r = __f(__neg ? __first + 1 : __first, __last, __x, __args...);48 switch (__r.ec) {49 case errc::invalid_argument:50 return {__first, __r.ec};51 case errc::result_out_of_range:52 return __r;53 default:54 break;55 }56 57 if (__neg) {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));61 return __r;62 }63 } else {64 if (__x <= std::__to_unsigned_like(__tl::max())) {65 __value = __x;66 return __r;67 }68 }69 70 return {__r.ptr, errc::result_out_of_range};71}72 73template <typename _Tp>74inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __in_pattern(_Tp __c) {75 return '0' <= __c && __c <= '9';76}77 78struct _LIBCPP_HIDDEN __in_pattern_result {79 bool __ok;80 int __val;81 82 explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; }83};84 85template <typename _Tp>86inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result __in_pattern(_Tp __c, int __base) {87 if (__base <= 10)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};93 else94 return {'A' <= __c && __c < 'A' + __base - 10, __c - 'A' + 10};95}96 97template <typename _It, typename _Tp, typename _Fn, typename... _Ts>98inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result99__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')103 break;104 return __firstit;105 };106 107 auto __p = __find_non_zero(__first, __last);108 if (__p == __last || !std::__in_pattern(*__p, __args...)) {109 if (__p == __first)110 return {__first, errc::invalid_argument};111 else {112 __value = 0;113 return {__p, {}};114 }115 }116 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...))121 break;122 }123 }124 125 return __r;126}127 128template <typename _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>129inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result130__from_chars_atoi(const char* __first, const char* __last, _Tp& __value) {131 using __tx = __itoa::__traits<_Tp>;132 using __output_type = typename __tx::type;133 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) {141 __val = __a + __b;142 return {__p, {}};143 }144 }145 return {__p, errc::result_out_of_range};146 });147}148 149template <typename _Tp, __enable_if_t<is_signed<_Tp>::value, int> = 0>150inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result151__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>);154}155 156/*157// Code used to generate __from_chars_log2f_lut.158#include <cmath>159#include <format>160#include <iostream>161 162int main() {163 for (int i = 2; i <= 36; ++i)164 std::cout << std::format("{},\n", log2f(i));165}166*/167/// log2f table for bases [2, 36].168inline 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};173 174template <typename _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>175inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result176__from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) {177 if (__base == 10)178 return std::__from_chars_atoi(__first, __last, __value);179 180 return std::__subject_seq_combinator(181 __first,182 __last,183 __value,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;189 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;194 else {195 if (!__itoa::__mul_overflowed(__x, __b, __x))196 ++__p;197 __y = __c.__val;198 break;199 }200 } else201 break;202 }203 204 if (__p == __lastp || !__in_pattern(*__p, __b)) {205 if (__tl::max() - __x >= __y) {206 __val = __x + __y;207 return {__p, {}};208 }209 }210 return {__p, errc::result_out_of_range};211 },212 __base);213}214 215template <typename _Tp, __enable_if_t<is_signed<_Tp>::value, int> = 0>216inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result217__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);220}221 222template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>223inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result224from_chars(const char* __first, const char* __last, _Tp& __value) {225 return std::__from_chars_atoi(__first, __last, __value);226}227 228template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>229inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result230from_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);233}234#endif // _LIBCPP_STD_VER >= 17235 236_LIBCPP_END_NAMESPACE_STD237 238_LIBCPP_POP_MACROS239 240#endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H241