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<forward_iterator I, sentinel_for<I> S, class Proj = identity,
1473ebcabfSKonstantin Varlamov //          indirect_unary_predicate<projected<I, Proj>> Pred>
1573ebcabfSKonstantin Varlamov //   constexpr I partition_point(I first, S last, Pred pred, Proj proj = {});                       // Since C++20
1673ebcabfSKonstantin Varlamov //
1773ebcabfSKonstantin Varlamov // template<forward_range R, class Proj = identity,
1873ebcabfSKonstantin Varlamov //          indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
1973ebcabfSKonstantin Varlamov //   constexpr borrowed_iterator_t<R>
2073ebcabfSKonstantin Varlamov //     partition_point(R&& r, Pred pred, Proj proj = {});                                           // Since C++20
2173ebcabfSKonstantin Varlamov 
2273ebcabfSKonstantin Varlamov #include <algorithm>
2373ebcabfSKonstantin Varlamov #include <array>
2473ebcabfSKonstantin Varlamov #include <concepts>
2573ebcabfSKonstantin Varlamov #include <functional>
2673ebcabfSKonstantin Varlamov #include <ranges>
27065202f3SKonstantin Varlamov #include <utility>
2873ebcabfSKonstantin Varlamov 
2973ebcabfSKonstantin Varlamov #include "almost_satisfies_types.h"
3073ebcabfSKonstantin Varlamov #include "test_iterators.h"
3173ebcabfSKonstantin Varlamov 
32065202f3SKonstantin Varlamov struct UnaryPred { bool operator()(int) const; };
33065202f3SKonstantin Varlamov 
34065202f3SKonstantin Varlamov // Test constraints of the (iterator, sentinel) overload.
35065202f3SKonstantin Varlamov // ======================================================
36065202f3SKonstantin Varlamov 
37065202f3SKonstantin Varlamov template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
38065202f3SKonstantin Varlamov concept HasPartitionPointIter =
39065202f3SKonstantin Varlamov     requires(Iter&& iter, Sent&& sent, Pred&& pred) {
40065202f3SKonstantin Varlamov       std::ranges::partition_point(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
41065202f3SKonstantin Varlamov     };
42065202f3SKonstantin Varlamov 
43065202f3SKonstantin Varlamov static_assert(HasPartitionPointIter<int*, int*, UnaryPred>);
44065202f3SKonstantin Varlamov 
45065202f3SKonstantin Varlamov // !forward_iterator<I>
46065202f3SKonstantin Varlamov static_assert(!HasPartitionPointIter<ForwardIteratorNotDerivedFrom>);
47065202f3SKonstantin Varlamov static_assert(!HasPartitionPointIter<ForwardIteratorNotIncrementable>);
48065202f3SKonstantin Varlamov 
49065202f3SKonstantin Varlamov // !sentinel_for<S, I>
50065202f3SKonstantin Varlamov static_assert(!HasPartitionPointIter<int*, SentinelForNotSemiregular>);
51065202f3SKonstantin Varlamov static_assert(!HasPartitionPointIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
52065202f3SKonstantin Varlamov 
53065202f3SKonstantin Varlamov // !indirect_unary_predicate<projected<I, Proj>>
54065202f3SKonstantin Varlamov static_assert(!HasPartitionPointIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
55065202f3SKonstantin Varlamov static_assert(!HasPartitionPointIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
56065202f3SKonstantin Varlamov 
57065202f3SKonstantin Varlamov // Test constraints of the (range) overload.
58065202f3SKonstantin Varlamov // =========================================
59065202f3SKonstantin Varlamov 
60065202f3SKonstantin Varlamov template <class Range, class Pred>
61065202f3SKonstantin Varlamov concept HasPartitionPointRange =
62065202f3SKonstantin Varlamov     requires(Range&& range, Pred&& pred) {
63065202f3SKonstantin Varlamov       std::ranges::partition_point(std::forward<Range>(range), std::forward<Pred>(pred));
64065202f3SKonstantin Varlamov     };
65065202f3SKonstantin Varlamov 
66065202f3SKonstantin Varlamov template <class T>
67065202f3SKonstantin Varlamov using R = UncheckedRange<T>;
68065202f3SKonstantin Varlamov 
69065202f3SKonstantin Varlamov static_assert(HasPartitionPointRange<R<int*>, UnaryPred>);
70065202f3SKonstantin Varlamov 
71065202f3SKonstantin Varlamov // !forward_range<R>
72065202f3SKonstantin Varlamov static_assert(!HasPartitionPointRange<ForwardRangeNotDerivedFrom, UnaryPred>);
73065202f3SKonstantin Varlamov static_assert(!HasPartitionPointRange<ForwardRangeNotIncrementable, UnaryPred>);
74065202f3SKonstantin Varlamov 
75065202f3SKonstantin Varlamov // !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
76065202f3SKonstantin Varlamov static_assert(!HasPartitionPointRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
77065202f3SKonstantin Varlamov static_assert(!HasPartitionPointRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
78065202f3SKonstantin Varlamov 
79*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)80*fb855eb9SMark de Wever constexpr void test_one(std::array<int, N> input, Pred pred, std::size_t partition_point) {
81065202f3SKonstantin Varlamov   assert(std::ranges::is_partitioned(input, pred));
82065202f3SKonstantin Varlamov 
83065202f3SKonstantin Varlamov   auto begin = Iter(input.data());
84065202f3SKonstantin Varlamov   auto end = Sent(Iter(input.data() + input.size()));
85065202f3SKonstantin Varlamov   auto neg_pred = [&](int x) { return !pred(x); };
86065202f3SKonstantin Varlamov 
87065202f3SKonstantin Varlamov   { // (iterator, sentinel) overload.
88065202f3SKonstantin Varlamov     std::same_as<Iter> decltype(auto) result = std::ranges::partition_point(begin, end, pred);
89065202f3SKonstantin Varlamov 
90065202f3SKonstantin Varlamov     assert(base(result) == input.data() + partition_point);
91065202f3SKonstantin Varlamov     assert(std::ranges::all_of(begin, result, pred));
92065202f3SKonstantin Varlamov     assert(std::ranges::all_of(result, end, neg_pred));
93065202f3SKonstantin Varlamov   }
94065202f3SKonstantin Varlamov 
95065202f3SKonstantin Varlamov   { // (range) overload.
96065202f3SKonstantin Varlamov     auto range = std::ranges::subrange(begin, end);
97065202f3SKonstantin Varlamov     std::same_as<Iter> decltype(auto) result = std::ranges::partition_point(range, pred);
98065202f3SKonstantin Varlamov 
99065202f3SKonstantin Varlamov     assert(base(result) == input.data() + partition_point);
100065202f3SKonstantin Varlamov     assert(std::ranges::all_of(begin, result, pred));
101065202f3SKonstantin Varlamov     assert(std::ranges::all_of(result, end, neg_pred));
102065202f3SKonstantin Varlamov   }
103065202f3SKonstantin Varlamov }
104065202f3SKonstantin Varlamov 
105065202f3SKonstantin Varlamov template <class Iter, class Sent>
test_iterators_2()106065202f3SKonstantin Varlamov constexpr void test_iterators_2() {
107065202f3SKonstantin Varlamov   auto is_odd = [](int x) { return x % 2 != 0; };
108065202f3SKonstantin Varlamov 
109065202f3SKonstantin Varlamov   // Empty sequence.
110065202f3SKonstantin Varlamov   test_one<Iter, Sent, 0>({}, is_odd, 0);
111065202f3SKonstantin Varlamov   // 1-element sequence, the element satisfies the predicate.
112065202f3SKonstantin Varlamov   test_one<Iter, Sent, 1>({1}, is_odd, 1);
113065202f3SKonstantin Varlamov   // 1-element sequence, the element doesn't satisfy the predicate.
114065202f3SKonstantin Varlamov   test_one<Iter, Sent, 1>({2}, is_odd, 0);
115065202f3SKonstantin Varlamov   // 2-element sequence.
116065202f3SKonstantin Varlamov   test_one<Iter, Sent, 2>({1, 2}, is_odd, 1);
117065202f3SKonstantin Varlamov   // 3-element sequence.
118065202f3SKonstantin Varlamov   test_one<Iter, Sent, 3>({3, 1, 2}, is_odd, 2);
119065202f3SKonstantin Varlamov   // Longer sequence.
120065202f3SKonstantin Varlamov   test_one<Iter, Sent, 8>({1, 3, 11, 5, 6, 2, 8, 4}, is_odd, 4);
121065202f3SKonstantin Varlamov   // Longer sequence with duplicates.
122065202f3SKonstantin Varlamov   test_one<Iter, Sent, 8>({1, 3, 3, 4, 6, 2, 8, 2}, is_odd, 3);
123065202f3SKonstantin Varlamov   // All elements are the same and satisfy the predicate.
124065202f3SKonstantin Varlamov   test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3);
125065202f3SKonstantin Varlamov   // All elements are the same and don't satisfy the predicate.
126065202f3SKonstantin Varlamov   test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0);
127065202f3SKonstantin Varlamov   // All non-satisfying and all satisfying elements are the same.
128065202f3SKonstantin Varlamov   test_one<Iter, Sent, 6>({1, 1, 1, 2, 2, 2}, is_odd, 3);
129065202f3SKonstantin Varlamov 
130065202f3SKonstantin Varlamov   auto is_negative = [](int x) { return x < 0; };
131065202f3SKonstantin Varlamov   // Different comparator.
132065202f3SKonstantin Varlamov   test_one<Iter, Sent, 5>({-3, -6, 5, 7, 2}, is_negative, 2);
133065202f3SKonstantin Varlamov }
134065202f3SKonstantin Varlamov 
135065202f3SKonstantin Varlamov template <class Iter>
test_iterators_1()136065202f3SKonstantin Varlamov constexpr void test_iterators_1() {
137065202f3SKonstantin Varlamov   test_iterators_2<Iter, Iter>();
138065202f3SKonstantin Varlamov   test_iterators_2<Iter, sentinel_wrapper<Iter>>();
139065202f3SKonstantin Varlamov }
140065202f3SKonstantin Varlamov 
test_iterators()141065202f3SKonstantin Varlamov constexpr void test_iterators() {
142065202f3SKonstantin Varlamov   test_iterators_1<forward_iterator<int*>>();
143065202f3SKonstantin Varlamov   test_iterators_1<bidirectional_iterator<int*>>();
144065202f3SKonstantin Varlamov   test_iterators_1<random_access_iterator<int*>>();
145065202f3SKonstantin Varlamov   test_iterators_1<contiguous_iterator<int*>>();
146065202f3SKonstantin Varlamov   test_iterators_1<int*>();
147065202f3SKonstantin Varlamov }
14873ebcabfSKonstantin Varlamov 
test()14973ebcabfSKonstantin Varlamov constexpr bool test() {
150065202f3SKonstantin Varlamov   test_iterators();
151065202f3SKonstantin Varlamov 
152065202f3SKonstantin Varlamov   { // A custom projection works.
153065202f3SKonstantin Varlamov     const std::array in = {1, 3, 4, 6, 8};
154065202f3SKonstantin Varlamov     auto is_odd = [](int x) { return x % 2 != 0; };
155065202f3SKonstantin Varlamov     auto x2 = [](int x) { return x * 2; };
156065202f3SKonstantin Varlamov     auto expected_no_proj = in.begin() + 2;
157065202f3SKonstantin Varlamov     auto expected_with_proj = in.begin();
158065202f3SKonstantin Varlamov 
159065202f3SKonstantin Varlamov     { // (iterator, sentinel) overload.
160065202f3SKonstantin Varlamov       auto result_no_proj = std::ranges::partition_point(in.begin(), in.end(), is_odd);
161065202f3SKonstantin Varlamov       assert(result_no_proj == expected_no_proj);
162065202f3SKonstantin Varlamov       auto result_with_proj = std::ranges::partition_point(in.begin(), in.end(), is_odd, x2);
163065202f3SKonstantin Varlamov       assert(result_with_proj == expected_with_proj);
164065202f3SKonstantin Varlamov     }
165065202f3SKonstantin Varlamov 
166065202f3SKonstantin Varlamov     { // (range) overload.
167065202f3SKonstantin Varlamov       auto result_no_proj = std::ranges::partition_point(in, is_odd);
168065202f3SKonstantin Varlamov       assert(result_no_proj == expected_no_proj);
169065202f3SKonstantin Varlamov       auto result_with_proj = std::ranges::partition_point(in, is_odd, x2);
170065202f3SKonstantin Varlamov       assert(result_with_proj == expected_with_proj);
171065202f3SKonstantin Varlamov     }
172065202f3SKonstantin Varlamov   }
17373ebcabfSKonstantin Varlamov 
17473ebcabfSKonstantin Varlamov   return true;
17573ebcabfSKonstantin Varlamov }
17673ebcabfSKonstantin Varlamov 
main(int,char **)17773ebcabfSKonstantin Varlamov int main(int, char**) {
17873ebcabfSKonstantin Varlamov   test();
17973ebcabfSKonstantin Varlamov   static_assert(test());
18073ebcabfSKonstantin Varlamov 
18173ebcabfSKonstantin Varlamov   return 0;
18273ebcabfSKonstantin Varlamov }
183