[libcxx-commits] [libcxx] 7217346 - [libc++] Refactor char_traits
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Dec 9 06:45:09 PST 2022
Author: Nikolas Klauser
Date: 2022-12-09T15:45:02+01:00
New Revision: 72173469dd020fd1eb81f607aa4782ec5ec7425c
URL: https://github.com/llvm/llvm-project/commit/72173469dd020fd1eb81f607aa4782ec5ec7425c
DIFF: https://github.com/llvm/llvm-project/commit/72173469dd020fd1eb81f607aa4782ec5ec7425c.diff
LOG: [libc++] Refactor char_traits
This allows us to reuse workarounds for compilers that don't provide the builtins or constexpr support.
Reviewed By: ldionne, Mordante, #libc
Spies: libcxx-commits
Differential Revision: https://reviews.llvm.org/D139555
Added:
libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp
libcxx/test/libcxx/strings/c.strings/constexpr.cwchar.compile.pass.cpp
Modified:
libcxx/include/__string/char_traits.h
libcxx/include/cstring
libcxx/include/cwchar
Removed:
################################################################################
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 617c6c156e961..98dcc2491547a 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -210,25 +210,22 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char>
static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
{return (unsigned char)__c1 < (unsigned char)__c2;}
- static _LIBCPP_CONSTEXPR_SINCE_CXX17
- int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
+ static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
+ if (__n == 0)
+ return 0;
+ return std::__constexpr_memcmp(__s1, __s2, __n);
+ }
- static inline size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {
- // GCC currently does not support __builtin_strlen during constant evaluation.
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70816
-#ifdef _LIBCPP_COMPILER_GCC
- if (__libcpp_is_constant_evaluated()) {
- size_t __i = 0;
- for (; __s[__i] != char_type('\0'); ++__i)
- ;
- return __i;
- }
-#endif
- return __builtin_strlen(__s);
- }
+ static inline size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT {
+ return std::__constexpr_strlen(__s);
+ }
- static _LIBCPP_CONSTEXPR_SINCE_CXX17
- const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+ static _LIBCPP_CONSTEXPR_SINCE_CXX17
+ const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
+ if (__n == 0)
+ return nullptr;
+ return std::__constexpr_char_memchr(__s, static_cast<int>(__a), __n);
+ }
static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
@@ -261,49 +258,6 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char>
{return int_type(EOF);}
};
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17
-int
-char_traits<char>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
-{
- if (__n == 0)
- return 0;
-#if __has_feature(cxx_constexpr_string_builtins)
- return __builtin_memcmp(__s1, __s2, __n);
-#elif _LIBCPP_STD_VER <= 14
- return _VSTD::memcmp(__s1, __s2, __n);
-#else
- for (; __n; --__n, ++__s1, ++__s2)
- {
- if (lt(*__s1, *__s2))
- return -1;
- if (lt(*__s2, *__s1))
- return 1;
- }
- return 0;
-#endif
-}
-
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17
-const char*
-char_traits<char>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
-{
- if (__n == 0)
- return nullptr;
-#if __has_feature(cxx_constexpr_string_builtins)
- return __builtin_char_memchr(__s, to_int_type(__a), __n);
-#elif _LIBCPP_STD_VER <= 14
- return (const char_type*) _VSTD::memchr(__s, to_int_type(__a), __n);
-#else
- for (; __n; --__n)
- {
- if (eq(*__s, __a))
- return __s;
- ++__s;
- }
- return nullptr;
-#endif
-}
-
// char_traits<wchar_t>
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -326,12 +280,22 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t>
static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
{return __c1 < __c2;}
- static _LIBCPP_CONSTEXPR_SINCE_CXX17
- int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
- static _LIBCPP_CONSTEXPR_SINCE_CXX17
- size_t length(const char_type* __s) _NOEXCEPT;
- static _LIBCPP_CONSTEXPR_SINCE_CXX17
- const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT;
+ static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
+ if (__n == 0)
+ return 0;
+ return std::__constexpr_wmemcmp(__s1, __s2, __n);
+ }
+
+ static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT {
+ return std::__constexpr_wcslen(__s);
+ }
+
+ static _LIBCPP_CONSTEXPR_SINCE_CXX17
+ const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT {
+ if (__n == 0)
+ return nullptr;
+ return std::__constexpr_wmemchr(__s, __a, __n);
+ }
static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
@@ -363,65 +327,6 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t>
static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
{return int_type(WEOF);}
};
-
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17
-int
-char_traits<wchar_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
-{
- if (__n == 0)
- return 0;
-#if __has_feature(cxx_constexpr_string_builtins)
- return __builtin_wmemcmp(__s1, __s2, __n);
-#elif _LIBCPP_STD_VER <= 14
- return _VSTD::wmemcmp(__s1, __s2, __n);
-#else
- for (; __n; --__n, ++__s1, ++__s2)
- {
- if (lt(*__s1, *__s2))
- return -1;
- if (lt(*__s2, *__s1))
- return 1;
- }
- return 0;
-#endif
-}
-
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17
-size_t
-char_traits<wchar_t>::length(const char_type* __s) _NOEXCEPT
-{
-#if __has_feature(cxx_constexpr_string_builtins)
- return __builtin_wcslen(__s);
-#elif _LIBCPP_STD_VER <= 14
- return _VSTD::wcslen(__s);
-#else
- size_t __len = 0;
- for (; !eq(*__s, char_type(0)); ++__s)
- ++__len;
- return __len;
-#endif
-}
-
-inline _LIBCPP_CONSTEXPR_SINCE_CXX17
-const wchar_t*
-char_traits<wchar_t>::find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT
-{
- if (__n == 0)
- return nullptr;
-#if __has_feature(cxx_constexpr_string_builtins)
- return __builtin_wmemchr(__s, __a, __n);
-#elif _LIBCPP_STD_VER <= 14
- return _VSTD::wmemchr(__s, __a, __n);
-#else
- for (; __n; --__n)
- {
- if (eq(*__s, __a))
- return __s;
- ++__s;
- }
- return nullptr;
-#endif
-}
#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
#ifndef _LIBCPP_HAS_NO_CHAR8_T
@@ -445,8 +350,10 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
static inline constexpr bool lt(char_type __c1, char_type __c2) noexcept
{return __c1 < __c2;}
- static constexpr
- int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT;
+ static _LIBCPP_HIDE_FROM_ABI constexpr int
+ compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
+ return std::__constexpr_memcmp(__s1, __s2, __n);
+ }
static constexpr
size_t length(const char_type* __s) _NOEXCEPT;
@@ -496,24 +403,6 @@ char_traits<char8_t>::length(const char_type* __s) _NOEXCEPT
return __len;
}
-inline constexpr
-int
-char_traits<char8_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT
-{
-#if __has_feature(cxx_constexpr_string_builtins)
- return __builtin_memcmp(__s1, __s2, __n);
-#else
- for (; __n; --__n, ++__s1, ++__s2)
- {
- if (lt(*__s1, *__s2))
- return -1;
- if (lt(*__s2, *__s1))
- return 1;
- }
- return 0;
-#endif
-}
-
// TODO use '__builtin_char_memchr' if it ever supports char8_t ??
inline constexpr
const char8_t*
diff --git a/libcxx/include/cstring b/libcxx/include/cstring
index 42bbe73924d3a..c88d97739f744 100644
--- a/libcxx/include/cstring
+++ b/libcxx/include/cstring
@@ -58,6 +58,7 @@ size_t strlen(const char* s);
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
+#include <__type_traits/is_constant_evaluated.h>
#include <string.h>
@@ -99,6 +100,53 @@ using ::memset _LIBCPP_USING_IF_EXISTS;
using ::strerror _LIBCPP_USING_IF_EXISTS;
using ::strlen _LIBCPP_USING_IF_EXISTS;
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_strlen(const char* __str) {
+ // 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()) {
+ size_t __i = 0;
+ for (; __str[__i] != '\0'; ++__i)
+ ;
+ return __i;
+ }
+#endif
+ return __builtin_strlen(__str);
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
+__constexpr_memcmp(const _Tp* __lhs, const _Tp* __rhs, size_t __count) {
+#ifdef _LIBCPP_COMPILER_GCC
+ if (__libcpp_is_constant_evaluated()) {
+ for (; __count; --__count, ++__lhs, ++__rhs) {
+ if (*__lhs < *__rhs)
+ return -1;
+ if (*__rhs < *__lhs)
+ return 1;
+ }
+ return 0;
+ }
+#endif
+ return __builtin_memcmp(__lhs, __rhs, __count);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const char*
+__constexpr_char_memchr(const char* __str, int __char, size_t __count) {
+#if __has_builtin(__builtin_char_memchr)
+ return __builtin_char_memchr(__str, __char, __count);
+#else
+ if (!__libcpp_is_constant_evaluated())
+ return static_cast<const char*>(std::memchr(__str, __char, __count));
+ for (; __count; --__count) {
+ if (*__str == __char)
+ return __str;
+ ++__str;
+ }
+ return nullptr;
+#endif
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_CSTRING
diff --git a/libcxx/include/cwchar b/libcxx/include/cwchar
index 220c817072de9..fb7b92b760af9 100644
--- a/libcxx/include/cwchar
+++ b/libcxx/include/cwchar
@@ -104,6 +104,7 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
+#include <__type_traits/is_constant_evaluated.h>
#include <cwctype>
#include <wchar.h>
@@ -189,6 +190,55 @@ using ::putwchar _LIBCPP_USING_IF_EXISTS;
using ::vwprintf _LIBCPP_USING_IF_EXISTS;
using ::wprintf _LIBCPP_USING_IF_EXISTS;
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_wcslen(const wchar_t* __str) {
+#if __has_builtin(__builtin_wcslen)
+ return __builtin_wcslen(__str);
+#else
+ if (!__libcpp_is_constant_evaluated())
+ return std::wcslen(__str);
+
+ size_t __len = 0;
+ for (; *__str != L'\0'; ++__str)
+ ++__len;
+ return __len;
+#endif
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
+__constexpr_wmemcmp(const wchar_t* __lhs, const wchar_t* __rhs, size_t __count) {
+#if __has_builtin(__builtin_wmemcmp)
+ return __builtin_wmemcmp(__lhs, __rhs, __count);
+#else
+ if (!__libcpp_is_constant_evaluated())
+ return std::wmemcmp(__lhs, __rhs, __count);
+
+ for (; __count; --__count, ++__lhs, ++__rhs) {
+ if (*__lhs < *__rhs)
+ return -1;
+ if (*__rhs < *__lhs)
+ return 1;
+ }
+ return 0;
+#endif
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const wchar_t*
+__constexpr_wmemchr(const wchar_t* __str, wchar_t __char, size_t __count) {
+#if __has_feature(cxx_constexpr_string_builtins)
+ return __builtin_wmemchr(__str, __char, __count);
+#else
+ if (!__libcpp_is_constant_evaluated())
+ return std::wmemchr(__str, __char, __count);
+
+ for (; __count; --__count) {
+ if (*__str == __char)
+ return __str;
+ ++__str;
+ }
+ return nullptr;
+#endif
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_CWCHAR
diff --git a/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp b/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp
new file mode 100644
index 0000000000000..ad078c0a21db4
--- /dev/null
+++ b/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// Check that __constexpr_* cstring functions are actually constexpr
+
+#include <cstring>
+
+static_assert(std::__constexpr_strlen("Banane") == 6, "");
+static_assert(std::__constexpr_memcmp("Banane", "Banand", 6) == 1, "");
+static_assert(std::__constexpr_memcmp("Banane", "Banane", 6) == 0, "");
+static_assert(std::__constexpr_memcmp("Banane", "Bananf", 6) == -1, "");
+
+constexpr bool test_constexpr_wmemchr() {
+ const char str[] = "Banane";
+ return std::__constexpr_char_memchr(str, 'n', 6) == str + 2;
+}
+static_assert(test_constexpr_wmemchr(), "");
diff --git a/libcxx/test/libcxx/strings/c.strings/constexpr.cwchar.compile.pass.cpp b/libcxx/test/libcxx/strings/c.strings/constexpr.cwchar.compile.pass.cpp
new file mode 100644
index 0000000000000..02feed064eacc
--- /dev/null
+++ b/libcxx/test/libcxx/strings/c.strings/constexpr.cwchar.compile.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// UNSUPPORTED: no-wide-characters
+
+// Check that __constexpr_* cwchar functions are actually constexpr
+
+#include <cwchar>
+
+static_assert(std::__constexpr_wcslen(L"Banane") == 6, "");
+static_assert(std::__constexpr_wmemcmp(L"Banane", L"Banand", 6) == 1, "");
+static_assert(std::__constexpr_wmemcmp(L"Banane", L"Banane", 6) == 0, "");
+static_assert(std::__constexpr_wmemcmp(L"Banane", L"Bananf", 6) == -1, "");
+
+constexpr bool test_constexpr_wmemchr() {
+ const wchar_t str[] = L"Banane";
+ return std::__constexpr_wmemchr(str, 'n', 6) == str + 2;
+}
+static_assert(test_constexpr_wmemchr(), "");
More information about the libcxx-commits
mailing list