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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
1173ebcabfSKonstantin Varlamov 
1273ebcabfSKonstantin Varlamov // <algorithm>
1373ebcabfSKonstantin Varlamov 
1473ebcabfSKonstantin Varlamov // template<permutable I, sentinel_for<I> S, class Proj = identity,
1573ebcabfSKonstantin Varlamov //          indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
1673ebcabfSKonstantin Varlamov //   constexpr subrange<I> unique(I first, S last, C comp = {}, Proj proj = {});                    // Since C++20
1773ebcabfSKonstantin Varlamov //
1873ebcabfSKonstantin Varlamov // template<forward_range R, class Proj = identity,
1973ebcabfSKonstantin Varlamov //          indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
2073ebcabfSKonstantin Varlamov //   requires permutable<iterator_t<R>>
2173ebcabfSKonstantin Varlamov //   constexpr borrowed_subrange_t<R>
2273ebcabfSKonstantin Varlamov //     unique(R&& r, C comp = {}, 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"
31*62f1e663SHui Xie #include "counting_predicates.h"
32*62f1e663SHui Xie #include "counting_projection.h"
3373ebcabfSKonstantin Varlamov #include "test_iterators.h"
3473ebcabfSKonstantin Varlamov 
35*62f1e663SHui Xie template <class Iter = int*, class Sent = int*, class Comp = std::ranges::equal_to, class Proj = std::identity>
36*62f1e663SHui Xie concept HasUniqueIter =
37*62f1e663SHui Xie     requires(Iter&& iter, Sent&& sent, Comp&& comp, Proj&& proj) {
38*62f1e663SHui Xie       std::ranges::unique(
39*62f1e663SHui Xie           std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Comp>(comp), std::forward<Proj>(proj));
40*62f1e663SHui Xie     };
41*62f1e663SHui Xie 
42*62f1e663SHui Xie static_assert(HasUniqueIter<int*, int*>);
43*62f1e663SHui Xie 
44*62f1e663SHui Xie // !permutable<I>
45*62f1e663SHui Xie static_assert(!HasUniqueIter<PermutableNotForwardIterator>);
46*62f1e663SHui Xie static_assert(!HasUniqueIter<PermutableNotSwappable>);
47*62f1e663SHui Xie 
48*62f1e663SHui Xie // !sentinel_for<S, I>
49*62f1e663SHui Xie static_assert(!HasUniqueIter<int*, SentinelForNotSemiregular>);
50*62f1e663SHui Xie 
51*62f1e663SHui Xie // !indirect_equivalence_relation<Comp, projected<I, Proj>>
52*62f1e663SHui Xie static_assert(!HasUniqueIter<int*, int*, ComparatorNotCopyable<int>>);
53*62f1e663SHui Xie 
54*62f1e663SHui Xie template <class Range, class Comp = std::ranges::equal_to, class Proj = std::identity>
55*62f1e663SHui Xie concept HasUniqueRange =
56*62f1e663SHui Xie     requires(Range&& range, Comp&& comp, Proj&& proj) {
57*62f1e663SHui Xie       std::ranges::unique(std::forward<Range>(range), std::forward<Comp>(comp), std::forward<Proj>(proj));
58*62f1e663SHui Xie     };
59*62f1e663SHui Xie 
60*62f1e663SHui Xie template <class T>
61*62f1e663SHui Xie using R = UncheckedRange<T>;
62*62f1e663SHui Xie 
63*62f1e663SHui Xie static_assert(HasUniqueRange<R<int*>>);
64*62f1e663SHui Xie 
65*62f1e663SHui Xie // !forward_range<R>
66*62f1e663SHui Xie static_assert(!HasUniqueRange<ForwardRangeNotDerivedFrom>);
67*62f1e663SHui Xie static_assert(!HasUniqueRange<ForwardRangeNotIncrementable>);
68*62f1e663SHui Xie 
69*62f1e663SHui Xie // permutable<ranges::iterator_t<R>>
70*62f1e663SHui Xie static_assert(!HasUniqueRange<R<PermutableNotForwardIterator>>);
71*62f1e663SHui Xie static_assert(!HasUniqueRange<R<PermutableNotSwappable>>);
72*62f1e663SHui Xie 
73*62f1e663SHui Xie // !indirect_equivalence_relation<Comp, projected<ranges::iterator_t<R>, Proj>>
74*62f1e663SHui Xie static_assert(!HasUniqueRange<R<int*>, ComparatorNotCopyable<int>>);
75*62f1e663SHui Xie 
76*62f1e663SHui Xie template <class Iter, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
testUniqueImpl(std::array<int,N1> input,std::array<int,N2> expected)77*62f1e663SHui Xie constexpr void testUniqueImpl(std::array<int, N1> input, std::array<int, N2> expected) {
78*62f1e663SHui Xie   using Sent = SentWrapper<Iter>;
79*62f1e663SHui Xie 
80*62f1e663SHui Xie   // iterator overload
81*62f1e663SHui Xie   {
82*62f1e663SHui Xie     auto in = input;
83*62f1e663SHui Xie     std::same_as<std::ranges::subrange<Iter>> decltype(auto) result =
84*62f1e663SHui Xie         std::ranges::unique(Iter{in.data()}, Sent{Iter{in.data() + in.size()}});
85*62f1e663SHui Xie     assert(std::ranges::equal(std::ranges::subrange<Iter>{Iter{in.data()}, result.begin()}, expected));
86*62f1e663SHui Xie     assert(base(result.end()) == in.data() + in.size());
87*62f1e663SHui Xie   }
88*62f1e663SHui Xie 
89*62f1e663SHui Xie   // range overload
90*62f1e663SHui Xie   {
91*62f1e663SHui Xie     auto in = input;
92*62f1e663SHui Xie     std::ranges::subrange r{Iter{in.data()}, Sent{Iter{in.data() + in.size()}}};
93*62f1e663SHui Xie     std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::unique(r);
94*62f1e663SHui Xie     assert(std::ranges::equal(std::ranges::subrange<Iter>{Iter{in.data()}, result.begin()}, expected));
95*62f1e663SHui Xie     assert(base(result.end()) == in.data() + in.size());
96*62f1e663SHui Xie   }
97*62f1e663SHui Xie }
98*62f1e663SHui Xie 
99*62f1e663SHui Xie template <class Iter, template <class> class SentWrapper>
testImpl()100*62f1e663SHui Xie constexpr void testImpl() {
101*62f1e663SHui Xie   // no consecutive elements
102*62f1e663SHui Xie   {
103*62f1e663SHui Xie     std::array in{1, 2, 3, 2, 1};
104*62f1e663SHui Xie     std::array expected{1, 2, 3, 2, 1};
105*62f1e663SHui Xie     testUniqueImpl<Iter, SentWrapper>(in, expected);
106*62f1e663SHui Xie   }
107*62f1e663SHui Xie 
108*62f1e663SHui Xie   // one group of consecutive elements
109*62f1e663SHui Xie   {
110*62f1e663SHui Xie     std::array in{2, 3, 3, 3, 4, 3};
111*62f1e663SHui Xie     std::array expected{2, 3, 4, 3};
112*62f1e663SHui Xie     testUniqueImpl<Iter, SentWrapper>(in, expected);
113*62f1e663SHui Xie   }
114*62f1e663SHui Xie 
115*62f1e663SHui Xie   // multiple groups of consecutive elements
116*62f1e663SHui Xie   {
117*62f1e663SHui Xie     std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5};
118*62f1e663SHui Xie     std::array expected{2, 3, 4, 3, 5};
119*62f1e663SHui Xie     testUniqueImpl<Iter, SentWrapper>(in, expected);
120*62f1e663SHui Xie   }
121*62f1e663SHui Xie 
122*62f1e663SHui Xie   // all the same
123*62f1e663SHui Xie   {
124*62f1e663SHui Xie     std::array in{1, 1, 1, 1, 1, 1};
125*62f1e663SHui Xie     std::array expected{1};
126*62f1e663SHui Xie     testUniqueImpl<Iter, SentWrapper>(in, expected);
127*62f1e663SHui Xie   }
128*62f1e663SHui Xie 
129*62f1e663SHui Xie   // empty range
130*62f1e663SHui Xie   {
131*62f1e663SHui Xie     std::array<int, 0> in{};
132*62f1e663SHui Xie     std::array<int, 0> expected{};
133*62f1e663SHui Xie     testUniqueImpl<Iter, SentWrapper>(in, expected);
134*62f1e663SHui Xie   }
135*62f1e663SHui Xie 
136*62f1e663SHui Xie   // single element range
137*62f1e663SHui Xie     std::array in{1};
138*62f1e663SHui Xie     std::array expected{1};
139*62f1e663SHui Xie     testUniqueImpl<Iter, SentWrapper>(in, expected);
140*62f1e663SHui Xie }
141*62f1e663SHui Xie 
142*62f1e663SHui Xie template <template <class> class SentWrapper>
withAllPermutationsOfIter()143*62f1e663SHui Xie constexpr void withAllPermutationsOfIter() {
144*62f1e663SHui Xie   testImpl<forward_iterator<int*>, SentWrapper>();
145*62f1e663SHui Xie   testImpl<bidirectional_iterator<int*>, SentWrapper>();
146*62f1e663SHui Xie   testImpl<random_access_iterator<int*>, SentWrapper>();
147*62f1e663SHui Xie   testImpl<contiguous_iterator<int*>, SentWrapper>();
148*62f1e663SHui Xie   testImpl<int*, SentWrapper>();
149*62f1e663SHui Xie }
15073ebcabfSKonstantin Varlamov 
test()15173ebcabfSKonstantin Varlamov constexpr bool test() {
152*62f1e663SHui Xie   withAllPermutationsOfIter<std::type_identity_t>();
153*62f1e663SHui Xie   withAllPermutationsOfIter<sentinel_wrapper>();
154*62f1e663SHui Xie 
155*62f1e663SHui Xie   struct Data {
156*62f1e663SHui Xie     int data;
157*62f1e663SHui Xie   };
158*62f1e663SHui Xie 
159*62f1e663SHui Xie   // Test custom comparator
160*62f1e663SHui Xie   {
161*62f1e663SHui Xie     std::array input{Data{4}, Data{8}, Data{8}, Data{8}};
162*62f1e663SHui Xie     std::array expected{Data{4}, Data{8}};
163*62f1e663SHui Xie     const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; };
164*62f1e663SHui Xie 
165*62f1e663SHui Xie     // iterator overload
166*62f1e663SHui Xie     {
167*62f1e663SHui Xie       auto in     = input;
168*62f1e663SHui Xie       auto result = std::ranges::unique(in.begin(), in.end(), comp);
169*62f1e663SHui Xie       assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), comp));
170*62f1e663SHui Xie       assert(base(result.end()) == in.end());
171*62f1e663SHui Xie     }
172*62f1e663SHui Xie 
173*62f1e663SHui Xie     // range overload
174*62f1e663SHui Xie     {
175*62f1e663SHui Xie       auto in     = input;
176*62f1e663SHui Xie       auto result = std::ranges::unique(in, comp);
177*62f1e663SHui Xie       assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), comp));
178*62f1e663SHui Xie       assert(base(result.end()) == in.end());
179*62f1e663SHui Xie     }
180*62f1e663SHui Xie   }
181*62f1e663SHui Xie 
182*62f1e663SHui Xie   // Test custom projection
183*62f1e663SHui Xie   {
184*62f1e663SHui Xie     std::array input{Data{4}, Data{8}, Data{8}, Data{8}};
185*62f1e663SHui Xie     std::array expected{Data{4}, Data{8}};
186*62f1e663SHui Xie 
187*62f1e663SHui Xie     const auto proj = &Data::data;
188*62f1e663SHui Xie 
189*62f1e663SHui Xie     // iterator overload
190*62f1e663SHui Xie     {
191*62f1e663SHui Xie       auto in     = input;
192*62f1e663SHui Xie       auto result = std::ranges::unique(in.begin(), in.end(), {}, proj);
193*62f1e663SHui Xie       assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), {}, proj, proj));
194*62f1e663SHui Xie       assert(base(result.end()) == in.end());
195*62f1e663SHui Xie     }
196*62f1e663SHui Xie 
197*62f1e663SHui Xie     // range overload
198*62f1e663SHui Xie     {
199*62f1e663SHui Xie       auto in     = input;
200*62f1e663SHui Xie       auto result = std::ranges::unique(in, {}, proj);
201*62f1e663SHui Xie       assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end(), {}, proj, proj));
202*62f1e663SHui Xie       assert(base(result.end()) == in.end());
203*62f1e663SHui Xie     }
204*62f1e663SHui Xie   }
205*62f1e663SHui Xie 
206*62f1e663SHui Xie   // Complexity: For nonempty ranges, exactly (last - first) - 1 applications of the corresponding predicate
207*62f1e663SHui Xie   // and no more than twice as many applications of any projection.
208*62f1e663SHui Xie   {
209*62f1e663SHui Xie     std::array input{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1};
210*62f1e663SHui Xie     std::array expected{1, 2, 3, 4, 3, 5, 6, 1};
211*62f1e663SHui Xie     // iterator overload
212*62f1e663SHui Xie     {
213*62f1e663SHui Xie       auto in          = input;
214*62f1e663SHui Xie       int numberOfComp = 0;
215*62f1e663SHui Xie       int numberOfProj = 0;
216*62f1e663SHui Xie       auto result      = std::ranges::unique(
217*62f1e663SHui Xie           in.begin(),
218*62f1e663SHui Xie           in.end(),
219*62f1e663SHui Xie           counting_predicate{std::ranges::equal_to{}, numberOfComp},
220*62f1e663SHui Xie           counting_projection{numberOfProj});
221*62f1e663SHui Xie       assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end()));
222*62f1e663SHui Xie       assert(base(result.end()) == in.end());
223*62f1e663SHui Xie       assert(numberOfComp == in.size() - 1);
224*62f1e663SHui Xie       assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
225*62f1e663SHui Xie     }
226*62f1e663SHui Xie     // range overload
227*62f1e663SHui Xie     {
228*62f1e663SHui Xie       auto in          = input;
229*62f1e663SHui Xie       int numberOfComp = 0;
230*62f1e663SHui Xie       int numberOfProj = 0;
231*62f1e663SHui Xie       auto result      = std::ranges::unique(
232*62f1e663SHui Xie           in, counting_predicate{std::ranges::equal_to{}, numberOfComp}, counting_projection{numberOfProj});
233*62f1e663SHui Xie       assert(std::ranges::equal(in.begin(), result.begin(), expected.begin(), expected.end()));
234*62f1e663SHui Xie       assert(base(result.end()) == in.end());
235*62f1e663SHui Xie       assert(numberOfComp == in.size() - 1);
236*62f1e663SHui Xie       assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
237*62f1e663SHui Xie     }
238*62f1e663SHui Xie   }
23973ebcabfSKonstantin Varlamov 
24073ebcabfSKonstantin Varlamov   return true;
24173ebcabfSKonstantin Varlamov }
24273ebcabfSKonstantin Varlamov 
main(int,char **)24373ebcabfSKonstantin Varlamov int main(int, char**) {
24473ebcabfSKonstantin Varlamov   test();
24573ebcabfSKonstantin Varlamov   static_assert(test());
24673ebcabfSKonstantin Varlamov 
24773ebcabfSKonstantin Varlamov   return 0;
24873ebcabfSKonstantin Varlamov }
249