master
  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 <__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/integral_constant.h>
 22#include <__type_traits/is_integral.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_header
 29#endif
 30
 31_LIBCPP_PUSH_MACROS
 32#include <__undef_macros>
 33
 34_LIBCPP_BEGIN_NAMESPACE_STD
 35
 36#if _LIBCPP_STD_VER >= 17
 37
 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_result
 42__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  else
 94    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_result
 99__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_result
130__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_result
151__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_result
176__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          } else
201            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_result
217__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_result
224from_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_result
230from_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 >= 17
235
236_LIBCPP_END_NAMESPACE_STD
237
238_LIBCPP_POP_MACROS
239
240#endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H