[libcxx-commits] [libcxx] [libc++] Optimize char_traits a bit (PR #72799)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Nov 19 08:58:34 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: None (philnik777)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/72799.diff
2 Files Affected:
- (modified) libcxx/include/__string/char_traits.h (+42-76)
- (modified) libcxx/include/__string/constexpr_c_functions.h (+9-4)
``````````diff
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 17eade2f8188f76..b3bde455eb4a260 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -11,12 +11,14 @@
#include <__algorithm/copy_n.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>
#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>
@@ -355,34 +357,35 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
{return __c1 < __c2;}
static _LIBCPP_HIDE_FROM_ABI constexpr int
- compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
+ compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept {
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_INLINE_VISIBILITY static constexpr
- const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+ static _LIBCPP_HIDE_FROM_ABI constexpr const char_type*
+ 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 {
- return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
- }
+ static _LIBCPP_HIDE_FROM_ABI constexpr char_type*
+ move(char_type* __s1, const char_type* __s2, size_t __n) noexcept {
+ return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
+ }
- static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
- char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
- _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
- "char_traits::copy: source and destination ranges overlap");
- std::copy_n(__s2, __n, __s1);
- return __s1;
- }
+ static _LIBCPP_HIDE_FROM_ABI constexpr char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) noexcept {
+ _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
+ "char_traits::copy: source and destination ranges overlap");
+ std::copy_n(__s2, __n, __s1);
+ return __s1;
+ }
- static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
- char_type* assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT {
- std::fill_n(__s, __n, __a);
- return __s;
- }
+ static _LIBCPP_HIDE_FROM_ABI constexpr char_type* assign(char_type* __s, size_t __n, char_type __a) noexcept {
+ std::fill_n(__s, __n, __a);
+ return __s;
+ }
static inline _LIBCPP_HIDE_FROM_ABI constexpr int_type not_eof(int_type __c) noexcept
{return eq_int_type(__c, eof()) ? ~eof() : __c;}
@@ -396,31 +399,6 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
{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 <>
@@ -446,8 +424,15 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>
int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
size_t length(const char_type* __s) _NOEXCEPT;
- _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
- const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+
+ static _LIBCPP_HIDE_FROM_ABI _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_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
@@ -504,19 +489,6 @@ char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT
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>
{
@@ -540,8 +512,15 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>
int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
size_t length(const char_type* __s) _NOEXCEPT;
- _LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
- const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+
+ static _LIBCPP_HIDE_FROM_ABI _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_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
@@ -596,19 +575,6 @@ char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT
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 198f0f5e6809147..c029c2d29fec88c 100644
--- a/libcxx/include/__string/constexpr_c_functions.h
+++ b/libcxx/include/__string/constexpr_c_functions.h
@@ -35,18 +35,23 @@ _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 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_strlen(const _Tp* __str) _NOEXCEPT {
+ static_assert(
+ is_integral<_Tp>::value && sizeof(_Tp) == 1, "__constexpr_strlen only works with integral types of size 1");
// 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
``````````
</details>
https://github.com/llvm/llvm-project/pull/72799
More information about the libcxx-commits
mailing list