1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
14 // indirect_unary_predicate<projected<I, Proj>> Pred>
15 // constexpr I partition_point(I first, S last, Pred pred, Proj proj = {}); // Since C++20
17 // template<forward_range R, class Proj = identity,
18 // indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
19 // constexpr borrowed_iterator_t<R>
20 // partition_point(R&& r, Pred pred, Proj proj = {}); // Since C++20
29 #include "almost_satisfies_types.h"
30 #include "test_iterators.h"
32 struct UnaryPred
{ bool operator()(int) const; };
34 // Test constraints of the (iterator, sentinel) overload.
35 // ======================================================
37 template <class Iter
= int*, class Sent
= int*, class Pred
= UnaryPred
>
38 concept HasPartitionPointIter
=
39 requires(Iter
&& iter
, Sent
&& sent
, Pred
&& pred
) {
40 std::ranges::partition_point(std::forward
<Iter
>(iter
), std::forward
<Sent
>(sent
), std::forward
<Pred
>(pred
));
43 static_assert(HasPartitionPointIter
<int*, int*, UnaryPred
>);
45 // !forward_iterator<I>
46 static_assert(!HasPartitionPointIter
<ForwardIteratorNotDerivedFrom
>);
47 static_assert(!HasPartitionPointIter
<ForwardIteratorNotIncrementable
>);
49 // !sentinel_for<S, I>
50 static_assert(!HasPartitionPointIter
<int*, SentinelForNotSemiregular
>);
51 static_assert(!HasPartitionPointIter
<int*, SentinelForNotWeaklyEqualityComparableWith
>);
53 // !indirect_unary_predicate<projected<I, Proj>>
54 static_assert(!HasPartitionPointIter
<int*, int*, IndirectUnaryPredicateNotPredicate
>);
55 static_assert(!HasPartitionPointIter
<int*, int*, IndirectUnaryPredicateNotCopyConstructible
>);
57 // Test constraints of the (range) overload.
58 // =========================================
60 template <class Range
, class Pred
>
61 concept HasPartitionPointRange
=
62 requires(Range
&& range
, Pred
&& pred
) {
63 std::ranges::partition_point(std::forward
<Range
>(range
), std::forward
<Pred
>(pred
));
67 using R
= UncheckedRange
<T
>;
69 static_assert(HasPartitionPointRange
<R
<int*>, UnaryPred
>);
72 static_assert(!HasPartitionPointRange
<ForwardRangeNotDerivedFrom
, UnaryPred
>);
73 static_assert(!HasPartitionPointRange
<ForwardRangeNotIncrementable
, UnaryPred
>);
75 // !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
76 static_assert(!HasPartitionPointRange
<R
<int*>, IndirectUnaryPredicateNotPredicate
>);
77 static_assert(!HasPartitionPointRange
<R
<int*>, IndirectUnaryPredicateNotCopyConstructible
>);
79 template <class Iter
, class Sent
, std::size_t N
, class Pred
>
80 constexpr void test_one(std::array
<int, N
> input
, Pred pred
, std::size_t partition_point
) {
81 assert(std::ranges::is_partitioned(input
, pred
));
83 auto begin
= Iter(input
.data());
84 auto end
= Sent(Iter(input
.data() + input
.size()));
85 auto neg_pred
= [&](int x
) { return !pred(x
); };
87 { // (iterator, sentinel) overload.
88 std::same_as
<Iter
> decltype(auto) result
= std::ranges::partition_point(begin
, end
, pred
);
90 assert(base(result
) == input
.data() + partition_point
);
91 assert(std::ranges::all_of(begin
, result
, pred
));
92 assert(std::ranges::all_of(result
, end
, neg_pred
));
95 { // (range) overload.
96 auto range
= std::ranges::subrange(begin
, end
);
97 std::same_as
<Iter
> decltype(auto) result
= std::ranges::partition_point(range
, pred
);
99 assert(base(result
) == input
.data() + partition_point
);
100 assert(std::ranges::all_of(begin
, result
, pred
));
101 assert(std::ranges::all_of(result
, end
, neg_pred
));
105 template <class Iter
, class Sent
>
106 constexpr void test_iterators_2() {
107 auto is_odd
= [](int x
) { return x
% 2 != 0; };
110 test_one
<Iter
, Sent
, 0>({}, is_odd
, 0);
111 // 1-element sequence, the element satisfies the predicate.
112 test_one
<Iter
, Sent
, 1>({1}, is_odd
, 1);
113 // 1-element sequence, the element doesn't satisfy the predicate.
114 test_one
<Iter
, Sent
, 1>({2}, is_odd
, 0);
115 // 2-element sequence.
116 test_one
<Iter
, Sent
, 2>({1, 2}, is_odd
, 1);
117 // 3-element sequence.
118 test_one
<Iter
, Sent
, 3>({3, 1, 2}, is_odd
, 2);
120 test_one
<Iter
, Sent
, 8>({1, 3, 11, 5, 6, 2, 8, 4}, is_odd
, 4);
121 // Longer sequence with duplicates.
122 test_one
<Iter
, Sent
, 8>({1, 3, 3, 4, 6, 2, 8, 2}, is_odd
, 3);
123 // All elements are the same and satisfy the predicate.
124 test_one
<Iter
, Sent
, 3>({1, 1, 1}, is_odd
, 3);
125 // All elements are the same and don't satisfy the predicate.
126 test_one
<Iter
, Sent
, 3>({2, 2, 2}, is_odd
, 0);
127 // All non-satisfying and all satisfying elements are the same.
128 test_one
<Iter
, Sent
, 6>({1, 1, 1, 2, 2, 2}, is_odd
, 3);
130 auto is_negative
= [](int x
) { return x
< 0; };
131 // Different comparator.
132 test_one
<Iter
, Sent
, 5>({-3, -6, 5, 7, 2}, is_negative
, 2);
135 template <class Iter
>
136 constexpr void test_iterators_1() {
137 test_iterators_2
<Iter
, Iter
>();
138 test_iterators_2
<Iter
, sentinel_wrapper
<Iter
>>();
141 constexpr void test_iterators() {
142 test_iterators_1
<forward_iterator
<int*>>();
143 test_iterators_1
<bidirectional_iterator
<int*>>();
144 test_iterators_1
<random_access_iterator
<int*>>();
145 test_iterators_1
<contiguous_iterator
<int*>>();
146 test_iterators_1
<int*>();
149 constexpr bool test() {
152 { // A custom projection works.
153 const std::array in
= {1, 3, 4, 6, 8};
154 auto is_odd
= [](int x
) { return x
% 2 != 0; };
155 auto x2
= [](int x
) { return x
* 2; };
156 auto expected_no_proj
= in
.begin() + 2;
157 auto expected_with_proj
= in
.begin();
159 { // (iterator, sentinel) overload.
160 auto result_no_proj
= std::ranges::partition_point(in
.begin(), in
.end(), is_odd
);
161 assert(result_no_proj
== expected_no_proj
);
162 auto result_with_proj
= std::ranges::partition_point(in
.begin(), in
.end(), is_odd
, x2
);
163 assert(result_with_proj
== expected_with_proj
);
166 { // (range) overload.
167 auto result_no_proj
= std::ranges::partition_point(in
, is_odd
);
168 assert(result_no_proj
== expected_no_proj
);
169 auto result_with_proj
= std::ranges::partition_point(in
, is_odd
, x2
);
170 assert(result_with_proj
== expected_with_proj
);
177 int main(int, char**) {
179 static_assert(test());