diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -702,6 +702,7 @@ __type_traits/is_trivially_copyable.h __type_traits/is_trivially_default_constructible.h __type_traits/is_trivially_destructible.h + __type_traits/is_trivially_lexicographically_comparable.h __type_traits/is_trivially_move_assignable.h __type_traits/is_trivially_move_constructible.h __type_traits/is_unbounded_array.h diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h --- a/libcxx/include/__algorithm/equal.h +++ b/libcxx/include/__algorithm/equal.h @@ -50,7 +50,7 @@ int> = 0> _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&) { - return std::__constexpr_memcmp(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)) == 0; + return std::__constexpr_memcmp_equal(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)); } template @@ -100,7 +100,7 @@ int> = 0> _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( _Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&, _Proj2&) { - return std::__constexpr_memcmp(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)) == 0; + return std::__constexpr_memcmp_equal(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)); } template diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h --- a/libcxx/include/__string/constexpr_c_functions.h +++ b/libcxx/include/__string/constexpr_c_functions.h @@ -13,6 +13,7 @@ #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_equality_comparable.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_trivially_lexicographically_comparable.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -38,8 +39,8 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, size_t __count) { - static_assert(__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, - "_Tp and _Up have to be trivially equality comparable"); + static_assert(__libcpp_is_trivially_lexicographically_comparable<_Tp, _Up>::value, + "_Tp and _Up have to be trivially lexicographically comparable"); if (__libcpp_is_constant_evaluated()) { #ifdef _LIBCPP_COMPILER_CLANG_BASED @@ -63,6 +64,31 @@ } } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +__constexpr_memcmp_equal(const _Tp* __lhs, const _Up* __rhs, size_t __count) { + static_assert(__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, + "_Tp and _Up have to be trivially equality comparable"); + + if (__libcpp_is_constant_evaluated()) { +#ifdef _LIBCPP_COMPILER_CLANG_BASED + if (sizeof(_Tp) == 1 && is_integral<_Tp>::value && !is_same<_Tp, bool>::value) + return __builtin_memcmp(__lhs, __rhs, __count) == 0; +#endif + while (__count != 0) { + if (*__lhs != *__rhs) + return false; + + __count -= sizeof(_Tp); + ++__lhs; + ++__rhs; + } + return true; + } else { + return __builtin_memcmp(__lhs, __rhs, __count) == 0; + } +} + 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) diff --git a/libcxx/include/__type_traits/is_equality_comparable.h b/libcxx/include/__type_traits/is_equality_comparable.h --- a/libcxx/include/__type_traits/is_equality_comparable.h +++ b/libcxx/include/__type_traits/is_equality_comparable.h @@ -15,6 +15,7 @@ #include <__type_traits/is_same.h> #include <__type_traits/is_void.h> #include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> @@ -43,20 +44,33 @@ // always compared. template -struct __libcpp_is_trivially_equality_comparable - : integral_constant::value && is_integral<_Tp>::value && - is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value> {}; +struct __libcpp_is_trivially_equality_comparable_impl + : integral_constant::value && is_same<_Tp, _Up>::value> {}; + +#if __has_builtin(__is_trivially_equality_comparable) + +template +struct __libcpp_is_trivially_equality_comparable_impl<_Tp, _Tp> + : integral_constant::value> {}; + +#endif // __has_builtin(__is_trivially_equality_comparable) + +template +struct __libcpp_is_trivially_equality_comparable_impl<_Tp*, _Tp*> : true_type {}; // TODO: Use is_pointer_inverconvertible_base_of template -struct __libcpp_is_trivially_equality_comparable<_Tp*, _Up*> +struct __libcpp_is_trivially_equality_comparable_impl<_Tp*, _Up*> : integral_constant< bool, __is_equality_comparable<_Tp*, _Up*>::value && (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value || is_void<_Tp>::value || is_void<_Up>::value)> { }; +template +using __libcpp_is_trivially_equality_comparable = + __libcpp_is_trivially_equality_comparable_impl<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TYPE_TRAITS_IS_EQUAILITY_COMPARABLE_H diff --git a/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h b/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__type_traits/is_trivially_lexicographically_comparable.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_LEXICOGRAPHICALLY_COMPARABLE_H +#define _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_LEXICOGRAPHICALLY_COMPARABLE_H + +#include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __libcpp_is_trivially_lexicographically_comparable + : integral_constant, __remove_cv_t<_Up> >::value && sizeof(_Tp) == 1 && + is_integral<_Tp>::value> {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_LEXICOGRAPHICALLY_COMPARABLE_H diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp @@ -98,14 +98,33 @@ } }; +#if TEST_STD_VER >= 20 +class trivially_equality_comparable { +public: + constexpr trivially_equality_comparable(int i) : i_(i) {} + bool operator==(const trivially_equality_comparable&) const = default; + +private: + int i_; +}; + +#endif + TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), TestIter2 >()); - types::for_each(types::cpp17_input_iterator_list(), TestIter2 >()); + types::for_each( + types::cpp17_input_iterator_list(), TestIter2 >()); types::for_each(types::cpp17_input_iterator_list(), - TestIter2 >()); + TestIter2 >()); types::for_each(types::integral_types(), TestNarrowingEqualTo()); +#if TEST_STD_VER >= 20 + types::for_each( + types::cpp17_input_iterator_list{}, + TestIter2>{}); +#endif + return true; } @@ -119,9 +138,9 @@ #endif types::for_each(types::as_pointers >(), - TestIter2 > >()); + TestIter2 > >()); types::for_each(types::as_pointers >(), - TestIter2 > >()); + TestIter2 > >()); { Derived d;