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