[libcxx-commits] [libcxx] [libc++] Optimize num_get integral functions (PR #121795)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 6 08:20:46 PST 2025
https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/121795
None
>From 6d70f2129e7c941f7e8fa46c6af21b4a32478689 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 5 Jan 2025 13:14:32 +0100
Subject: [PATCH] [libc++] Optimize num_get integral functions
---
libcxx/include/__algorithm/simd_utils.h | 24 ++
libcxx/include/__configuration/abi.h | 2 -
libcxx/include/__locale_dir/locale_base_api.h | 11 -
.../include/__locale_dir/support/bsd_like.h | 9 -
libcxx/include/__locale_dir/support/windows.h | 8 -
libcxx/include/locale | 363 +++++++++---------
libcxx/src/locale.cpp | 10 +
7 files changed, 211 insertions(+), 216 deletions(-)
diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h
index 3ca79247bbd03c..a855cbea2257b1 100644
--- a/libcxx/include/__algorithm/simd_utils.h
+++ b/libcxx/include/__algorithm/simd_utils.h
@@ -116,11 +116,35 @@ 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]...};
+ }(make_index_sequence<_Np>{}, make_index_sequence<__simd_vector_size_v<_VecT> - _Np>{});
+}
+
+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 <size_t _Np>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __all_of(__simd_vector<bool, _Np> __vec) noexcept {
return __builtin_reduce_and(__vec);
}
+template <size_t _Np>
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __none_of(__simd_vector<bool, _Np> __vec) noexcept {
+ return !__builtin_reduce_or(__vec);
+}
+
template <class _Tp, size_t _Np>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI auto __as_mask(__simd_vector<_Tp, _Np> __vec) noexcept {
static_assert(!is_same<_Tp, bool>::value, "vector type should not be a bool!");
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index c6ef6fdcdf96e6..5e40e308c8926c 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -57,8 +57,6 @@
// because it changes the mangling of the virtual function located in the vtable, which
// changes how it gets signed.
# define _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE
-// Enable optimized version of __do_get_(un)signed which avoids redundant copies.
-# define _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
// Give reverse_iterator<T> one data member of type T, not two.
// Also, in C++17 and later, don't derive iterator types from std::iterator.
# define _LIBCPP_ABI_NO_ITERATOR_BASES
diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h
index c8097beb9052df..63fef085527812 100644
--- a/libcxx/include/__locale_dir/locale_base_api.h
+++ b/libcxx/include/__locale_dir/locale_base_api.h
@@ -40,8 +40,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
@@ -160,15 +158,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
//
diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h
index da31aeaf3c58e3..8359a07f895224 100644
--- a/libcxx/include/__locale_dir/support/bsd_like.h
+++ b/libcxx/include/__locale_dir/support/bsd_like.h
@@ -61,15 +61,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
//
diff --git a/libcxx/include/__locale_dir/support/windows.h b/libcxx/include/__locale_dir/support/windows.h
index 03d05a410fdc3b..d5af1ee0866108 100644
--- a/libcxx/include/__locale_dir/support/windows.h
+++ b/libcxx/include/__locale_dir/support/windows.h
@@ -174,14 +174,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
//
diff --git a/libcxx/include/locale b/libcxx/include/locale
index 981f25ed1e98cf..8757074a50f880 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -198,7 +198,9 @@ template <class charT> class messages_byname;
# include <__algorithm/equal.h>
# include <__algorithm/find.h>
# include <__algorithm/max.h>
+# include <__algorithm/min.h>
# include <__algorithm/reverse.h>
+# include <__algorithm/simd_utils.h>
# include <__algorithm/unwrap_iter.h>
# include <__assert>
# include <__iterator/access.h>
@@ -375,7 +377,7 @@ 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;
};
@@ -400,8 +402,30 @@ struct __num_get : protected __num_get_base {
unsigned*& __g_end,
unsigned& __dc,
_CharT* __atoms);
-# ifndef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
- static string __stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep);
+
+ [[__deprecated__("This exists only for ABI compatibility")]] static string
+ __stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep);
+
+ _LIBCPP_HIDE_FROM_ABI static ptrdiff_t __atoms_offset(const _CharT* __atoms, _CharT __val) {
+# if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS
+ _LIBCPP_DIAGNOSTIC_PUSH
+ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")
+ if constexpr (is_same<_CharT, char>::value) {
+ using __vec = __simd_vector<char, 32>;
+ __vec __chars = std::__broadcast<__vec>(__val);
+ __vec __cmp = std::__partial_load<__vec, __int_chr_cnt>(__atoms);
+ auto __res = std::__as_mask(__chars == __cmp);
+ if (std::__none_of(__res))
+ return __int_chr_cnt;
+ return std::min(__int_chr_cnt, std::__find_first_set(__res));
+ } else
+ _LIBCPP_DIAGNOSTIC_POP
+# endif
+ {
+ return std::find(__atoms, __atoms + __int_chr_cnt, __val) - __atoms;
+ }
+ }
+
static int __stage2_int_loop(
_CharT __ct,
int __base,
@@ -414,55 +438,32 @@ struct __num_get : protected __num_get_base {
unsigned*& __g_end,
_CharT* __atoms);
-# else
- static string __stage2_int_prep(ios_base& __iob, _CharT& __thousands_sep) {
+ _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();
}
- const _CharT* __do_widen(ios_base& __iob, _CharT* __atoms) const { return __do_widen_p(__iob, __atoms); }
-
- static int __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,
- const _CharT* __atoms);
+ _LIBCPP_HIDE_FROM_ABI const _CharT* __do_widen(ios_base& __iob, _CharT* __atoms) const {
+ return __do_widen_p(__iob, __atoms);
+ }
private:
template <typename _Tp>
- const _Tp* __do_widen_p(ios_base& __iob, _Tp* __atoms) const {
+ _LIBCPP_HIDE_FROM_ABI const _Tp* __do_widen_p(ios_base& __iob, _Tp* __atoms) const {
locale __loc = __iob.getloc();
use_facet<ctype<_Tp> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);
return __atoms;
}
- const char* __do_widen_p(ios_base& __iob, char* __atoms) const {
+ _LIBCPP_HIDE_FROM_ABI const char* __do_widen_p(ios_base& __iob, char* __atoms) const {
(void)__iob;
(void)__atoms;
return __src;
}
-# endif
};
-# ifndef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
-template <class _CharT>
-string __num_get<_CharT>::__stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep) {
- locale __loc = __iob.getloc();
- std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);
- const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__loc);
- __thousands_sep = __np.thousands_sep();
- return __np.grouping();
-}
-# endif
-
template <class _CharT>
string __num_get<_CharT>::__stage2_float_prep(
ios_base& __iob, _CharT* __atoms, _CharT& __decimal_point, _CharT& __thousands_sep) {
@@ -475,18 +476,17 @@ string __num_get<_CharT>::__stage2_float_prep(
}
template <class _CharT>
-int
-# ifndef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
-__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)
-# else
-__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, const _CharT* __atoms)
-
-# endif
-{
+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;
@@ -499,7 +499,7 @@ __num_get<_CharT>::__stage2_int_loop(_CharT __ct, int __base, char* __a, char*&
}
return 0;
}
- ptrdiff_t __f = std::find(__atoms, __atoms + __int_chr_cnt, __ct) - __atoms;
+ ptrdiff_t __f = __atoms_offset(__atoms, __ct);
if (__f >= 24)
return -1;
switch (__base) {
@@ -660,43 +660,39 @@ protected:
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS iter_type
__do_get_floating_point(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Fp& __v) const;
- template <class _Signed>
+ template <class _MaybeSigned>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS iter_type
- __do_get_signed(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Signed& __v) const;
-
- template <class _Unsigned>
- _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS iter_type
- __do_get_unsigned(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Unsigned& __v) const;
+ __do_get_integral(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _MaybeSigned& __v) const;
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 {
@@ -718,65 +714,6 @@ protected:
template <class _CharT, class _InputIterator>
locale::id num_get<_CharT, _InputIterator>::id;
-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 _Tp>
_LIBCPP_HIDE_FROM_ABI _Tp __do_strtod(const char* __a, char** __p2);
@@ -845,102 +782,156 @@ _InputIterator num_get<_CharT, _InputIterator>::do_get(
return __b;
}
-// signed
-
template <class _CharT, class _InputIterator>
-template <class _Signed>
-_InputIterator num_get<_CharT, _InputIterator>::__do_get_signed(
- iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Signed& __v) const {
+template <class _MaybeSigned>
+_InputIterator num_get<_CharT, _InputIterator>::__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>;
+
// Stage 1
int __base = this->__get_base(__iob);
// Stage 2
char_type __thousands_sep;
const int __atoms_size = __num_get_base::__int_chr_cnt;
-# ifdef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
char_type __atoms1[__atoms_size];
const char_type* __atoms = this->__do_widen(__iob, __atoms1);
string __grouping = this->__stage2_int_prep(__iob, __thousands_sep);
-# else
- char_type __atoms[__atoms_size];
- string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
-# endif
- 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 (__first == __last) {
+ __err |= ios_base::eofbit;
+ return __first;
+ }
+
+ while (!__grouping.empty() && *__first == __thousands_sep) {
+ ++__first;
+ if (__g_end - __g < this->__num_get_buf_sz) {
+ *__g_end++ = __dc;
+ __dc = 0;
}
- if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc, __thousands_sep, __grouping, __g, __g_end, __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)
+
+ 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;
- return __b;
-}
+ return __first;
+ }
-// unsigned
+ bool __parsed_num = false;
-template <class _CharT, class _InputIterator>
-template <class _Unsigned>
-_InputIterator num_get<_CharT, _InputIterator>::__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;
-# ifdef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
- char_type __atoms1[__atoms_size];
- const char_type* __atoms = this->__do_widen(__iob, __atoms1);
- string __grouping = this->__stage2_int_prep(__iob, __thousands_sep);
-# else
- char_type __atoms[__atoms_size];
- string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
-# endif
- 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 we don't have a pre-set base, figure it out
+ 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 (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc, __thousands_sep, __grouping, __g, __g_end, __atoms))
+ } else if (__base == 16) {
+ // Try to swallow '0x'
+
+ // *__first == '0'
+ if (*__first == __atoms[0]) {
+ ++__first;
+ if (__first == __last) {
+ __err |= ios_base::eofbit;
+ 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)
break;
+ switch (__base) {
+ case 16:
+ if (__offset >= 16)
+ __offset -= 6;
+ [[__fallthrough__]];
+ case 8:
+ case 10:
+ if (__offset >= __base)
+ break;
+ __overflowed |= __builtin_mul_overflow(__val, __base, &__val) || __builtin_add_overflow(__val, __offset, &__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 > 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;
}
// floating point
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index a1e10401f0b299..0b41136ea1e0a7 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -5645,6 +5645,16 @@ void moneypunct_byname<wchar_t, true>::init(const char* nm) {
void __do_nothing(void*) {}
+// Legacy ABI __num_get functions - the new ones are _LIBCPP_HIDE_FROM_ABI
+template <class _CharT>
+string __num_get<_CharT>::__stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep) {
+ locale __loc = __iob.getloc();
+ std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);
+ const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__loc);
+ __thousands_sep = __np.thousands_sep();
+ return __np.grouping();
+}
+
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
_LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;)
More information about the libcxx-commits
mailing list