Skip to content
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: 2 additions & 0 deletions libcxx/docs/ReleaseNotes/21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ Improvements and New Features
- The ``flat_map::insert`` and ``flat_set::insert_range`` have been optimized, resulting in a performance improvement of up
to 10x for inserting elements into a ``flat_map`` when the input range is a ``flat_map`` or a ``zip_view``.

- ``ctype::tolower`` and ``ctype::toupper`` have been optimized, resulting in a 2x performane improvement.

Deprecations and Removals
-------------------------

Expand Down
4 changes: 0 additions & 4 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -639,10 +639,6 @@ typedef __char32_t char32_t;
# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 1
# endif

# if defined(__APPLE__) || defined(__FreeBSD__)
# define _LIBCPP_HAS_DEFAULTRUNELOCALE
# endif

# if defined(__APPLE__) || defined(__FreeBSD__)
# define _LIBCPP_WCTYPE_IS_MASK
# endif
Expand Down
12 changes: 0 additions & 12 deletions libcxx/include/__locale
Original file line number Diff line number Diff line change
Expand Up @@ -589,18 +589,6 @@ public:
# endif
_LIBCPP_HIDE_FROM_ABI const mask* table() const _NOEXCEPT { return __tab_; }
static const mask* classic_table() _NOEXCEPT;
# if defined(__GLIBC__) || defined(__EMSCRIPTEN__)
static const int* __classic_upper_table() _NOEXCEPT;
static const int* __classic_lower_table() _NOEXCEPT;
# endif
# if defined(__NetBSD__)
static const short* __classic_upper_table() _NOEXCEPT;
static const short* __classic_lower_table() _NOEXCEPT;
# endif
# if defined(__MVS__)
static const unsigned short* __classic_upper_table() _NOEXCEPT;
static const unsigned short* __classic_lower_table() _NOEXCEPT;
# endif

protected:
~ctype() override;
Expand Down
7 changes: 0 additions & 7 deletions libcxx/include/__locale_dir/locale_base_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@
// Character manipulation functions
// --------------------------------
// namespace __locale {
// int __islower(int, __locale_t);
// int __isupper(int, __locale_t);
// int __isdigit(int, __locale_t); // required by the headers
// int __isxdigit(int, __locale_t); // required by the headers
// int __toupper(int, __locale_t);
Expand Down Expand Up @@ -208,11 +206,6 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
//
// Character manipulation functions
//
# if defined(_LIBCPP_BUILDING_LIBRARY)
inline _LIBCPP_HIDE_FROM_ABI int __islower(int __ch, __locale_t __loc) { return islower_l(__ch, __loc); }
inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __ch, __locale_t __loc) { return isupper_l(__ch, __loc); }
# endif

inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __ch, __locale_t __loc) { return isdigit_l(__ch, __loc); }
inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __ch, __locale_t __loc) { return isxdigit_l(__ch, __loc); }

Expand Down
6 changes: 0 additions & 6 deletions libcxx/include/__locale_dir/support/bsd_like.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,6 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
//
// Character manipulation functions
//
#if defined(_LIBCPP_BUILDING_LIBRARY)
inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t __loc) { return ::islower_l(__c, __loc); }

inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t __loc) { return ::isupper_l(__c, __loc); }
#endif

inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return ::isdigit_l(__c, __loc); }

inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return ::isxdigit_l(__c, __loc); }
Expand Down
6 changes: 0 additions & 6 deletions libcxx/include/__locale_dir/support/linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,6 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
//
// Character manipulation functions
//
#if defined(_LIBCPP_BUILDING_LIBRARY)
inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t __loc) { return islower_l(__c, __loc); }

inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t __loc) { return isupper_l(__c, __loc); }
#endif

inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return isdigit_l(__c, __loc); }

inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return isxdigit_l(__c, __loc); }
Expand Down
6 changes: 0 additions & 6 deletions libcxx/include/__locale_dir/support/no_locale/characters.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ namespace __locale {
//
// Character manipulation functions
//
#if defined(_LIBCPP_BUILDING_LIBRARY)
inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t) { return std::islower(__c); }

inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t) { return std::isupper(__c); }
#endif

inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t) { return std::isdigit(__c); }

inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t) { return std::isxdigit(__c); }
Expand Down
6 changes: 0 additions & 6 deletions libcxx/include/__locale_dir/support/windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,6 @@ __strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) {
//
// Character manipulation functions
//
#if defined(_LIBCPP_BUILDING_LIBRARY)
inline _LIBCPP_HIDE_FROM_ABI int __islower(int __c, __locale_t __loc) { return _islower_l(__c, __loc); }

inline _LIBCPP_HIDE_FROM_ABI int __isupper(int __c, __locale_t __loc) { return _isupper_l(__c, __loc); }
#endif

inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return _isdigit_l(__c, __loc); }

inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return _isxdigit_l(__c, __loc); }
Expand Down
9 changes: 9 additions & 0 deletions libcxx/lib/abi/CHANGELOG.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ New entries should be added directly below the "Version" header.
Version 21.0
------------

* [libc++] Optimize ctype::to{lower,upper}

This patch removed __classic_upper_table() and __classic_lower_table(), which were only ever accessed from the dylib.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing those function breaks ABI. The z/OS intends to keep them around. Wonder why this was not discussed among different vendors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions were never used outside the dylib, so no program can ever reference them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see these were used inside locale.cpp only so they should never be externalized. In theory once the symbol is exported nothing stops of being called externally though I would think this is unlikely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. This is a libc++-internal function. We've never used it ourselves in the headers, so it's your own fault if you call them. It's even more unlikely anybody even tried to use them, since it's not available on most platforms either.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear we never called this function except the internal code which was removed in this PR. After reviewing this internally we decided to remove those symbols. I appreciate your time and the clarity you've provided.


x86_64-unknown-gnu-linux
------------------------
Symbol removed: _ZNSt3__15ctypeIcE21__classic_lower_tableEv
Symbol removed: _ZNSt3__15ctypeIcE21__classic_upper_tableEv

* [libc++] Instantiate hash function externally

This has multiple benefits:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1318,8 +1318,6 @@
{'is_defined': True, 'name': '_ZNSt3__15alignEmmRPvRm', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE10table_sizeE', 'size': 8, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE13classic_tableEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE21__classic_lower_tableEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE21__classic_upper_tableEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE2idE', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcEC1EPKtbm', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcEC2EPKtbm', 'type': 'FUNC'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1289,8 +1289,6 @@
{'is_defined': True, 'name': '_ZNSt3__15alignEmmRPvRm', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE10table_sizeE', 'size': 8, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE13classic_tableEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE21__classic_lower_tableEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE21__classic_upper_tableEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcE2idE', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcEC1EPKtbm', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__15ctypeIcEC2EPKtbm', 'type': 'FUNC'}
Expand Down
129 changes: 22 additions & 107 deletions libcxx/src/locale.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,20 @@ const ctype_base::mask ctype_base::graph;

// template <> class ctype<wchar_t>;

template <class CharT>
static CharT to_upper_impl(CharT c) {
if (c < 'a' || c > 'z')
return c;
return c & ~0x20;
}

template <class CharT>
static CharT to_lower_impl(CharT c) {
if (c < 'A' || c > 'Z')
return c;
return c | 0x20;
}

Comment on lines +700 to +713
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code does not work for non-ASCII encodings since the assumption of char ordering cannot be assumed. Is there any reason why we cannot simply call C functions ::tolower(c) and touppoer(c) here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming system call to :tolower(c) and touppoer(c) are macro expanded and/or get inlined the performance should be equivalent to above implementation, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the classic C locale, not the currently installed locale.

#if _LIBCPP_HAS_WIDE_CHARACTERS
constinit locale::id ctype<wchar_t>::id;

Expand Down Expand Up @@ -726,48 +740,19 @@ const wchar_t* ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const c
return low;
}

wchar_t ctype<wchar_t>::do_toupper(char_type c) const {
# ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return std::__libcpp_isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
# elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
return std::__libcpp_isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
# else
return (std::__libcpp_isascii(c) && __locale::__iswlower(c, _LIBCPP_GET_C_LOCALE)) ? c - L'a' + L'A' : c;
# endif
}
wchar_t ctype<wchar_t>::do_toupper(char_type c) const { return to_upper_impl(c); }

const wchar_t* ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const {
for (; low != high; ++low)
# ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = std::__libcpp_isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
# elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
*low = std::__libcpp_isascii(*low) ? ctype<char>::__classic_upper_table()[*low] : *low;
# else
*low =
(std::__libcpp_isascii(*low) && __locale::__islower(*low, _LIBCPP_GET_C_LOCALE)) ? (*low - L'a' + L'A') : *low;
# endif
*low = to_upper_impl(*low);
return low;
}

wchar_t ctype<wchar_t>::do_tolower(char_type c) const {
# ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return std::__libcpp_isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
# elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
return std::__libcpp_isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
# else
return (std::__libcpp_isascii(c) && __locale::__isupper(c, _LIBCPP_GET_C_LOCALE)) ? c - L'A' + 'a' : c;
# endif
}
wchar_t ctype<wchar_t>::do_tolower(char_type c) const { return to_lower_impl(c); }

const wchar_t* ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const {
for (; low != high; ++low)
# ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = std::__libcpp_isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
# elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
*low = std::__libcpp_isascii(*low) ? ctype<char>::__classic_lower_table()[*low] : *low;
# else
*low = (std::__libcpp_isascii(*low) && __locale::__isupper(*low, _LIBCPP_GET_C_LOCALE)) ? *low - L'A' + L'a' : *low;
# endif
*low = to_lower_impl(*low);
return low;
}

Expand Down Expand Up @@ -811,59 +796,19 @@ ctype<char>::~ctype() {
delete[] __tab_;
}

char ctype<char>::do_toupper(char_type c) const {
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return std::__libcpp_isascii(c) ? static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
#elif defined(__NetBSD__)
return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
return std::__libcpp_isascii(c) ? static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
#else
return (std::__libcpp_isascii(c) && __locale::__islower(c, _LIBCPP_GET_C_LOCALE)) ? c - 'a' + 'A' : c;
#endif
}
char ctype<char>::do_toupper(char_type c) const { return to_upper_impl(c); }

const char* ctype<char>::do_toupper(char_type* low, const char_type* high) const {
for (; low != high; ++low)
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = std::__libcpp_isascii(*low)
? static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)])
: *low;
#elif defined(__NetBSD__)
*low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
*low = std::__libcpp_isascii(*low) ? static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
#else
*low = (std::__libcpp_isascii(*low) && __locale::__islower(*low, _LIBCPP_GET_C_LOCALE)) ? *low - 'a' + 'A' : *low;
#endif
*low = to_upper_impl(*low);
return low;
}

char ctype<char>::do_tolower(char_type c) const {
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return std::__libcpp_isascii(c) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
#elif defined(__NetBSD__)
return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
return std::__libcpp_isascii(c) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
#else
return (std::__libcpp_isascii(c) && __locale::__isupper(c, _LIBCPP_GET_C_LOCALE)) ? c - 'A' + 'a' : c;
#endif
}
char ctype<char>::do_tolower(char_type c) const { return to_lower_impl(c); }

const char* ctype<char>::do_tolower(char_type* low, const char_type* high) const {
for (; low != high; ++low)
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = std::__libcpp_isascii(*low)
? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)])
: *low;
#elif defined(__NetBSD__)
*low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
*low = std::__libcpp_isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
#else
*low = (std::__libcpp_isascii(*low) && __locale::__isupper(*low, _LIBCPP_GET_C_LOCALE)) ? *low - 'A' + 'a' : *low;
#endif
*low = to_lower_impl(*low);
return low;
}

Expand Down Expand Up @@ -1010,36 +955,6 @@ const ctype<char>::mask* ctype<char>::classic_table() noexcept {
}
#endif

#if defined(__GLIBC__)
const int* ctype<char>::__classic_lower_table() noexcept { return _LIBCPP_GET_C_LOCALE->__ctype_tolower; }

const int* ctype<char>::__classic_upper_table() noexcept { return _LIBCPP_GET_C_LOCALE->__ctype_toupper; }
#elif defined(__NetBSD__)
const short* ctype<char>::__classic_lower_table() noexcept { return _C_tolower_tab_ + 1; }

const short* ctype<char>::__classic_upper_table() noexcept { return _C_toupper_tab_ + 1; }

#elif defined(__EMSCRIPTEN__)
const int* ctype<char>::__classic_lower_table() noexcept { return *__ctype_tolower_loc(); }

const int* ctype<char>::__classic_upper_table() noexcept { return *__ctype_toupper_loc(); }
#elif defined(__MVS__)
const unsigned short* ctype<char>::__classic_lower_table() _NOEXCEPT {
# if defined(__NATIVE_ASCII_F)
return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->lower);
# else
return const_cast<const unsigned short*>(__ctype + __TOLOWER_INDEX);
# endif
}
const unsigned short* ctype<char>::__classic_upper_table() _NOEXCEPT {
# if defined(__NATIVE_ASCII_F)
return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->upper);
# else
return const_cast<const unsigned short*>(__ctype + __TOUPPER_INDEX);
# endif
}
#endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__ || __MVS__

// template <> class ctype_byname<char>

ctype_byname<char>::ctype_byname(const char* name, size_t refs)
Expand Down
Loading
Loading