forked from OSchip/llvm-project
[libc++][ranges] Implement `std::ranges::partition_{point,copy}`.
Reviewed By: #libc, huixie90, ldionne Differential Revision: https://reviews.llvm.org/D130070
This commit is contained in:
parent
15f685eaa8
commit
065202f3ca
|
@ -10,7 +10,7 @@ Search,adjacent_find,Nikolas Klauser,`D126610 <https://llvm.org/D126610>`_,✅
|
|||
Search,mismatch,Nikolas Klauser,`D117817 <https://llvm.org/D117817>`_,✅
|
||||
Search,equal,Nikolas Klauser,`D123681 <https://llvm.org/D123681>`_,✅
|
||||
Search,lexicographical_compare,Nikolas Klauser,`D127130 <https://llvm.org/D127130>`_,✅
|
||||
Search,partition_point,Konstantin Varlamov,n/a,In progress
|
||||
Search,partition_point,Konstantin Varlamov,`D130070 <https://llvm.org/D130070>`_,✅
|
||||
Search,lower_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||
Search,upper_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||
Search,equal_range,Christopher Di Bella,n/a,Not started
|
||||
|
@ -58,7 +58,7 @@ Write,reverse_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
|
|||
Write,rotate_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
|
||||
Write,sample,Not assigned,n/a,Not started
|
||||
Write,unique_copy,Not assigned,n/a,Not started
|
||||
Write,partition_copy,Konstantin Varlamov,n/a,In progress
|
||||
Write,partition_copy,Konstantin Varlamov,`D130070 <https://llvm.org/D130070>`_,✅
|
||||
Write,partial_sort_copy,Konstantin Varlamov,n/a,In progress
|
||||
Merge,merge,Hui Xie,`D128611 <https://llvm.org/D128611>`_,✅
|
||||
Merge,set_difference,Hui Xie,`D128983 <https://llvm.org/D128983>`_,✅
|
||||
|
|
|
|
@ -10,20 +10,17 @@
|
|||
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_COPY_H
|
||||
|
||||
#include <__algorithm/in_out_out_result.h>
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__algorithm/partition_copy.h>
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/projected.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/dangling.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
|
@ -42,6 +39,27 @@ namespace __partition_copy {
|
|||
|
||||
struct __fn {
|
||||
|
||||
// TODO(ranges): delegate to the classic algorithm.
|
||||
template <class _InIter, class _Sent, class _OutIter1, class _OutIter2, class _Proj, class _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
static partition_copy_result<
|
||||
__uncvref_t<_InIter>, __uncvref_t<_OutIter1>, __uncvref_t<_OutIter2>
|
||||
> __partition_copy_fn_impl( _InIter&& __first, _Sent&& __last, _OutIter1&& __out_true, _OutIter2&& __out_false,
|
||||
_Pred& __pred, _Proj& __proj) {
|
||||
for (; __first != __last; ++__first) {
|
||||
if (std::invoke(__pred, std::invoke(__proj, *__first))) {
|
||||
*__out_true = *__first;
|
||||
++__out_true;
|
||||
|
||||
} else {
|
||||
*__out_false = *__first;
|
||||
++__out_false;
|
||||
}
|
||||
}
|
||||
|
||||
return {std::move(__first), std::move(__out_true), std::move(__out_false)};
|
||||
}
|
||||
|
||||
template <input_iterator _InIter, sentinel_for<_InIter> _Sent,
|
||||
weakly_incrementable _OutIter1, weakly_incrementable _OutIter2,
|
||||
class _Proj = identity, indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
|
||||
|
@ -50,9 +68,8 @@ struct __fn {
|
|||
partition_copy_result<_InIter, _OutIter1, _OutIter2>
|
||||
operator()(_InIter __first, _Sent __last, _OutIter1 __out_true, _OutIter2 __out_false,
|
||||
_Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__last; (void)__out_true; (void)__out_false; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __partition_copy_fn_impl(
|
||||
std::move(__first), std::move(__last), std::move(__out_true), std::move(__out_false), __pred, __proj);
|
||||
}
|
||||
|
||||
template <input_range _Range, weakly_incrementable _OutIter1, weakly_incrementable _OutIter2,
|
||||
|
@ -61,9 +78,8 @@ struct __fn {
|
|||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
partition_copy_result<borrowed_iterator_t<_Range>, _OutIter1, _OutIter2>
|
||||
operator()(_Range&& __range, _OutIter1 __out_true, _OutIter2 __out_false, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__out_true; (void)__out_false; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __partition_copy_fn_impl(
|
||||
ranges::begin(__range), ranges::end(__range), std::move(__out_true), std::move(__out_false), __pred, __proj);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -9,19 +9,18 @@
|
|||
#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H
|
||||
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H
|
||||
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__algorithm/partition_point.h>
|
||||
#include <__algorithm/half_positive.h>
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/distance.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/projected.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/dangling.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
@ -37,22 +36,40 @@ namespace __partition_point {
|
|||
|
||||
struct __fn {
|
||||
|
||||
// TODO(ranges): delegate to the classic algorithm.
|
||||
template <class _Iter, class _Sent, class _Proj, class _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
static _Iter __partition_point_fn_impl(_Iter&& __first, _Sent&& __last, _Pred& __pred, _Proj& __proj) {
|
||||
auto __len = ranges::distance(__first, __last);
|
||||
|
||||
while (__len != 0) {
|
||||
auto __half_len = std::__half_positive(__len);
|
||||
auto __mid = ranges::next(__first, __half_len);
|
||||
|
||||
if (std::invoke(__pred, std::invoke(__proj, *__mid))) {
|
||||
__first = ++__mid;
|
||||
__len -= __half_len + 1;
|
||||
|
||||
} else {
|
||||
__len = __half_len;
|
||||
}
|
||||
}
|
||||
|
||||
return __first;
|
||||
}
|
||||
|
||||
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
|
||||
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
_Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__last; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __partition_point_fn_impl(std::move(__first), std::move(__last), __pred, __proj);
|
||||
}
|
||||
|
||||
template <forward_range _Range, class _Proj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__pred; (void)__proj;
|
||||
return {};
|
||||
return __partition_point_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -581,6 +581,34 @@ namespace ranges {
|
|||
constexpr ranges::move_result<borrowed_iterator_t<R>, O>
|
||||
ranges::move(R&& r, O result); // since C++20
|
||||
|
||||
template<class I, class O1, class O2>
|
||||
using partition_copy_result = in_out_out_result<I, O1, O2>; // since C++20
|
||||
|
||||
template<input_iterator I, sentinel_for<I> S,
|
||||
weakly_incrementable O1, weakly_incrementable O2,
|
||||
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
|
||||
requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
|
||||
constexpr partition_copy_result<I, O1, O2>
|
||||
partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
|
||||
Proj proj = {}); // Since C++20
|
||||
|
||||
template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
|
||||
class Proj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
requires indirectly_copyable<iterator_t<R>, O1> &&
|
||||
indirectly_copyable<iterator_t<R>, O2>
|
||||
constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
|
||||
partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
|
||||
indirect_unary_predicate<projected<I, Proj>> Pred>
|
||||
constexpr I partition_point(I first, S last, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<forward_range R, class Proj = identity,
|
||||
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
constexpr borrowed_iterator_t<R>
|
||||
partition_point(R&& r, Pred pred, Proj proj = {}); // Since C++20
|
||||
|
||||
template<class I1, class I2, class O>
|
||||
using merge_result = in_in_out_result<I1, I2, O>; // since C++20
|
||||
|
||||
|
@ -1531,6 +1559,8 @@ template <class BidirectionalIterator, class Compare>
|
|||
#include <__algorithm/ranges_nth_element.h>
|
||||
#include <__algorithm/ranges_partial_sort.h>
|
||||
#include <__algorithm/ranges_partition.h>
|
||||
#include <__algorithm/ranges_partition_copy.h>
|
||||
#include <__algorithm/ranges_partition_point.h>
|
||||
#include <__algorithm/ranges_pop_heap.h>
|
||||
#include <__algorithm/ranges_push_heap.h>
|
||||
#include <__algorithm/ranges_remove.h>
|
||||
|
|
|
@ -177,10 +177,10 @@ constexpr bool all_the_algorithms()
|
|||
//(void)std::ranges::partial_sort_copy(a, b, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_point(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_point(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_point(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_point(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::pop_heap(first, last, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::pop_heap(a, Less(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::prev_permutation(first, last, Less(&copies)); assert(copies == 0);
|
||||
|
|
|
@ -160,10 +160,10 @@ constexpr bool all_the_algorithms()
|
|||
//(void)std::ranges::partial_sort_copy(a, b, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_point(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::partition_point(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_point(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::partition_point(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::pop_heap(first, last, Less(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::pop_heap(a, Less(), Proj(&copies)); assert(copies == 0);
|
||||
//(void)std::ranges::prev_permutation(first, last, Less(), Proj(&copies)); assert(copies == 0);
|
||||
|
|
|
@ -72,7 +72,7 @@ static_assert(HasPartitionRange<R<int*>, UnaryPred>);
|
|||
|
||||
// !forward_range<R>
|
||||
static_assert(!HasPartitionRange<ForwardRangeNotDerivedFrom, UnaryPred>);
|
||||
static_assert(!HasPartitionRange<ForwardIteratorNotIncrementable, UnaryPred>);
|
||||
static_assert(!HasPartitionRange<ForwardRangeNotIncrementable, UnaryPred>);
|
||||
|
||||
// !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
static_assert(!HasPartitionRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
|
||||
|
@ -147,6 +147,10 @@ constexpr void test_iterators_2() {
|
|||
test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3);
|
||||
// Repeating pattern.
|
||||
test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3);
|
||||
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
// Different comparator.
|
||||
test_one<Iter, Sent, 5>({-3, 5, 7, -6, 2}, is_negative, 2);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
|
|
|
@ -32,16 +32,268 @@
|
|||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "counting_predicates.h"
|
||||
#include "counting_projection.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
struct UnaryPred { bool operator()(int) const; };
|
||||
|
||||
// Test constraints of the (iterator, sentinel) overload.
|
||||
// ======================================================
|
||||
|
||||
template <class InIter = int*, class Sent = int*, class Output1 = int*, class Output2 = int*, class Pred = UnaryPred>
|
||||
concept HasPartitionCopyIter =
|
||||
requires(InIter&& input, Sent&& sent, Output1&& output1, Output2&& output2, Pred&& pred) {
|
||||
std::ranges::partition_copy(std::forward<InIter>(input), std::forward<Sent>(sent),
|
||||
std::forward<Output1>(output1), std::forward<Output2>(output2), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
static_assert(HasPartitionCopyIter<int*, int*, int*, int*, UnaryPred>);
|
||||
|
||||
// !input_iterator<I>
|
||||
static_assert(!HasPartitionCopyIter<InputIteratorNotDerivedFrom>);
|
||||
static_assert(!HasPartitionCopyIter<InputIteratorNotIndirectlyReadable>);
|
||||
static_assert(!HasPartitionCopyIter<InputIteratorNotInputOrOutputIterator>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasPartitionCopyIter<int*, SentinelForNotSemiregular>);
|
||||
static_assert(!HasPartitionCopyIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
|
||||
|
||||
// !weakly_incrementable<O1>
|
||||
static_assert(!HasPartitionCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
|
||||
|
||||
// !weakly_incrementable<O2>
|
||||
static_assert(!HasPartitionCopyIter<int*, int*, int*, WeaklyIncrementableNotMovable>);
|
||||
|
||||
// !indirect_unary_predicate<projected<I, Proj>>
|
||||
static_assert(!HasPartitionCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasPartitionCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
struct Uncopyable {
|
||||
Uncopyable(int&&);
|
||||
Uncopyable(const int&) = delete;
|
||||
};
|
||||
// !indirectly_copyable<I, O1>
|
||||
static_assert(!HasPartitionCopyIter<int*, int*, Uncopyable*>);
|
||||
// !indirectly_copyable<I, O2>
|
||||
static_assert(!HasPartitionCopyIter<int*, int*, int*, Uncopyable*>);
|
||||
|
||||
// Test constraints of the (range) overload.
|
||||
// =========================================
|
||||
|
||||
template <class InputRange, class Output1 = int*, class Output2 = int*, class Pred = UnaryPred>
|
||||
concept HasPartitionCopyRange =
|
||||
requires(InputRange&& input, Output1&& output1, Output2&& output2, Pred&& pred) {
|
||||
std::ranges::partition_copy(std::forward<InputRange>(input),
|
||||
std::forward<Output1>(output1), std::forward<Output2>(output2), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasPartitionCopyRange<R<int*>, int*, int*, UnaryPred>);
|
||||
|
||||
// !input_iterator<I>
|
||||
static_assert(!HasPartitionCopyRange<InputRangeNotDerivedFrom>);
|
||||
static_assert(!HasPartitionCopyRange<InputRangeNotIndirectlyReadable>);
|
||||
static_assert(!HasPartitionCopyRange<InputRangeNotInputOrOutputIterator>);
|
||||
|
||||
// !weakly_incrementable<O1>
|
||||
static_assert(!HasPartitionCopyRange<R<int*>, WeaklyIncrementableNotMovable>);
|
||||
|
||||
// !weakly_incrementable<O2>
|
||||
static_assert(!HasPartitionCopyRange<R<int*>, int*, WeaklyIncrementableNotMovable>);
|
||||
|
||||
// !indirect_unary_predicate<projected<I, Proj>>
|
||||
static_assert(!HasPartitionCopyRange<R<int*>, int*, int*, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasPartitionCopyRange<R<int*>, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
// !indirectly_copyable<I, O1>
|
||||
static_assert(!HasPartitionCopyRange<R<int*>, Uncopyable*>);
|
||||
// !indirectly_copyable<I, O2>
|
||||
static_assert(!HasPartitionCopyRange<R<int*>, int*, Uncopyable*>);
|
||||
|
||||
static_assert(std::is_same_v<std::ranges::partition_copy_result<int, int, int>,
|
||||
std::ranges::in_out_out_result<int, int, int>>);
|
||||
|
||||
template <class Iter, class Sent, class OutIter1, class OutIter2, size_t N1, size_t N2, size_t N3, class Pred>
|
||||
constexpr void test_one(std::array<int, N1> input, Pred pred, std::array<int, N2> expected_true,
|
||||
std::array<int, N3> expected_false) {
|
||||
static_assert(N2 + N3 == N1);
|
||||
using ResultT = std::ranges::partition_copy_result<Iter, OutIter1, OutIter2>;
|
||||
|
||||
auto begin = input.data();
|
||||
auto end = input.data() + input.size();
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
std::array<int, N2> out1;
|
||||
std::array<int, N3> out2;
|
||||
|
||||
std::same_as<ResultT> decltype(auto) result = std::ranges::partition_copy(
|
||||
Iter(begin), Sent(Iter(end)), OutIter1(out1.begin()), OutIter2(out2.begin()), pred);
|
||||
|
||||
assert(base(result.in) == input.data() + input.size());
|
||||
assert(base(result.out1) == out1.data() + expected_true.size());
|
||||
assert(base(result.out2) == out2.data() + expected_false.size());
|
||||
|
||||
assert(std::ranges::equal(out1, expected_true));
|
||||
assert(std::ranges::equal(out2, expected_false));
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
std::ranges::subrange range{Iter(begin), Sent(Iter(end))};
|
||||
std::array<int, N2> out1;
|
||||
std::array<int, N3> out2;
|
||||
|
||||
std::same_as<ResultT> decltype(auto) result = std::ranges::partition_copy(
|
||||
range, OutIter1(out1.begin()), OutIter2(out2.begin()), pred);
|
||||
|
||||
assert(base(result.in) == input.data() + input.size());
|
||||
assert(base(result.out1) == out1.data() + expected_true.size());
|
||||
assert(base(result.out2) == out2.data() + expected_false.size());
|
||||
|
||||
assert(std::ranges::equal(out1, expected_true));
|
||||
assert(std::ranges::equal(out2, expected_false));
|
||||
}
|
||||
}
|
||||
|
||||
template <class InIter, class Sent, class Out1, class Out2>
|
||||
constexpr void test_iterators_in_sent_out1_out2() {
|
||||
auto is_odd = [](int x) { return x % 2 != 0; };
|
||||
|
||||
// Empty sequence.
|
||||
test_one<InIter, Sent, Out1, Out2, 0, 0, 0>({}, is_odd, {}, {});
|
||||
// 1-element sequence, the element satisfies the predicate.
|
||||
test_one<InIter, Sent, Out1, Out2, 1, 1, 0>({1}, is_odd, {1}, {});
|
||||
// 1-element sequence, the element doesn't satisfy the predicate.
|
||||
test_one<InIter, Sent, Out1, Out2, 1, 0, 1>({2}, is_odd, {}, {2});
|
||||
// 2-element sequence, not in order.
|
||||
test_one<InIter, Sent, Out1, Out2, 2, 1, 1>({2, 1}, is_odd, {1}, {2});
|
||||
// 2-element sequence, already in order.
|
||||
test_one<InIter, Sent, Out1, Out2, 2, 1, 1>({1, 2}, is_odd, {1}, {2});
|
||||
// 3-element sequence.
|
||||
test_one<InIter, Sent, Out1, Out2, 3, 2, 1>({2, 1, 3}, is_odd, {1, 3}, {2});
|
||||
// Longer sequence.
|
||||
test_one<InIter, Sent, Out1, Out2, 8, 4, 4>({2, 1, 3, 6, 8, 4, 11, 5}, is_odd, {1, 3, 11, 5}, {2, 6, 8, 4});
|
||||
// Longer sequence with duplicates.
|
||||
test_one<InIter, Sent, Out1, Out2, 8, 3, 5>({2, 1, 3, 6, 2, 8, 1, 6}, is_odd, {1, 3, 1}, {2, 6, 2, 8, 6});
|
||||
// All elements are the same and satisfy the predicate.
|
||||
test_one<InIter, Sent, Out1, Out2, 3, 3, 0>({1, 1, 1}, is_odd, {1, 1, 1}, {});
|
||||
// All elements are the same and don't satisfy the predicate.
|
||||
test_one<InIter, Sent, Out1, Out2, 3, 0, 3>({2, 2, 2}, is_odd, {}, {2, 2, 2});
|
||||
// Already partitioned.
|
||||
test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({1, 3, 5, 4, 6, 8}, is_odd, {1, 3, 5}, {4, 6, 8});
|
||||
// Reverse-partitioned.
|
||||
test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({4, 6, 8, 1, 3, 5}, is_odd, {1, 3, 5}, {4, 6, 8});
|
||||
// Repeating pattern.
|
||||
test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({1, 2, 1, 2, 1, 2}, is_odd, {1, 1, 1}, {2, 2, 2});
|
||||
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
// Different comparator.
|
||||
test_one<InIter, Sent, Out1, Out2, 5, 2, 3>({-3, 5, 7, -6, 2}, is_negative, {-3, -6}, {5, 7, 2});
|
||||
}
|
||||
|
||||
template <class InIter, class Sent, class Out1>
|
||||
constexpr void test_iterators_in_sent_out1() {
|
||||
test_iterators_in_sent_out1_out2<InIter, Sent, Out1, cpp20_output_iterator<int*>>();
|
||||
test_iterators_in_sent_out1_out2<InIter, Sent, Out1, random_access_iterator<int*>>();
|
||||
test_iterators_in_sent_out1_out2<InIter, Sent, Out1, int*>();
|
||||
}
|
||||
|
||||
template <class InIter, class Sent>
|
||||
constexpr void test_iterators_in_sent() {
|
||||
test_iterators_in_sent_out1<InIter, Sent, cpp17_output_iterator<int*>>();
|
||||
test_iterators_in_sent_out1<InIter, Sent, cpp20_output_iterator<int*>>();
|
||||
test_iterators_in_sent_out1<InIter, Sent, random_access_iterator<int*>>();
|
||||
test_iterators_in_sent_out1<InIter, Sent, int*>();
|
||||
}
|
||||
|
||||
template <class InIter>
|
||||
constexpr void test_iterators_in() {
|
||||
if constexpr (std::sentinel_for<InIter, InIter>) {
|
||||
test_iterators_in_sent<InIter, InIter>();
|
||||
}
|
||||
test_iterators_in_sent<InIter, sentinel_wrapper<InIter>>();
|
||||
}
|
||||
|
||||
constexpr void test_iterators() {
|
||||
// Note: deliberately testing with only the weakest and "strongest" iterator types to minimize combinatorial
|
||||
// explosion.
|
||||
test_iterators_in<cpp20_input_iterator<int*>>();
|
||||
test_iterators_in<int*>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
test_iterators();
|
||||
|
||||
{ // A custom projection works.
|
||||
const std::array in = {1, 3, 9, -2, -5, -8};
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
auto negate = [](int x) { return -x; };
|
||||
const std::array expected_negative = {-2, -5, -8};
|
||||
const std::array expected_positive = {1, 3, 9};
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
{
|
||||
std::array<int, 3> out1, out2;
|
||||
std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), is_negative);
|
||||
assert(out1 == expected_negative);
|
||||
assert(out2 == expected_positive);
|
||||
}
|
||||
{
|
||||
std::array<int, 3> out1, out2;
|
||||
std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), is_negative, negate);
|
||||
assert(out1 == expected_positive);
|
||||
assert(out2 == expected_negative);
|
||||
}
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
{
|
||||
std::array<int, 3> out1, out2;
|
||||
std::ranges::partition_copy(in, out1.begin(), out2.begin(), is_negative);
|
||||
assert(out1 == expected_negative);
|
||||
assert(out2 == expected_positive);
|
||||
}
|
||||
{
|
||||
std::array<int, 3> out1, out2;
|
||||
std::ranges::partition_copy(in, out1.begin(), out2.begin(), is_negative, negate);
|
||||
assert(out1 == expected_positive);
|
||||
assert(out2 == expected_negative);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Complexity: Exactly `last - first` applications of `pred` and `proj`.
|
||||
{
|
||||
const std::array in = {-2, -5, -8, -11, -10, -5, 1, 3, 9, 6, 8, 2, 4, 2};
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
std::array<int, 6> out1;
|
||||
std::array<int, 8> out2;
|
||||
|
||||
int pred_count = 0, proj_count = 0;
|
||||
counting_predicate pred(is_negative, pred_count);
|
||||
counting_projection proj(proj_count);
|
||||
auto expected = static_cast<int>(in.size());
|
||||
|
||||
{
|
||||
std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), pred, proj);
|
||||
assert(pred_count == expected);
|
||||
assert(proj_count == expected);
|
||||
pred_count = proj_count = 0;
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::partition_copy(in, out1.begin(), out2.begin(), pred, proj);
|
||||
assert(pred_count == expected);
|
||||
assert(proj_count == expected);
|
||||
pred_count = proj_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,16 +25,152 @@
|
|||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
struct UnaryPred { bool operator()(int) const; };
|
||||
|
||||
// Test constraints of the (iterator, sentinel) overload.
|
||||
// ======================================================
|
||||
|
||||
template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
|
||||
concept HasPartitionPointIter =
|
||||
requires(Iter&& iter, Sent&& sent, Pred&& pred) {
|
||||
std::ranges::partition_point(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
static_assert(HasPartitionPointIter<int*, int*, UnaryPred>);
|
||||
|
||||
// !forward_iterator<I>
|
||||
static_assert(!HasPartitionPointIter<ForwardIteratorNotDerivedFrom>);
|
||||
static_assert(!HasPartitionPointIter<ForwardIteratorNotIncrementable>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasPartitionPointIter<int*, SentinelForNotSemiregular>);
|
||||
static_assert(!HasPartitionPointIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
|
||||
|
||||
// !indirect_unary_predicate<projected<I, Proj>>
|
||||
static_assert(!HasPartitionPointIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasPartitionPointIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
// Test constraints of the (range) overload.
|
||||
// =========================================
|
||||
|
||||
template <class Range, class Pred>
|
||||
concept HasPartitionPointRange =
|
||||
requires(Range&& range, Pred&& pred) {
|
||||
std::ranges::partition_point(std::forward<Range>(range), std::forward<Pred>(pred));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasPartitionPointRange<R<int*>, UnaryPred>);
|
||||
|
||||
// !forward_range<R>
|
||||
static_assert(!HasPartitionPointRange<ForwardRangeNotDerivedFrom, UnaryPred>);
|
||||
static_assert(!HasPartitionPointRange<ForwardRangeNotIncrementable, UnaryPred>);
|
||||
|
||||
// !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
|
||||
static_assert(!HasPartitionPointRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
|
||||
static_assert(!HasPartitionPointRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
|
||||
|
||||
template <class Iter, class Sent, size_t N, class Pred>
|
||||
constexpr void test_one(std::array<int, N> input, Pred pred, size_t partition_point) {
|
||||
assert(std::ranges::is_partitioned(input, pred));
|
||||
|
||||
auto begin = Iter(input.data());
|
||||
auto end = Sent(Iter(input.data() + input.size()));
|
||||
auto neg_pred = [&](int x) { return !pred(x); };
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
std::same_as<Iter> decltype(auto) result = std::ranges::partition_point(begin, end, pred);
|
||||
|
||||
assert(base(result) == input.data() + partition_point);
|
||||
assert(std::ranges::all_of(begin, result, pred));
|
||||
assert(std::ranges::all_of(result, end, neg_pred));
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
auto range = std::ranges::subrange(begin, end);
|
||||
std::same_as<Iter> decltype(auto) result = std::ranges::partition_point(range, pred);
|
||||
|
||||
assert(base(result) == input.data() + partition_point);
|
||||
assert(std::ranges::all_of(begin, result, pred));
|
||||
assert(std::ranges::all_of(result, end, neg_pred));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter, class Sent>
|
||||
constexpr void test_iterators_2() {
|
||||
auto is_odd = [](int x) { return x % 2 != 0; };
|
||||
|
||||
// Empty sequence.
|
||||
test_one<Iter, Sent, 0>({}, is_odd, 0);
|
||||
// 1-element sequence, the element satisfies the predicate.
|
||||
test_one<Iter, Sent, 1>({1}, is_odd, 1);
|
||||
// 1-element sequence, the element doesn't satisfy the predicate.
|
||||
test_one<Iter, Sent, 1>({2}, is_odd, 0);
|
||||
// 2-element sequence.
|
||||
test_one<Iter, Sent, 2>({1, 2}, is_odd, 1);
|
||||
// 3-element sequence.
|
||||
test_one<Iter, Sent, 3>({3, 1, 2}, is_odd, 2);
|
||||
// Longer sequence.
|
||||
test_one<Iter, Sent, 8>({1, 3, 11, 5, 6, 2, 8, 4}, is_odd, 4);
|
||||
// Longer sequence with duplicates.
|
||||
test_one<Iter, Sent, 8>({1, 3, 3, 4, 6, 2, 8, 2}, is_odd, 3);
|
||||
// All elements are the same and satisfy the predicate.
|
||||
test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3);
|
||||
// All elements are the same and don't satisfy the predicate.
|
||||
test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0);
|
||||
// All non-satisfying and all satisfying elements are the same.
|
||||
test_one<Iter, Sent, 6>({1, 1, 1, 2, 2, 2}, is_odd, 3);
|
||||
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
// Different comparator.
|
||||
test_one<Iter, Sent, 5>({-3, -6, 5, 7, 2}, is_negative, 2);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
constexpr void test_iterators_1() {
|
||||
test_iterators_2<Iter, Iter>();
|
||||
test_iterators_2<Iter, sentinel_wrapper<Iter>>();
|
||||
}
|
||||
|
||||
constexpr void test_iterators() {
|
||||
test_iterators_1<forward_iterator<int*>>();
|
||||
test_iterators_1<bidirectional_iterator<int*>>();
|
||||
test_iterators_1<random_access_iterator<int*>>();
|
||||
test_iterators_1<contiguous_iterator<int*>>();
|
||||
test_iterators_1<int*>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
test_iterators();
|
||||
|
||||
{ // A custom projection works.
|
||||
const std::array in = {1, 3, 4, 6, 8};
|
||||
auto is_odd = [](int x) { return x % 2 != 0; };
|
||||
auto x2 = [](int x) { return x * 2; };
|
||||
auto expected_no_proj = in.begin() + 2;
|
||||
auto expected_with_proj = in.begin();
|
||||
|
||||
{ // (iterator, sentinel) overload.
|
||||
auto result_no_proj = std::ranges::partition_point(in.begin(), in.end(), is_odd);
|
||||
assert(result_no_proj == expected_no_proj);
|
||||
auto result_with_proj = std::ranges::partition_point(in.begin(), in.end(), is_odd, x2);
|
||||
assert(result_with_proj == expected_with_proj);
|
||||
}
|
||||
|
||||
{ // (range) overload.
|
||||
auto result_no_proj = std::ranges::partition_point(in, is_odd);
|
||||
assert(result_no_proj == expected_no_proj);
|
||||
auto result_with_proj = std::ranges::partition_point(in, is_odd, x2);
|
||||
assert(result_with_proj == expected_with_proj);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -151,6 +151,10 @@ void test_iterators_2() {
|
|||
test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3, {1, 3, 5, 4, 6, 8});
|
||||
// Repeating pattern.
|
||||
test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3, {1, 1, 1, 2, 2, 2});
|
||||
|
||||
auto is_negative = [](int x) { return x < 0; };
|
||||
// Different comparator.
|
||||
test_one<Iter, Sent, 5>({-3, 5, 7, -6, 2}, is_negative, 2, {-3, -6, 5, 7, 2});
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
|
|
|
@ -47,11 +47,11 @@ static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_move_n_resu
|
|||
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, binary_transform_result<int, long, char>>);
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, merge_result<int, long, char>>);
|
||||
// static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_symmetric_difference_result<int, long, char>>);
|
||||
// static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_union_result<int, long, char>>);
|
||||
// static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_intersection_result<int, long, char>>);
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_symmetric_difference_result<int, long, char>>);
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_union_result<int, long, char>>);
|
||||
static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_intersection_result<int, long, char>>);
|
||||
|
||||
// static_assert(std::is_same_v<in_out_out_result<int, long, char>, partition_copy_result<int, long, char>>);
|
||||
static_assert(std::is_same_v<in_out_out_result<int, long, char>, partition_copy_result<int, long, char>>);
|
||||
|
||||
static_assert(std::is_same_v<min_max_result<int>, minmax_result<int>>);
|
||||
static_assert(std::is_same_v<min_max_result<int>, minmax_element_result<int>>);
|
||||
|
|
|
@ -75,7 +75,7 @@ constexpr bool test_all() {
|
|||
using std::ranges::move_result;
|
||||
//using std::ranges::move_backward_result;
|
||||
//using std::ranges::partial_sort_copy_result;
|
||||
//using std::ranges::partition_copy_result;
|
||||
using std::ranges::partition_copy_result;
|
||||
//using std::ranges::remove_copy_result;
|
||||
//using std::ranges::remove_copy_if_result;
|
||||
using std::ranges::reverse_copy_result;
|
||||
|
@ -100,7 +100,7 @@ constexpr bool test_all() {
|
|||
|
||||
std::array output = {7, 8, 9, 10, 11, 12};
|
||||
auto out = output.begin();
|
||||
//auto out2 = output.begin() + 1;
|
||||
auto out2 = output.begin() + 1;
|
||||
|
||||
int x = 2;
|
||||
size_t count = 1;
|
||||
|
@ -113,7 +113,7 @@ constexpr bool test_all() {
|
|||
dangling_1st<mismatch_result<dangling, int*>>(std::ranges::mismatch, in, in2);
|
||||
dangling_2nd<mismatch_result<int*, dangling>>(std::ranges::mismatch, in, in2);
|
||||
dangling_both<mismatch_result<dangling, dangling>>(std::ranges::mismatch, in, in2);
|
||||
//dangling_1st(std::ranges::partition_point, in, unary_pred);
|
||||
dangling_1st(std::ranges::partition_point, in, unary_pred);
|
||||
dangling_1st(std::ranges::lower_bound, in, x);
|
||||
dangling_1st(std::ranges::upper_bound, in, x);
|
||||
//dangling_1st(std::ranges::equal_range, in, x);
|
||||
|
@ -157,7 +157,7 @@ constexpr bool test_all() {
|
|||
dangling_1st<reverse_copy_result<dangling, int*>>(std::ranges::reverse_copy, in, out);
|
||||
dangling_1st<rotate_copy_result<dangling, int*>>(std::ranges::rotate_copy, in, mid, out);
|
||||
//dangling_1st<unique_copy_result<dangling, int*>>(std::ranges::unique_copy, in, out);
|
||||
//dangling_1st<partition_copy_result<dangling, int*, int*>>std::ranges::partition_copy(in, out, out2, unary_pred);
|
||||
dangling_1st<partition_copy_result<dangling, int*, int*>>(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
//dangling_1st<partial_sort_copy_result<dangling, int*>>(std::ranges::partial_sort_copy, in, in2);
|
||||
//dangling_2nd<partial_sort_copy_result<int*, dangling>>(std::ranges::partial_sort_copy, in, in2);
|
||||
//dangling_both<partial_sort_copy_result<dangling, dangling>>(std::ranges::partial_sort_copy, in, in2);
|
||||
|
|
|
@ -62,7 +62,7 @@ constexpr bool test_all() {
|
|||
|
||||
std::array output = {7, 8, 9, 10, 11, 12};
|
||||
auto out = output.begin();
|
||||
//auto out2 = output.begin() + 1;
|
||||
auto out2 = output.begin() + 1;
|
||||
|
||||
int x = 2;
|
||||
int count = 1;
|
||||
|
@ -77,7 +77,7 @@ constexpr bool test_all() {
|
|||
test(std::ranges::mismatch, in, in2, binary_pred);
|
||||
test(std::ranges::equal, in, in2, binary_pred);
|
||||
test(std::ranges::lexicographical_compare, in, in2, binary_pred);
|
||||
//test(std::ranges::partition_point, unary_pred);
|
||||
test(std::ranges::partition_point, in, unary_pred);
|
||||
test(std::ranges::lower_bound, in, x, binary_pred);
|
||||
test(std::ranges::upper_bound, in, x, binary_pred);
|
||||
//test(std::ranges::equal_range, in, x, binary_pred);
|
||||
|
@ -116,7 +116,7 @@ constexpr bool test_all() {
|
|||
test(std::ranges::replace_if, in, unary_pred, x);
|
||||
//test(std::ranges::replace_copy_if, in, out, unary_pred, x);
|
||||
//test(std::ranges::unique_copy, in, out, binary_pred);
|
||||
//test(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
test(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
//test(std::ranges::partial_sort_copy, in, in2, binary_pred);
|
||||
test(std::ranges::merge, in, in2, out, binary_pred);
|
||||
test(std::ranges::set_difference, in, in2, out, binary_pred);
|
||||
|
|
|
@ -63,7 +63,7 @@ constexpr bool test_all() {
|
|||
|
||||
std::array output = {Bar{Foo{7}}, Bar{Foo{8}}, Bar{Foo{9}}, Bar{Foo{10}}, Bar{Foo{11}}, Bar{Foo{12}}};
|
||||
auto out = output.begin();
|
||||
//auto out2 = output.begin() + 1;
|
||||
auto out2 = output.begin() + 1;
|
||||
|
||||
Bar a{Foo{1}};
|
||||
Bar b{Foo{2}};
|
||||
|
@ -83,7 +83,7 @@ constexpr bool test_all() {
|
|||
test(std::ranges::mismatch, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
|
||||
test(std::ranges::equal, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
|
||||
test(std::ranges::lexicographical_compare, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
|
||||
//test(std::ranges::partition_point, in, &Foo::unary_pred, &Bar::val);
|
||||
test(std::ranges::partition_point, in, &Foo::unary_pred, &Bar::val);
|
||||
test(std::ranges::lower_bound, in, x, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::upper_bound, in, x, &Foo::binary_pred, &Bar::val);
|
||||
//test(std::ranges::equal_range, in, x, &Foo::binary_pred, &Bar::val);
|
||||
|
@ -142,7 +142,7 @@ constexpr bool test_all() {
|
|||
// `rotate_copy` has neither a projection nor a predicate.
|
||||
// `sample` has no requirement that the given generator be invoked via `std::invoke`.
|
||||
//test(std::ranges::unique_copy, in, out, &Foo::binary_pred, &Bar::val);
|
||||
//test(std::ranges::partition_copy, in, out, out2, &Foo::unary_pred, &Bar::val);
|
||||
test(std::ranges::partition_copy, in, out, out2, &Foo::unary_pred, &Bar::val);
|
||||
//test(std::ranges::partial_sort_copy, in, in2, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::merge, in, in2, out, &Foo::binary_pred, &Bar::val, &Bar::val);
|
||||
test(std::ranges::set_difference, in, in2, out, &Foo::binary_pred, &Bar::val, &Bar::val);
|
||||
|
|
|
@ -59,7 +59,7 @@ constexpr void run_tests() {
|
|||
|
||||
std::array output = {T{4}, T{5}, T{6}, T{7}, T{8}, T{9}};
|
||||
ProxyIterator out{output.begin()};
|
||||
//auto out2 = output.begin() + 1;
|
||||
ProxyIterator out2{output.begin() + 1};
|
||||
|
||||
T num{2};
|
||||
Proxy<T&> x{num};
|
||||
|
@ -82,7 +82,7 @@ constexpr void run_tests() {
|
|||
test(std::ranges::mismatch, in, in2);
|
||||
test(std::ranges::equal, in, in2);
|
||||
test(std::ranges::lexicographical_compare, in, in2);
|
||||
//test(std::ranges::partition_point, unary_pred);
|
||||
test(std::ranges::partition_point, in, unary_pred);
|
||||
test(std::ranges::lower_bound, in, x);
|
||||
test(std::ranges::upper_bound, in, x);
|
||||
//test(std::ranges::equal_range, in, x);
|
||||
|
@ -136,7 +136,7 @@ constexpr void run_tests() {
|
|||
test(std::ranges::reverse_copy, in, out);
|
||||
test_mid(std::ranges::rotate_copy, in, mid, out);
|
||||
//test(std::ranges::unique_copy, in, out);
|
||||
//test(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
test(std::ranges::partition_copy, in, out, out2, unary_pred);
|
||||
//test_mid(std::ranges::partial_sort_copy, in, in2);
|
||||
test(std::ranges::merge, in, in2, out);
|
||||
test(std::ranges::set_difference, in, in2, out);
|
||||
|
|
|
@ -113,8 +113,8 @@ static_assert(test(std::ranges::nth_element, a, a+5));
|
|||
static_assert(test(std::ranges::partial_sort, a, a+5));
|
||||
//static_assert(test(std::ranges::partial_sort_copy, a, a));
|
||||
static_assert(test(std::ranges::partition, a, odd));
|
||||
//static_assert(test(std::ranges::partition_copy, a, a, a, odd));
|
||||
//static_assert(test(std::ranges::partition_point, a, odd));
|
||||
static_assert(test(std::ranges::partition_copy, a, a, a, odd));
|
||||
static_assert(test(std::ranges::partition_point, a, odd));
|
||||
static_assert(test(std::ranges::pop_heap, a));
|
||||
//static_assert(test(std::ranges::prev_permutation, a));
|
||||
static_assert(test(std::ranges::push_heap, a));
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#define TEST_SUPPORT_COUNTING_PREDICATES_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename Predicate, typename Arg>
|
||||
struct unary_counting_predicate {
|
||||
|
@ -49,4 +51,27 @@ private:
|
|||
mutable size_t count_;
|
||||
};
|
||||
|
||||
#if TEST_STD_VER > 14
|
||||
|
||||
template <class Predicate>
|
||||
class counting_predicate {
|
||||
Predicate pred_;
|
||||
int* count_ = nullptr;
|
||||
|
||||
public:
|
||||
constexpr counting_predicate() = default;
|
||||
constexpr counting_predicate(Predicate pred, int& count) : pred_(std::move(pred)), count_(&count) {}
|
||||
|
||||
template <class... Args>
|
||||
constexpr decltype(auto) operator()(Args&& ...args) const {
|
||||
++(*count_);
|
||||
return pred_(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Predicate>
|
||||
counting_predicate(Predicate pred, int& count) -> counting_predicate<Predicate>;
|
||||
|
||||
#endif // TEST_STD_VER > 14
|
||||
|
||||
#endif // TEST_SUPPORT_COUNTING_PREDICATES_H
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 TEST_SUPPORT_COUNTING_PROJECTION_H
|
||||
#define TEST_SUPPORT_COUNTING_PROJECTION_H
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include "test_macros.h"
|
||||
|
||||
#if TEST_STD_VER > 14
|
||||
|
||||
template <class Proj = std::identity>
|
||||
class counting_projection {
|
||||
Proj proj_;
|
||||
int* count_ = nullptr;
|
||||
|
||||
public:
|
||||
constexpr counting_projection() = default;
|
||||
constexpr counting_projection(int& count) : count_(&count) {}
|
||||
constexpr counting_projection(Proj proj, int& count) : proj_(std::move(proj)), count_(&count) {}
|
||||
|
||||
template <class T>
|
||||
constexpr decltype(auto) operator()(T&& value) const {
|
||||
++(*count_);
|
||||
return proj_(std::forward<T>(value));
|
||||
}
|
||||
};
|
||||
|
||||
counting_projection(int& count) -> counting_projection<std::identity>;
|
||||
template <class Proj>
|
||||
counting_projection(Proj proj, int& count) -> counting_projection<Proj>;
|
||||
|
||||
#endif // TEST_STD_VER > 14
|
||||
|
||||
#endif // TEST_SUPPORT_COUNTING_PROJECTION_H
|
Loading…
Reference in New Issue