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