Skip to content

[libc++] Refactor num_get optimization to not be ABI breaking #121690

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions libcxx/include/__configuration/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
97 changes: 42 additions & 55 deletions libcxx/include/locale
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,9 @@ 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);
static int __stage2_int_loop(
_CharT __ct,
int __base,
Expand All @@ -414,55 +415,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) {
Expand All @@ -475,18 +453,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;
Expand Down Expand Up @@ -856,14 +833,9 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_signed(
// 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];
Expand All @@ -879,7 +851,17 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_signed(
__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))
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)
Expand All @@ -905,14 +887,9 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_unsigned(
// 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];
Expand All @@ -928,7 +905,17 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_unsigned(
__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))
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)
Expand Down
10 changes: 10 additions & 0 deletions libcxx/src/locale.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5650,6 +5650,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>;)

Expand Down