1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H
10 #define _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H
13 #include <__cstddef/size_t.h>
14 #include <__memory/addressof.h>
15 #include <__memory/construct_at.h>
16 #include <__type_traits/datasizeof.h>
17 #include <__type_traits/enable_if.h>
18 #include <__type_traits/is_always_bitcastable.h>
19 #include <__type_traits/is_assignable.h>
20 #include <__type_traits/is_constant_evaluated.h>
21 #include <__type_traits/is_constructible.h>
22 #include <__type_traits/is_equality_comparable.h>
23 #include <__type_traits/is_integral.h>
24 #include <__type_traits/is_same.h>
25 #include <__type_traits/is_trivially_copyable.h>
26 #include <__type_traits/is_trivially_lexicographically_comparable.h>
27 #include <__type_traits/remove_cv.h>
28 #include <__utility/is_pointer_in_range.h>
30 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
31 # pragma GCC system_header
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 // Type used to encode that a function takes an integer that represents a number
37 // of elements as opposed to a number of bytes.
38 enum class __element_count
: size_t {};
41 inline const bool __is_char_type
= false;
44 inline const bool __is_char_type
<char> = true;
46 #if _LIBCPP_HAS_CHAR8_T
48 inline const bool __is_char_type
<char8_t
> = true;
52 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
size_t __constexpr_strlen(const _Tp
* __str
) _NOEXCEPT
{
53 static_assert(__is_char_type
<_Tp
>, "__constexpr_strlen only works with char and char8_t");
54 // GCC currently doesn't support __builtin_strlen for heap-allocated memory during constant evaluation.
55 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70816
56 if (__libcpp_is_constant_evaluated()) {
57 #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_COMPILER_CLANG_BASED)
58 if constexpr (is_same_v
<_Tp
, char>)
59 return __builtin_strlen(__str
);
62 for (; __str
[__i
] != '\0'; ++__i
)
66 return __builtin_strlen(reinterpret_cast<const char*>(__str
));
69 // Because of __is_trivially_lexicographically_comparable_v we know that comparing the object representations is
70 // equivalent to a std::memcmp. Since we have multiple objects contiguously in memory, we can call memcmp once instead
71 // of invoking it on every object individually.
72 template <class _Tp
, class _Up
>
73 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
int
74 __constexpr_memcmp(const _Tp
* __lhs
, const _Up
* __rhs
, __element_count __n
) {
75 static_assert(__is_trivially_lexicographically_comparable_v
<_Tp
, _Up
>,
76 "_Tp and _Up have to be trivially lexicographically comparable");
78 auto __count
= static_cast<size_t>(__n
);
80 if (__libcpp_is_constant_evaluated()) {
81 #ifdef _LIBCPP_COMPILER_CLANG_BASED
82 if (sizeof(_Tp
) == 1 && !is_same
<_Tp
, bool>::value
)
83 return __builtin_memcmp(__lhs
, __rhs
, __count
* sizeof(_Tp
));
86 while (__count
!= 0) {
98 return __builtin_memcmp(__lhs
, __rhs
, __count
* sizeof(_Tp
));
102 // Because of __libcpp_is_trivially_equality_comparable we know that comparing the object representations is equivalent
103 // to a std::memcmp(...) == 0. Since we have multiple objects contiguously in memory, we can call memcmp once instead
104 // of invoking it on every object individually.
105 template <class _Tp
, class _Up
>
106 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
bool
107 __constexpr_memcmp_equal(const _Tp
* __lhs
, const _Up
* __rhs
, __element_count __n
) {
108 static_assert(__libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
,
109 "_Tp and _Up have to be trivially equality comparable");
111 auto __count
= static_cast<size_t>(__n
);
113 if (__libcpp_is_constant_evaluated()) {
114 #ifdef _LIBCPP_COMPILER_CLANG_BASED
115 if (sizeof(_Tp
) == 1 && is_integral
<_Tp
>::value
&& !is_same
<_Tp
, bool>::value
)
116 return __builtin_memcmp(__lhs
, __rhs
, __count
* sizeof(_Tp
)) == 0;
118 while (__count
!= 0) {
119 if (*__lhs
!= *__rhs
)
128 return ::__builtin_memcmp(__lhs
, __rhs
, __count
* sizeof(_Tp
)) == 0;
132 template <class _Tp
, class _Up
>
133 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
* __constexpr_memchr(_Tp
* __str
, _Up __value
, size_t __count
) {
134 static_assert(sizeof(_Tp
) == 1 && __libcpp_is_trivially_equality_comparable
<_Tp
, _Up
>::value
,
135 "Calling memchr on non-trivially equality comparable types is unsafe.");
137 if (__libcpp_is_constant_evaluated()) {
138 // use __builtin_char_memchr to optimize constexpr evaluation if we can
139 #if _LIBCPP_STD_VER >= 17 && __has_builtin(__builtin_char_memchr)
140 if constexpr (is_same_v
<remove_cv_t
<_Tp
>, char> && is_same_v
<remove_cv_t
<_Up
>, char>)
141 return __builtin_char_memchr(__str
, __value
, __count
);
144 for (; __count
; --__count
) {
145 if (*__str
== __value
)
151 char __value_buffer
= 0;
152 __builtin_memcpy(&__value_buffer
, &__value
, sizeof(char));
153 return static_cast<_Tp
*>(__builtin_memchr(__str
, __value_buffer
, __count
));
157 // This function performs an assignment to an existing, already alive TriviallyCopyable object
158 // from another TriviallyCopyable object.
160 // It basically works around the fact that TriviallyCopyable objects are not required to be
161 // syntactically copy/move constructible or copy/move assignable. Technically, only one of the
162 // four operations is required to be syntactically valid -- but at least one definitely has to
165 // This is necessary in order to implement __constexpr_memmove below in a way that mirrors as
166 // closely as possible what the compiler's __builtin_memmove is able to do.
167 template <class _Tp
, class _Up
, __enable_if_t
<is_assignable
<_Tp
&, _Up
const&>::value
, int> = 0>
168 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
& __assign_trivially_copyable(_Tp
& __dest
, _Up
const& __src
) {
174 template <class _Tp
, class _Up
, __enable_if_t
<!is_assignable
<_Tp
&, _Up
const&>::value
&&
175 is_assignable
<_Tp
&, _Up
&&>::value
, int> = 0>
177 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
& __assign_trivially_copyable(_Tp
& __dest
, _Up
& __src
) {
179 static_cast<_Up
&&>(__src
); // this is safe, we're not actually moving anything since the assignment is trivial
184 template <class _Tp
, class _Up
, __enable_if_t
<!is_assignable
<_Tp
&, _Up
const&>::value
&&
185 !is_assignable
<_Tp
&, _Up
&&>::value
&&
186 is_constructible
<_Tp
, _Up
const&>::value
, int> = 0>
188 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp
& __assign_trivially_copyable(_Tp
& __dest
, _Up
const& __src
) {
189 // _Tp is trivially destructible, so we don't need to call its destructor to end the lifetime of the object
190 // that was there previously
191 std::__construct_at(std::addressof(__dest
), __src
);
196 template <class _Tp
, class _Up
, __enable_if_t
<!is_assignable
<_Tp
&, _Up
const&>::value
&&
197 !is_assignable
<_Tp
&, _Up
&&>::value
&&
198 !is_constructible
<_Tp
, _Up
const&>::value
&&
199 is_constructible
<_Tp
, _Up
&&>::value
, int> = 0>
201 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp
& __assign_trivially_copyable(_Tp
& __dest
, _Up
& __src
) {
202 // _Tp is trivially destructible, so we don't need to call its destructor to end the lifetime of the object
203 // that was there previously
205 std::addressof(__dest
),
206 static_cast<_Up
&&>(__src
)); // this is safe, we're not actually moving anything since the constructor is trivial
210 template <class _Tp
, class _Up
, __enable_if_t
<__is_always_bitcastable
<_Up
, _Tp
>::value
, int> = 0>
211 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp
*
212 __constexpr_memmove(_Tp
* __dest
, _Up
* __src
, __element_count __n
) {
213 size_t __count
= static_cast<size_t>(__n
);
214 if (__libcpp_is_constant_evaluated()) {
215 #ifdef _LIBCPP_COMPILER_CLANG_BASED
216 if (is_same
<__remove_cv_t
<_Tp
>, __remove_cv_t
<_Up
> >::value
) {
217 ::__builtin_memmove(__dest
, __src
, __count
* sizeof(_Tp
));
221 if (std::__is_pointer_in_range(__src
, __src
+ __count
, __dest
)) {
222 for (; __count
> 0; --__count
)
223 std::__assign_trivially_copyable(__dest
[__count
- 1], __src
[__count
- 1]);
225 for (size_t __i
= 0; __i
!= __count
; ++__i
)
226 std::__assign_trivially_copyable(__dest
[__i
], __src
[__i
]);
228 } else if (__count
> 0) {
229 ::__builtin_memmove(__dest
, __src
, (__count
- 1) * sizeof(_Tp
) + __datasizeof_v
<_Tp
>);
234 _LIBCPP_END_NAMESPACE_STD
236 #endif // _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H