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 
11 // <algorithm>
12 
13 // template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
14 //          indirect_unary_predicate<projected<I, Proj>> Pred>
15 //   requires permutable<I>
16 //   subrange<I> stable_partition(I first, S last, Pred pred, Proj proj = {});                      // Since C++20
17 //
18 // template<bidirectional_range R, class Proj = identity,
19 //          indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
20 //   requires permutable<iterator_t<R>>
21 //   borrowed_subrange_t<R> stable_partition(R&& r, Pred pred, Proj proj = {});                     // Since C++20
22 
23 #include <algorithm>
24 #include <array>
25 #include <concepts>
26 #include <functional>
27 #include <ranges>
28 
29 #include "almost_satisfies_types.h"
30 #include "test_iterators.h"
31 
32 struct UnaryPred { bool operator()(int) const; };
33 
34 // Test constraints of the (iterator, sentinel) overload.
35 // ======================================================
36 
37 template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
38 concept HasStablePartitionIter =
39     requires(Iter&& iter, Sent&& sent, Pred&& pred) {
40       std::ranges::stable_partition(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
41     };
42 
43 static_assert(HasStablePartitionIter<int*, int*, UnaryPred>);
44 
45 // !bidirectional_iterator<I>
46 static_assert(!HasStablePartitionIter<BidirectionalIteratorNotDerivedFrom>);
47 static_assert(!HasStablePartitionIter<BidirectionalIteratorNotDecrementable>);
48 
49 // !sentinel_for<S, I>
50 static_assert(!HasStablePartitionIter<int*, SentinelForNotSemiregular>);
51 static_assert(!HasStablePartitionIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
52 
53 // !indirect_unary_predicate<projected<I, Proj>>
54 static_assert(!HasStablePartitionIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
55 static_assert(!HasStablePartitionIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
56 
57 // !permutable<I>
58 static_assert(!HasStablePartitionIter<PermutableNotForwardIterator>);
59 static_assert(!HasStablePartitionIter<PermutableNotSwappable>);
60 
61 // Test constraints of the (range) overload.
62 // =========================================
63 
64 template <class Range, class Pred>
65 concept HasStablePartitionRange =
66     requires(Range&& range, Pred&& pred) {
67       std::ranges::stable_partition(std::forward<Range>(range), std::forward<Pred>(pred));
68     };
69 
70 template <class T>
71 using R = UncheckedRange<T>;
72 
73 static_assert(HasStablePartitionRange<R<int*>, UnaryPred>);
74 
75 // !bidirectional_range<R>
76 static_assert(!HasStablePartitionRange<BidirectionalRangeNotDerivedFrom, UnaryPred>);
77 static_assert(!HasStablePartitionRange<BidirectionalRangeNotDecrementable, UnaryPred>);
78 
79 // !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
80 static_assert(!HasStablePartitionRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
81 static_assert(!HasStablePartitionRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
82 
83 // !permutable<iterator_t<R>>
84 static_assert(!HasStablePartitionRange<R<PermutableNotForwardIterator>, UnaryPred>);
85 static_assert(!HasStablePartitionRange<R<PermutableNotSwappable>, UnaryPred>);
86 
87 template <class Iter, class Sent, std::size_t N, class Pred>
test_one(std::array<int,N> input,Pred pred,std::size_t partition_point,std::array<int,N> expected)88 void test_one(std::array<int, N> input, Pred pred, std::size_t partition_point, std::array<int, N> expected) {
89   auto neg_pred = [&](int x) { return !pred(x); };
90 
91   { // (iterator, sentinel) overload.
92     auto partitioned = input;
93     auto b = Iter(partitioned.data());
94     auto e = Sent(Iter(partitioned.data() + partitioned.size()));
95 
96     std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::stable_partition(b, e, pred);
97 
98     assert(partitioned == expected);
99     assert(base(result.begin()) == partitioned.data() + partition_point);
100     assert(base(result.end()) == partitioned.data() + partitioned.size());
101 
102     assert(std::ranges::all_of(b, result.begin(), pred));
103     assert(std::ranges::all_of(result.begin(), e, neg_pred));
104   }
105 
106   { // (range) overload.
107     auto partitioned = input;
108     auto b = Iter(partitioned.data());
109     auto e = Sent(Iter(partitioned.data() + partitioned.size()));
110     auto range = std::ranges::subrange(b, e);
111 
112     std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::stable_partition(range, pred);
113 
114     assert(partitioned == expected);
115     assert(base(result.begin()) == partitioned.data() + partition_point);
116     assert(base(result.end()) == partitioned.data() + partitioned.size());
117 
118     assert(std::ranges::all_of(b, result.begin(), pred));
119     assert(std::ranges::all_of(result.begin(), e, neg_pred));
120   }
121 }
122 
123 template <class Iter, class Sent>
test_iterators_2()124 void test_iterators_2() {
125   auto is_odd = [](int x) { return x % 2 != 0; };
126 
127   // Empty sequence.
128   test_one<Iter, Sent, 0>({}, is_odd, 0, {});
129   // 1-element sequence, the element satisfies the predicate.
130   test_one<Iter, Sent, 1>({1}, is_odd, 1, {1});
131   // 1-element sequence, the element doesn't satisfy the predicate.
132   test_one<Iter, Sent, 1>({2}, is_odd, 0, {2});
133   // 2-element sequence, not in order.
134   test_one<Iter, Sent, 2>({2, 1}, is_odd, 1, {1, 2});
135   // 2-element sequence, already in order.
136   test_one<Iter, Sent, 2>({1, 2}, is_odd, 1, {1, 2});
137   // 3-element sequence.
138   test_one<Iter, Sent, 3>({2, 1, 3}, is_odd, 2, {1, 3, 2});
139   // Longer sequence.
140   test_one<Iter, Sent, 8>({2, 1, 3, 6, 8, 4, 11, 5}, is_odd, 4, {1, 3, 11, 5, 2, 6, 8, 4});
141   // Longer sequence with duplicates.
142   test_one<Iter, Sent, 8>({2, 1, 3, 6, 2, 8, 1, 6}, is_odd, 3, {1, 3, 1, 2, 6, 2, 8, 6});
143   // All elements are the same and satisfy the predicate.
144   test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3, {1, 1, 1});
145   // All elements are the same and don't satisfy the predicate.
146   test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0, {2, 2, 2});
147   // Already partitioned.
148   test_one<Iter, Sent, 6>({1, 3, 5, 4, 6, 8}, is_odd, 3, {1, 3, 5, 4, 6, 8});
149   // Reverse-partitioned.
150   test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3, {1, 3, 5, 4, 6, 8});
151   // Repeating pattern.
152   test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3, {1, 1, 1, 2, 2, 2});
153 
154   auto is_negative = [](int x) { return x < 0; };
155   // Different comparator.
156   test_one<Iter, Sent, 5>({-3, 5, 7, -6, 2}, is_negative, 2, {-3, -6, 5, 7, 2});
157 }
158 
159 template <class Iter>
test_iterators_1()160 void test_iterators_1() {
161   test_iterators_2<Iter, Iter>();
162   test_iterators_2<Iter, sentinel_wrapper<Iter>>();
163 }
164 
test_iterators()165 void test_iterators() {
166   test_iterators_1<bidirectional_iterator<int*>>();
167   test_iterators_1<random_access_iterator<int*>>();
168   test_iterators_1<contiguous_iterator<int*>>();
169   test_iterators_1<int*>();
170 }
171 
test()172 void test() {
173   test_iterators();
174 
175   { // The algorithm is stable (equivalent elements remain in the same order).
176     struct OrderedValue {
177       int value;
178       double original_order;
179       bool operator==(const OrderedValue&) const = default;
180     };
181 
182     auto is_odd = [](OrderedValue x) { return x.value % 2 != 0; };
183 
184     using V = OrderedValue;
185     using Array = std::array<V, 20>;
186     Array orig_in = {
187       V{10, 2.1}, {12, 2.2}, {3, 1.1}, {5, 1.2}, {3, 1.3}, {3, 1.4}, {11, 1.5}, {12, 2.3}, {4, 2.4}, {4, 2.5},
188       {4, 2.6}, {1, 1.6}, {6, 2.7}, {3, 1.7}, {10, 2.8}, {8, 2.9}, {12, 2.10}, {1, 1.8}, {1, 1.9}, {5, 1.10}
189     };
190     Array expected = {
191       V{3, 1.1}, {5, 1.2}, {3, 1.3}, {3, 1.4}, {11, 1.5}, {1, 1.6}, {3, 1.7}, {1, 1.8}, {1, 1.9}, {5, 1.10},
192       {10, 2.1}, {12, 2.2}, {12, 2.3}, {4, 2.4}, {4, 2.5}, {4, 2.6}, {6, 2.7}, {10, 2.8}, {8, 2.9}, {12, 2.10}
193     };
194 
195     {
196       auto in = orig_in;
197       std::ranges::stable_partition(in.begin(), in.end(), is_odd);
198       assert(in == expected);
199     }
200 
201     {
202       auto in = orig_in;
203       std::ranges::stable_partition(in, is_odd);
204       assert(in == expected);
205     }
206   }
207 
208   { // A custom projection works.
209     const std::array input = {1, -1};
210     auto is_negative = [](int x) { return x < 0; };
211     auto negate = [](int x) { return -x; };
212     const std::array expected_no_proj = {-1, 1};
213     const std::array expected_with_proj = {1, -1};
214 
215     { // (iterator, sentinel) overload.
216       {
217         auto in = input;
218         std::ranges::partition(in.begin(), in.end(), is_negative);
219         assert(in == expected_no_proj);
220       }
221       {
222         auto in = input;
223         std::ranges::partition(in.begin(), in.end(), is_negative, negate);
224         assert(in == expected_with_proj);
225       }
226     }
227 
228     { // (range) overload.
229       {
230         auto in = input;
231         std::ranges::partition(in, is_negative);
232         assert(in == expected_no_proj);
233       }
234       {
235         auto in = input;
236         std::ranges::partition(in, is_negative, negate);
237         assert(in == expected_with_proj);
238       }
239     }
240   }
241 }
242 
main(int,char **)243 int main(int, char**) {
244   test();
245   // Note: `stable_partition` is not `constexpr`.
246 
247   return 0;
248 }
249