[libc++] Optimize num_get integral functions (#121795)
```
---------------------------------------------------
Benchmark old new
---------------------------------------------------
BM_num_get<bool> 86.5 ns 32.3 ns
BM_num_get<long> 82.1 ns 30.3 ns
BM_num_get<long long> 85.2 ns 33.4 ns
BM_num_get<unsigned short> 85.3 ns 31.2 ns
BM_num_get<unsigned int> 84.2 ns 31.1 ns
BM_num_get<unsigned long> 83.6 ns 31.9 ns
BM_num_get<unsigned long long> 87.7 ns 31.5 ns
BM_num_get<float> 116 ns 114 ns
BM_num_get<double> 114 ns 114 ns
BM_num_get<long double> 113 ns 114 ns
BM_num_get<void*> 151 ns 144 ns
```
This patch applies multiple optimizations:
- Stages two and three of do_get are merged and a custom integer parser
has been implemented
This avoids allocations, removes the need for strto{,u}ll and avoids
__stage2_int_loop (avoiding extra writes to memory)
- std::find has been replaced with __atoms_offset, which uses vector
instructions to look for a character
Fixes #158100
Fixes #158102
This commit is contained in:
parent
29cfef1880
commit
2bdd1357c8
@ -83,6 +83,8 @@ Improvements and New Features
|
||||
iterators, resulting in a performance improvement for ``std::deque<short>`` and
|
||||
``std::join_view<vector<vector<short>>>`` iterators.
|
||||
|
||||
- The ``num_get::do_get`` integral overloads have been optimized, resulting in a performance improvement of up to 2.8x.
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
|
||||
@ -520,7 +520,6 @@ set(files
|
||||
__locale_dir/locale_base_api.h
|
||||
__locale_dir/locale_base_api/bsd_locale_fallbacks.h
|
||||
__locale_dir/locale_base_api/ibm.h
|
||||
__locale_dir/locale_base_api/musl.h
|
||||
__locale_dir/locale_base_api/openbsd.h
|
||||
__locale_dir/messages.h
|
||||
__locale_dir/money.h
|
||||
|
||||
@ -114,6 +114,27 @@ template <class _VecT, class _Iter>
|
||||
}(make_index_sequence<__simd_vector_size_v<_VecT>>{});
|
||||
}
|
||||
|
||||
// Load the first _Np elements, zero the rest
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")
|
||||
template <class _VecT, size_t _Np, class _Iter>
|
||||
[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT __partial_load(_Iter __iter) noexcept {
|
||||
return [=]<size_t... _LoadIndices, size_t... _ZeroIndices>(
|
||||
index_sequence<_LoadIndices...>, index_sequence<_ZeroIndices...>) _LIBCPP_ALWAYS_INLINE noexcept {
|
||||
return _VecT{__iter[_LoadIndices]..., ((void)_ZeroIndices, 0)...};
|
||||
}(make_index_sequence<_Np>{}, make_index_sequence<__simd_vector_size_v<_VecT> - _Np>{});
|
||||
}
|
||||
|
||||
// Create a vector where every elements is __val
|
||||
template <class _VecT>
|
||||
[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT
|
||||
__broadcast(__simd_vector_underlying_type_t<_VecT> __val) {
|
||||
return [&]<std::size_t... _Indices>(index_sequence<_Indices...>) {
|
||||
return _VecT{((void)_Indices, __val)...};
|
||||
}(make_index_sequence<__simd_vector_size_v<_VecT>>());
|
||||
}
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
|
||||
template <class _Tp, size_t _Np>
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __any_of(__simd_vector<_Tp, _Np> __vec) noexcept {
|
||||
return __builtin_reduce_or(__builtin_convertvector(__vec, __simd_vector<bool, _Np>));
|
||||
@ -124,6 +145,11 @@ template <class _Tp, size_t _Np>
|
||||
return __builtin_reduce_and(__builtin_convertvector(__vec, __simd_vector<bool, _Np>));
|
||||
}
|
||||
|
||||
template <class _Tp, size_t _Np>
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __none_of(__simd_vector<_Tp, _Np> __vec) noexcept {
|
||||
return !__builtin_reduce_or(__builtin_convertvector(__vec, __simd_vector<bool, _Np>));
|
||||
}
|
||||
|
||||
template <class _Tp, size_t _Np>
|
||||
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t __find_first_set(__simd_vector<_Tp, _Np> __vec) noexcept {
|
||||
using __mask_vec = __simd_vector<bool, _Np>;
|
||||
|
||||
@ -57,8 +57,6 @@
|
||||
// float __strtof(const char*, char**, __locale_t);
|
||||
// double __strtod(const char*, char**, __locale_t);
|
||||
// long double __strtold(const char*, char**, __locale_t);
|
||||
// long long __strtoll(const char*, char**, __locale_t);
|
||||
// unsigned long long __strtoull(const char*, char**, __locale_t);
|
||||
// }
|
||||
//
|
||||
// Character manipulation functions
|
||||
@ -104,7 +102,6 @@
|
||||
//
|
||||
// int __snprintf(char*, size_t, __locale_t, const char*, ...); // required by the headers
|
||||
// int __asprintf(char**, __locale_t, const char*, ...); // required by the headers
|
||||
// int __sscanf(const char*, __locale_t, const char*, ...); // required by the headers
|
||||
// }
|
||||
|
||||
#if _LIBCPP_HAS_LOCALIZATION
|
||||
@ -131,8 +128,6 @@
|
||||
# include <__locale_dir/locale_base_api/ibm.h>
|
||||
# elif defined(__OpenBSD__)
|
||||
# include <__locale_dir/locale_base_api/openbsd.h>
|
||||
# elif defined(__wasi__) || _LIBCPP_HAS_MUSL_LIBC
|
||||
# include <__locale_dir/locale_base_api/musl.h>
|
||||
# endif
|
||||
|
||||
# include <__locale_dir/locale_base_api/bsd_locale_fallbacks.h>
|
||||
@ -192,15 +187,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __
|
||||
return strtold_l(__nptr, __endptr, __loc);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
return strtoll_l(__nptr, __endptr, __base, __loc);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
return strtoull_l(__nptr, __endptr, __base, __loc);
|
||||
}
|
||||
|
||||
//
|
||||
// Character manipulation functions
|
||||
//
|
||||
@ -299,11 +285,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __
|
||||
char** __s, __locale_t __loc, const char* __format, _Args&&... __args) {
|
||||
return std::__libcpp_asprintf_l(__s, __loc, __format, std::forward<_Args>(__args)...);
|
||||
}
|
||||
template <class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf(
|
||||
const char* __s, __locale_t __loc, const char* __format, _Args&&... __args) {
|
||||
return std::__libcpp_sscanf_l(__s, __loc, __format, std::forward<_Args>(__args)...);
|
||||
}
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
# undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT
|
||||
|
||||
|
||||
@ -125,16 +125,6 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __libcpp_asprintf_l(
|
||||
return __res;
|
||||
}
|
||||
|
||||
inline _LIBCPP_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __libcpp_sscanf_l(
|
||||
const char* __s, locale_t __l, const char* __format, ...) {
|
||||
va_list __va;
|
||||
va_start(__va, __format);
|
||||
__locale_guard __current(__l);
|
||||
int __res = vsscanf(__s, __format, __va);
|
||||
va_end(__va);
|
||||
return __res;
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H
|
||||
|
||||
@ -53,11 +53,6 @@ private:
|
||||
|
||||
// The following are not POSIX routines. These are quick-and-dirty hacks
|
||||
// to make things pretend to work
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtoll(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI double strtod_l(const char* __nptr, char** __endptr, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtod(__nptr, __endptr);
|
||||
@ -73,12 +68,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double strtold_l(const char* __nptr, char** __
|
||||
return ::strtold(__nptr, __endptr);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t locale) {
|
||||
__setAndRestore __newloc(locale);
|
||||
return ::strtoull(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char* fmt, va_list ap) {
|
||||
const size_t buff_size = 256;
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
//===-----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This adds support for the extended locale functions that are currently
|
||||
// missing from the Musl C library.
|
||||
//
|
||||
// This only works when the specified locale is "C" or "POSIX", but that's
|
||||
// about as good as we can do without implementing full xlocale support
|
||||
// in Musl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_MUSL_H
|
||||
#define _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_MUSL_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cwchar>
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t) {
|
||||
return ::strtoll(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t) {
|
||||
return ::strtoull(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_MUSL_H
|
||||
@ -12,6 +12,7 @@
|
||||
#include <__algorithm/copy.h>
|
||||
#include <__algorithm/find.h>
|
||||
#include <__algorithm/reverse.h>
|
||||
#include <__algorithm/simd_utils.h>
|
||||
#include <__charconv/to_chars_integral.h>
|
||||
#include <__charconv/traits.h>
|
||||
#include <__config>
|
||||
@ -48,9 +49,9 @@ struct _LIBCPP_EXPORTED_FROM_ABI __num_get_base {
|
||||
static int __get_base(ios_base&);
|
||||
static const char __src[33]; // "0123456789abcdefABCDEFxX+-pPiInN"
|
||||
// count of leading characters in __src used for parsing integers ("012..X+-")
|
||||
static const size_t __int_chr_cnt = 26;
|
||||
static inline const size_t __int_chr_cnt = 26;
|
||||
// count of leading characters in __src used for parsing floating-point values ("012..-pP")
|
||||
static const size_t __fp_chr_cnt = 28;
|
||||
static inline const size_t __fp_chr_cnt = 28;
|
||||
};
|
||||
|
||||
template <class _CharT>
|
||||
@ -73,7 +74,8 @@ struct __num_get : protected __num_get_base {
|
||||
|
||||
[[__deprecated__("This exists only for ABI compatibility")]] static string
|
||||
__stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep);
|
||||
static int __stage2_int_loop(
|
||||
|
||||
[[__deprecated__("This exists only for ABI compatibility")]] static int __stage2_int_loop(
|
||||
_CharT __ct,
|
||||
int __base,
|
||||
char* __a,
|
||||
@ -85,11 +87,24 @@ struct __num_get : protected __num_get_base {
|
||||
unsigned*& __g_end,
|
||||
_CharT* __atoms);
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI static string __stage2_int_prep(ios_base& __iob, _CharT& __thousands_sep) {
|
||||
locale __loc = __iob.getloc();
|
||||
const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
|
||||
__thousands_sep = __np.thousands_sep();
|
||||
return __np.grouping();
|
||||
_LIBCPP_HIDE_FROM_ABI static ptrdiff_t __atoms_offset(const _CharT* __atoms, _CharT __val) {
|
||||
// TODO: Remove the manual vectorization once https://llvm.org/PR168551 is resolved
|
||||
# if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS
|
||||
if constexpr (is_same<_CharT, char>::value) {
|
||||
// TODO(LLVM 24): This can be removed, since -Wpsabi doesn't warn on [[gnu::always_inline]] functions anymore.
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")
|
||||
using __vec = __simd_vector<char, 32>;
|
||||
__vec __chars = std::__broadcast<__vec>(__val);
|
||||
__vec __cmp = std::__partial_load<__vec, __int_chr_cnt>(__atoms);
|
||||
auto __res = __chars == __cmp;
|
||||
if (std::__none_of(__res))
|
||||
return __int_chr_cnt;
|
||||
return std::min(__int_chr_cnt, std::__find_first_set(__res));
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
}
|
||||
# endif
|
||||
return std::find(__atoms, __atoms + __int_chr_cnt, __val) - __atoms;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI const _CharT* __do_widen(ios_base& __iob, _CharT* __atoms) const {
|
||||
@ -122,54 +137,6 @@ string __num_get<_CharT>::__stage2_float_prep(
|
||||
return __np.grouping();
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
int __num_get<_CharT>::__stage2_int_loop(
|
||||
_CharT __ct,
|
||||
int __base,
|
||||
char* __a,
|
||||
char*& __a_end,
|
||||
unsigned& __dc,
|
||||
_CharT __thousands_sep,
|
||||
const string& __grouping,
|
||||
unsigned* __g,
|
||||
unsigned*& __g_end,
|
||||
_CharT* __atoms) {
|
||||
if (__a_end == __a && (__ct == __atoms[24] || __ct == __atoms[25])) {
|
||||
*__a_end++ = __ct == __atoms[24] ? '+' : '-';
|
||||
__dc = 0;
|
||||
return 0;
|
||||
}
|
||||
if (__grouping.size() != 0 && __ct == __thousands_sep) {
|
||||
if (__g_end - __g < __num_get_buf_sz) {
|
||||
*__g_end++ = __dc;
|
||||
__dc = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ptrdiff_t __f = std::find(__atoms, __atoms + __int_chr_cnt, __ct) - __atoms;
|
||||
if (__f >= 24)
|
||||
return -1;
|
||||
switch (__base) {
|
||||
case 8:
|
||||
case 10:
|
||||
if (__f >= __base)
|
||||
return -1;
|
||||
break;
|
||||
case 16:
|
||||
if (__f < 22)
|
||||
break;
|
||||
if (__a_end != __a && __a_end - __a <= 2 && __a_end[-1] == '0') {
|
||||
__dc = 0;
|
||||
*__a_end++ = __src[__f];
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
*__a_end++ = __src[__f];
|
||||
++__dc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
int __num_get<_CharT>::__stage2_float_loop(
|
||||
_CharT __ct,
|
||||
@ -274,65 +241,6 @@ _LIBCPP_HIDE_FROM_ABI _Tp __num_get_float(const char* __a, const char* __a_end,
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI _Tp
|
||||
__num_get_signed_integral(const char* __a, const char* __a_end, ios_base::iostate& __err, int __base) {
|
||||
if (__a != __a_end) {
|
||||
__libcpp_remove_reference_t<decltype(errno)> __save_errno = errno;
|
||||
errno = 0;
|
||||
char* __p2;
|
||||
long long __ll = __locale::__strtoll(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE);
|
||||
__libcpp_remove_reference_t<decltype(errno)> __current_errno = errno;
|
||||
if (__current_errno == 0)
|
||||
errno = __save_errno;
|
||||
if (__p2 != __a_end) {
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
} else if (__current_errno == ERANGE || __ll < numeric_limits<_Tp>::min() || numeric_limits<_Tp>::max() < __ll) {
|
||||
__err = ios_base::failbit;
|
||||
if (__ll > 0)
|
||||
return numeric_limits<_Tp>::max();
|
||||
else
|
||||
return numeric_limits<_Tp>::min();
|
||||
}
|
||||
return static_cast<_Tp>(__ll);
|
||||
}
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI _Tp
|
||||
__num_get_unsigned_integral(const char* __a, const char* __a_end, ios_base::iostate& __err, int __base) {
|
||||
if (__a != __a_end) {
|
||||
const bool __negate = *__a == '-';
|
||||
if (__negate && ++__a == __a_end) {
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
}
|
||||
__libcpp_remove_reference_t<decltype(errno)> __save_errno = errno;
|
||||
errno = 0;
|
||||
char* __p2;
|
||||
unsigned long long __ll = __locale::__strtoull(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE);
|
||||
__libcpp_remove_reference_t<decltype(errno)> __current_errno = errno;
|
||||
if (__current_errno == 0)
|
||||
errno = __save_errno;
|
||||
if (__p2 != __a_end) {
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
} else if (__current_errno == ERANGE || numeric_limits<_Tp>::max() < __ll) {
|
||||
__err = ios_base::failbit;
|
||||
return numeric_limits<_Tp>::max();
|
||||
}
|
||||
_Tp __res = static_cast<_Tp>(__ll);
|
||||
if (__negate)
|
||||
__res = -__res;
|
||||
return __res;
|
||||
}
|
||||
__err = ios_base::failbit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >
|
||||
class num_get : public locale::facet, private __num_get<_CharT> {
|
||||
public:
|
||||
@ -470,137 +378,194 @@ protected:
|
||||
return __b;
|
||||
}
|
||||
|
||||
template <class _Signed>
|
||||
_LIBCPP_HIDE_FROM_ABI iter_type
|
||||
__do_get_signed(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Signed& __v) const {
|
||||
// Stage 1
|
||||
int __base = this->__get_base(__iob);
|
||||
// Stage 2
|
||||
char_type __thousands_sep;
|
||||
const int __atoms_size = __num_get_base::__int_chr_cnt;
|
||||
char_type __atoms1[__atoms_size];
|
||||
const char_type* __atoms = this->__do_widen(__iob, __atoms1);
|
||||
string __grouping = this->__stage2_int_prep(__iob, __thousands_sep);
|
||||
string __buf;
|
||||
__buf.resize(__buf.capacity());
|
||||
char* __a = &__buf[0];
|
||||
char* __a_end = __a;
|
||||
unsigned __g[__num_get_base::__num_get_buf_sz];
|
||||
unsigned* __g_end = __g;
|
||||
unsigned __dc = 0;
|
||||
for (; __b != __e; ++__b) {
|
||||
if (__a_end == __a + __buf.size()) {
|
||||
size_t __tmp = __buf.size();
|
||||
__buf.resize(2 * __buf.size());
|
||||
__buf.resize(__buf.capacity());
|
||||
__a = &__buf[0];
|
||||
__a_end = __a + __tmp;
|
||||
}
|
||||
if (this->__stage2_int_loop(
|
||||
*__b,
|
||||
__base,
|
||||
__a,
|
||||
__a_end,
|
||||
__dc,
|
||||
__thousands_sep,
|
||||
__grouping,
|
||||
__g,
|
||||
__g_end,
|
||||
const_cast<char_type*>(__atoms)))
|
||||
break;
|
||||
}
|
||||
if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz)
|
||||
*__g_end++ = __dc;
|
||||
// Stage 3
|
||||
__v = std::__num_get_signed_integral<_Signed>(__a, __a_end, __err, __base);
|
||||
// Digit grouping checked
|
||||
__check_grouping(__grouping, __g, __g_end, __err);
|
||||
// EOF checked
|
||||
if (__b == __e)
|
||||
__err |= ios_base::eofbit;
|
||||
return __b;
|
||||
}
|
||||
template <class _MaybeSigned>
|
||||
iter_type __do_get_integral(
|
||||
iter_type __first, iter_type __last, ios_base& __iob, ios_base::iostate& __err, _MaybeSigned& __v) const {
|
||||
using _Unsigned = __make_unsigned_t<_MaybeSigned>;
|
||||
|
||||
template <class _Unsigned>
|
||||
_LIBCPP_HIDE_FROM_ABI iter_type
|
||||
__do_get_unsigned(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Unsigned& __v) const {
|
||||
// Stage 1
|
||||
int __base = this->__get_base(__iob);
|
||||
// Stage 2
|
||||
char_type __thousands_sep;
|
||||
const int __atoms_size = __num_get_base::__int_chr_cnt;
|
||||
char_type __atoms1[__atoms_size];
|
||||
const char_type* __atoms = this->__do_widen(__iob, __atoms1);
|
||||
string __grouping = this->__stage2_int_prep(__iob, __thousands_sep);
|
||||
string __buf;
|
||||
__buf.resize(__buf.capacity());
|
||||
char* __a = &__buf[0];
|
||||
char* __a_end = __a;
|
||||
|
||||
// Stages 2 & 3
|
||||
// These are combined into a single step where we parse the characters and calculate the value in one go instead of
|
||||
// storing the relevant characters first (in an allocated buffer) and parse the characters after we extracted them.
|
||||
// This makes the whole process significantly faster, since we avoid potential allocations and copies.
|
||||
|
||||
const auto& __numpunct = use_facet<numpunct<_CharT> >(__iob.getloc());
|
||||
char_type __thousands_sep = __numpunct.thousands_sep();
|
||||
string __grouping = __numpunct.grouping();
|
||||
|
||||
char_type __atoms_buffer[__num_get_base::__int_chr_cnt];
|
||||
const char_type* __atoms = this->__do_widen(__iob, __atoms_buffer);
|
||||
unsigned __g[__num_get_base::__num_get_buf_sz];
|
||||
unsigned* __g_end = __g;
|
||||
unsigned __dc = 0;
|
||||
for (; __b != __e; ++__b) {
|
||||
if (__a_end == __a + __buf.size()) {
|
||||
size_t __tmp = __buf.size();
|
||||
__buf.resize(2 * __buf.size());
|
||||
__buf.resize(__buf.capacity());
|
||||
__a = &__buf[0];
|
||||
__a_end = __a + __tmp;
|
||||
}
|
||||
if (this->__stage2_int_loop(
|
||||
*__b,
|
||||
__base,
|
||||
__a,
|
||||
__a_end,
|
||||
__dc,
|
||||
__thousands_sep,
|
||||
__grouping,
|
||||
__g,
|
||||
__g_end,
|
||||
const_cast<char_type*>(__atoms)))
|
||||
break;
|
||||
|
||||
if (__first == __last) {
|
||||
__err |= ios_base::eofbit | ios_base::failbit;
|
||||
__v = 0;
|
||||
return __first;
|
||||
}
|
||||
|
||||
while (!__grouping.empty() && *__first == __thousands_sep) {
|
||||
++__first;
|
||||
if (__g_end - __g < this->__num_get_buf_sz)
|
||||
*__g_end++ = 0;
|
||||
}
|
||||
|
||||
bool __negate = false;
|
||||
// __c == '+' || __c == '-'
|
||||
if (auto __c = *__first; __c == __atoms[24] || __c == __atoms[25]) {
|
||||
__negate = __c == __atoms[25];
|
||||
++__first;
|
||||
}
|
||||
|
||||
if (__first == __last) {
|
||||
__err |= ios_base::eofbit | ios_base::failbit;
|
||||
__v = 0;
|
||||
return __first;
|
||||
}
|
||||
|
||||
bool __parsed_num = false;
|
||||
|
||||
// If we don't have a pre-set base, figure it out and swallow any prefix
|
||||
if (__base == 0) {
|
||||
auto __c = *__first;
|
||||
// __c == '0'
|
||||
if (__c == __atoms[0]) {
|
||||
++__first;
|
||||
if (__first == __last) {
|
||||
__err |= ios_base::eofbit;
|
||||
return __first;
|
||||
}
|
||||
// __c2 == 'x' || __c2 == 'X'
|
||||
if (auto __c2 = *__first; __c2 == __atoms[22] || __c2 == __atoms[23]) {
|
||||
__base = 16;
|
||||
++__first;
|
||||
} else {
|
||||
__base = 8;
|
||||
}
|
||||
} else {
|
||||
__base = 10;
|
||||
}
|
||||
|
||||
// If the base has been specified explicitly, try to swallow the appropriate prefix. We only need to do something
|
||||
// special for hex, since decimal has no prefix and octal's prefix is '0', which doesn't change the value that
|
||||
// we'll parse if we don't swallow it.
|
||||
} else if (__base == 16) {
|
||||
// Try to swallow '0x'
|
||||
|
||||
// *__first == '0'
|
||||
if (*__first == __atoms[0]) {
|
||||
++__first;
|
||||
if (__first == __last) {
|
||||
__err |= ios_base::eofbit;
|
||||
__v = 0;
|
||||
return __first;
|
||||
}
|
||||
// __c == 'x' || __c == 'X'
|
||||
if (auto __c = *__first; __c == __atoms[22] || __c == __atoms[23])
|
||||
++__first;
|
||||
else
|
||||
__parsed_num = true; // We only swallowed '0', so we've started to parse a number
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the actual number
|
||||
_Unsigned __val = 0;
|
||||
bool __overflowed = false;
|
||||
for (; __first != __last; ++__first) {
|
||||
auto __c = *__first;
|
||||
if (!__grouping.empty() && __c == __thousands_sep) {
|
||||
if (__g_end - __g < this->__num_get_buf_sz) {
|
||||
*__g_end++ = __dc;
|
||||
__dc = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
auto __offset = this->__atoms_offset(__atoms, __c);
|
||||
if (__offset >= 22) // Not a valid integer character
|
||||
break;
|
||||
|
||||
if (__base == 16 && __offset >= 16)
|
||||
__offset -= 6;
|
||||
if (__offset >= __base)
|
||||
break;
|
||||
// __val = (__val * __base) + __offset
|
||||
__overflowed |= __builtin_mul_overflow(__val, __base, std::addressof(__val)) ||
|
||||
__builtin_add_overflow(__val, __offset, std::addressof(__val));
|
||||
__parsed_num = true;
|
||||
++__dc;
|
||||
}
|
||||
|
||||
if (!__parsed_num) {
|
||||
__err |= ios_base::failbit;
|
||||
__v = 0;
|
||||
} else if (__overflowed) {
|
||||
__err |= ios_base::failbit;
|
||||
__v = is_signed<_MaybeSigned>::value && __negate
|
||||
? numeric_limits<_MaybeSigned>::min()
|
||||
: numeric_limits<_MaybeSigned>::max();
|
||||
} else if (!__negate) {
|
||||
if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max())) {
|
||||
__err |= ios_base::failbit;
|
||||
__v = numeric_limits<_MaybeSigned>::max();
|
||||
} else {
|
||||
__v = __val;
|
||||
}
|
||||
} else if (is_signed<_MaybeSigned>::value) {
|
||||
if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
|
||||
__err |= ios_base::failbit;
|
||||
__v = numeric_limits<_MaybeSigned>::min();
|
||||
} else if (__val == static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
|
||||
__v = numeric_limits<_MaybeSigned>::min();
|
||||
} else {
|
||||
__v = -__val;
|
||||
}
|
||||
} else {
|
||||
__v = -__val;
|
||||
}
|
||||
|
||||
if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz)
|
||||
*__g_end++ = __dc;
|
||||
// Stage 3
|
||||
__v = std::__num_get_unsigned_integral<_Unsigned>(__a, __a_end, __err, __base);
|
||||
|
||||
// Digit grouping checked
|
||||
__check_grouping(__grouping, __g, __g_end, __err);
|
||||
// EOF checked
|
||||
if (__b == __e)
|
||||
if (__first == __last)
|
||||
__err |= ios_base::eofbit;
|
||||
return __b;
|
||||
return __first;
|
||||
}
|
||||
|
||||
virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const;
|
||||
|
||||
virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long& __v) const {
|
||||
return this->__do_get_signed(__b, __e, __iob, __err, __v);
|
||||
return this->__do_get_integral(__b, __e, __iob, __err, __v);
|
||||
}
|
||||
|
||||
virtual iter_type
|
||||
do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long long& __v) const {
|
||||
return this->__do_get_signed(__b, __e, __iob, __err, __v);
|
||||
return this->__do_get_integral(__b, __e, __iob, __err, __v);
|
||||
}
|
||||
|
||||
virtual iter_type
|
||||
do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned short& __v) const {
|
||||
return this->__do_get_unsigned(__b, __e, __iob, __err, __v);
|
||||
return this->__do_get_integral(__b, __e, __iob, __err, __v);
|
||||
}
|
||||
|
||||
virtual iter_type
|
||||
do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned int& __v) const {
|
||||
return this->__do_get_unsigned(__b, __e, __iob, __err, __v);
|
||||
return this->__do_get_integral(__b, __e, __iob, __err, __v);
|
||||
}
|
||||
|
||||
virtual iter_type
|
||||
do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long& __v) const {
|
||||
return this->__do_get_unsigned(__b, __e, __iob, __err, __v);
|
||||
return this->__do_get_integral(__b, __e, __iob, __err, __v);
|
||||
}
|
||||
|
||||
virtual iter_type
|
||||
do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long long& __v) const {
|
||||
return this->__do_get_unsigned(__b, __e, __iob, __err, __v);
|
||||
return this->__do_get_integral(__b, __e, __iob, __err, __v);
|
||||
}
|
||||
|
||||
virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, float& __v) const {
|
||||
@ -654,40 +619,13 @@ _InputIterator num_get<_CharT, _InputIterator>::do_get(
|
||||
template <class _CharT, class _InputIterator>
|
||||
_InputIterator num_get<_CharT, _InputIterator>::do_get(
|
||||
iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const {
|
||||
// Stage 1
|
||||
int __base = 16;
|
||||
// Stage 2
|
||||
char_type __atoms[__num_get_base::__int_chr_cnt];
|
||||
char_type __thousands_sep = char_type();
|
||||
string __grouping;
|
||||
std::use_facet<ctype<_CharT> >(__iob.getloc())
|
||||
.widen(__num_get_base::__src, __num_get_base::__src + __num_get_base::__int_chr_cnt, __atoms);
|
||||
string __buf;
|
||||
__buf.resize(__buf.capacity());
|
||||
char* __a = &__buf[0];
|
||||
char* __a_end = __a;
|
||||
unsigned __g[__num_get_base::__num_get_buf_sz];
|
||||
unsigned* __g_end = __g;
|
||||
unsigned __dc = 0;
|
||||
for (; __b != __e; ++__b) {
|
||||
if (__a_end == __a + __buf.size()) {
|
||||
size_t __tmp = __buf.size();
|
||||
__buf.resize(2 * __buf.size());
|
||||
__buf.resize(__buf.capacity());
|
||||
__a = &__buf[0];
|
||||
__a_end = __a + __tmp;
|
||||
}
|
||||
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc, __thousands_sep, __grouping, __g, __g_end, __atoms))
|
||||
break;
|
||||
}
|
||||
// Stage 3
|
||||
__buf.resize(__a_end - __a);
|
||||
if (__locale::__sscanf(__buf.c_str(), _LIBCPP_GET_C_LOCALE, "%p", &__v) != 1)
|
||||
__err = ios_base::failbit;
|
||||
// EOF checked
|
||||
if (__b == __e)
|
||||
__err |= ios_base::eofbit;
|
||||
return __b;
|
||||
auto __flags = __iob.flags();
|
||||
__iob.flags((__flags & ~ios_base::basefield & ~ios_base::uppercase) | ios_base::hex);
|
||||
uintptr_t __ptr;
|
||||
auto __res = __do_get_integral(__b, __e, __iob, __err, __ptr);
|
||||
__iob.flags(__flags);
|
||||
__v = reinterpret_cast<void*>(__ptr);
|
||||
return __res;
|
||||
}
|
||||
|
||||
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_get<char>;
|
||||
|
||||
@ -79,15 +79,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __
|
||||
return ::strtold_l(__nptr, __endptr, __loc);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
return ::strtoll_l(__nptr, __endptr, __base, __loc);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
return ::strtoull_l(__nptr, __endptr, __base, __loc);
|
||||
}
|
||||
|
||||
//
|
||||
// Character manipulation functions
|
||||
//
|
||||
@ -211,12 +202,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __
|
||||
char** __s, __locale_t __loc, const char* __format, _Args&&... __args) {
|
||||
return ::asprintf_l(__s, __loc, __format, std::forward<_Args>(__args)...); // non-standard
|
||||
}
|
||||
|
||||
template <class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf(
|
||||
const char* __s, __locale_t __loc, const char* __format, _Args&&... __args) {
|
||||
return ::sscanf_l(__s, __loc, __format, std::forward<_Args>(__args)...);
|
||||
}
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
#undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT
|
||||
|
||||
|
||||
@ -141,13 +141,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __
|
||||
__locale_guard __current(__loc);
|
||||
return ::asprintf(__s, __format, std::forward<_Args>(__args)...); // non-standard
|
||||
}
|
||||
template <class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf(
|
||||
const char* __s, __locale_t __loc, const char* __format, _Args&&... __args) {
|
||||
__locale_guard __current(__loc);
|
||||
return std::sscanf(__s, __format, std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
#undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT
|
||||
|
||||
|
||||
@ -94,25 +94,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __
|
||||
return ::strtold_l(__nptr, __endptr, __loc);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
#if !_LIBCPP_HAS_MUSL_LIBC
|
||||
return ::strtoll_l(__nptr, __endptr, __base, __loc);
|
||||
#else
|
||||
(void)__loc;
|
||||
return ::strtoll(__nptr, __endptr, __base);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
#if !_LIBCPP_HAS_MUSL_LIBC
|
||||
return ::strtoull_l(__nptr, __endptr, __base, __loc);
|
||||
#else
|
||||
(void)__loc;
|
||||
return ::strtoull(__nptr, __endptr, __base);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Character manipulation functions
|
||||
//
|
||||
@ -257,20 +238,6 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf(
|
||||
va_end(__va);
|
||||
return __res;
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_COMPILER_GCC // GCC complains that this can't be always_inline due to C-style varargs
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
#endif
|
||||
inline _LIBCPP_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf(
|
||||
const char* __s, __locale_t __loc, const char* __format, ...) {
|
||||
va_list __va;
|
||||
va_start(__va, __format);
|
||||
__locale_guard __current(__loc);
|
||||
int __res = std::vsscanf(__s, __format, __va);
|
||||
va_end(__va);
|
||||
return __res;
|
||||
}
|
||||
|
||||
} // namespace __locale
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
|
||||
@ -34,15 +34,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __
|
||||
return std::strtold(__nptr, __endptr);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t) {
|
||||
return std::strtoll(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t) {
|
||||
return std::strtoull(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
} // namespace __locale
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
|
||||
@ -186,14 +186,6 @@ inline _LIBCPP_HIDE_FROM_ABI double __strtod(const char* __nptr, char** __endptr
|
||||
return ::_strtod_l(__nptr, __endptr, __loc);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
return ::_strtoi64_l(__nptr, __endptr, __base, __loc);
|
||||
}
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long
|
||||
__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
|
||||
return ::_strtoui64_l(__nptr, __endptr, __base, __loc);
|
||||
}
|
||||
|
||||
//
|
||||
// Character manipulation functions
|
||||
//
|
||||
@ -276,23 +268,6 @@ _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 4, 5) int __snpri
|
||||
_LIBCPP_EXPORTED_FROM_ABI
|
||||
_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf(char** __ret, __locale_t __loc, const char* __format, ...);
|
||||
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgcc-compat")
|
||||
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wformat-nonliteral") // GCC doesn't support [[gnu::format]] on variadic templates
|
||||
#ifdef _LIBCPP_COMPILER_CLANG_BASED
|
||||
# define _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(...) _LIBCPP_ATTRIBUTE_FORMAT(__VA_ARGS__)
|
||||
#else
|
||||
# define _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(...) /* nothing */
|
||||
#endif
|
||||
|
||||
template <class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf(
|
||||
const char* __dest, __locale_t __loc, const char* __format, _Args&&... __args) {
|
||||
return ::_sscanf_l(__dest, __format, __loc, std::forward<_Args>(__args)...);
|
||||
}
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
#undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT
|
||||
|
||||
#if defined(_LIBCPP_BUILDING_LIBRARY)
|
||||
struct __locale_guard {
|
||||
_LIBCPP_HIDE_FROM_ABI __locale_guard(__locale_t __l) : __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)) {
|
||||
|
||||
@ -34,12 +34,4 @@ inline _LIBCPP_HIDE_FROM_ABI long double strtold_l(const char* __nptr, char** __
|
||||
return ::strtold(__nptr, __endptr);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t) {
|
||||
return ::strtoll(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI unsigned long long strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t) {
|
||||
return ::strtoull(__nptr, __endptr, __base);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP___SUPPORT_XLOCALE_STRTONUM_FALLBACK_H
|
||||
|
||||
@ -1591,7 +1591,6 @@ module std [system] {
|
||||
module locale_base_api {
|
||||
textual header "__locale_dir/locale_base_api/bsd_locale_fallbacks.h"
|
||||
textual header "__locale_dir/locale_base_api/ibm.h"
|
||||
textual header "__locale_dir/locale_base_api/musl.h"
|
||||
textual header "__locale_dir/locale_base_api/openbsd.h"
|
||||
}
|
||||
export *
|
||||
|
||||
@ -5557,6 +5557,54 @@ string __num_get<_CharT>::__stage2_int_prep(ios_base& __iob, _CharT* __atoms, _C
|
||||
return __np.grouping();
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
int __num_get<_CharT>::__stage2_int_loop(
|
||||
_CharT __ct,
|
||||
int __base,
|
||||
char* __a,
|
||||
char*& __a_end,
|
||||
unsigned& __dc,
|
||||
_CharT __thousands_sep,
|
||||
const string& __grouping,
|
||||
unsigned* __g,
|
||||
unsigned*& __g_end,
|
||||
_CharT* __atoms) {
|
||||
if (__a_end == __a && (__ct == __atoms[24] || __ct == __atoms[25])) {
|
||||
*__a_end++ = __ct == __atoms[24] ? '+' : '-';
|
||||
__dc = 0;
|
||||
return 0;
|
||||
}
|
||||
if (__grouping.size() != 0 && __ct == __thousands_sep) {
|
||||
if (__g_end - __g < __num_get_buf_sz) {
|
||||
*__g_end++ = __dc;
|
||||
__dc = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ptrdiff_t __f = __atoms_offset(__atoms, __ct);
|
||||
if (__f >= 24)
|
||||
return -1;
|
||||
switch (__base) {
|
||||
case 8:
|
||||
case 10:
|
||||
if (__f >= __base)
|
||||
return -1;
|
||||
break;
|
||||
case 16:
|
||||
if (__f < 22)
|
||||
break;
|
||||
if (__a_end != __a && __a_end - __a <= 2 && __a_end[-1] == '0') {
|
||||
__dc = 0;
|
||||
*__a_end++ = __src[__f];
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
*__a_end++ = __src[__f];
|
||||
++__dc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
|
||||
_LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;)
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
// iter_type get(iter_type in, iter_type end, ios_base&,
|
||||
// ios_base::iostate& err, long& v) const;
|
||||
|
||||
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
|
||||
|
||||
#include <locale>
|
||||
#include <ios>
|
||||
#include <cassert>
|
||||
@ -98,6 +100,18 @@ int main(int, char**)
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 291);
|
||||
}
|
||||
{
|
||||
const char str[] = "a123";
|
||||
std::dec(ios);
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str),
|
||||
cpp17_input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(base(iter) == str);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == 0);
|
||||
}
|
||||
{
|
||||
const char str[] = "0x123";
|
||||
std::hex(ios);
|
||||
@ -519,6 +533,142 @@ int main(int, char**)
|
||||
assert(err == ios.failbit);
|
||||
assert(v == std::numeric_limits<long>::max());
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
const char str[] = "";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str), cpp17_input_iterator<const char*>(str), ios, err, v);
|
||||
assert(base(iter) == str);
|
||||
assert(err == (std::ios::eofbit | std::ios::failbit));
|
||||
assert(v == 0);
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
const char str[] = "+";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str), cpp17_input_iterator<const char*>(str + 1), ios, err, v);
|
||||
assert(base(iter) == str + 1);
|
||||
assert(err == (std::ios::eofbit | std::ios::failbit));
|
||||
assert(v == 0);
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
const char str[] = "+";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(std::begin(str)),
|
||||
cpp17_input_iterator<const char*>(std::end(str)),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str + 1);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == 0);
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
const char str[] = "-";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(std::begin(str)),
|
||||
cpp17_input_iterator<const char*>(std::end(str)),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str + 1);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == 0);
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
const char str[] = "0";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(std::begin(str)),
|
||||
cpp17_input_iterator<const char*>(std::end(str)),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str + 1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 0);
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
const char str[] = "078";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
ios.flags(ios.flags() & ~ios.basefield);
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(std::begin(str)),
|
||||
cpp17_input_iterator<const char*>(std::end(str)),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str + 2);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 7);
|
||||
ios.flags(ios.flags() | ios.dec);
|
||||
}
|
||||
{
|
||||
v = -1;
|
||||
std::string str = std::to_string(std::numeric_limits<unsigned long>::max()) + "99a";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(str.data()),
|
||||
cpp17_input_iterator<const char*>(str.data() + str.size()),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str.data() + str.size() - 1);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == std::numeric_limits<long>::max());
|
||||
}
|
||||
{
|
||||
std::string str = std::to_string(std::numeric_limits<long>::max()) + 'c';
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str.data()),
|
||||
cpp17_input_iterator<const char*>(str.data() + str.size()),
|
||||
ios, err, v);
|
||||
assert(base(iter) == str.data() + str.size() - 1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == std::numeric_limits<long>::max());
|
||||
}
|
||||
{
|
||||
std::string str = std::to_string(static_cast<unsigned long>(std::numeric_limits<long>::max()) + 1) + 'c';
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(str.data()),
|
||||
cpp17_input_iterator<const char*>(str.data() + str.size()),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str.data() + str.size() - 1);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == std::numeric_limits<long>::max());
|
||||
}
|
||||
{
|
||||
std::string str = '-' + std::to_string(static_cast<unsigned long>(std::numeric_limits<long>::max()) + 2) + 'c';
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter = f.get(
|
||||
cpp17_input_iterator<const char*>(str.data()),
|
||||
cpp17_input_iterator<const char*>(str.data() + str.size()),
|
||||
ios,
|
||||
err,
|
||||
v);
|
||||
assert(base(iter) == str.data() + str.size() - 1);
|
||||
assert(err == ios.failbit);
|
||||
assert(v == std::numeric_limits<long>::min());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -68,6 +68,17 @@ int main(int, char**)
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 1);
|
||||
}
|
||||
{
|
||||
const char str[] = "-1";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str),
|
||||
cpp17_input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(base(iter) == str+sizeof(str)-1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == std::numeric_limits<unsigned int>::max());
|
||||
}
|
||||
std::hex(ios);
|
||||
{
|
||||
const char str[] = "0xFFFFFFFF";
|
||||
|
||||
@ -68,6 +68,17 @@ int main(int, char**)
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 1);
|
||||
}
|
||||
{
|
||||
const char str[] = "-1";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str),
|
||||
cpp17_input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(base(iter) == str+sizeof(str)-1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == std::numeric_limits<unsigned long>::max());
|
||||
}
|
||||
std::hex(ios);
|
||||
{
|
||||
const char str[] = "0xFFFFFFFF";
|
||||
|
||||
@ -68,6 +68,17 @@ int main(int, char**)
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 1);
|
||||
}
|
||||
{
|
||||
const char str[] = "-1";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str),
|
||||
cpp17_input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(base(iter) == str+sizeof(str)-1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == std::numeric_limits<unsigned long long>::max());
|
||||
}
|
||||
std::hex(ios);
|
||||
{
|
||||
const char str[] = "0xFFFFFFFFFFFFFFFF";
|
||||
|
||||
@ -68,6 +68,17 @@ int main(int, char**)
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == 1);
|
||||
}
|
||||
{
|
||||
const char str[] = "-1";
|
||||
std::ios_base::iostate err = ios.goodbit;
|
||||
cpp17_input_iterator<const char*> iter =
|
||||
f.get(cpp17_input_iterator<const char*>(str),
|
||||
cpp17_input_iterator<const char*>(str+sizeof(str)),
|
||||
ios, err, v);
|
||||
assert(base(iter) == str+sizeof(str)-1);
|
||||
assert(err == ios.goodbit);
|
||||
assert(v == std::numeric_limits<unsigned short>::max());
|
||||
}
|
||||
std::hex(ios);
|
||||
{
|
||||
const char str[] = "0xFFFF";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user