brintos

brintos / llvm-project-archived public Read only

0
0
Text · 35.7 KiB · 98b8eb0 Raw
1018 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___LOCALE_DIR_NUM_H10#define _LIBCPP___LOCALE_DIR_NUM_H11 12#include <__algorithm/copy.h>13#include <__algorithm/find.h>14#include <__algorithm/reverse.h>15#include <__algorithm/simd_utils.h>16#include <__charconv/to_chars_integral.h>17#include <__charconv/traits.h>18#include <__config>19#include <__iterator/istreambuf_iterator.h>20#include <__iterator/ostreambuf_iterator.h>21#include <__locale_dir/check_grouping.h>22#include <__locale_dir/get_c_locale.h>23#include <__locale_dir/pad_and_output.h>24#include <__locale_dir/scan_keyword.h>25#include <__memory/unique_ptr.h>26#include <__system_error/errc.h>27#include <__type_traits/is_signed.h>28#include <cerrno>29#include <ios>30#include <streambuf>31 32#if _LIBCPP_HAS_LOCALIZATION33 34#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)35#    pragma GCC system_header36#  endif37 38// TODO: Properly qualify calls now that the locale base API defines functions instead of macros39// NOLINTBEGIN(libcpp-robust-against-adl)40 41_LIBCPP_PUSH_MACROS42#  include <__undef_macros>43 44_LIBCPP_BEGIN_NAMESPACE_STD45 46struct _LIBCPP_EXPORTED_FROM_ABI __num_get_base {47  static const int __num_get_buf_sz = 40;48 49  static int __get_base(ios_base&);50  static const char __src[33]; // "0123456789abcdefABCDEFxX+-pPiInN"51  // count of leading characters in __src used for parsing integers ("012..X+-")52  static inline const size_t __int_chr_cnt = 26;53  // count of leading characters in __src used for parsing floating-point values ("012..-pP")54  static inline const size_t __fp_chr_cnt = 28;55};56 57template <class _CharT>58struct __num_get : protected __num_get_base {59  static string __stage2_float_prep(ios_base& __iob, _CharT* __atoms, _CharT& __decimal_point, _CharT& __thousands_sep);60 61  static int __stage2_float_loop(62      _CharT __ct,63      bool& __in_units,64      char& __exp,65      char* __a,66      char*& __a_end,67      _CharT __decimal_point,68      _CharT __thousands_sep,69      const string& __grouping,70      unsigned* __g,71      unsigned*& __g_end,72      unsigned& __dc,73      _CharT* __atoms);74 75  [[__deprecated__("This exists only for ABI compatibility")]] static string76  __stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep);77 78  [[__deprecated__("This exists only for ABI compatibility")]] static int __stage2_int_loop(79      _CharT __ct,80      int __base,81      char* __a,82      char*& __a_end,83      unsigned& __dc,84      _CharT __thousands_sep,85      const string& __grouping,86      unsigned* __g,87      unsigned*& __g_end,88      _CharT* __atoms);89 90  _LIBCPP_HIDE_FROM_ABI static ptrdiff_t __atoms_offset(const _CharT* __atoms, _CharT __val) {91    // TODO: Remove the manual vectorization once https://llvm.org/PR168551 is resolved92#  if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS93    if constexpr (is_same<_CharT, char>::value) {94      // TODO(LLVM 24): This can be removed, since -Wpsabi doesn't warn on [[gnu::always_inline]] functions anymore.95      _LIBCPP_DIAGNOSTIC_PUSH96      _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")97      using __vec   = __simd_vector<char, 32>;98      __vec __chars = std::__broadcast<__vec>(__val);99      __vec __cmp   = std::__partial_load<__vec, __int_chr_cnt>(__atoms);100      auto __res    = __chars == __cmp;101      if (std::__none_of(__res))102        return __int_chr_cnt;103      return std::min(__int_chr_cnt, std::__find_first_set(__res));104      _LIBCPP_DIAGNOSTIC_POP105    }106#  endif107    return std::find(__atoms, __atoms + __int_chr_cnt, __val) - __atoms;108  }109 110  _LIBCPP_HIDE_FROM_ABI const _CharT* __do_widen(ios_base& __iob, _CharT* __atoms) const {111    return __do_widen_p(__iob, __atoms);112  }113 114private:115  template <typename _Tp>116  _LIBCPP_HIDE_FROM_ABI const _Tp* __do_widen_p(ios_base& __iob, _Tp* __atoms) const {117    locale __loc = __iob.getloc();118    use_facet<ctype<_Tp> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);119    return __atoms;120  }121 122  _LIBCPP_HIDE_FROM_ABI const char* __do_widen_p(ios_base& __iob, char* __atoms) const {123    (void)__iob;124    (void)__atoms;125    return __src;126  }127};128 129template <class _CharT>130string __num_get<_CharT>::__stage2_float_prep(131    ios_base& __iob, _CharT* __atoms, _CharT& __decimal_point, _CharT& __thousands_sep) {132  locale __loc = __iob.getloc();133  std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + __fp_chr_cnt, __atoms);134  const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__loc);135  __decimal_point              = __np.decimal_point();136  __thousands_sep              = __np.thousands_sep();137  return __np.grouping();138}139 140template <class _CharT>141int __num_get<_CharT>::__stage2_float_loop(142    _CharT __ct,143    bool& __in_units,144    char& __exp,145    char* __a,146    char*& __a_end,147    _CharT __decimal_point,148    _CharT __thousands_sep,149    const string& __grouping,150    unsigned* __g,151    unsigned*& __g_end,152    unsigned& __dc,153    _CharT* __atoms) {154  if (__ct == __decimal_point) {155    if (!__in_units)156      return -1;157    __in_units = false;158    *__a_end++ = '.';159    if (__grouping.size() != 0 && __g_end - __g < __num_get_buf_sz)160      *__g_end++ = __dc;161    return 0;162  }163  if (__ct == __thousands_sep && __grouping.size() != 0) {164    if (!__in_units)165      return -1;166    if (__g_end - __g < __num_get_buf_sz) {167      *__g_end++ = __dc;168      __dc       = 0;169    }170    return 0;171  }172  ptrdiff_t __f = std::find(__atoms, __atoms + __num_get_base::__fp_chr_cnt, __ct) - __atoms;173  if (__f >= static_cast<ptrdiff_t>(__num_get_base::__fp_chr_cnt))174    return -1;175  char __x = __src[__f];176  if (__x == '-' || __x == '+') {177    if (__a_end == __a || (std::toupper(__a_end[-1]) == std::toupper(__exp))) {178      *__a_end++ = __x;179      return 0;180    }181    return -1;182  }183  if (__x == 'x' || __x == 'X')184    __exp = 'P';185  else if (std::toupper(__x) == __exp) {186    __exp = std::tolower(__exp);187    if (__in_units) {188      __in_units = false;189      if (__grouping.size() != 0 && __g_end - __g < __num_get_buf_sz)190        *__g_end++ = __dc;191    }192  }193  *__a_end++ = __x;194  if (__f >= 22)195    return 0;196  ++__dc;197  return 0;198}199 200extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_get<char>;201#  if _LIBCPP_HAS_WIDE_CHARACTERS202extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_get<wchar_t>;203#  endif204 205template <class _Tp>206_LIBCPP_HIDE_FROM_ABI _Tp __do_strtod(const char* __a, char** __p2);207 208template <>209inline _LIBCPP_HIDE_FROM_ABI float __do_strtod<float>(const char* __a, char** __p2) {210  return __locale::__strtof(__a, __p2, _LIBCPP_GET_C_LOCALE);211}212 213template <>214inline _LIBCPP_HIDE_FROM_ABI double __do_strtod<double>(const char* __a, char** __p2) {215  return __locale::__strtod(__a, __p2, _LIBCPP_GET_C_LOCALE);216}217 218template <>219inline _LIBCPP_HIDE_FROM_ABI long double __do_strtod<long double>(const char* __a, char** __p2) {220  return __locale::__strtold(__a, __p2, _LIBCPP_GET_C_LOCALE);221}222 223template <class _Tp>224_LIBCPP_HIDE_FROM_ABI _Tp __num_get_float(const char* __a, const char* __a_end, ios_base::iostate& __err) {225  if (__a != __a_end) {226    __libcpp_remove_reference_t<decltype(errno)> __save_errno = errno;227    errno                                                     = 0;228    char* __p2;229    _Tp __ld                                                     = std::__do_strtod<_Tp>(__a, &__p2);230    __libcpp_remove_reference_t<decltype(errno)> __current_errno = errno;231    if (__current_errno == 0)232      errno = __save_errno;233    if (__p2 != __a_end) {234      __err = ios_base::failbit;235      return 0;236    } else if (__current_errno == ERANGE)237      __err = ios_base::failbit;238    return __ld;239  }240  __err = ios_base::failbit;241  return 0;242}243 244template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >245class num_get : public locale::facet, private __num_get<_CharT> {246public:247  typedef _CharT char_type;248  typedef _InputIterator iter_type;249 250  _LIBCPP_HIDE_FROM_ABI explicit num_get(size_t __refs = 0) : locale::facet(__refs) {}251 252  _LIBCPP_HIDE_FROM_ABI iter_type253  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const {254    return do_get(__b, __e, __iob, __err, __v);255  }256 257  _LIBCPP_HIDE_FROM_ABI iter_type258  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long& __v) const {259    return do_get(__b, __e, __iob, __err, __v);260  }261 262  _LIBCPP_HIDE_FROM_ABI iter_type263  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long long& __v) const {264    return do_get(__b, __e, __iob, __err, __v);265  }266 267  _LIBCPP_HIDE_FROM_ABI iter_type268  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned short& __v) const {269    return do_get(__b, __e, __iob, __err, __v);270  }271 272  _LIBCPP_HIDE_FROM_ABI iter_type273  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned int& __v) const {274    return do_get(__b, __e, __iob, __err, __v);275  }276 277  _LIBCPP_HIDE_FROM_ABI iter_type278  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long& __v) const {279    return do_get(__b, __e, __iob, __err, __v);280  }281 282  _LIBCPP_HIDE_FROM_ABI iter_type283  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long long& __v) const {284    return do_get(__b, __e, __iob, __err, __v);285  }286 287  _LIBCPP_HIDE_FROM_ABI iter_type288  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, float& __v) const {289    return do_get(__b, __e, __iob, __err, __v);290  }291 292  _LIBCPP_HIDE_FROM_ABI iter_type293  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, double& __v) const {294    return do_get(__b, __e, __iob, __err, __v);295  }296 297  _LIBCPP_HIDE_FROM_ABI iter_type298  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long double& __v) const {299    return do_get(__b, __e, __iob, __err, __v);300  }301 302  _LIBCPP_HIDE_FROM_ABI iter_type303  get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const {304    return do_get(__b, __e, __iob, __err, __v);305  }306 307  static locale::id id;308 309protected:310  _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~num_get() override {}311 312  template <class _Fp>313  _LIBCPP_HIDE_FROM_ABI iter_type314  __do_get_floating_point(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Fp& __v) const {315    // Stage 1, nothing to do316    // Stage 2317    char_type __atoms[__num_get_base::__fp_chr_cnt];318    char_type __decimal_point;319    char_type __thousands_sep;320    string __grouping = this->__stage2_float_prep(__iob, __atoms, __decimal_point, __thousands_sep);321    string __buf;322    __buf.resize(__buf.capacity());323    char* __a     = &__buf[0];324    char* __a_end = __a;325    unsigned __g[__num_get_base::__num_get_buf_sz];326    unsigned* __g_end        = __g;327    unsigned __dc            = 0;328    bool __in_units          = true;329    char __exp               = 'E';330    bool __is_leading_parsed = false;331    for (; __b != __e; ++__b) {332      if (__a_end == __a + __buf.size()) {333        size_t __tmp = __buf.size();334        __buf.resize(2 * __buf.size());335        __buf.resize(__buf.capacity());336        __a     = &__buf[0];337        __a_end = __a + __tmp;338      }339      if (this->__stage2_float_loop(340              *__b,341              __in_units,342              __exp,343              __a,344              __a_end,345              __decimal_point,346              __thousands_sep,347              __grouping,348              __g,349              __g_end,350              __dc,351              __atoms))352        break;353 354      // the leading character excluding the sign must be a decimal digit355      if (!__is_leading_parsed) {356        if (__a_end - __a >= 1 && __a[0] != '-' && __a[0] != '+') {357          if (('0' <= __a[0] && __a[0] <= '9') || __a[0] == '.')358            __is_leading_parsed = true;359          else360            break;361        } else if (__a_end - __a >= 2 && (__a[0] == '-' || __a[0] == '+')) {362          if (('0' <= __a[1] && __a[1] <= '9') || __a[1] == '.')363            __is_leading_parsed = true;364          else365            break;366        }367      }368    }369    if (__grouping.size() != 0 && __in_units && __g_end - __g < __num_get_base::__num_get_buf_sz)370      *__g_end++ = __dc;371    // Stage 3372    __v = std::__num_get_float<_Fp>(__a, __a_end, __err);373    // Digit grouping checked374    __check_grouping(__grouping, __g, __g_end, __err);375    // EOF checked376    if (__b == __e)377      __err |= ios_base::eofbit;378    return __b;379  }380 381  template <class _MaybeSigned>382  iter_type __do_get_integral(383      iter_type __first, iter_type __last, ios_base& __iob, ios_base::iostate& __err, _MaybeSigned& __v) const {384    using _Unsigned = __make_unsigned_t<_MaybeSigned>;385 386    // Stage 1387    int __base = this->__get_base(__iob);388 389    // Stages 2 & 3390    // These are combined into a single step where we parse the characters and calculate the value in one go instead of391    // storing the relevant characters first (in an allocated buffer) and parse the characters after we extracted them.392    // This makes the whole process significantly faster, since we avoid potential allocations and copies.393 394    const auto& __numpunct    = use_facet<numpunct<_CharT> >(__iob.getloc());395    char_type __thousands_sep = __numpunct.thousands_sep();396    string __grouping         = __numpunct.grouping();397 398    char_type __atoms_buffer[__num_get_base::__int_chr_cnt];399    const char_type* __atoms = this->__do_widen(__iob, __atoms_buffer);400    unsigned __g[__num_get_base::__num_get_buf_sz];401    unsigned* __g_end = __g;402    unsigned __dc     = 0;403 404    if (__first == __last) {405      __err |= ios_base::eofbit | ios_base::failbit;406      __v = 0;407      return __first;408    }409 410    while (!__grouping.empty() && *__first == __thousands_sep) {411      ++__first;412      if (__g_end - __g < this->__num_get_buf_sz)413        *__g_end++ = 0;414    }415 416    bool __negate = false;417    // __c == '+' || __c == '-'418    if (auto __c = *__first; __c == __atoms[24] || __c == __atoms[25]) {419      __negate = __c == __atoms[25];420      ++__first;421    }422 423    if (__first == __last) {424      __err |= ios_base::eofbit | ios_base::failbit;425      __v = 0;426      return __first;427    }428 429    bool __parsed_num = false;430 431    // If we don't have a pre-set base, figure it out and swallow any prefix432    if (__base == 0) {433      auto __c = *__first;434      // __c == '0'435      if (__c == __atoms[0]) {436        ++__first;437        if (__first == __last) {438          __err |= ios_base::eofbit;439          return __first;440        }441        // __c2 == 'x' || __c2 == 'X'442        if (auto __c2 = *__first; __c2 == __atoms[22] || __c2 == __atoms[23]) {443          __base = 16;444          ++__first;445        } else {446          __base = 8;447        }448      } else {449        __base = 10;450      }451 452      // If the base has been specified explicitly, try to swallow the appropriate prefix. We only need to do something453      // special for hex, since decimal has no prefix and octal's prefix is '0', which doesn't change the value that454      // we'll parse if we don't swallow it.455    } else if (__base == 16) {456      // Try to swallow '0x'457 458      // *__first == '0'459      if (*__first == __atoms[0]) {460        ++__first;461        if (__first == __last) {462          __err |= ios_base::eofbit;463          __v = 0;464          return __first;465        }466        // __c == 'x' || __c == 'X'467        if (auto __c = *__first; __c == __atoms[22] || __c == __atoms[23])468          ++__first;469        else470          __parsed_num = true; // We only swallowed '0', so we've started to parse a number471      }472    }473 474    // Calculate the actual number475    _Unsigned __val   = 0;476    bool __overflowed = false;477    for (; __first != __last; ++__first) {478      auto __c = *__first;479      if (!__grouping.empty() && __c == __thousands_sep) {480        if (__g_end - __g < this->__num_get_buf_sz) {481          *__g_end++ = __dc;482          __dc       = 0;483        }484        continue;485      }486      auto __offset = this->__atoms_offset(__atoms, __c);487      if (__offset >= 22) // Not a valid integer character488        break;489 490      if (__base == 16 && __offset >= 16)491        __offset -= 6;492      if (__offset >= __base)493        break;494      // __val = (__val * __base) + __offset495      __overflowed |= __builtin_mul_overflow(__val, __base, std::addressof(__val)) ||496                      __builtin_add_overflow(__val, __offset, std::addressof(__val));497      __parsed_num = true;498      ++__dc;499    }500 501    if (!__parsed_num) {502      __err |= ios_base::failbit;503      __v = 0;504    } else if (__overflowed) {505      __err |= ios_base::failbit;506      __v = is_signed<_MaybeSigned>::value && __negate507              ? numeric_limits<_MaybeSigned>::min()508              : numeric_limits<_MaybeSigned>::max();509    } else if (!__negate) {510      if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max())) {511        __err |= ios_base::failbit;512        __v = numeric_limits<_MaybeSigned>::max();513      } else {514        __v = __val;515      }516    } else if (is_signed<_MaybeSigned>::value) {517      if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {518        __err |= ios_base::failbit;519        __v = numeric_limits<_MaybeSigned>::min();520      } else if (__val == static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {521        __v = numeric_limits<_MaybeSigned>::min();522      } else {523        __v = -__val;524      }525    } else {526      __v = -__val;527    }528 529    if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz)530      *__g_end++ = __dc;531 532    // Digit grouping checked533    __check_grouping(__grouping, __g, __g_end, __err);534    // EOF checked535    if (__first == __last)536      __err |= ios_base::eofbit;537    return __first;538  }539 540  virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const;541 542  virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long& __v) const {543    return this->__do_get_integral(__b, __e, __iob, __err, __v);544  }545 546  virtual iter_type547  do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long long& __v) const {548    return this->__do_get_integral(__b, __e, __iob, __err, __v);549  }550 551  virtual iter_type552  do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned short& __v) const {553    return this->__do_get_integral(__b, __e, __iob, __err, __v);554  }555 556  virtual iter_type557  do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned int& __v) const {558    return this->__do_get_integral(__b, __e, __iob, __err, __v);559  }560 561  virtual iter_type562  do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long& __v) const {563    return this->__do_get_integral(__b, __e, __iob, __err, __v);564  }565 566  virtual iter_type567  do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long long& __v) const {568    return this->__do_get_integral(__b, __e, __iob, __err, __v);569  }570 571  virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, float& __v) const {572    return this->__do_get_floating_point(__b, __e, __iob, __err, __v);573  }574 575  virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, double& __v) const {576    return this->__do_get_floating_point(__b, __e, __iob, __err, __v);577  }578 579  virtual iter_type580  do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long double& __v) const {581    return this->__do_get_floating_point(__b, __e, __iob, __err, __v);582  }583 584  virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const;585};586 587template <class _CharT, class _InputIterator>588locale::id num_get<_CharT, _InputIterator>::id;589 590template <class _CharT, class _InputIterator>591_InputIterator num_get<_CharT, _InputIterator>::do_get(592    iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const {593  if ((__iob.flags() & ios_base::boolalpha) == 0) {594    long __lv = -1;595    __b       = do_get(__b, __e, __iob, __err, __lv);596    switch (__lv) {597    case 0:598      __v = false;599      break;600    case 1:601      __v = true;602      break;603    default:604      __v   = true;605      __err = ios_base::failbit;606      break;607    }608    return __b;609  }610  const ctype<_CharT>& __ct    = std::use_facet<ctype<_CharT> >(__iob.getloc());611  const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__iob.getloc());612  typedef typename numpunct<_CharT>::string_type string_type;613  const string_type __names[2] = {__np.truename(), __np.falsename()};614  const string_type* __i       = std::__scan_keyword(__b, __e, __names, __names + 2, __ct, __err);615  __v                          = __i == __names;616  return __b;617}618 619template <class _CharT, class _InputIterator>620_InputIterator num_get<_CharT, _InputIterator>::do_get(621    iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const {622  auto __flags = __iob.flags();623  __iob.flags((__flags & ~ios_base::basefield & ~ios_base::uppercase) | ios_base::hex);624  uintptr_t __ptr;625  auto __res = __do_get_integral(__b, __e, __iob, __err, __ptr);626  __iob.flags(__flags);627  __v = reinterpret_cast<void*>(__ptr);628  return __res;629}630 631extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_get<char>;632#  if _LIBCPP_HAS_WIDE_CHARACTERS633extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_get<wchar_t>;634#  endif635 636struct _LIBCPP_EXPORTED_FROM_ABI __num_put_base {637protected:638  static void __format_int(char* __fmt, const char* __len, bool __signd, ios_base::fmtflags __flags);639  static bool __format_float(char* __fmt, const char* __len, ios_base::fmtflags __flags);640  static char* __identify_padding(char* __nb, char* __ne, const ios_base& __iob);641};642 643template <class _CharT>644struct __num_put : protected __num_put_base {645  static void __widen_and_group_int(646      char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc);647  static void __widen_and_group_float(648      char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc);649};650 651template <class _CharT>652void __num_put<_CharT>::__widen_and_group_int(653    char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc) {654  const ctype<_CharT>& __ct     = std::use_facet<ctype<_CharT> >(__loc);655  const numpunct<_CharT>& __npt = std::use_facet<numpunct<_CharT> >(__loc);656  string __grouping             = __npt.grouping();657  if (__grouping.empty()) {658    __ct.widen(__nb, __ne, __ob);659    __oe = __ob + (__ne - __nb);660  } else {661    __oe       = __ob;662    char* __nf = __nb;663    if (*__nf == '-' || *__nf == '+')664      *__oe++ = __ct.widen(*__nf++);665    if (__ne - __nf >= 2 && __nf[0] == '0' && (__nf[1] == 'x' || __nf[1] == 'X')) {666      *__oe++ = __ct.widen(*__nf++);667      *__oe++ = __ct.widen(*__nf++);668    }669    std::reverse(__nf, __ne);670    _CharT __thousands_sep = __npt.thousands_sep();671    unsigned __dc          = 0;672    unsigned __dg          = 0;673    for (char* __p = __nf; __p < __ne; ++__p) {674      if (static_cast<unsigned>(__grouping[__dg]) > 0 && __dc == static_cast<unsigned>(__grouping[__dg])) {675        *__oe++ = __thousands_sep;676        __dc    = 0;677        if (__dg < __grouping.size() - 1)678          ++__dg;679      }680      *__oe++ = __ct.widen(*__p);681      ++__dc;682    }683    std::reverse(__ob + (__nf - __nb), __oe);684  }685  if (__np == __ne)686    __op = __oe;687  else688    __op = __ob + (__np - __nb);689}690 691_LIBCPP_HIDE_FROM_ABI inline bool __isdigit(char __c) { return __c >= '0' && __c <= '9'; }692 693_LIBCPP_HIDE_FROM_ABI inline bool __isxdigit(char __c) {694  auto __lower = __c | 0x20;695  return std::__isdigit(__c) || (__lower >= 'a' && __lower <= 'f');696}697 698template <class _CharT>699void __num_put<_CharT>::__widen_and_group_float(700    char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc) {701  const ctype<_CharT>& __ct     = std::use_facet<ctype<_CharT> >(__loc);702  const numpunct<_CharT>& __npt = std::use_facet<numpunct<_CharT> >(__loc);703  string __grouping             = __npt.grouping();704  __oe                          = __ob;705  char* __nf                    = __nb;706  if (*__nf == '-' || *__nf == '+')707    *__oe++ = __ct.widen(*__nf++);708  char* __ns;709  if (__ne - __nf >= 2 && __nf[0] == '0' && (__nf[1] == 'x' || __nf[1] == 'X')) {710    *__oe++ = __ct.widen(*__nf++);711    *__oe++ = __ct.widen(*__nf++);712    for (__ns = __nf; __ns < __ne; ++__ns)713      if (!std::__isxdigit(*__ns))714        break;715  } else {716    for (__ns = __nf; __ns < __ne; ++__ns)717      if (!std::__isdigit(*__ns))718        break;719  }720  if (__grouping.empty()) {721    __ct.widen(__nf, __ns, __oe);722    __oe += __ns - __nf;723  } else {724    std::reverse(__nf, __ns);725    _CharT __thousands_sep = __npt.thousands_sep();726    unsigned __dc          = 0;727    unsigned __dg          = 0;728    for (char* __p = __nf; __p < __ns; ++__p) {729      if (__grouping[__dg] > 0 && __dc == static_cast<unsigned>(__grouping[__dg])) {730        *__oe++ = __thousands_sep;731        __dc    = 0;732        if (__dg < __grouping.size() - 1)733          ++__dg;734      }735      *__oe++ = __ct.widen(*__p);736      ++__dc;737    }738    std::reverse(__ob + (__nf - __nb), __oe);739  }740  for (__nf = __ns; __nf < __ne; ++__nf) {741    if (*__nf == '.') {742      *__oe++ = __npt.decimal_point();743      ++__nf;744      break;745    } else746      *__oe++ = __ct.widen(*__nf);747  }748  __ct.widen(__nf, __ne, __oe);749  __oe += __ne - __nf;750  if (__np == __ne)751    __op = __oe;752  else753    __op = __ob + (__np - __nb);754}755 756extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_put<char>;757#  if _LIBCPP_HAS_WIDE_CHARACTERS758extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_put<wchar_t>;759#  endif760 761template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >762class num_put : public locale::facet, private __num_put<_CharT> {763public:764  typedef _CharT char_type;765  typedef _OutputIterator iter_type;766 767  _LIBCPP_HIDE_FROM_ABI explicit num_put(size_t __refs = 0) : locale::facet(__refs) {}768 769  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, bool __v) const {770    return do_put(__s, __iob, __fl, __v);771  }772 773  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, long __v) const {774    return do_put(__s, __iob, __fl, __v);775  }776 777  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, long long __v) const {778    return do_put(__s, __iob, __fl, __v);779  }780 781  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long __v) const {782    return do_put(__s, __iob, __fl, __v);783  }784 785  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long long __v) const {786    return do_put(__s, __iob, __fl, __v);787  }788 789  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, double __v) const {790    return do_put(__s, __iob, __fl, __v);791  }792 793  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, long double __v) const {794    return do_put(__s, __iob, __fl, __v);795  }796 797  _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, const void* __v) const {798    return do_put(__s, __iob, __fl, __v);799  }800 801  static locale::id id;802 803protected:804  _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~num_put() override {}805 806  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, bool __v) const;807  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, long __v) const;808  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, long long __v) const;809  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long) const;810  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long long) const;811  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, double __v) const;812  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, long double __v) const;813  virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, const void* __v) const;814 815  template <class _Integral>816  _LIBCPP_HIDE_FROM_ABI inline _OutputIterator817  __do_put_integral(iter_type __s, ios_base& __iob, char_type __fl, _Integral __v) const;818 819  template <class _Float>820  _LIBCPP_HIDE_FROM_ABI inline _OutputIterator821  __do_put_floating_point(iter_type __s, ios_base& __iob, char_type __fl, _Float __v, char const* __len) const;822};823 824template <class _CharT, class _OutputIterator>825locale::id num_put<_CharT, _OutputIterator>::id;826 827template <class _CharT, class _OutputIterator>828_OutputIterator829num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, bool __v) const {830  if ((__iob.flags() & ios_base::boolalpha) == 0)831    return do_put(__s, __iob, __fl, (unsigned long)__v);832  const numpunct<char_type>& __np = std::use_facet<numpunct<char_type> >(__iob.getloc());833  typedef typename numpunct<char_type>::string_type string_type;834  string_type __nm = __v ? __np.truename() : __np.falsename();835  return std::copy(__nm.begin(), __nm.end(), __s);836}837 838template <class _CharT, class _OutputIterator>839template <class _Integral>840_LIBCPP_HIDE_FROM_ABI inline _OutputIterator num_put<_CharT, _OutputIterator>::__do_put_integral(841    iter_type __s, ios_base& __iob, char_type __fl, _Integral __v) const {842  // Stage 1 - Get number in narrow char843 844  // Worst case is octal, with showbase enabled. Note that octal is always845  // printed as an unsigned value.846  using _Unsigned = typename make_unsigned<_Integral>::type;847  _LIBCPP_CONSTEXPR const unsigned __buffer_size =848      (numeric_limits<_Unsigned>::digits / 3)          // 1 char per 3 bits849      + ((numeric_limits<_Unsigned>::digits % 3) != 0) // round up850      + 2;                                             // base prefix + terminating null character851 852  char __char_buffer[__buffer_size];853  char* __buffer_ptr = __char_buffer;854 855  auto __flags = __iob.flags();856 857  auto __basefield = (__flags & ios_base::basefield);858 859  // Extract base860  int __base = 10;861  if (__basefield == ios_base::oct)862    __base = 8;863  else if (__basefield == ios_base::hex)864    __base = 16;865 866  // Print '-' and make the argument unsigned867  auto __uval = std::__to_unsigned_like(__v);868  if (__basefield != ios_base::oct && __basefield != ios_base::hex && __v < 0) {869    *__buffer_ptr++ = '-';870    __uval          = std::__complement(__uval);871  }872 873  // Maybe add '+' prefix874  if (std::is_signed<_Integral>::value && (__flags & ios_base::showpos) && __basefield != ios_base::oct &&875      __basefield != ios_base::hex && __v >= 0)876    *__buffer_ptr++ = '+';877 878  // Add base prefix879  if (__v != 0 && __flags & ios_base::showbase) {880    if (__basefield == ios_base::oct) {881      *__buffer_ptr++ = '0';882    } else if (__basefield == ios_base::hex) {883      *__buffer_ptr++ = '0';884      *__buffer_ptr++ = (__flags & ios_base::uppercase ? 'X' : 'x');885    }886  }887 888  auto __res = std::__to_chars_integral(__buffer_ptr, __char_buffer + __buffer_size, __uval, __base);889  _LIBCPP_ASSERT_INTERNAL(__res.__ec == std::errc(0), "to_chars: invalid maximum buffer size computed?");890 891  // Make letters uppercase892  if (__flags & ios_base::hex && __flags & ios_base::uppercase) {893    for (; __buffer_ptr != __res.__ptr; ++__buffer_ptr)894      *__buffer_ptr = std::__hex_to_upper(*__buffer_ptr);895  }896 897  char* __np = this->__identify_padding(__char_buffer, __res.__ptr, __iob);898  // Stage 2 - Widen __nar while adding thousands separators899  char_type __o[2 * (__buffer_size - 1) - 1];900  char_type* __op; // pad here901  char_type* __oe; // end of output902  this->__widen_and_group_int(__char_buffer, __np, __res.__ptr, __o, __op, __oe, __iob.getloc());903  // [__o, __oe) contains thousands_sep'd wide number904  // Stage 3 & 4905  return std::__pad_and_output(__s, __o, __op, __oe, __iob, __fl);906}907 908template <class _CharT, class _OutputIterator>909_OutputIterator910num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, long __v) const {911  return this->__do_put_integral(__s, __iob, __fl, __v);912}913 914template <class _CharT, class _OutputIterator>915_OutputIterator916num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, long long __v) const {917  return this->__do_put_integral(__s, __iob, __fl, __v);918}919 920template <class _CharT, class _OutputIterator>921_OutputIterator922num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long __v) const {923  return this->__do_put_integral(__s, __iob, __fl, __v);924}925 926template <class _CharT, class _OutputIterator>927_OutputIterator928num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long long __v) const {929  return this->__do_put_integral(__s, __iob, __fl, __v);930}931 932template <class _CharT, class _OutputIterator>933template <class _Float>934_LIBCPP_HIDE_FROM_ABI inline _OutputIterator num_put<_CharT, _OutputIterator>::__do_put_floating_point(935    iter_type __s, ios_base& __iob, char_type __fl, _Float __v, char const* __len) const {936  // Stage 1 - Get number in narrow char937  char __fmt[8]            = {'%', 0};938  bool __specify_precision = this->__format_float(__fmt + 1, __len, __iob.flags());939  const unsigned __nbuf    = 30;940  char __nar[__nbuf];941  char* __nb = __nar;942  int __nc;943  _LIBCPP_DIAGNOSTIC_PUSH944  _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")945  _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")946  if (__specify_precision)947    __nc = __locale::__snprintf(__nb, __nbuf, _LIBCPP_GET_C_LOCALE, __fmt, (int)__iob.precision(), __v);948  else949    __nc = __locale::__snprintf(__nb, __nbuf, _LIBCPP_GET_C_LOCALE, __fmt, __v);950  unique_ptr<char, void (*)(void*)> __nbh(nullptr, free);951  if (__nc > static_cast<int>(__nbuf - 1)) {952    if (__specify_precision)953      __nc = __locale::__asprintf(&__nb, _LIBCPP_GET_C_LOCALE, __fmt, (int)__iob.precision(), __v);954    else955      __nc = __locale::__asprintf(&__nb, _LIBCPP_GET_C_LOCALE, __fmt, __v);956    if (__nc == -1)957      std::__throw_bad_alloc();958    __nbh.reset(__nb);959  }960  _LIBCPP_DIAGNOSTIC_POP961  char* __ne = __nb + __nc;962  char* __np = this->__identify_padding(__nb, __ne, __iob);963  // Stage 2 - Widen __nar while adding thousands separators964  char_type __o[2 * (__nbuf - 1) - 1];965  char_type* __ob = __o;966  unique_ptr<char_type, void (*)(void*)> __obh(0, free);967  if (__nb != __nar) {968    __ob = (char_type*)malloc(2 * static_cast<size_t>(__nc) * sizeof(char_type));969    if (__ob == 0)970      std::__throw_bad_alloc();971    __obh.reset(__ob);972  }973  char_type* __op; // pad here974  char_type* __oe; // end of output975  this->__widen_and_group_float(__nb, __np, __ne, __ob, __op, __oe, __iob.getloc());976  // [__o, __oe) contains thousands_sep'd wide number977  // Stage 3 & 4978  __s = std::__pad_and_output(__s, __ob, __op, __oe, __iob, __fl);979  return __s;980}981 982template <class _CharT, class _OutputIterator>983_OutputIterator984num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, double __v) const {985  return this->__do_put_floating_point(__s, __iob, __fl, __v, "");986}987 988template <class _CharT, class _OutputIterator>989_OutputIterator990num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, long double __v) const {991  return this->__do_put_floating_point(__s, __iob, __fl, __v, "L");992}993 994template <class _CharT, class _OutputIterator>995_OutputIterator996num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, const void* __v) const {997  auto __flags = __iob.flags();998  __iob.flags((__flags & ~ios_base::basefield & ~ios_base::uppercase) | ios_base::hex | ios_base::showbase);999  auto __res = __do_put_integral(__s, __iob, __fl, reinterpret_cast<uintptr_t>(__v));1000  __iob.flags(__flags);1001  return __res;1002}1003 1004extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_put<char>;1005#  if _LIBCPP_HAS_WIDE_CHARACTERS1006extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_put<wchar_t>;1007#  endif1008 1009_LIBCPP_END_NAMESPACE_STD1010 1011_LIBCPP_POP_MACROS1012 1013// NOLINTEND(libcpp-robust-against-adl)1014 1015#endif // _LIBCPP_HAS_LOCALIZATION1016 1017#endif // _LIBCPP___LOCALE_DIR_NUM_H1018