1 //===----------------------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11 
12 // <algorithm>
13 
14 // template<input_iterator I, sentinel_for<I> S,
15 //          weakly_incrementable O1, weakly_incrementable O2,
16 //          class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
17 //   requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
18 //   constexpr partition_copy_result<I, O1, O2>
19 //     partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
20 //                    Proj proj = {});                                                              // Since C++20
21 //
22 // template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
23 //          class Proj = identity,
24 //          indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
25 //   requires indirectly_copyable<iterator_t<R>, O1> &&
26 //            indirectly_copyable<iterator_t<R>, O2>
27 //   constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
28 //     partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {});                 // Since C++20
29 
30 #include <algorithm>
31 #include <array>
32 #include <concepts>
33 #include <functional>
34 #include <ranges>
35 #include <utility>
36 
37 #include "almost_satisfies_types.h"
38 #include "counting_predicates.h"
39 #include "counting_projection.h"
40 #include "test_iterators.h"
41 
42 struct UnaryPred { bool operator()(int) const; };
43 
44 // Test constraints of the (iterator, sentinel) overload.
45 // ======================================================
46 
47 template <class InIter = int*, class Sent = int*, class Output1 = int*, class Output2 = int*, class Pred = UnaryPred>
48 concept HasPartitionCopyIter =
49     requires(InIter&& input, Sent&& sent, Output1&& output1, Output2&& output2, Pred&& pred) {
50       std::ranges::partition_copy(std::forward<InIter>(input), std::forward<Sent>(sent),
51           std::forward<Output1>(output1), std::forward<Output2>(output2), std::forward<Pred>(pred));
52     };
53 
54 static_assert(HasPartitionCopyIter<int*, int*, int*, int*, UnaryPred>);
55 
56 // !input_iterator<I>
57 static_assert(!HasPartitionCopyIter<InputIteratorNotDerivedFrom>);
58 static_assert(!HasPartitionCopyIter<InputIteratorNotIndirectlyReadable>);
59 static_assert(!HasPartitionCopyIter<InputIteratorNotInputOrOutputIterator>);
60 
61 // !sentinel_for<S, I>
62 static_assert(!HasPartitionCopyIter<int*, SentinelForNotSemiregular>);
63 static_assert(!HasPartitionCopyIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
64 
65 // !weakly_incrementable<O1>
66 static_assert(!HasPartitionCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
67 
68 // !weakly_incrementable<O2>
69 static_assert(!HasPartitionCopyIter<int*, int*, int*, WeaklyIncrementableNotMovable>);
70 
71 // !indirect_unary_predicate<projected<I, Proj>>
72 static_assert(!HasPartitionCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotPredicate>);
73 static_assert(!HasPartitionCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
74 
75 struct Uncopyable {
76   Uncopyable(int&&);
77   Uncopyable(const int&) = delete;
78 };
79 // !indirectly_copyable<I, O1>
80 static_assert(!HasPartitionCopyIter<int*, int*, Uncopyable*>);
81 // !indirectly_copyable<I, O2>
82 static_assert(!HasPartitionCopyIter<int*, int*, int*, Uncopyable*>);
83 
84 // Test constraints of the (range) overload.
85 // =========================================
86 
87 template <class InputRange, class Output1 = int*, class Output2 = int*, class Pred = UnaryPred>
88 concept HasPartitionCopyRange =
89     requires(InputRange&& input, Output1&& output1, Output2&& output2, Pred&& pred) {
90       std::ranges::partition_copy(std::forward<InputRange>(input),
91           std::forward<Output1>(output1), std::forward<Output2>(output2), std::forward<Pred>(pred));
92     };
93 
94 template <class T>
95 using R = UncheckedRange<T>;
96 
97 static_assert(HasPartitionCopyRange<R<int*>, int*, int*, UnaryPred>);
98 
99 // !input_iterator<I>
100 static_assert(!HasPartitionCopyRange<InputRangeNotDerivedFrom>);
101 static_assert(!HasPartitionCopyRange<InputRangeNotIndirectlyReadable>);
102 static_assert(!HasPartitionCopyRange<InputRangeNotInputOrOutputIterator>);
103 
104 // !weakly_incrementable<O1>
105 static_assert(!HasPartitionCopyRange<R<int*>, WeaklyIncrementableNotMovable>);
106 
107 // !weakly_incrementable<O2>
108 static_assert(!HasPartitionCopyRange<R<int*>, int*, WeaklyIncrementableNotMovable>);
109 
110 // !indirect_unary_predicate<projected<I, Proj>>
111 static_assert(!HasPartitionCopyRange<R<int*>, int*, int*, IndirectUnaryPredicateNotPredicate>);
112 static_assert(!HasPartitionCopyRange<R<int*>, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
113 
114 // !indirectly_copyable<I, O1>
115 static_assert(!HasPartitionCopyRange<R<int*>, Uncopyable*>);
116 // !indirectly_copyable<I, O2>
117 static_assert(!HasPartitionCopyRange<R<int*>, int*, Uncopyable*>);
118 
119 static_assert(std::is_same_v<std::ranges::partition_copy_result<int, int, int>,
120     std::ranges::in_out_out_result<int, int, int>>);
121 
122 template <class Iter, class Sent, class OutIter1, class OutIter2, size_t N1, size_t N2, size_t N3, class Pred>
test_one(std::array<int,N1> input,Pred pred,std::array<int,N2> expected_true,std::array<int,N3> expected_false)123 constexpr void test_one(std::array<int, N1> input, Pred pred, std::array<int, N2> expected_true,
124     std::array<int, N3> expected_false) {
125   static_assert(N2 + N3 == N1);
126   using ResultT = std::ranges::partition_copy_result<Iter, OutIter1, OutIter2>;
127 
128   auto begin = input.data();
129   auto end = input.data() + input.size();
130 
131   { // (iterator, sentinel) overload.
132     std::array<int, N2> out1;
133     std::array<int, N3> out2;
134 
135     std::same_as<ResultT> decltype(auto) result = std::ranges::partition_copy(
136         Iter(begin), Sent(Iter(end)), OutIter1(out1.begin()), OutIter2(out2.begin()), pred);
137 
138     assert(base(result.in) == input.data() + input.size());
139     assert(base(result.out1) == out1.data() + expected_true.size());
140     assert(base(result.out2) == out2.data() + expected_false.size());
141 
142     assert(std::ranges::equal(out1, expected_true));
143     assert(std::ranges::equal(out2, expected_false));
144   }
145 
146   { // (range) overload.
147     std::ranges::subrange range{Iter(begin), Sent(Iter(end))};
148     std::array<int, N2> out1;
149     std::array<int, N3> out2;
150 
151     std::same_as<ResultT> decltype(auto) result = std::ranges::partition_copy(
152         range, OutIter1(out1.begin()), OutIter2(out2.begin()), pred);
153 
154     assert(base(result.in) == input.data() + input.size());
155     assert(base(result.out1) == out1.data() + expected_true.size());
156     assert(base(result.out2) == out2.data() + expected_false.size());
157 
158     assert(std::ranges::equal(out1, expected_true));
159     assert(std::ranges::equal(out2, expected_false));
160   }
161 }
162 
163 template <class InIter, class Sent, class Out1, class Out2>
test_iterators_in_sent_out1_out2()164 constexpr void test_iterators_in_sent_out1_out2() {
165   auto is_odd = [](int x) { return x % 2 != 0; };
166 
167   // Empty sequence.
168   test_one<InIter, Sent, Out1, Out2, 0, 0, 0>({}, is_odd, {}, {});
169   // 1-element sequence, the element satisfies the predicate.
170   test_one<InIter, Sent, Out1, Out2, 1, 1, 0>({1}, is_odd, {1}, {});
171   // 1-element sequence, the element doesn't satisfy the predicate.
172   test_one<InIter, Sent, Out1, Out2, 1, 0, 1>({2}, is_odd, {}, {2});
173   // 2-element sequence, not in order.
174   test_one<InIter, Sent, Out1, Out2, 2, 1, 1>({2, 1}, is_odd, {1}, {2});
175   // 2-element sequence, already in order.
176   test_one<InIter, Sent, Out1, Out2, 2, 1, 1>({1, 2}, is_odd, {1}, {2});
177   // 3-element sequence.
178   test_one<InIter, Sent, Out1, Out2, 3, 2, 1>({2, 1, 3}, is_odd, {1, 3}, {2});
179   // Longer sequence.
180   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});
181   // Longer sequence with duplicates.
182   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});
183   // All elements are the same and satisfy the predicate.
184   test_one<InIter, Sent, Out1, Out2, 3, 3, 0>({1, 1, 1}, is_odd, {1, 1, 1}, {});
185   // All elements are the same and don't satisfy the predicate.
186   test_one<InIter, Sent, Out1, Out2, 3, 0, 3>({2, 2, 2}, is_odd, {}, {2, 2, 2});
187   // Already partitioned.
188   test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({1, 3, 5, 4, 6, 8}, is_odd, {1, 3, 5}, {4, 6, 8});
189   // Reverse-partitioned.
190   test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({4, 6, 8, 1, 3, 5}, is_odd, {1, 3, 5}, {4, 6, 8});
191   // Repeating pattern.
192   test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({1, 2, 1, 2, 1, 2}, is_odd, {1, 1, 1}, {2, 2, 2});
193 
194   auto is_negative = [](int x) { return x < 0; };
195   // Different comparator.
196   test_one<InIter, Sent, Out1, Out2, 5, 2, 3>({-3, 5, 7, -6, 2}, is_negative, {-3, -6}, {5, 7, 2});
197 }
198 
199 template <class InIter, class Sent, class Out1>
test_iterators_in_sent_out1()200 constexpr void test_iterators_in_sent_out1() {
201   test_iterators_in_sent_out1_out2<InIter, Sent, Out1, cpp20_output_iterator<int*>>();
202   test_iterators_in_sent_out1_out2<InIter, Sent, Out1, random_access_iterator<int*>>();
203   test_iterators_in_sent_out1_out2<InIter, Sent, Out1, int*>();
204 }
205 
206 template <class InIter, class Sent>
test_iterators_in_sent()207 constexpr void test_iterators_in_sent() {
208   test_iterators_in_sent_out1<InIter, Sent, cpp17_output_iterator<int*>>();
209   test_iterators_in_sent_out1<InIter, Sent, cpp20_output_iterator<int*>>();
210   test_iterators_in_sent_out1<InIter, Sent, random_access_iterator<int*>>();
211   test_iterators_in_sent_out1<InIter, Sent, int*>();
212 }
213 
214 template <class InIter>
test_iterators_in()215 constexpr void test_iterators_in() {
216   if constexpr (std::sentinel_for<InIter, InIter>) {
217     test_iterators_in_sent<InIter, InIter>();
218   }
219   test_iterators_in_sent<InIter, sentinel_wrapper<InIter>>();
220 }
221 
test_iterators()222 constexpr void test_iterators() {
223   // Note: deliberately testing with only the weakest and "strongest" iterator types to minimize combinatorial
224   // explosion.
225   test_iterators_in<cpp20_input_iterator<int*>>();
226   test_iterators_in<int*>();
227 }
228 
test()229 constexpr bool test() {
230   test_iterators();
231 
232   { // A custom projection works.
233     const std::array in = {1, 3, 9, -2, -5, -8};
234     auto is_negative = [](int x) { return x < 0; };
235     auto negate = [](int x) { return -x; };
236     const std::array expected_negative = {-2, -5, -8};
237     const std::array expected_positive = {1, 3, 9};
238 
239     { // (iterator, sentinel) overload.
240       {
241         std::array<int, 3> out1, out2;
242         std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), is_negative);
243         assert(out1 == expected_negative);
244         assert(out2 == expected_positive);
245       }
246       {
247         std::array<int, 3> out1, out2;
248         std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), is_negative, negate);
249         assert(out1 == expected_positive);
250         assert(out2 == expected_negative);
251       }
252     }
253 
254     { // (range) overload.
255       {
256         std::array<int, 3> out1, out2;
257         std::ranges::partition_copy(in, out1.begin(), out2.begin(), is_negative);
258         assert(out1 == expected_negative);
259         assert(out2 == expected_positive);
260       }
261       {
262         std::array<int, 3> out1, out2;
263         std::ranges::partition_copy(in, out1.begin(), out2.begin(), is_negative, negate);
264         assert(out1 == expected_positive);
265         assert(out2 == expected_negative);
266       }
267     }
268   }
269 
270   { // Complexity: Exactly `last - first` applications of `pred` and `proj`.
271     {
272       const std::array in = {-2, -5, -8, -11, -10, -5, 1, 3, 9, 6, 8, 2, 4, 2};
273       auto is_negative = [](int x) { return x < 0; };
274       std::array<int, 6> out1;
275       std::array<int, 8> out2;
276 
277       int pred_count = 0, proj_count = 0;
278       counting_predicate pred(is_negative, pred_count);
279       counting_projection proj(proj_count);
280       auto expected = static_cast<int>(in.size());
281 
282       {
283         std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), pred, proj);
284         assert(pred_count == expected);
285         assert(proj_count == expected);
286         pred_count = proj_count = 0;
287       }
288 
289       {
290         std::ranges::partition_copy(in, out1.begin(), out2.begin(), pred, proj);
291         assert(pred_count == expected);
292         assert(proj_count == expected);
293         pred_count = proj_count = 0;
294       }
295     }
296   }
297 
298   return true;
299 }
300 
main(int,char **)301 int main(int, char**) {
302   test();
303   static_assert(test());
304 
305   return 0;
306 }
307