[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