Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / std / algorithms / alg.modifying.operations / alg.unique / ranges_unique_copy.pass.cpp
blob801385cf691ad130ea5152f6d6455f8ca8db7bbe
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 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
11 // <algorithm>
13 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
14 // indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
15 // requires indirectly_copyable<I, O> &&
16 // (forward_iterator<I> ||
17 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
18 // indirectly_copyable_storable<I, O>)
19 // constexpr unique_copy_result<I, O>
20 // unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); // Since C++20
22 // template<input_range R, weakly_incrementable O, class Proj = identity,
23 // indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
24 // requires indirectly_copyable<iterator_t<R>, O> &&
25 // (forward_iterator<iterator_t<R>> ||
26 // (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
27 // indirectly_copyable_storable<iterator_t<R>, O>)
28 // constexpr unique_copy_result<borrowed_iterator_t<R>, O>
29 // unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20
31 #include <algorithm>
32 #include <array>
33 #include <concepts>
34 #include <functional>
35 #include <ranges>
37 #include "almost_satisfies_types.h"
38 #include "counting_predicates.h"
39 #include "counting_projection.h"
40 #include "MoveOnly.h"
41 #include "test_iterators.h"
43 template <
44 class InIter = int*,
45 class Sent = int*,
46 class OutIter = int*,
47 class Comp = std::ranges::equal_to,
48 class Proj = std::identity>
49 concept HasUniqueCopyIter =
50 requires(InIter&& in, Sent&& sent, OutIter&& out, Comp&& comp, Proj&& proj) {
51 std::ranges::unique_copy(
52 std::forward<InIter>(in),
53 std::forward<Sent>(sent),
54 std::forward<OutIter>(out),
55 std::forward<Comp>(comp),
56 std::forward<Proj>(proj));
59 static_assert(HasUniqueCopyIter<int*, int*, int*>);
61 // !input_iterator<I>
62 static_assert(!HasUniqueCopyIter<InputIteratorNotDerivedFrom, sentinel_wrapper<InputIteratorNotDerivedFrom>>);
64 // !sentinel_for<S, I>
65 static_assert(!HasUniqueCopyIter<int*, SentinelForNotSemiregular>);
67 // !weakly_incrementable<O>
68 static_assert(!HasUniqueCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
70 // !indirect_equivalence_relation<Comp, projected<I, Proj>>
71 static_assert(!HasUniqueCopyIter<int*, int*, int*, ComparatorNotCopyable<int>>);
73 // !indirectly_copyable<I, O>
74 static_assert(!HasUniqueCopyIter<const int*, const int*, const int*>);
76 // forward_iterator<I>
77 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
78 // !indirectly_copyable_storable<I, O>
79 struct AssignableFromMoveOnly {
80 int data;
81 constexpr AssignableFromMoveOnly& operator=(MoveOnly const& m) {
82 data = m.get();
83 return *this;
86 static_assert(HasUniqueCopyIter<MoveOnly*, MoveOnly*, AssignableFromMoveOnly*>);
87 // because:
88 static_assert(std::forward_iterator<MoveOnly*>);
89 static_assert(!std::same_as<std::iter_value_t<MoveOnly*>, std::iter_value_t<AssignableFromMoveOnly*>>);
90 static_assert(!std::indirectly_copyable_storable<MoveOnly*, AssignableFromMoveOnly*>);
92 // !forward_iterator<I>
93 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
94 // !indirectly_copyable_storable<I, O>
95 struct CopyAssignableNotCopyConstructible {
96 int data;
97 constexpr CopyAssignableNotCopyConstructible(int i = 0) : data(i) {}
98 CopyAssignableNotCopyConstructible(const CopyAssignableNotCopyConstructible&) = delete;
99 CopyAssignableNotCopyConstructible& operator=(const CopyAssignableNotCopyConstructible&) = default;
100 friend constexpr bool
101 operator==(CopyAssignableNotCopyConstructible const&, CopyAssignableNotCopyConstructible const&) = default;
104 using InputAndOutputIterator = cpp17_input_iterator<CopyAssignableNotCopyConstructible*>;
105 static_assert(std::input_iterator<InputAndOutputIterator>);
106 static_assert(std::output_iterator<InputAndOutputIterator, CopyAssignableNotCopyConstructible>);
108 static_assert(
109 HasUniqueCopyIter<
110 cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
111 sentinel_wrapper<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
112 InputAndOutputIterator>);
113 // because:
114 static_assert(!std::forward_iterator< cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>);
115 static_assert(
116 std::input_iterator<InputAndOutputIterator> &&
117 std::same_as<std::iter_value_t<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
118 std::iter_value_t<InputAndOutputIterator>>);
119 static_assert(
120 !std::indirectly_copyable_storable<
121 cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
122 InputAndOutputIterator>);
124 // !forward_iterator<I>
125 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
126 // indirectly_copyable_storable<I, O>
127 static_assert(
128 HasUniqueCopyIter<
129 cpp20_input_iterator<int*>,
130 sentinel_wrapper<cpp20_input_iterator<int*>>,
131 cpp20_output_iterator<int*>>);
132 // because:
133 static_assert(!std::forward_iterator<cpp20_input_iterator<int*>>);
134 static_assert(!std::input_iterator<cpp20_output_iterator<int*>>);
135 static_assert(std::indirectly_copyable_storable<cpp20_input_iterator<int*>, cpp20_output_iterator<int*>>);
137 // !forward_iterator<I>
138 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
139 // !indirectly_copyable_storable<I, O>
140 static_assert(
141 !HasUniqueCopyIter<
142 cpp20_input_iterator<MoveOnly*>,
143 sentinel_wrapper<cpp20_input_iterator<MoveOnly*>>,
144 cpp20_output_iterator<AssignableFromMoveOnly*>>);
145 // because:
146 static_assert(!std::forward_iterator<cpp20_input_iterator<MoveOnly*>>);
147 static_assert(!std::input_iterator<cpp20_output_iterator<MoveOnly*>>);
148 static_assert(
149 !std::
150 indirectly_copyable_storable<cpp20_input_iterator<MoveOnly*>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
152 template < class Range, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity>
153 concept HasUniqueCopyRange =
154 requires(Range&& range, OutIter&& out, Comp&& comp, Proj&& proj) {
155 std::ranges::unique_copy(
156 std::forward<Range>(range), std::forward<OutIter>(out), std::forward<Comp>(comp), std::forward<Proj>(proj));
159 template <class T>
160 using R = UncheckedRange<T>;
162 static_assert(HasUniqueCopyRange<R<int*>, int*>);
164 // !input_range<R>
165 static_assert(!HasUniqueCopyRange<R<InputIteratorNotDerivedFrom>>);
167 // !weakly_incrementable<O>
168 static_assert(!HasUniqueCopyIter<R<int*>, WeaklyIncrementableNotMovable>);
170 // !indirect_equivalence_relation<Comp, projected<I, Proj>>
171 static_assert(!HasUniqueCopyIter<R<int*>, int*, ComparatorNotCopyable<int>>);
173 // !indirectly_copyable<I, O>
174 static_assert(!HasUniqueCopyIter<R<const int*>, const int*>);
176 // !forward_iterator<iterator_t<R>>
177 // !(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>)
178 // !indirectly_copyable_storable<iterator_t<R>, O>
179 static_assert(!HasUniqueCopyIter< R<cpp20_input_iterator<MoveOnly*>>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
181 template <class InIter, class OutIter, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
182 constexpr void testUniqueCopyImpl(std::array<int, N1> in, std::array<int, N2> expected) {
183 using Sent = SentWrapper<InIter>;
185 // iterator overload
187 std::array<int, N2> out;
188 std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
189 std::ranges::unique_copy(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.begin()});
190 assert(std::ranges::equal(out, expected));
191 assert(base(result.in) == in.data() + in.size());
192 assert(base(result.out) == out.data() + out.size());
195 // range overload
197 std::array<int, N2> out;
198 std::ranges::subrange r{InIter{in.data()}, Sent{InIter{in.data() + in.size()}}};
199 std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
200 std::ranges::unique_copy(r, OutIter{out.begin()});
201 assert(std::ranges::equal(out, expected));
202 assert(base(result.in) == in.data() + in.size());
203 assert(base(result.out) == out.data() + out.size());
207 template <class InIter, class OutIter, template <class> class SentWrapper>
208 constexpr void testImpl() {
209 // no consecutive elements
211 std::array in{1, 2, 3, 2, 1};
212 std::array expected{1, 2, 3, 2, 1};
213 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
216 // one group of consecutive elements
218 std::array in{2, 3, 3, 3, 4, 3};
219 std::array expected{2, 3, 4, 3};
220 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
223 // multiple groups of consecutive elements
225 std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5};
226 std::array expected{2, 3, 4, 3, 5};
227 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
230 // all the same
232 std::array in{1, 1, 1, 1, 1, 1};
233 std::array expected{1};
234 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
237 // empty range
239 std::array<int, 0> in{};
240 std::array<int, 0> expected{};
241 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
245 template <class OutIter, template <class> class SentWrapper>
246 constexpr void withAllPermutationsOfInIter() {
247 testImpl<cpp20_input_iterator<int*>, OutIter, sentinel_wrapper>();
248 testImpl<forward_iterator<int*>, OutIter, SentWrapper>();
249 testImpl<bidirectional_iterator<int*>, OutIter, SentWrapper>();
250 testImpl<random_access_iterator<int*>, OutIter, SentWrapper>();
251 testImpl<contiguous_iterator<int*>, OutIter, SentWrapper>();
252 testImpl<int*, OutIter, SentWrapper>();
255 template <template <class> class SentWrapper>
256 constexpr void withAllPermutationsOfInIterAndOutIter() {
257 withAllPermutationsOfInIter<cpp20_output_iterator<int*>, SentWrapper>();
258 withAllPermutationsOfInIter<forward_iterator<int*>, SentWrapper>();
259 withAllPermutationsOfInIter<bidirectional_iterator<int*>, SentWrapper>();
260 withAllPermutationsOfInIter<random_access_iterator<int*>, SentWrapper>();
261 withAllPermutationsOfInIter<contiguous_iterator<int*>, SentWrapper>();
262 withAllPermutationsOfInIter<int*, SentWrapper>();
265 constexpr bool test() {
266 withAllPermutationsOfInIterAndOutIter<std::type_identity_t>();
267 withAllPermutationsOfInIterAndOutIter<sentinel_wrapper>();
269 // Test the overload that re-reads from the input iterator
270 // forward_iterator<I>
271 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
272 // !indirectly_copyable_storable<I, O>
274 MoveOnly in[5] = {1, 3, 3, 3, 1};
275 // iterator overload
277 AssignableFromMoveOnly out[3] = {};
278 auto result = std::ranges::unique_copy(in, in + 5, out);
279 assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
280 assert(result.in == in + 5);
281 assert(result.out == out + 3);
283 // range overload
285 AssignableFromMoveOnly out[3] = {};
286 auto result = std::ranges::unique_copy(std::ranges::subrange{in, in + 5}, out);
287 assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
288 assert(result.in == in + 5);
289 assert(result.out == out + 3);
293 // Test the overload that re-reads from the output iterator
294 // !forward_iterator<I>
295 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
296 // !indirectly_copyable_storable<I, O>
298 using InIter = cpp20_input_iterator<CopyAssignableNotCopyConstructible*>;
299 using Sent = sentinel_wrapper<InIter>;
300 CopyAssignableNotCopyConstructible in[6] = {1, 1, 2, 2, 3, 3};
301 // iterator overload
303 CopyAssignableNotCopyConstructible out[3];
304 auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 6}}, InputAndOutputIterator{out});
305 assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
306 assert(base(result.in) == in + 6);
307 assert(base(result.out) == out + 3);
309 // range overload
311 CopyAssignableNotCopyConstructible out[3];
312 auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 6}});
313 auto result = std::ranges::unique_copy(r, InputAndOutputIterator{out});
314 assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
315 assert(base(result.in) == in + 6);
316 assert(base(result.out) == out + 3);
320 // Test the overload that reads from the temporary copy of the value
321 // !forward_iterator<I>
322 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
323 // indirectly_copyable_storable<I, O>
325 using InIter = cpp20_input_iterator<int*>;
326 using Sent = sentinel_wrapper<InIter>;
327 int in[4] = {1, 1, 1, 2};
328 // iterator overload
330 int out[2];
331 auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 4}}, cpp20_output_iterator<int*>{out});
332 assert(std::ranges::equal(out, std::array{1, 2}));
333 assert(base(result.in) == in + 4);
334 assert(base(result.out) == out + 2);
336 // range overload
338 int out[2];
339 auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 4}});
340 auto result = std::ranges::unique_copy(r, cpp20_output_iterator<int*>{out});
341 assert(std::ranges::equal(out, std::array{1, 2}));
342 assert(base(result.in) == in + 4);
343 assert(base(result.out) == out + 2);
347 struct Data {
348 int data;
351 // Test custom comparator
353 std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
354 std::array expected{Data{4}, Data{8}};
355 const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; };
357 // iterator overload
359 std::array<Data, 2> out;
360 auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), comp);
361 assert(std::ranges::equal(out, expected, comp));
362 assert(base(result.in) == in.begin() + 4);
363 assert(base(result.out) == out.begin() + 2);
366 // range overload
368 std::array<Data, 2> out;
369 auto result = std::ranges::unique_copy(in, out.begin(), comp);
370 assert(std::ranges::equal(out, expected, comp));
371 assert(base(result.in) == in.begin() + 4);
372 assert(base(result.out) == out.begin() + 2);
376 // Test custom projection
378 std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
379 std::array expected{Data{4}, Data{8}};
381 const auto proj = &Data::data;
383 // iterator overload
385 std::array<Data, 2> out;
386 auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), {}, proj);
387 assert(std::ranges::equal(out, expected, {}, proj, proj));
388 assert(base(result.in) == in.begin() + 4);
389 assert(base(result.out) == out.begin() + 2);
392 // range overload
394 std::array<Data, 2> out;
395 auto result = std::ranges::unique_copy(in, out.begin(), {}, proj);
396 assert(std::ranges::equal(out, expected, {}, proj, proj));
397 assert(base(result.in) == in.begin() + 4);
398 assert(base(result.out) == out.begin() + 2);
402 // Exactly last - first - 1 applications of the corresponding predicate and no
403 // more than twice as many applications of any projection.
405 std::array in{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1};
406 std::array expected{1, 2, 3, 4, 3, 5, 6, 1};
407 // iterator overload
409 std::array<int, 8> out;
410 int numberOfComp = 0;
411 int numberOfProj = 0;
412 auto result = std::ranges::unique_copy(
413 in.begin(),
414 in.end(),
415 out.begin(),
416 counting_predicate{std::ranges::equal_to{}, numberOfComp},
417 counting_projection{numberOfProj});
418 assert(std::ranges::equal(out, expected));
419 assert(base(result.in) == in.end());
420 assert(base(result.out) == out.end());
421 assert(numberOfComp == in.size() - 1);
422 assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
424 // range overload
426 std::array<int, 8> out;
427 int numberOfComp = 0;
428 int numberOfProj = 0;
429 auto result = std::ranges::unique_copy(
431 out.begin(),
432 counting_predicate{std::ranges::equal_to{}, numberOfComp},
433 counting_projection{numberOfProj});
434 assert(std::ranges::equal(out, expected));
435 assert(base(result.in) == in.end());
436 assert(base(result.out) == out.end());
437 assert(numberOfComp == in.size() - 1);
438 assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
441 return true;
444 int main(int, char**) {
445 test();
446 static_assert(test());
448 return 0;