diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -108,6 +108,7 @@ target_link_libraries( cxx-benchmarks-flags-libcxx INTERFACE cxx-benchmarks-flags) target_compile_options(cxx-benchmarks-flags-libcxx INTERFACE ${SANITIZER_FLAGS} -Wno-user-defined-literals -Wno-suggest-override) target_link_options( cxx-benchmarks-flags-libcxx INTERFACE -nodefaultlibs "-L${BENCHMARK_LIBCXX_INSTALL}/lib" ${SANITIZER_FLAGS}) +target_link_options( cxx-benchmarks-flags-libcxx INTERFACE -nodefaultlibs "-L${BENCHMARK_LIBCXX_INSTALL}/lib64" ${SANITIZER_FLAGS}) set(libcxx_benchmark_targets) @@ -158,6 +159,7 @@ #============================================================================== set(BENCHMARK_TESTS algorithms.partition_point.bench.cpp + algorithms/equal.bench.cpp algorithms/lower_bound.bench.cpp algorithms/make_heap.bench.cpp algorithms/make_heap_then_sort_heap.bench.cpp diff --git a/libcxx/benchmarks/algorithms/equal.bench.cpp b/libcxx/benchmarks/algorithms/equal.bench.cpp new file mode 100644 --- /dev/null +++ b/libcxx/benchmarks/algorithms/equal.bench.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +static void bm_equal_iter(benchmark::State& state) { + std::vector vec1(state.range(), '1'); + std::vector vec2(state.range(), '1'); + for (auto _ : state) { + benchmark::DoNotOptimize(vec1); + benchmark::DoNotOptimize(vec2); + benchmark::DoNotOptimize(std::equal(vec1.begin(), vec1.end(), vec2.begin())); + } +} +BENCHMARK(bm_equal_iter)->DenseRange(1, 8)->Range(16, 1 << 20); + +static void bm_equal(benchmark::State& state) { + std::vector vec1(state.range(), '1'); + std::vector vec2(state.range(), '1'); + for (auto _ : state) { + benchmark::DoNotOptimize(vec1); + benchmark::DoNotOptimize(vec2); + benchmark::DoNotOptimize(std::equal(vec1.begin(), vec1.end(), vec2.begin(), vec2.end())); + } +} +BENCHMARK(bm_equal)->DenseRange(1, 8)->Range(16, 1 << 20); + +static void bm_ranges_equal(benchmark::State& state) { + std::vector vec1(state.range(), '1'); + std::vector vec2(state.range(), '1'); + for (auto _ : state) { + benchmark::DoNotOptimize(vec1); + benchmark::DoNotOptimize(vec2); + benchmark::DoNotOptimize(std::ranges::equal(vec1, vec2)); + } +} +BENCHMARK(bm_ranges_equal)->DenseRange(1, 8)->Range(16, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -580,6 +580,7 @@ __type_traits/is_callable.h __type_traits/is_char_like_type.h __type_traits/is_class.h + __type_traits/is_comparable.h __type_traits/is_compound.h __type_traits/is_const.h __type_traits/is_constant_evaluated.h @@ -618,6 +619,7 @@ __type_traits/is_pod.h __type_traits/is_pointer.h __type_traits/is_polymorphic.h + __type_traits/is_predicate_kind.h __type_traits/is_primary_template.h __type_traits/is_reference.h __type_traits/is_reference_wrapper.h diff --git a/libcxx/include/__algorithm/comp.h b/libcxx/include/__algorithm/comp.h --- a/libcxx/include/__algorithm/comp.h +++ b/libcxx/include/__algorithm/comp.h @@ -10,6 +10,8 @@ #define _LIBCPP___ALGORITHM_COMP_H #include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_predicate_kind.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -24,6 +26,9 @@ } }; +template <> +struct __is_equal_to_predicate<__equal_to> : true_type {}; + template struct __less { 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 @@ -11,9 +11,19 @@ #define _LIBCPP___ALGORITHM_EQUAL_H #include <__algorithm/comp.h> +#include <__algorithm/unwrap_iter.h> #include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_comparable.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_predicate_kind.h> +#include <__type_traits/is_volatile.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -22,14 +32,40 @@ _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool -equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { +_LIBCPP_NODISCARD inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_trivial_impl( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { for (; __first1 != __last1; ++__first1, (void)++__first2) if (!__pred(*__first1, *__first2)) return false; return true; } +template +_LIBCPP_NODISCARD inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { + return std::__equal_iter_trivial_impl(__first1, __last1, __first2, __pred); +} + +template ::value && !is_volatile<_Tp>::value && + !is_volatile<_Up>::value && __is_trivially_equality_comparable<_Tp, _Up>::value, + int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +__equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate __pred) { + if (!__libcpp_is_constant_evaluated() || sizeof(_Tp) == 1) + return std::__constexpr_memcmp(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)) == 0; + return std::__equal_iter_trivial_impl(__first1, __last1, __first2, __pred); +} + +template +_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { + return std::__equal_iter_impl( + std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred); +} + template _LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2) { @@ -47,6 +83,40 @@ return __first1 == __last1 && __first2 == __last2; } +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_trivial_impl( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __comp, _Proj1& __proj1, _Proj2& __proj2) { + while (__first1 != __last1 && __first2 != __last2) { + if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + return false; + ++__first1; + ++__first2; + } + return __first1 == __last1 && __first2 == __last2; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __comp, _Proj1& __proj1, _Proj2& __proj2) { + return std::__equal_trivial_impl(__first1, __last1, __first2, __last2, __comp, __proj1, __proj2); +} + +template ::value && __is_identity<_Proj1>::value && + __is_identity<_Proj2>::value && !is_volatile<_Tp>::value && !is_volatile<_Up>::value && + __is_trivially_equality_comparable<_Tp, _Up>::value, + int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( + _Tp* __first1, _Tp* __last1, _Up* __first2, _Up* __last2, _Pred& __comp, _Proj1& __proj1, _Proj2& __proj2) { + if (!__libcpp_is_constant_evaluated() || sizeof(_Tp) == 1) + return std::__constexpr_memcmp(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)) == 0; + return std::__equal_trivial_impl(__first1, __last1, __first2, __last2, __comp, __proj1, __proj2); +} + template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -54,8 +124,15 @@ random_access_iterator_tag) { if (_VSTD::distance(__first1, __last1) != _VSTD::distance(__first2, __last2)) return false; - return _VSTD::equal<_RandomAccessIterator1, _RandomAccessIterator2, - _BinaryPredicate&>(__first1, __last1, __first2, __pred); + __identity __proj; + return std::__equal_impl( + std::__unwrap_iter(__first1), + std::__unwrap_iter(__last1), + std::__unwrap_iter(__first2), + std::__unwrap_iter(__last2), + __pred, + __proj, + __proj); } template diff --git a/libcxx/include/__algorithm/ranges_equal.h b/libcxx/include/__algorithm/ranges_equal.h --- a/libcxx/include/__algorithm/ranges_equal.h +++ b/libcxx/include/__algorithm/ranges_equal.h @@ -9,6 +9,8 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_EQUAL_H #define _LIBCPP___ALGORITHM_RANGES_EQUAL_H +#include <__algorithm/equal.h> +#include <__algorithm/unwrap_range.h> #include <__config> #include <__functional/identity.h> #include <__functional/invoke.h> @@ -19,6 +21,7 @@ #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__utility/move.h> +#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -31,29 +34,6 @@ namespace ranges { namespace __equal { struct __fn { -private: - template - _LIBCPP_HIDE_FROM_ABI constexpr static - bool __equal_impl(_Iter1 __first1, _Sent1 __last1, - _Iter2 __first2, _Sent2 __last2, - _Pred& __pred, - _Proj1& __proj1, - _Proj2& __proj2) { - while (__first1 != __last1 && __first2 != __last2) { - if (!std::invoke(__pred, std::invoke(__proj1, *__first1), std::invoke(__proj2, *__first2))) - return false; - ++__first1; - ++__first2; - } - return __first1 == __last1 && __first2 == __last2; - } - -public: - template _Sent1, input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, class _Pred = ranges::equal_to, @@ -70,11 +50,13 @@ if (__last1 - __first1 != __last2 - __first2) return false; } - return __equal_impl(std::move(__first1), std::move(__last1), - std::move(__first2), std::move(__last2), - __pred, - __proj1, - __proj2); + auto __unwrapped1 = std::__unwrap_range(std::move(__first1), std::move(__last1)); + auto __unwrapped2 = std::__unwrap_range(std::move(__first2), std::move(__last2)); + return std::__equal_impl(std::move(__unwrapped1.first), std::move(__unwrapped1.second), + std::move(__unwrapped2.first), std::move(__unwrapped2.second), + __pred, + __proj1, + __proj2); } template +#include <__type_traits/integral_constant.h> #include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -19,6 +20,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct __is_identity : false_type {}; + struct __identity { template _LIBCPP_NODISCARD _LIBCPP_CONSTEXPR _Tp&& operator()(_Tp&& __t) const _NOEXCEPT { @@ -28,6 +32,9 @@ using is_transparent = void; }; +template <> +struct __is_identity<__identity> : true_type {}; + #if _LIBCPP_STD_VER > 17 struct identity { @@ -39,6 +46,10 @@ using is_transparent = void; }; + +template <> +struct __is_identity : true_type {}; + #endif // _LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__functional/operations.h b/libcxx/include/__functional/operations.h --- a/libcxx/include/__functional/operations.h +++ b/libcxx/include/__functional/operations.h @@ -13,6 +13,8 @@ #include <__config> #include <__functional/binary_function.h> #include <__functional/unary_function.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_predicate_kind.h> #include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -341,6 +343,9 @@ }; #endif +template +struct __is_equal_to_predicate> : true_type {}; + #if _LIBCPP_STD_VER > 11 template #else diff --git a/libcxx/include/__functional/ranges_operations.h b/libcxx/include/__functional/ranges_operations.h --- a/libcxx/include/__functional/ranges_operations.h +++ b/libcxx/include/__functional/ranges_operations.h @@ -13,6 +13,8 @@ #include <__concepts/equality_comparable.h> #include <__concepts/totally_ordered.h> #include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_predicate_kind.h> #include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -93,6 +95,9 @@ } // namespace ranges +template <> +struct __is_equal_to_predicate : true_type {}; + #endif // _LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__type_traits/is_comparable.h b/libcxx/include/__type_traits/is_comparable.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__type_traits/is_comparable.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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_COMPARABLE_H +#define _LIBCPP___TYPE_TRAITS_IS_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> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __is_equality_comparable : false_type {}; + +template +struct __is_equality_comparable<_Tp, _Up, __void_t() == std::declval<_Up>())>> : true_type { +}; + +template +struct __is_trivially_equality_comparable + : integral_constant::value && is_integral<_Tp>::value && + is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up>>::value> {}; + +template +struct __is_trivially_equality_comparable<_Tp*, _Up*> : __is_equality_comparable<_Tp*, _Up*> {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_COMPARABLE_H diff --git a/libcxx/include/__type_traits/is_predicate_kind.h b/libcxx/include/__type_traits/is_predicate_kind.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__type_traits/is_predicate_kind.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_PREDICATE_KIND +#define _LIBCPP___TYPE_TRAITS_IS_PREDICATE_KIND + +#include <__config> +#include <__type_traits/integral_constant.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __is_equal_to_predicate : false_type {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_PREDICATE_KIND diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1383,6 +1383,7 @@ module is_callable { private header "__type_traits/is_callable.h" } module is_char_like_type { private header "__type_traits/is_char_like_type.h" } module is_class { private header "__type_traits/is_class.h" } + module is_comparable { private header "__type_traits/is_comparable.h" } module is_compound { private header "__type_traits/is_compound.h" } module is_const { private header "__type_traits/is_const.h" } module is_constant_evaluated { private header "__type_traits/is_constant_evaluated.h" } @@ -1421,6 +1422,7 @@ module is_pod { private header "__type_traits/is_pod.h" } module is_pointer { private header "__type_traits/is_pointer.h" } module is_polymorphic { private header "__type_traits/is_polymorphic.h" } + module is_predicate_kind { private header "__type_traits/is_predicate_kind.h" } module is_primary_template { private header "__type_traits/is_primary_template.h" } module is_reference { private header "__type_traits/is_reference.h" } module is_reference_wrapper { private header "__type_traits/is_reference_wrapper.h" } diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -593,6 +593,7 @@ #include <__type_traits/is_callable.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_callable.h'}} #include <__type_traits/is_char_like_type.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_char_like_type.h'}} #include <__type_traits/is_class.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_class.h'}} +#include <__type_traits/is_comparable.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_comparable.h'}} #include <__type_traits/is_compound.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_compound.h'}} #include <__type_traits/is_const.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_const.h'}} #include <__type_traits/is_constant_evaluated.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_constant_evaluated.h'}} @@ -631,6 +632,7 @@ #include <__type_traits/is_pod.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_pod.h'}} #include <__type_traits/is_pointer.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_pointer.h'}} #include <__type_traits/is_polymorphic.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_polymorphic.h'}} +#include <__type_traits/is_predicate_kind.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_predicate_kind.h'}} #include <__type_traits/is_primary_template.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_primary_template.h'}} #include <__type_traits/is_reference.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_reference.h'}} #include <__type_traits/is_reference_wrapper.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_reference_wrapper.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 @@ -21,67 +21,67 @@ #include #include -#include "test_macros.h" #include "test_iterators.h" +#include "test_macros.h" +#include "type_algorithms.h" -template -void test_equal() { - int a[] = {0, 1, 2, 3, 4, 5}; - const unsigned s = sizeof(a) / sizeof(a[0]); - int b[s] = {0, 1, 2, 5, 4, 5}; +template +struct Test { + template + TEST_CONSTEXPR_CXX20 void operator()() { + UnderlyingType a[] = {0, 1, 2, 3, 4, 5}; + const unsigned s = sizeof(a) / sizeof(a[0]); + UnderlyingType b[s] = {0, 1, 2, 5, 4, 5}; - assert(std::equal(Iter1(a), Iter1(a + s), Iter2(a))); - assert(std::equal(Iter2(a), Iter2(a + s), Iter1(a))); - assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(b))); + assert(std::equal(Iter1(a), Iter1(a + s), Iter2(a))); + assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(b))); #if TEST_STD_VER >= 14 - assert(std::equal(Iter1(a), Iter1(a + s), Iter2(a), Iter2(a + s))); - assert(std::equal(Iter2(a), Iter2(a + s), Iter1(a), Iter1(a + s))); - assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(a), Iter2(a + s - 1))); - assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(b), Iter2(b + s))); + assert(std::equal(Iter1(a), Iter1(a + s), Iter2(a), Iter2(a + s))); + assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(a), Iter2(a + s - 1))); + assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(b), Iter2(b + s))); #endif -} + } +}; -#if TEST_STD_VER > 17 -TEST_CONSTEXPR bool test_constexpr() { - int ia[] = {1, 3, 6, 7}; - int ib[] = {1, 3}; - int ic[] = {1, 3, 5, 7}; - typedef cpp17_input_iterator II; - typedef bidirectional_iterator BI; - - return !std::equal(std::begin(ia), std::end(ia), std::begin(ic)) - && !std::equal(std::begin(ia), std::end(ia), std::begin(ic), std::end(ic)) - && std::equal(std::begin(ib), std::end(ib), std::begin(ic)) - && !std::equal(std::begin(ib), std::end(ib), std::begin(ic), std::end(ic)) - - && std::equal(II(std::begin(ib)), II(std::end(ib)), II(std::begin(ic))) - && !std::equal(BI(std::begin(ib)), BI(std::end(ib)), BI(std::begin(ic)), BI(std::end(ic))) - ; - } -#endif +template +struct TestIter2 { + template + TEST_CONSTEXPR_CXX20 void operator()() { + meta::for_each(TypeList(), Test()); + } +}; + +struct AddressCompare { + int i = 0; + TEST_CONSTEXPR_CXX20 AddressCompare(int) {} + friend TEST_CONSTEXPR_CXX20 bool operator==(const AddressCompare& lhs, const AddressCompare& rhs) { + return &lhs == &rhs; + } -int main(int, char**) -{ - test_equal >(); - test_equal >(); - - // Test all combinations of cv-qualifiers: - test_equal(); - test_equal(); - test_equal(); - test_equal(); - test_equal(); - test_equal(); - test_equal(); - test_equal(); - test_equal(); - test_equal(); - -#if TEST_STD_VER > 17 - static_assert(test_constexpr()); + friend TEST_CONSTEXPR_CXX20 bool operator!=(const AddressCompare& lhs, const AddressCompare& rhs) { + return &lhs != &rhs; + } +}; + +TEST_CONSTEXPR_CXX20 bool test() { + meta::for_each(meta::cpp17_input_iterator_list(), TestIter2>()); + meta::for_each(meta::cpp17_input_iterator_list(), TestIter2>()); + meta::for_each(meta::cpp17_input_iterator_list(), + TestIter2>()); + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 20 + static_assert(test()); #endif + meta::for_each(meta::cv_qualified_ptr(), TestIter2>()); + meta::for_each(meta::cv_qualified_ptr(), TestIter2>()); + return 0; } diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1298,23 +1298,31 @@ requires std::ranges::viewable_range ProxyRange(R&&) -> ProxyRange>; +#endif // TEST_STD_VER > 17 + namespace meta { template -using random_access_iterator_list = type_list, random_access_iterator>; +using random_access_iterator_list = type_list, random_access_iterator >; template using bidirectional_iterator_list = - concatenate_t, type_list>>; + concatenate_t, type_list > >; + +template +using forward_iterator_list = concatenate_t, type_list > >; template -using forward_iterator_list = concatenate_t, type_list>>; +using cpp17_input_iterator_list = concatenate_t, type_list > >; +#if TEST_STD_VER >= 20 template using cpp20_input_iterator_list = concatenate_t, type_list, cpp17_input_iterator>>; +#endif +template +using cv_qualified_ptr = type_list; } // namespace meta -#endif // TEST_STD_VER > 17 #endif // SUPPORT_TEST_ITERATORS_H