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<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
15 //          indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
16 //   requires indirectly_copyable<I, O> &&
17 //            (forward_iterator<I> ||
18 //             (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
19 //             indirectly_copyable_storable<I, O>)
20 //   constexpr unique_copy_result<I, O>
21 //     unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});                         // Since C++20
22 //
23 // template<input_range R, weakly_incrementable O, class Proj = identity,
24 //          indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
25 //   requires indirectly_copyable<iterator_t<R>, O> &&
26 //            (forward_iterator<iterator_t<R>> ||
27 //             (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
28 //             indirectly_copyable_storable<iterator_t<R>, O>)
29 //   constexpr unique_copy_result<borrowed_iterator_t<R>, O>
30 //     unique_copy(R&& r, O result, C comp = {}, Proj proj = {});                                   // Since C++20
31 
32 #include <algorithm>
33 #include <array>
34 #include <concepts>
35 #include <functional>
36 #include <ranges>
37 
38 #include "almost_satisfies_types.h"
39 #include "counting_predicates.h"
40 #include "counting_projection.h"
41 #include "MoveOnly.h"
42 #include "test_iterators.h"
43 
44 template <
45     class InIter  = int*,
46     class Sent    = int*,
47     class OutIter = int*,
48     class Comp    = std::ranges::equal_to,
49     class Proj    = std::identity>
50 concept HasUniqueCopyIter =
51     requires(InIter&& in, Sent&& sent, OutIter&& out, Comp&& comp, Proj&& proj) {
52       std::ranges::unique_copy(
53           std::forward<InIter>(in),
54           std::forward<Sent>(sent),
55           std::forward<OutIter>(out),
56           std::forward<Comp>(comp),
57           std::forward<Proj>(proj));
58     };
59 
60 static_assert(HasUniqueCopyIter<int*, int*, int*>);
61 
62 // !input_iterator<I>
63 static_assert(!HasUniqueCopyIter<InputIteratorNotDerivedFrom, sentinel_wrapper<InputIteratorNotDerivedFrom>>);
64 
65 // !sentinel_for<S, I>
66 static_assert(!HasUniqueCopyIter<int*, SentinelForNotSemiregular>);
67 
68 // !weakly_incrementable<O>
69 static_assert(!HasUniqueCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
70 
71 // !indirect_equivalence_relation<Comp, projected<I, Proj>>
72 static_assert(!HasUniqueCopyIter<int*, int*, int*, ComparatorNotCopyable<int>>);
73 
74 // !indirectly_copyable<I, O>
75 static_assert(!HasUniqueCopyIter<const int*, const int*, const int*>);
76 
77 // forward_iterator<I>
78 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
79 // !indirectly_copyable_storable<I, O>
80 struct AssignableFromMoveOnly {
81   int data;
82   constexpr AssignableFromMoveOnly& operator=(MoveOnly const& m) {
83     data = m.get();
84     return *this;
85   }
86 };
87 static_assert(HasUniqueCopyIter<MoveOnly*, MoveOnly*, AssignableFromMoveOnly*>);
88 // because:
89 static_assert(std::forward_iterator<MoveOnly*>);
90 static_assert(!std::same_as<std::iter_value_t<MoveOnly*>, std::iter_value_t<AssignableFromMoveOnly*>>);
91 static_assert(!std::indirectly_copyable_storable<MoveOnly*, AssignableFromMoveOnly*>);
92 
93 // !forward_iterator<I>
94 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
95 // !indirectly_copyable_storable<I, O>
96 struct CopyAssignableNotCopyConstructible {
97   int data;
98   constexpr CopyAssignableNotCopyConstructible(int i = 0) : data(i) {}
99   CopyAssignableNotCopyConstructible(const CopyAssignableNotCopyConstructible&)            = delete;
100   CopyAssignableNotCopyConstructible& operator=(const CopyAssignableNotCopyConstructible&) = default;
101   friend constexpr bool
102   operator==(CopyAssignableNotCopyConstructible const&, CopyAssignableNotCopyConstructible const&) = default;
103 };
104 
105 using InputAndOutputIterator = cpp17_input_iterator<CopyAssignableNotCopyConstructible*>;
106 static_assert(std::input_iterator<InputAndOutputIterator>);
107 static_assert(std::output_iterator<InputAndOutputIterator, CopyAssignableNotCopyConstructible>);
108 
109 static_assert(
110     HasUniqueCopyIter<
111         cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
112         sentinel_wrapper<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
113         InputAndOutputIterator>);
114 // because:
115 static_assert(!std::forward_iterator< cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>);
116 static_assert(
117     std::input_iterator<InputAndOutputIterator> &&
118     std::same_as<std::iter_value_t<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
119                  std::iter_value_t<InputAndOutputIterator>>);
120 static_assert(
121     !std::indirectly_copyable_storable<
122         cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
123         InputAndOutputIterator>);
124 
125 // !forward_iterator<I>
126 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
127 // indirectly_copyable_storable<I, O>
128 static_assert(
129     HasUniqueCopyIter<
130         cpp20_input_iterator<int*>,
131         sentinel_wrapper<cpp20_input_iterator<int*>>,
132         cpp20_output_iterator<int*>>);
133 // because:
134 static_assert(!std::forward_iterator<cpp20_input_iterator<int*>>);
135 static_assert(!std::input_iterator<cpp20_output_iterator<int*>>);
136 static_assert(std::indirectly_copyable_storable<cpp20_input_iterator<int*>, cpp20_output_iterator<int*>>);
137 
138 // !forward_iterator<I>
139 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
140 // !indirectly_copyable_storable<I, O>
141 static_assert(
142     !HasUniqueCopyIter<
143         cpp20_input_iterator<MoveOnly*>,
144         sentinel_wrapper<cpp20_input_iterator<MoveOnly*>>,
145         cpp20_output_iterator<AssignableFromMoveOnly*>>);
146 // because:
147 static_assert(!std::forward_iterator<cpp20_input_iterator<MoveOnly*>>);
148 static_assert(!std::input_iterator<cpp20_output_iterator<MoveOnly*>>);
149 static_assert(
150     !std::
151         indirectly_copyable_storable<cpp20_input_iterator<MoveOnly*>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
152 
153 template < class Range, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity>
154 concept HasUniqueCopyRange =
155     requires(Range&& range, OutIter&& out, Comp&& comp, Proj&& proj) {
156       std::ranges::unique_copy(
157           std::forward<Range>(range), std::forward<OutIter>(out), std::forward<Comp>(comp), std::forward<Proj>(proj));
158     };
159 
160 template <class T>
161 using R = UncheckedRange<T>;
162 
163 static_assert(HasUniqueCopyRange<R<int*>, int*>);
164 
165 // !input_range<R>
166 static_assert(!HasUniqueCopyRange<R<InputIteratorNotDerivedFrom>>);
167 
168 // !weakly_incrementable<O>
169 static_assert(!HasUniqueCopyIter<R<int*>, WeaklyIncrementableNotMovable>);
170 
171 // !indirect_equivalence_relation<Comp, projected<I, Proj>>
172 static_assert(!HasUniqueCopyIter<R<int*>, int*, ComparatorNotCopyable<int>>);
173 
174 // !indirectly_copyable<I, O>
175 static_assert(!HasUniqueCopyIter<R<const int*>, const int*>);
176 
177 // !forward_iterator<iterator_t<R>>
178 // !(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>)
179 // !indirectly_copyable_storable<iterator_t<R>, O>
180 static_assert(!HasUniqueCopyIter< R<cpp20_input_iterator<MoveOnly*>>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
181 
182 template <class InIter, class OutIter, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
183 constexpr void testUniqueCopyImpl(std::array<int, N1> in, std::array<int, N2> expected) {
184   using Sent = SentWrapper<InIter>;
185 
186   // iterator overload
187   {
188     std::array<int, N2> out;
189     std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
190         std::ranges::unique_copy(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.begin()});
191     assert(std::ranges::equal(out, expected));
192     assert(base(result.in) == in.data() + in.size());
193     assert(base(result.out) == out.data() + out.size());
194   }
195 
196   // range overload
197   {
198     std::array<int, N2> out;
199     std::ranges::subrange r{InIter{in.data()}, Sent{InIter{in.data() + in.size()}}};
200     std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
201         std::ranges::unique_copy(r, OutIter{out.begin()});
202     assert(std::ranges::equal(out, expected));
203     assert(base(result.in) == in.data() + in.size());
204     assert(base(result.out) == out.data() + out.size());
205   }
206 }
207 
208 template <class InIter, class OutIter, template <class> class SentWrapper>
209 constexpr void testImpl() {
210   // no consecutive elements
211   {
212     std::array in{1, 2, 3, 2, 1};
213     std::array expected{1, 2, 3, 2, 1};
214     testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
215   }
216 
217   // one group of consecutive elements
218   {
219     std::array in{2, 3, 3, 3, 4, 3};
220     std::array expected{2, 3, 4, 3};
221     testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
222   }
223 
224   // multiple groups of consecutive elements
225   {
226     std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5};
227     std::array expected{2, 3, 4, 3, 5};
228     testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
229   }
230 
231   // all the same
232   {
233     std::array in{1, 1, 1, 1, 1, 1};
234     std::array expected{1};
235     testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
236   }
237 
238   // empty range
239   {
240     std::array<int, 0> in{};
241     std::array<int, 0> expected{};
242     testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
243   }
244 }
245 
246 template <class OutIter, template <class> class SentWrapper>
247 constexpr void withAllPermutationsOfInIter() {
248   testImpl<cpp20_input_iterator<int*>, OutIter, sentinel_wrapper>();
249   testImpl<forward_iterator<int*>, OutIter, SentWrapper>();
250   testImpl<bidirectional_iterator<int*>, OutIter, SentWrapper>();
251   testImpl<random_access_iterator<int*>, OutIter, SentWrapper>();
252   testImpl<contiguous_iterator<int*>, OutIter, SentWrapper>();
253   testImpl<int*, OutIter, SentWrapper>();
254 }
255 
256 template <template <class> class SentWrapper>
257 constexpr void withAllPermutationsOfInIterAndOutIter() {
258   withAllPermutationsOfInIter<cpp20_output_iterator<int*>, SentWrapper>();
259   withAllPermutationsOfInIter<forward_iterator<int*>, SentWrapper>();
260   withAllPermutationsOfInIter<bidirectional_iterator<int*>, SentWrapper>();
261   withAllPermutationsOfInIter<random_access_iterator<int*>, SentWrapper>();
262   withAllPermutationsOfInIter<contiguous_iterator<int*>, SentWrapper>();
263   withAllPermutationsOfInIter<int*, SentWrapper>();
264 }
265 
266 constexpr bool test() {
267   withAllPermutationsOfInIterAndOutIter<std::type_identity_t>();
268   withAllPermutationsOfInIterAndOutIter<sentinel_wrapper>();
269 
270   // Test the overload that re-reads from the input iterator
271   // forward_iterator<I>
272   // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
273   // !indirectly_copyable_storable<I, O>
274   {
275     MoveOnly in[5] = {1, 3, 3, 3, 1};
276     // iterator overload
277     {
278       AssignableFromMoveOnly out[3] = {};
279       auto result                   = std::ranges::unique_copy(in, in + 5, out);
280       assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
281       assert(result.in == in + 5);
282       assert(result.out == out + 3);
283     }
284     // range overload
285     {
286       AssignableFromMoveOnly out[3] = {};
287       auto result                   = std::ranges::unique_copy(std::ranges::subrange{in, in + 5}, out);
288       assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
289       assert(result.in == in + 5);
290       assert(result.out == out + 3);
291     }
292   }
293 
294   // Test the overload that re-reads from the output iterator
295   // !forward_iterator<I>
296   // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
297   // !indirectly_copyable_storable<I, O>
298   {
299     using InIter                             = cpp20_input_iterator<CopyAssignableNotCopyConstructible*>;
300     using Sent                               = sentinel_wrapper<InIter>;
301     CopyAssignableNotCopyConstructible in[6] = {1, 1, 2, 2, 3, 3};
302     // iterator overload
303     {
304       CopyAssignableNotCopyConstructible out[3];
305       auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 6}}, InputAndOutputIterator{out});
306       assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
307       assert(base(result.in) == in + 6);
308       assert(base(result.out) == out + 3);
309     }
310     // range overload
311     {
312       CopyAssignableNotCopyConstructible out[3];
313       auto r      = std::ranges::subrange(InIter{in}, Sent{InIter{in + 6}});
314       auto result = std::ranges::unique_copy(r, InputAndOutputIterator{out});
315       assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
316       assert(base(result.in) == in + 6);
317       assert(base(result.out) == out + 3);
318     }
319   }
320 
321   // Test the overload that reads from the temporary copy of the value
322   // !forward_iterator<I>
323   // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
324   // indirectly_copyable_storable<I, O>
325   {
326     using InIter = cpp20_input_iterator<int*>;
327     using Sent   = sentinel_wrapper<InIter>;
328     int in[4]    = {1, 1, 1, 2};
329     // iterator overload
330     {
331       int out[2];
332       auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 4}}, cpp20_output_iterator<int*>{out});
333       assert(std::ranges::equal(out, std::array{1, 2}));
334       assert(base(result.in) == in + 4);
335       assert(base(result.out) == out + 2);
336     }
337     // range overload
338     {
339       int out[2];
340       auto r      = std::ranges::subrange(InIter{in}, Sent{InIter{in + 4}});
341       auto result = std::ranges::unique_copy(r, cpp20_output_iterator<int*>{out});
342       assert(std::ranges::equal(out, std::array{1, 2}));
343       assert(base(result.in) == in + 4);
344       assert(base(result.out) == out + 2);
345     }
346   }
347 
348   struct Data {
349     int data;
350   };
351 
352   // Test custom comparator
353   {
354     std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
355     std::array expected{Data{4}, Data{8}};
356     const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; };
357 
358     // iterator overload
359     {
360       std::array<Data, 2> out;
361       auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), comp);
362       assert(std::ranges::equal(out, expected, comp));
363       assert(base(result.in) == in.begin() + 4);
364       assert(base(result.out) == out.begin() + 2);
365     }
366 
367     // range overload
368     {
369       std::array<Data, 2> out;
370       auto result = std::ranges::unique_copy(in, out.begin(), comp);
371       assert(std::ranges::equal(out, expected, comp));
372       assert(base(result.in) == in.begin() + 4);
373       assert(base(result.out) == out.begin() + 2);
374     }
375   }
376 
377   // Test custom projection
378   {
379     std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
380     std::array expected{Data{4}, Data{8}};
381 
382     const auto proj = &Data::data;
383 
384     // iterator overload
385     {
386       std::array<Data, 2> out;
387       auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), {}, proj);
388       assert(std::ranges::equal(out, expected, {}, proj, proj));
389       assert(base(result.in) == in.begin() + 4);
390       assert(base(result.out) == out.begin() + 2);
391     }
392 
393     // range overload
394     {
395       std::array<Data, 2> out;
396       auto result = std::ranges::unique_copy(in, out.begin(), {}, proj);
397       assert(std::ranges::equal(out, expected, {}, proj, proj));
398       assert(base(result.in) == in.begin() + 4);
399       assert(base(result.out) == out.begin() + 2);
400     }
401   }
402 
403   // Exactly last - first - 1 applications of the corresponding predicate and no
404   // more than twice as many applications of any projection.
405   {
406     std::array in{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1};
407     std::array expected{1, 2, 3, 4, 3, 5, 6, 1};
408     // iterator overload
409     {
410       std::array<int, 8> out;
411       int numberOfComp = 0;
412       int numberOfProj = 0;
413       auto result      = std::ranges::unique_copy(
414           in.begin(),
415           in.end(),
416           out.begin(),
417           counting_predicate{std::ranges::equal_to{}, numberOfComp},
418           counting_projection{numberOfProj});
419       assert(std::ranges::equal(out, expected));
420       assert(base(result.in) == in.end());
421       assert(base(result.out) == out.end());
422       assert(numberOfComp == in.size() - 1);
423       assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
424     }
425     // range overload
426     {
427       std::array<int, 8> out;
428       int numberOfComp = 0;
429       int numberOfProj = 0;
430       auto result      = std::ranges::unique_copy(
431           in,
432           out.begin(),
433           counting_predicate{std::ranges::equal_to{}, numberOfComp},
434           counting_projection{numberOfProj});
435       assert(std::ranges::equal(out, expected));
436       assert(base(result.in) == in.end());
437       assert(base(result.out) == out.end());
438       assert(numberOfComp == in.size() - 1);
439       assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
440     }
441   }
442   return true;
443 }
444 
445 int main(int, char**) {
446   test();
447   static_assert(test());
448 
449   return 0;
450 }
451