173ebcabfSKonstantin Varlamov //===----------------------------------------------------------------------===//
273ebcabfSKonstantin Varlamov //
373ebcabfSKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473ebcabfSKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
573ebcabfSKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673ebcabfSKonstantin Varlamov //
773ebcabfSKonstantin Varlamov //===----------------------------------------------------------------------===//
873ebcabfSKonstantin Varlamov 
973ebcabfSKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
1073ebcabfSKonstantin Varlamov 
1173ebcabfSKonstantin Varlamov // <algorithm>
1273ebcabfSKonstantin Varlamov 
1373ebcabfSKonstantin Varlamov // template<permutable I, sentinel_for<I> S, class Proj = identity,
1473ebcabfSKonstantin Varlamov //          indirect_unary_predicate<projected<I, Proj>> Pred>
1573ebcabfSKonstantin Varlamov //   constexpr subrange<I>
1673ebcabfSKonstantin Varlamov //     partition(I first, S last, Pred pred, Proj proj = {});                                       // Since C++20
1773ebcabfSKonstantin Varlamov //
1873ebcabfSKonstantin Varlamov // template<forward_range R, class Proj = identity,
1973ebcabfSKonstantin Varlamov //          indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
2073ebcabfSKonstantin Varlamov //   requires permutable<iterator_t<R>>
2173ebcabfSKonstantin Varlamov //   constexpr borrowed_subrange_t<R>
2273ebcabfSKonstantin Varlamov //     partition(R&& r, Pred pred, Proj proj = {});                                                 // Since C++20
2373ebcabfSKonstantin Varlamov 
2473ebcabfSKonstantin Varlamov #include <algorithm>
2573ebcabfSKonstantin Varlamov #include <array>
2673ebcabfSKonstantin Varlamov #include <concepts>
2773ebcabfSKonstantin Varlamov #include <functional>
2873ebcabfSKonstantin Varlamov #include <ranges>
2973ebcabfSKonstantin Varlamov 
3073ebcabfSKonstantin Varlamov #include "almost_satisfies_types.h"
3173ebcabfSKonstantin Varlamov #include "test_iterators.h"
3273ebcabfSKonstantin Varlamov 
338ed702b8SKonstantin Varlamov struct UnaryPred { bool operator()(int) const; };
348ed702b8SKonstantin Varlamov 
358ed702b8SKonstantin Varlamov // Test constraints of the (iterator, sentinel) overload.
368ed702b8SKonstantin Varlamov // ======================================================
378ed702b8SKonstantin Varlamov 
388ed702b8SKonstantin Varlamov template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
398ed702b8SKonstantin Varlamov concept HasPartitionIter =
408ed702b8SKonstantin Varlamov     requires(Iter&& iter, Sent&& sent, Pred&& pred) {
418ed702b8SKonstantin Varlamov       std::ranges::partition(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
428ed702b8SKonstantin Varlamov     };
438ed702b8SKonstantin Varlamov 
448ed702b8SKonstantin Varlamov static_assert(HasPartitionIter<int*, int*, UnaryPred>);
458ed702b8SKonstantin Varlamov 
468ed702b8SKonstantin Varlamov // !permutable<I>
478ed702b8SKonstantin Varlamov static_assert(!HasPartitionIter<PermutableNotForwardIterator>);
488ed702b8SKonstantin Varlamov static_assert(!HasPartitionIter<PermutableNotSwappable>);
498ed702b8SKonstantin Varlamov 
508ed702b8SKonstantin Varlamov // !sentinel_for<S, I>
518ed702b8SKonstantin Varlamov static_assert(!HasPartitionIter<int*, SentinelForNotSemiregular>);
528ed702b8SKonstantin Varlamov static_assert(!HasPartitionIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
538ed702b8SKonstantin Varlamov 
548ed702b8SKonstantin Varlamov // !indirect_unary_predicate<projected<I, Proj>>
558ed702b8SKonstantin Varlamov static_assert(!HasPartitionIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
568ed702b8SKonstantin Varlamov static_assert(!HasPartitionIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
578ed702b8SKonstantin Varlamov 
588ed702b8SKonstantin Varlamov // Test constraints of the (range) overload.
598ed702b8SKonstantin Varlamov // =========================================
608ed702b8SKonstantin Varlamov 
618ed702b8SKonstantin Varlamov template <class Range, class Pred>
628ed702b8SKonstantin Varlamov concept HasPartitionRange =
638ed702b8SKonstantin Varlamov     requires(Range&& range, Pred&& pred) {
648ed702b8SKonstantin Varlamov       std::ranges::partition(std::forward<Range>(range), std::forward<Pred>(pred));
658ed702b8SKonstantin Varlamov     };
668ed702b8SKonstantin Varlamov 
678ed702b8SKonstantin Varlamov template <class T>
688ed702b8SKonstantin Varlamov using R = UncheckedRange<T>;
698ed702b8SKonstantin Varlamov 
708ed702b8SKonstantin Varlamov static_assert(HasPartitionRange<R<int*>, UnaryPred>);
718ed702b8SKonstantin Varlamov 
728ed702b8SKonstantin Varlamov // !forward_range<R>
738ed702b8SKonstantin Varlamov static_assert(!HasPartitionRange<ForwardRangeNotDerivedFrom, UnaryPred>);
74065202f3SKonstantin Varlamov static_assert(!HasPartitionRange<ForwardRangeNotIncrementable, UnaryPred>);
758ed702b8SKonstantin Varlamov 
768ed702b8SKonstantin Varlamov // !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
778ed702b8SKonstantin Varlamov static_assert(!HasPartitionRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
788ed702b8SKonstantin Varlamov static_assert(!HasPartitionRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
798ed702b8SKonstantin Varlamov 
808ed702b8SKonstantin Varlamov // !permutable<iterator_t<R>>
818ed702b8SKonstantin Varlamov static_assert(!HasPartitionRange<R<PermutableNotForwardIterator>, UnaryPred>);
828ed702b8SKonstantin Varlamov static_assert(!HasPartitionRange<R<PermutableNotSwappable>, UnaryPred>);
838ed702b8SKonstantin Varlamov 
848ed702b8SKonstantin Varlamov // `partition` isn't a stable algorithm so this function cannot test the exact output.
85*fb855eb9SMark de Wever 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)86*fb855eb9SMark de Wever constexpr void test_one(std::array<int, N> input, Pred pred, std::size_t partition_point) {
878ed702b8SKonstantin Varlamov   auto neg_pred = [&](int x) { return !pred(x); };
888ed702b8SKonstantin Varlamov 
898ed702b8SKonstantin Varlamov   { // (iterator, sentinel) overload.
908ed702b8SKonstantin Varlamov     auto partitioned = input;
918ed702b8SKonstantin Varlamov     auto b = Iter(partitioned.data());
928ed702b8SKonstantin Varlamov     auto e = Sent(Iter(partitioned.data() + partitioned.size()));
938ed702b8SKonstantin Varlamov 
948ed702b8SKonstantin Varlamov     std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::partition(b, e, pred);
958ed702b8SKonstantin Varlamov 
968ed702b8SKonstantin Varlamov     assert(base(result.begin()) == partitioned.data() + partition_point);
978ed702b8SKonstantin Varlamov     assert(base(result.end()) == partitioned.data() + partitioned.size());
988ed702b8SKonstantin Varlamov 
998ed702b8SKonstantin Varlamov     assert(std::ranges::all_of(b, result.begin(), pred));
1008ed702b8SKonstantin Varlamov     assert(std::ranges::all_of(result.begin(), e, neg_pred));
1018ed702b8SKonstantin Varlamov   }
1028ed702b8SKonstantin Varlamov 
1038ed702b8SKonstantin Varlamov   { // (range) overload.
1048ed702b8SKonstantin Varlamov     auto partitioned = input;
1058ed702b8SKonstantin Varlamov     auto b = Iter(partitioned.data());
1068ed702b8SKonstantin Varlamov     auto e = Sent(Iter(partitioned.data() + partitioned.size()));
1078ed702b8SKonstantin Varlamov     auto range = std::ranges::subrange(b, e);
1088ed702b8SKonstantin Varlamov 
1098ed702b8SKonstantin Varlamov     std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::partition(range, pred);
1108ed702b8SKonstantin Varlamov 
1118ed702b8SKonstantin Varlamov     assert(base(result.begin()) == partitioned.data() + partition_point);
1128ed702b8SKonstantin Varlamov     assert(base(result.end()) == partitioned.data() + partitioned.size());
1138ed702b8SKonstantin Varlamov 
1148ed702b8SKonstantin Varlamov     assert(std::ranges::all_of(b, result.begin(), pred));
1158ed702b8SKonstantin Varlamov     assert(std::ranges::all_of(result.begin(), e, neg_pred));
1168ed702b8SKonstantin Varlamov   }
1178ed702b8SKonstantin Varlamov }
1188ed702b8SKonstantin Varlamov 
1198ed702b8SKonstantin Varlamov template <class Iter, class Sent>
test_iterators_2()1208ed702b8SKonstantin Varlamov constexpr void test_iterators_2() {
1218ed702b8SKonstantin Varlamov   auto is_odd = [](int x) { return x % 2 != 0; };
1228ed702b8SKonstantin Varlamov 
1238ed702b8SKonstantin Varlamov   // Empty sequence.
1248ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 0>({}, is_odd, 0);
1258ed702b8SKonstantin Varlamov   // 1-element sequence, the element satisfies the predicate.
1268ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 1>({1}, is_odd, 1);
1278ed702b8SKonstantin Varlamov   // 1-element sequence, the element doesn't satisfy the predicate.
1288ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 1>({2}, is_odd, 0);
1298ed702b8SKonstantin Varlamov   // 2-element sequence, not in order.
1308ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 2>({2, 1}, is_odd, 1);
1318ed702b8SKonstantin Varlamov   // 2-element sequence, already in order.
1328ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 2>({1, 2}, is_odd, 1);
1338ed702b8SKonstantin Varlamov   // 3-element sequence.
1348ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 3>({2, 1, 3}, is_odd, 2);
1358ed702b8SKonstantin Varlamov   // Longer sequence.
1368ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 8>({2, 1, 3, 6, 8, 4, 11, 5}, is_odd, 4);
1378ed702b8SKonstantin Varlamov   // Longer sequence with duplicates.
1388ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 8>({2, 1, 3, 6, 2, 8, 1, 6}, is_odd, 3);
1398ed702b8SKonstantin Varlamov   // All elements are the same and satisfy the predicate.
1408ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3);
1418ed702b8SKonstantin Varlamov   // All elements are the same and don't satisfy the predicate.
1428ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0);
1438ed702b8SKonstantin Varlamov   // Already partitioned.
1448ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 6>({1, 3, 5, 4, 6, 8}, is_odd, 3);
1458ed702b8SKonstantin Varlamov   // Reverse-partitioned.
1468ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3);
1478ed702b8SKonstantin Varlamov   // Repeating pattern.
1488ed702b8SKonstantin Varlamov   test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3);
149065202f3SKonstantin Varlamov 
150065202f3SKonstantin Varlamov   auto is_negative = [](int x) { return x < 0; };
151065202f3SKonstantin Varlamov   // Different comparator.
152065202f3SKonstantin Varlamov   test_one<Iter, Sent, 5>({-3, 5, 7, -6, 2}, is_negative, 2);
1538ed702b8SKonstantin Varlamov }
1548ed702b8SKonstantin Varlamov 
1558ed702b8SKonstantin Varlamov template <class Iter>
test_iterators_1()1568ed702b8SKonstantin Varlamov constexpr void test_iterators_1() {
1578ed702b8SKonstantin Varlamov   test_iterators_2<Iter, Iter>();
1588ed702b8SKonstantin Varlamov   test_iterators_2<Iter, sentinel_wrapper<Iter>>();
1598ed702b8SKonstantin Varlamov }
1608ed702b8SKonstantin Varlamov 
test_iterators()1618ed702b8SKonstantin Varlamov constexpr void test_iterators() {
1628ed702b8SKonstantin Varlamov   test_iterators_1<forward_iterator<int*>>();
1638ed702b8SKonstantin Varlamov   test_iterators_1<bidirectional_iterator<int*>>();
1648ed702b8SKonstantin Varlamov   test_iterators_1<random_access_iterator<int*>>();
1658ed702b8SKonstantin Varlamov   test_iterators_1<contiguous_iterator<int*>>();
1668ed702b8SKonstantin Varlamov   test_iterators_1<int*>();
1678ed702b8SKonstantin Varlamov }
16873ebcabfSKonstantin Varlamov 
test()16973ebcabfSKonstantin Varlamov constexpr bool test() {
1708ed702b8SKonstantin Varlamov   test_iterators();
1718ed702b8SKonstantin Varlamov 
1728ed702b8SKonstantin Varlamov   { // A custom projection works.
1738ed702b8SKonstantin Varlamov     const std::array input = {1, -1};
1748ed702b8SKonstantin Varlamov     auto is_negative = [](int x) { return x < 0; };
1758ed702b8SKonstantin Varlamov     auto negate = [](int x) { return -x; };
1768ed702b8SKonstantin Varlamov     const std::array expected_no_proj = {-1, 1};
1778ed702b8SKonstantin Varlamov     const std::array expected_with_proj = {1, -1};
1788ed702b8SKonstantin Varlamov 
1798ed702b8SKonstantin Varlamov     { // (iterator, sentinel) overload.
1808ed702b8SKonstantin Varlamov       {
1818ed702b8SKonstantin Varlamov         auto in = input;
1828ed702b8SKonstantin Varlamov         std::ranges::partition(in.begin(), in.end(), is_negative);
1838ed702b8SKonstantin Varlamov         assert(in == expected_no_proj);
1848ed702b8SKonstantin Varlamov       }
1858ed702b8SKonstantin Varlamov       {
1868ed702b8SKonstantin Varlamov         auto in = input;
1878ed702b8SKonstantin Varlamov         std::ranges::partition(in.begin(), in.end(), is_negative, negate);
1888ed702b8SKonstantin Varlamov         assert(in == expected_with_proj);
1898ed702b8SKonstantin Varlamov       }
1908ed702b8SKonstantin Varlamov     }
1918ed702b8SKonstantin Varlamov 
1928ed702b8SKonstantin Varlamov     { // (range) overload.
1938ed702b8SKonstantin Varlamov       {
1948ed702b8SKonstantin Varlamov         auto in = input;
1958ed702b8SKonstantin Varlamov         std::ranges::partition(in, is_negative);
1968ed702b8SKonstantin Varlamov         assert(in == expected_no_proj);
1978ed702b8SKonstantin Varlamov       }
1988ed702b8SKonstantin Varlamov       {
1998ed702b8SKonstantin Varlamov         auto in = input;
2008ed702b8SKonstantin Varlamov         std::ranges::partition(in, is_negative, negate);
2018ed702b8SKonstantin Varlamov         assert(in == expected_with_proj);
2028ed702b8SKonstantin Varlamov       }
2038ed702b8SKonstantin Varlamov     }
2048ed702b8SKonstantin Varlamov   }
20573ebcabfSKonstantin Varlamov 
20673ebcabfSKonstantin Varlamov   return true;
20773ebcabfSKonstantin Varlamov }
20873ebcabfSKonstantin Varlamov 
main(int,char **)20973ebcabfSKonstantin Varlamov int main(int, char**) {
21073ebcabfSKonstantin Varlamov   test();
21173ebcabfSKonstantin Varlamov   static_assert(test());
21273ebcabfSKonstantin Varlamov 
21373ebcabfSKonstantin Varlamov   return 0;
21473ebcabfSKonstantin Varlamov }
215