[libc++] Optimize char_traits a bit (#72799)
This implements two kinds of optimizations. Specifically
- `char_traits<char8_t>` uses `char` code paths; these are heavily
optimized and the operations are equivalent
- `char16_t` and `char32_t` `find` uses `std::find` to forward to
`wmemchr` if they have the same size
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 47ed105..1fd22d5 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -10,6 +10,7 @@
#define _LIBCPP___STRING_CHAR_TRAITS_H
#include <__algorithm/fill_n.h>
+#include <__algorithm/find.h>
#include <__algorithm/find_end.h>
#include <__algorithm/find_first_of.h>
#include <__algorithm/min.h>
@@ -17,6 +18,7 @@
#include <__compare/ordering.h>
#include <__config>
#include <__functional/hash.h>
+#include <__functional/identity.h>
#include <__iterator/iterator_traits.h>
#include <__string/constexpr_c_functions.h>
#include <__type_traits/is_constant_evaluated.h>
@@ -272,10 +274,14 @@
return std::__constexpr_memcmp(__s1, __s2, __element_count(__n));
}
- static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __s) _NOEXCEPT;
+ static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) _NOEXCEPT {
+ return std::__constexpr_strlen(__str);
+ }
_LIBCPP_HIDE_FROM_ABI static constexpr const char_type*
- find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+ find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
+ return std::__constexpr_memchr(__s, __a, __n);
+ }
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type*
move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
@@ -307,25 +313,6 @@
static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type eof() noexcept { return int_type(EOF); }
};
-// TODO use '__builtin_strlen' if it ever supports char8_t ??
-inline constexpr size_t char_traits<char8_t>::length(const char_type* __s) _NOEXCEPT {
- size_t __len = 0;
- for (; !eq(*__s, char_type(0)); ++__s)
- ++__len;
- return __len;
-}
-
-// TODO use '__builtin_char_memchr' if it ever supports char8_t ??
-inline constexpr const char8_t*
-char_traits<char8_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
- for (; __n; --__n) {
- if (eq(*__s, __a))
- return __s;
- ++__s;
- }
- return nullptr;
-}
-
#endif // _LIBCPP_HAS_NO_CHAR8_T
template <>
@@ -353,9 +340,15 @@
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
- find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
+ find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
+ __identity __proj;
+ const char_type* __match = std::__find_impl(__s, __s + __n, __a, __proj);
+ if (__match == __s + __n)
+ return nullptr;
+ return __match;
+ }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
@@ -408,16 +401,6 @@
return __len;
}
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17 const char16_t*
-char_traits<char16_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
- for (; __n; --__n) {
- if (eq(*__s, __a))
- return __s;
- ++__s;
- }
- return nullptr;
-}
-
template <>
struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t> {
using char_type = char32_t;
@@ -443,8 +426,15 @@
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int
compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT;
+
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type*
- find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+ find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
+ __identity __proj;
+ const char_type* __match = std::__find_impl(__s, __s + __n, __a, __proj);
+ if (__match == __s + __n)
+ return nullptr;
+ return __match;
+ }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
@@ -496,16 +486,6 @@
return __len;
}
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17 const char32_t*
-char_traits<char32_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
- for (; __n; --__n) {
- if (eq(*__s, __a))
- return __s;
- ++__s;
- }
- return nullptr;
-}
-
// helper fns for basic_string and string_view
// __str_find