mirror of
https://github.com/intel/llvm.git
synced 2026-01-20 01:58:44 +08:00
[libc++] Forward to std::memcmp for trivially comparable types in equal
Reviewed By: #libc, ldionne Spies: ldionne, Mordante, libcxx-commits Differential Revision: https://reviews.llvm.org/D139554
This commit is contained in:
@@ -107,7 +107,7 @@ endif()
|
||||
add_library( cxx-benchmarks-flags-libcxx INTERFACE)
|
||||
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}/lib" "-L${BENCHMARK_LIBCXX_INSTALL}/lib64" ${SANITIZER_FLAGS})
|
||||
|
||||
set(libcxx_benchmark_targets)
|
||||
|
||||
@@ -158,6 +158,7 @@ endfunction()
|
||||
#==============================================================================
|
||||
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
|
||||
|
||||
46
libcxx/benchmarks/algorithms/equal.bench.cpp
Normal file
46
libcxx/benchmarks/algorithms/equal.bench.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <vector>
|
||||
|
||||
static void bm_equal_iter(benchmark::State& state) {
|
||||
std::vector<char> vec1(state.range(), '1');
|
||||
std::vector<char> 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<char> vec1(state.range(), '1');
|
||||
std::vector<char> 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<char> vec1(state.range(), '1');
|
||||
std::vector<char> 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();
|
||||
@@ -42,6 +42,8 @@ Implemented Papers
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
- ``std::equal`` and ``std::ranges::equal`` are now forwarding to ``std::memcmp`` for integral types and pointers,
|
||||
which can lead up to 40x performance improvements.
|
||||
|
||||
- ``std::string_view`` now provides iterators that check for out-of-bounds accesses when the safe
|
||||
libc++ mode is enabled.
|
||||
|
||||
@@ -638,6 +638,7 @@ set(files
|
||||
__type_traits/is_destructible.h
|
||||
__type_traits/is_empty.h
|
||||
__type_traits/is_enum.h
|
||||
__type_traits/is_equality_comparable.h
|
||||
__type_traits/is_final.h
|
||||
__type_traits/is_floating_point.h
|
||||
__type_traits/is_function.h
|
||||
@@ -702,6 +703,7 @@ set(files
|
||||
__type_traits/nat.h
|
||||
__type_traits/negation.h
|
||||
__type_traits/noexcept_move_assign_container.h
|
||||
__type_traits/predicate_traits.h
|
||||
__type_traits/promote.h
|
||||
__type_traits/rank.h
|
||||
__type_traits/remove_all_extents.h
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define _LIBCPP___ALGORITHM_COMP_H
|
||||
|
||||
#include <__config>
|
||||
#include <__type_traits/integral_constant.h>
|
||||
#include <__type_traits/predicate_traits.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@@ -24,6 +26,9 @@ struct __equal_to {
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Lhs, class _Rhs>
|
||||
struct __is_trivial_equality_predicate<__equal_to, _Lhs, _Rhs> : true_type {};
|
||||
|
||||
template <class _T1, class _T2 = _T1>
|
||||
struct __less
|
||||
{
|
||||
|
||||
@@ -11,9 +11,20 @@
|
||||
#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 <__string/constexpr_c_functions.h>
|
||||
#include <__type_traits/enable_if.h>
|
||||
#include <__type_traits/integral_constant.h>
|
||||
#include <__type_traits/is_constant_evaluated.h>
|
||||
#include <__type_traits/is_equality_comparable.h>
|
||||
#include <__type_traits/is_volatile.h>
|
||||
#include <__type_traits/predicate_traits.h>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@@ -22,23 +33,42 @@
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
|
||||
_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_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl(
|
||||
_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate& __pred) {
|
||||
for (; __first1 != __last1; ++__first1, (void)++__first2)
|
||||
if (!__pred(*__first1, *__first2))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <
|
||||
class _Tp,
|
||||
class _Up,
|
||||
class _BinaryPredicate,
|
||||
__enable_if_t<__is_trivial_equality_predicate<_BinaryPredicate, _Tp, _Up>::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_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&) {
|
||||
return std::__constexpr_memcmp(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)) == 0;
|
||||
}
|
||||
|
||||
template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _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 <class _InputIterator1, class _InputIterator2>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2) {
|
||||
return std::equal(__first1, __last1, __first2, __equal_to());
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER >= 14
|
||||
template <class _BinaryPredicate, class _InputIterator1, class _InputIterator2>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
__equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2,
|
||||
_BinaryPredicate __pred, input_iterator_tag, input_iterator_tag) {
|
||||
for (; __first1 != __last1 && __first2 != __last2; ++__first1, (void)++__first2)
|
||||
@@ -47,19 +77,52 @@ __equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __fir
|
||||
return __first1 == __last1 && __first2 == __last2;
|
||||
}
|
||||
|
||||
template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2>
|
||||
_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) {
|
||||
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 <class _Tp,
|
||||
class _Up,
|
||||
class _Pred,
|
||||
class _Proj1,
|
||||
class _Proj2,
|
||||
__enable_if_t<__is_trivial_equality_predicate<_Pred, _Tp, _Up>::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*, _Pred&, _Proj1&, _Proj2&) {
|
||||
return std::__constexpr_memcmp(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)) == 0;
|
||||
}
|
||||
|
||||
template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
__equal(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2,
|
||||
_RandomAccessIterator2 __last2, _BinaryPredicate __pred, random_access_iterator_tag,
|
||||
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 <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2,
|
||||
_BinaryPredicate __pred) {
|
||||
return _VSTD::__equal<_BinaryPredicate&>(
|
||||
@@ -68,7 +131,7 @@ equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first
|
||||
}
|
||||
|
||||
template <class _InputIterator1, class _InputIterator2>
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
|
||||
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) {
|
||||
return std::__equal(
|
||||
__first1,
|
||||
|
||||
@@ -55,25 +55,12 @@ struct _ProjectedPred {
|
||||
|
||||
};
|
||||
|
||||
template <class _Pred, class _Proj, class = void>
|
||||
struct __can_use_pristine_comp : false_type {};
|
||||
|
||||
template <class _Pred, class _Proj>
|
||||
struct __can_use_pristine_comp<_Pred, _Proj, __enable_if_t<
|
||||
!is_member_pointer<typename decay<_Pred>::type>::value && (
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
is_same<typename decay<_Proj>::type, identity>::value ||
|
||||
#endif
|
||||
is_same<typename decay<_Proj>::type, __identity>::value
|
||||
)
|
||||
> > : true_type {};
|
||||
|
||||
template <class _Pred, class _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static
|
||||
__enable_if_t<
|
||||
!__can_use_pristine_comp<_Pred, _Proj>::value,
|
||||
_ProjectedPred<_Pred, _Proj>
|
||||
>
|
||||
template <class _Pred,
|
||||
class _Proj,
|
||||
__enable_if_t<!(!is_member_pointer<typename decay<_Pred>::type>::value &&
|
||||
__is_identity<typename decay<_Proj>::type>::value),
|
||||
int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _ProjectedPred<_Pred, _Proj>
|
||||
__make_projected(_Pred& __pred, _Proj& __proj) {
|
||||
return _ProjectedPred<_Pred, _Proj>(__pred, __proj);
|
||||
}
|
||||
@@ -81,13 +68,12 @@ __make_projected(_Pred& __pred, _Proj& __proj) {
|
||||
// Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable
|
||||
// optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in
|
||||
// the call stack when the comparator is invoked, even in an unoptimized build.
|
||||
template <class _Pred, class _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static
|
||||
__enable_if_t<
|
||||
__can_use_pristine_comp<_Pred, _Proj>::value,
|
||||
_Pred&
|
||||
>
|
||||
__make_projected(_Pred& __pred, _Proj&) {
|
||||
template <class _Pred,
|
||||
class _Proj,
|
||||
__enable_if_t<!is_member_pointer<typename decay<_Pred>::type>::value &&
|
||||
__is_identity<typename decay<_Proj>::type>::value,
|
||||
int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Pred& __make_projected(_Pred& __pred, _Proj&) {
|
||||
return __pred;
|
||||
}
|
||||
|
||||
@@ -102,7 +88,7 @@ namespace ranges {
|
||||
template <class _Comp, class _Proj1, class _Proj2>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr static
|
||||
decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) {
|
||||
if constexpr (same_as<decay_t<_Proj1>, identity> && same_as<decay_t<_Proj2>, identity> &&
|
||||
if constexpr (__is_identity<decay_t<_Proj1>>::value && __is_identity<decay_t<_Proj2>>::value &&
|
||||
!is_member_pointer_v<decay_t<_Comp>>) {
|
||||
// Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
|
||||
// optimizations that rely on the type of the comparator.
|
||||
|
||||
@@ -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>
|
||||
@@ -31,29 +33,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
||||
namespace ranges {
|
||||
namespace __equal {
|
||||
struct __fn {
|
||||
private:
|
||||
template <class _Iter1, class _Sent1,
|
||||
class _Iter2, class _Sent2,
|
||||
class _Pred,
|
||||
class _Proj1,
|
||||
class _Proj2>
|
||||
_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 <input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
|
||||
input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
|
||||
class _Pred = ranges::equal_to,
|
||||
@@ -70,11 +49,13 @@ public:
|
||||
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 <input_range _Range1,
|
||||
@@ -93,11 +74,13 @@ public:
|
||||
if (ranges::distance(__range1) != ranges::distance(__range2))
|
||||
return false;
|
||||
}
|
||||
return __equal_impl(ranges::begin(__range1), ranges::end(__range1),
|
||||
ranges::begin(__range2), ranges::end(__range2),
|
||||
__pred,
|
||||
__proj1,
|
||||
__proj2);
|
||||
auto __unwrapped1 = std::__unwrap_range(ranges::begin(__range1), ranges::end(__range1));
|
||||
auto __unwrapped2 = std::__unwrap_range(ranges::begin(__range2), ranges::end(__range2));
|
||||
return std::__equal_impl(std::move(__unwrapped1.first), std::move(__unwrapped1.second),
|
||||
std::move(__unwrapped2.first), std::move(__unwrapped2.second),
|
||||
__pred,
|
||||
__proj1,
|
||||
__proj2);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -64,6 +64,14 @@ decltype(_Impl::__unwrap(std::declval<_Iter>())) __unwrap_iter(_Iter __i) _NOEXC
|
||||
return _Impl::__unwrap(__i);
|
||||
}
|
||||
|
||||
// Allow input_iterators to be passed to __unwrap_iter (but not __rewrap_iter)
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
template <class _Iter, __enable_if_t<!is_copy_constructible<_Iter>::value, int> = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI constexpr _Iter __unwrap_iter(_Iter __i) noexcept {
|
||||
return __i;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class _OrigIter, class _Iter, class _Impl = __unwrap_iter_impl<_OrigIter> >
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter __orig_iter, _Iter __iter) _NOEXCEPT {
|
||||
return _Impl::__rewrap(std::move(__orig_iter), std::move(__iter));
|
||||
|
||||
@@ -43,7 +43,7 @@ struct __unwrap_range_impl {
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI static constexpr auto
|
||||
__rewrap(_Iter __orig_iter, decltype(std::__unwrap_iter(__orig_iter)) __iter)
|
||||
__rewrap(_Iter __orig_iter, decltype(std::__unwrap_iter(std::move(__orig_iter))) __iter)
|
||||
requires random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>
|
||||
{
|
||||
return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter));
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define _LIBCPP___FUNCTIONAL_IDENTITY_H
|
||||
|
||||
#include <__config>
|
||||
#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 <class _Tp>
|
||||
struct __is_identity : false_type {};
|
||||
|
||||
struct __identity {
|
||||
template <class _Tp>
|
||||
_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR _Tp&& operator()(_Tp&& __t) const _NOEXCEPT {
|
||||
@@ -28,6 +32,9 @@ struct __identity {
|
||||
using is_transparent = void;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct __is_identity<__identity> : true_type {};
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
struct identity {
|
||||
@@ -39,6 +46,10 @@ struct identity {
|
||||
|
||||
using is_transparent = void;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct __is_identity<identity> : true_type {};
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
@@ -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/predicate_traits.h>
|
||||
#include <__utility/forward.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
@@ -341,6 +343,14 @@ struct _LIBCPP_TEMPLATE_VIS equal_to<void>
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class _Tp>
|
||||
struct __is_trivial_equality_predicate<equal_to<_Tp>, _Tp, _Tp> : true_type {};
|
||||
|
||||
#if _LIBCPP_STD_VER >= 14
|
||||
template <class _Tp>
|
||||
struct __is_trivial_equality_predicate<equal_to<>, _Tp, _Tp> : true_type {};
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER >= 14
|
||||
template <class _Tp = void>
|
||||
#else
|
||||
|
||||
@@ -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/predicate_traits.h>
|
||||
#include <__utility/forward.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
@@ -93,6 +95,9 @@ struct greater_equal {
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
template <class _Lhs, class _Rhs>
|
||||
struct __is_trivial_equality_predicate<ranges::equal_to, _Lhs, _Rhs> : true_type {};
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <__config>
|
||||
#include <__type_traits/is_constant_evaluated.h>
|
||||
#include <__type_traits/is_equality_comparable.h>
|
||||
#include <__type_traits/is_same.h>
|
||||
#include <cstddef>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
@@ -33,21 +35,32 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_st
|
||||
return __builtin_strlen(__str);
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
template <class _Tp, class _Up>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
|
||||
__constexpr_memcmp(const _Tp* __lhs, const _Tp* __rhs, size_t __count) {
|
||||
#ifdef _LIBCPP_COMPILER_GCC
|
||||
__constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, size_t __count) {
|
||||
static_assert(
|
||||
__is_trivially_equality_comparable<_Tp, _Up>::value, "_Tp and _Up have to be trivially equality comparable");
|
||||
|
||||
if (__libcpp_is_constant_evaluated()) {
|
||||
for (; __count; --__count, ++__lhs, ++__rhs) {
|
||||
#ifdef _LIBCPP_COMPILER_CLANG_BASED
|
||||
if (sizeof(_Tp) == 1 && !is_same<_Tp, bool>::value)
|
||||
return __builtin_memcmp(__lhs, __rhs, __count);
|
||||
#endif
|
||||
|
||||
while (__count != 0) {
|
||||
if (*__lhs < *__rhs)
|
||||
return -1;
|
||||
if (*__rhs < *__lhs)
|
||||
return 1;
|
||||
|
||||
__count -= sizeof(_Tp);
|
||||
++__lhs;
|
||||
++__rhs;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return __builtin_memcmp(__lhs, __rhs, __count);
|
||||
}
|
||||
#endif
|
||||
return __builtin_memcmp(__lhs, __rhs, __count);
|
||||
}
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const char*
|
||||
|
||||
62
libcxx/include/__type_traits/is_equality_comparable.h
Normal file
62
libcxx/include/__type_traits/is_equality_comparable.h
Normal file
@@ -0,0 +1,62 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_EQUAILITY_COMPARABLE_H
|
||||
#define _LIBCPP___TYPE_TRAITS_IS_EQUAILITY_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/is_void.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 <class _Tp, class _Up, class = void>
|
||||
struct __is_equality_comparable : false_type {};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
struct __is_equality_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() == std::declval<_Up>())> > : true_type {
|
||||
};
|
||||
|
||||
// A type is_trivially_equality_comparable if the expression `a == b` is equivalent to `std::memcmp(&a, &b, sizeof(T))`
|
||||
// (with `a` and `b` being of type `T`). There is no compiler built-in to check this, so we can only do this for known
|
||||
// types. In particular, these are the integral types and raw pointers.
|
||||
//
|
||||
// The following types are not trivially equality comparable:
|
||||
// floating-point types: different bit-patterns can compare equal. (e.g 0.0 and -0.0)
|
||||
// enums: The user is allowed to specialize operator== for enums
|
||||
// pointers that don't have the same type (ignoring cv-qualifiers): pointers to virtual bases are equality comparable,
|
||||
// but don't have the same bit-pattern. An exception to this is comparing to a void-pointer. There the bit-pattern is
|
||||
// always compared.
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
struct __is_trivially_equality_comparable
|
||||
: integral_constant<bool,
|
||||
__is_equality_comparable<_Tp, _Up>::value && is_integral<_Tp>::value &&
|
||||
is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value> {};
|
||||
|
||||
// TODO: Use is_pointer_inverconvertible_base_of
|
||||
template <class _Tp, class _Up>
|
||||
struct __is_trivially_equality_comparable<_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)> {
|
||||
};
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___TYPE_TRAITS_IS_EQUAILITY_COMPARABLE_H
|
||||
26
libcxx/include/__type_traits/predicate_traits.h
Normal file
26
libcxx/include/__type_traits/predicate_traits.h
Normal file
@@ -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_PREDICATE_TRAITS
|
||||
#define _LIBCPP___TYPE_TRAITS_PREDICATE_TRAITS
|
||||
|
||||
#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 <class _Pred, class _Lhs, class _Rhs>
|
||||
struct __is_trivial_equality_predicate : false_type {};
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___TYPE_TRAITS_PREDICATE_TRAITS
|
||||
@@ -604,7 +604,10 @@ module std [system] {
|
||||
module unique { private header "__algorithm/unique.h" }
|
||||
module unique_copy { private header "__algorithm/unique_copy.h" }
|
||||
module unwrap_iter { private header "__algorithm/unwrap_iter.h" }
|
||||
module unwrap_range { private header "__algorithm/unwrap_range.h" }
|
||||
module unwrap_range {
|
||||
private header "__algorithm/unwrap_range.h"
|
||||
export utility.__utility.pair
|
||||
}
|
||||
module upper_bound { private header "__algorithm/upper_bound.h" }
|
||||
}
|
||||
}
|
||||
@@ -1491,6 +1494,10 @@ module std [system] {
|
||||
module is_destructible { private header "__type_traits/is_destructible.h" }
|
||||
module is_empty { private header "__type_traits/is_empty.h" }
|
||||
module is_enum { private header "__type_traits/is_enum.h" }
|
||||
module is_equality_comparable {
|
||||
private header "__type_traits/is_equality_comparable.h"
|
||||
export integral_constant
|
||||
}
|
||||
module is_final { private header "__type_traits/is_final.h" }
|
||||
module is_floating_point { private header "__type_traits/is_floating_point.h" }
|
||||
module is_function { private header "__type_traits/is_function.h" }
|
||||
@@ -1561,6 +1568,7 @@ module std [system] {
|
||||
module nat { private header "__type_traits/nat.h" }
|
||||
module negation { private header "__type_traits/negation.h" }
|
||||
module noexcept_move_assign_container { private header "__type_traits/noexcept_move_assign_container.h" }
|
||||
module predicate_traits { private header "__type_traits/predicate_traits.h" }
|
||||
module promote { private header "__type_traits/promote.h" }
|
||||
module rank { private header "__type_traits/rank.h" }
|
||||
module remove_all_extents { private header "__type_traits/remove_all_extents.h" }
|
||||
|
||||
@@ -651,6 +651,7 @@ END-SCRIPT
|
||||
#include <__type_traits/is_destructible.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_destructible.h'}}
|
||||
#include <__type_traits/is_empty.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_empty.h'}}
|
||||
#include <__type_traits/is_enum.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_enum.h'}}
|
||||
#include <__type_traits/is_equality_comparable.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_equality_comparable.h'}}
|
||||
#include <__type_traits/is_final.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_final.h'}}
|
||||
#include <__type_traits/is_floating_point.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_floating_point.h'}}
|
||||
#include <__type_traits/is_function.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_function.h'}}
|
||||
@@ -715,6 +716,7 @@ END-SCRIPT
|
||||
#include <__type_traits/nat.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/nat.h'}}
|
||||
#include <__type_traits/negation.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/negation.h'}}
|
||||
#include <__type_traits/noexcept_move_assign_container.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/noexcept_move_assign_container.h'}}
|
||||
#include <__type_traits/predicate_traits.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/predicate_traits.h'}}
|
||||
#include <__type_traits/promote.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/promote.h'}}
|
||||
#include <__type_traits/rank.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/rank.h'}}
|
||||
#include <__type_traits/remove_all_extents.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/remove_all_extents.h'}}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header
|
||||
|
||||
#include <__type_traits/is_equality_comparable.h>
|
||||
|
||||
enum Enum : int {};
|
||||
enum class EnumClass : int {};
|
||||
|
||||
static_assert(std::__is_trivially_equality_comparable<int, int>::value, "");
|
||||
static_assert(std::__is_trivially_equality_comparable<const int, int>::value, "");
|
||||
static_assert(std::__is_trivially_equality_comparable<int, const int>::value, "");
|
||||
|
||||
static_assert(std::__is_trivially_equality_comparable<unsigned int, unsigned int>::value, "");
|
||||
static_assert(std::__is_trivially_equality_comparable<const unsigned int, unsigned int>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<unsigned int, int>::value, "");
|
||||
|
||||
static_assert(!std::__is_trivially_equality_comparable<long, int>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<int, long>::value, "");
|
||||
|
||||
static_assert(std::__is_trivially_equality_comparable<int*, int*>::value, "");
|
||||
static_assert(std::__is_trivially_equality_comparable<int*, void*>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<int*, long*>::value, "");
|
||||
|
||||
static_assert(!std::__is_trivially_equality_comparable<Enum, int>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<EnumClass, int>::value, "");
|
||||
|
||||
static_assert(!std::__is_trivially_equality_comparable<float, int>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<double, long long>::value, "");
|
||||
|
||||
static_assert(!std::__is_trivially_equality_comparable<float, int>::value, "");
|
||||
|
||||
static_assert(!std::__is_trivially_equality_comparable<float, float>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<double, double>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<long double, long double>::value, "");
|
||||
|
||||
struct S {
|
||||
char c;
|
||||
};
|
||||
|
||||
struct S2 {
|
||||
char c;
|
||||
};
|
||||
|
||||
struct VirtualBase : virtual S {};
|
||||
struct NonVirtualBase : S, S2 {};
|
||||
|
||||
static_assert(!std::__is_trivially_equality_comparable<S*, VirtualBase*>::value, "");
|
||||
static_assert(!std::__is_trivially_equality_comparable<S2*, VirtualBase*>::value, "");
|
||||
|
||||
// This is trivially_equality_comparable, but we can't detect it currently
|
||||
static_assert(!std::__is_trivially_equality_comparable<S*, NonVirtualBase*>::value, "");
|
||||
@@ -20,68 +20,119 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
|
||||
template <class Iter1, class Iter2 = Iter1>
|
||||
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 <class UnderlyingType, class Iter1>
|
||||
struct Test {
|
||||
template <class Iter2>
|
||||
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), std::equal_to<>()));
|
||||
assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(b), std::equal_to<>()));
|
||||
|
||||
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)));
|
||||
|
||||
assert(std::equal(Iter1(a), Iter1(a + s), Iter2(a), Iter2(a + s), std::equal_to<>()));
|
||||
assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(a), Iter2(a + s - 1), std::equal_to<>()));
|
||||
assert(!std::equal(Iter1(a), Iter1(a + s), Iter2(b), Iter2(b + s), std::equal_to<>()));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct TestNarrowingEqualTo {
|
||||
template <class UnderlyingType>
|
||||
TEST_CONSTEXPR_CXX20 void operator()() {
|
||||
UnderlyingType a[] = {
|
||||
UnderlyingType(0x1000),
|
||||
UnderlyingType(0x1001),
|
||||
UnderlyingType(0x1002),
|
||||
UnderlyingType(0x1003),
|
||||
UnderlyingType(0x1004)};
|
||||
UnderlyingType b[] = {
|
||||
UnderlyingType(0x1600),
|
||||
UnderlyingType(0x1601),
|
||||
UnderlyingType(0x1602),
|
||||
UnderlyingType(0x1603),
|
||||
UnderlyingType(0x1604)};
|
||||
|
||||
assert(std::equal(a, a + 5, b, std::equal_to<char>()));
|
||||
#if TEST_STD_VER >= 14
|
||||
assert(std::equal(a, a + 5, b, b + 5, std::equal_to<char>()));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <class UnderlyingType, class TypeList>
|
||||
struct TestIter2 {
|
||||
template <class Iter1>
|
||||
TEST_CONSTEXPR_CXX20 void operator()() {
|
||||
meta::for_each(TypeList(), Test<UnderlyingType, Iter1>());
|
||||
}
|
||||
};
|
||||
|
||||
struct AddressCompare {
|
||||
int i = 0;
|
||||
TEST_CONSTEXPR_CXX20 AddressCompare(int) {}
|
||||
|
||||
operator char() { return static_cast<char>(i); }
|
||||
|
||||
friend TEST_CONSTEXPR_CXX20 bool operator==(const AddressCompare& lhs, const AddressCompare& rhs) {
|
||||
return &lhs == &rhs;
|
||||
}
|
||||
|
||||
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<int*>(), TestIter2<int, meta::cpp17_input_iterator_list<int*> >());
|
||||
meta::for_each(meta::cpp17_input_iterator_list<char*>(), TestIter2<char, meta::cpp17_input_iterator_list<char*> >());
|
||||
meta::for_each(meta::cpp17_input_iterator_list<AddressCompare*>(),
|
||||
TestIter2<AddressCompare, meta::cpp17_input_iterator_list<AddressCompare*> >());
|
||||
|
||||
meta::for_each(meta::integral_types(), TestNarrowingEqualTo());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#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<int*> II;
|
||||
typedef bidirectional_iterator<int*> BI;
|
||||
struct Base {};
|
||||
struct Derived : virtual Base {};
|
||||
|
||||
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)))
|
||||
;
|
||||
}
|
||||
int main(int, char**) {
|
||||
test();
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
meta::for_each(meta::as_pointers<meta::cv_qualified_versions<int> >(),
|
||||
TestIter2<int, meta::as_pointers<meta::cv_qualified_versions<int> > >());
|
||||
meta::for_each(meta::as_pointers<meta::cv_qualified_versions<char> >(),
|
||||
TestIter2<char, meta::as_pointers<meta::cv_qualified_versions<char> > >());
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test_equal<cpp17_input_iterator<const int*> >();
|
||||
test_equal<random_access_iterator<const int*> >();
|
||||
{
|
||||
Derived d;
|
||||
Derived* a[] = {&d, nullptr};
|
||||
Base* b[] = {&d, nullptr};
|
||||
|
||||
// Test all combinations of cv-qualifiers:
|
||||
test_equal<int*>();
|
||||
test_equal<int*, const int*>();
|
||||
test_equal<int*, volatile int*>();
|
||||
test_equal<int*, const volatile int*>();
|
||||
test_equal<const int*>();
|
||||
test_equal<const int*, volatile int*>();
|
||||
test_equal<const int*, const volatile int*>();
|
||||
test_equal<volatile int*>();
|
||||
test_equal<volatile int*, const volatile int*>();
|
||||
test_equal<const volatile int*>();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test_constexpr());
|
||||
assert(std::equal(a, a + 2, b));
|
||||
#if TEST_STD_VER >= 14
|
||||
assert(std::equal(a, a + 2, b, b + 2));
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,21 @@ constexpr void test_iterators() {
|
||||
}
|
||||
}
|
||||
|
||||
{ // check that false is returned for non-equal ranges
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
int b[] = {1, 2, 4, 4};
|
||||
assert(!std::ranges::equal(Iter1(a), Sent1(Iter1(a + 4)), Iter2(b), Sent2(Iter2(b + 4))));
|
||||
}
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
int b[] = {1, 2, 4, 4};
|
||||
auto range1 = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 4)));
|
||||
auto range2 = std::ranges::subrange(Iter2(b), Sent2(Iter2(b + 4)));
|
||||
assert(!std::ranges::equal(range1, range2));
|
||||
}
|
||||
}
|
||||
|
||||
{ // check that the predicate is used (return true)
|
||||
{
|
||||
int a[] = {1, 2, 3, 4};
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
// <algorithm>
|
||||
|
||||
// https://buildkite.com/llvm-project/libcxx-ci/builds/15823#0184fc0b-d56b-4774-9e1d-35fe24e09e37
|
||||
// It seems like the CI gcc version is buggy. I can't reproduce the failure on my system or on
|
||||
// godbolt (https://godbolt.org/z/rsPv8e8fn).
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
@@ -1418,23 +1418,33 @@ template <std::ranges::input_range R>
|
||||
requires std::ranges::viewable_range<R&&>
|
||||
ProxyRange(R&&) -> ProxyRange<std::views::all_t<R&&>>;
|
||||
|
||||
#endif // TEST_STD_VER > 17
|
||||
|
||||
namespace meta {
|
||||
template <class Ptr>
|
||||
using random_access_iterator_list = type_list<Ptr, contiguous_iterator<Ptr>, random_access_iterator<Ptr>>;
|
||||
using random_access_iterator_list =
|
||||
type_list<Ptr,
|
||||
#if TEST_STD_VER >= 20
|
||||
contiguous_iterator<Ptr>,
|
||||
#endif
|
||||
random_access_iterator<Ptr> >;
|
||||
|
||||
template <class Ptr>
|
||||
using bidirectional_iterator_list =
|
||||
concatenate_t<random_access_iterator_list<Ptr>, type_list<bidirectional_iterator<Ptr>>>;
|
||||
concatenate_t<random_access_iterator_list<Ptr>, type_list<bidirectional_iterator<Ptr> > >;
|
||||
|
||||
template <class Ptr>
|
||||
using forward_iterator_list = concatenate_t<bidirectional_iterator_list<Ptr>, type_list<forward_iterator<Ptr>>>;
|
||||
using forward_iterator_list = concatenate_t<bidirectional_iterator_list<Ptr>, type_list<forward_iterator<Ptr> > >;
|
||||
|
||||
template <class Ptr>
|
||||
using cpp17_input_iterator_list = concatenate_t<forward_iterator_list<Ptr>, type_list<cpp17_input_iterator<Ptr> > >;
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
template <class Ptr>
|
||||
using cpp20_input_iterator_list =
|
||||
concatenate_t<forward_iterator_list<Ptr>, type_list<cpp20_input_iterator<Ptr>, cpp17_input_iterator<Ptr>>>;
|
||||
|
||||
#endif
|
||||
} // namespace meta
|
||||
|
||||
#endif // TEST_STD_VER > 17
|
||||
|
||||
#endif // SUPPORT_TEST_ITERATORS_H
|
||||
|
||||
@@ -100,6 +100,20 @@ using integral_types = concatenate_t<character_types, signed_integer_types, unsi
|
||||
using floating_point_types = type_list<float, double, long double>;
|
||||
|
||||
using arithmetic_types = concatenate_t<integral_types, floating_point_types>;
|
||||
|
||||
template <class T>
|
||||
using cv_qualified_versions = type_list<T, const T, volatile T, const volatile T>;
|
||||
|
||||
template <class T>
|
||||
struct type_list_as_pointers;
|
||||
|
||||
template <class... Types>
|
||||
struct type_list_as_pointers<type_list<Types...> > {
|
||||
using type = type_list<Types*...>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using as_pointers = typename type_list_as_pointers<T>::type;
|
||||
} // namespace meta
|
||||
|
||||
#endif // TEST_SUPPORT_TYPE_ALGORITHMS_H
|
||||
|
||||
Reference in New Issue
Block a user