[libcxx-commits] [libcxx] [libc++] Optimize ctype::to{lower, upper} (PR #145344)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 9 02:26:04 PDT 2025
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/145344
>From ec779246ace7d2ddfa49fdd4e646516c6919b2ae Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 23 Jun 2025 17:40:34 +0200
Subject: [PATCH] [libc++] Optimize ctype::to{lower,upper}
---
libcxx/docs/ReleaseNotes/21.rst | 2 +
libcxx/include/__config | 4 -
libcxx/include/__locale | 12 --
libcxx/include/__locale_dir/locale_base_api.h | 7 -
.../include/__locale_dir/support/bsd_like.h | 6 -
libcxx/include/__locale_dir/support/linux.h | 6 -
.../support/no_locale/characters.h | 6 -
libcxx/include/__locale_dir/support/windows.h | 6 -
libcxx/lib/abi/CHANGELOG.TXT | 9 ++
...bcxxabi.v1.stable.exceptions.nonew.abilist | 2 -
...xxabi.v1.stable.noexceptions.nonew.abilist | 2 -
libcxx/src/locale.cpp | 129 +++---------------
libcxx/test/benchmarks/locale/ctype.bench.cpp | 82 +++++++++++
13 files changed, 115 insertions(+), 158 deletions(-)
create mode 100644 libcxx/test/benchmarks/locale/ctype.bench.cpp
diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index 08b32bb508dc1..fd8a1a9590592 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -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
-------------------------
diff --git a/libcxx/include/__config b/libcxx/include/__config
index af8a297fdf3fd..e5f94d31d8535 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -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
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index 92e45e2531c2a..757a53951f66e 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -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;
diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h
index bbc30b1cfe03f..8dbc28e839839 100644
--- a/libcxx/include/__locale_dir/locale_base_api.h
+++ b/libcxx/include/__locale_dir/locale_base_api.h
@@ -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);
@@ -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); }
diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h
index 54eb397358d7a..ac402924709e5 100644
--- a/libcxx/include/__locale_dir/support/bsd_like.h
+++ b/libcxx/include/__locale_dir/support/bsd_like.h
@@ -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); }
diff --git a/libcxx/include/__locale_dir/support/linux.h b/libcxx/include/__locale_dir/support/linux.h
index fa0b03c646a2a..23bcf44c31dbf 100644
--- a/libcxx/include/__locale_dir/support/linux.h
+++ b/libcxx/include/__locale_dir/support/linux.h
@@ -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); }
diff --git a/libcxx/include/__locale_dir/support/no_locale/characters.h b/libcxx/include/__locale_dir/support/no_locale/characters.h
index 4fb48ed9ceac1..1281b8bd13094 100644
--- a/libcxx/include/__locale_dir/support/no_locale/characters.h
+++ b/libcxx/include/__locale_dir/support/no_locale/characters.h
@@ -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); }
diff --git a/libcxx/include/__locale_dir/support/windows.h b/libcxx/include/__locale_dir/support/windows.h
index 0d3089c150081..0df8709f118d0 100644
--- a/libcxx/include/__locale_dir/support/windows.h
+++ b/libcxx/include/__locale_dir/support/windows.h
@@ -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); }
diff --git a/libcxx/lib/abi/CHANGELOG.TXT b/libcxx/lib/abi/CHANGELOG.TXT
index bba9163837206..8c1841648f821 100644
--- a/libcxx/lib/abi/CHANGELOG.TXT
+++ b/libcxx/lib/abi/CHANGELOG.TXT
@@ -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.
+
+ 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:
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 679a0626d3268..8c55c4385f6f6 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 02bec0e7cbefb..51caa07a74330 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 30a7a54e1c016..da735865c322c 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -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;
+}
+
#if _LIBCPP_HAS_WIDE_CHARACTERS
constinit locale::id ctype<wchar_t>::id;
@@ -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;
}
@@ -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;
}
@@ -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)
diff --git a/libcxx/test/benchmarks/locale/ctype.bench.cpp b/libcxx/test/benchmarks/locale/ctype.bench.cpp
new file mode 100644
index 0000000000000..2bb40ef96b61f
--- /dev/null
+++ b/libcxx/test/benchmarks/locale/ctype.bench.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+#include <locale>
+
+#include <benchmark/benchmark.h>
+
+#include "make_string.h"
+#include "test_macros.h"
+
+template <class CharT>
+static void BM_tolower_char(benchmark::State& state) {
+ const auto& ct = std::use_facet<std::ctype<CharT>>(std::locale::classic());
+
+ for (auto _ : state) {
+ CharT c('c');
+ benchmark::DoNotOptimize(c);
+ benchmark::DoNotOptimize(ct.tolower(c));
+ }
+}
+
+BENCHMARK(BM_tolower_char<char>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+BENCHMARK(BM_tolower_char<wchar_t>);
+#endif
+
+template <class CharT>
+static void BM_tolower_string(benchmark::State& state) {
+ const auto& ct = std::use_facet<std::ctype<CharT>>(std::locale::classic());
+ std::basic_string<CharT> str;
+
+ for (auto _ : state) {
+ str = MAKE_STRING_VIEW(CharT, "THIS IS A LONG STRING TO MAKE TO LOWER");
+ benchmark::DoNotOptimize(str);
+ benchmark::DoNotOptimize(ct.tolower(str.data(), str.data() + str.size()));
+ }
+}
+
+BENCHMARK(BM_tolower_string<char>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+BENCHMARK(BM_tolower_string<wchar_t>);
+#endif
+
+template <class CharT>
+static void BM_toupper_char(benchmark::State& state) {
+ const auto& ct = std::use_facet<std::ctype<CharT>>(std::locale::classic());
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(ct.toupper(CharT('c')));
+ }
+}
+
+BENCHMARK(BM_toupper_char<char>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+BENCHMARK(BM_toupper_char<wchar_t>);
+#endif
+
+template <class CharT>
+static void BM_toupper_string(benchmark::State& state) {
+ const auto& ct = std::use_facet<std::ctype<CharT>>(std::locale::classic());
+ std::basic_string<CharT> str;
+
+ for (auto _ : state) {
+ str = MAKE_STRING_VIEW(CharT, "this is a long string to make to upper");
+ benchmark::DoNotOptimize(str);
+ benchmark::DoNotOptimize(ct.toupper(str.data(), str.data() + str.size()));
+ }
+}
+
+BENCHMARK(BM_toupper_string<char>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+BENCHMARK(BM_toupper_string<wchar_t>);
+#endif
+
+BENCHMARK_MAIN();
More information about the libcxx-commits
mailing list