[libcxx-commits] [libcxx] 29312d3 - [libc++] Optimize char_traits a bit (#72799)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Apr 20 02:40:22 PDT 2024
Author: Nikolas Klauser
Date: 2024-04-20T11:40:18+02:00
New Revision: 29312d39ff89b664138c497716dd11d4e1f2876b
URL: https://github.com/llvm/llvm-project/commit/29312d39ff89b664138c497716dd11d4e1f2876b
DIFF: https://github.com/llvm/llvm-project/commit/29312d39ff89b664138c497716dd11d4e1f2876b.diff
LOG: [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
Added:
Modified:
libcxx/include/__string/char_traits.h
libcxx/include/__string/constexpr_c_functions.h
Removed:
################################################################################
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 47ed1057caaab1..1fd22d518e1ab6 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 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t> {
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 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t> {
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 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t> {
_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 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const
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 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t> {
_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 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char32_t>::length(const
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
diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h
index 198f0f5e680914..72c6ce69b60bb6 100644
--- a/libcxx/include/__string/constexpr_c_functions.h
+++ b/libcxx/include/__string/constexpr_c_functions.h
@@ -35,18 +35,33 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// of elements as opposed to a number of bytes.
enum class __element_count : size_t {};
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_strlen(const char* __str) {
+template <class _Tp>
+inline const bool __is_char_type = false;
+
+template <>
+inline const bool __is_char_type<char> = true;
+
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+template <>
+inline const bool __is_char_type<char8_t> = true;
+#endif
+
+template <class _Tp>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_strlen(const _Tp* __str) _NOEXCEPT {
+ static_assert(__is_char_type<_Tp>, "__constexpr_strlen only works with char and char8_t");
// GCC currently doesn't support __builtin_strlen for heap-allocated memory during constant evaluation.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70816
-#ifdef _LIBCPP_COMPILER_GCC
if (__libcpp_is_constant_evaluated()) {
+#if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_COMPILER_CLANG_BASED)
+ if constexpr (is_same_v<_Tp, char>)
+ return __builtin_strlen(__str);
+#endif
size_t __i = 0;
for (; __str[__i] != '\0'; ++__i)
;
return __i;
}
-#endif
- return __builtin_strlen(__str);
+ return __builtin_strlen(reinterpret_cast<const char*>(__str));
}
// Because of __libcpp_is_trivially_lexicographically_comparable we know that comparing the object representations is
More information about the libcxx-commits
mailing list