1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
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
37 #include "almost_satisfies_types.h"
38 #include "counting_predicates.h"
39 #include "counting_projection.h"
41 #include "test_iterators.h"
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*>);
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
{
81 constexpr AssignableFromMoveOnly
& operator=(MoveOnly
const& m
) {
86 static_assert(HasUniqueCopyIter
<MoveOnly
*, MoveOnly
*, AssignableFromMoveOnly
*>);
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
{
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
>);
110 cpp20_input_iterator
<CopyAssignableNotCopyConstructible
*>,
111 sentinel_wrapper
<cpp20_input_iterator
<CopyAssignableNotCopyConstructible
*>>,
112 InputAndOutputIterator
>);
114 static_assert(!std::forward_iterator
< cpp20_input_iterator
<CopyAssignableNotCopyConstructible
*>>);
116 std::input_iterator
<InputAndOutputIterator
> &&
117 std::same_as
<std::iter_value_t
<cpp20_input_iterator
<CopyAssignableNotCopyConstructible
*>>,
118 std::iter_value_t
<InputAndOutputIterator
>>);
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>
129 cpp20_input_iterator
<int*>,
130 sentinel_wrapper
<cpp20_input_iterator
<int*>>,
131 cpp20_output_iterator
<int*>>);
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>
142 cpp20_input_iterator
<MoveOnly
*>,
143 sentinel_wrapper
<cpp20_input_iterator
<MoveOnly
*>>,
144 cpp20_output_iterator
<AssignableFromMoveOnly
*>>);
146 static_assert(!std::forward_iterator
<cpp20_input_iterator
<MoveOnly
*>>);
147 static_assert(!std::input_iterator
<cpp20_output_iterator
<MoveOnly
*>>);
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
));
160 using R
= UncheckedRange
<T
>;
162 static_assert(HasUniqueCopyRange
<R
<int*>, int*>);
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
>;
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());
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
);
232 std::array in
{1, 1, 1, 1, 1, 1};
233 std::array expected
{1};
234 testUniqueCopyImpl
<InIter
, OutIter
, SentWrapper
>(in
, expected
);
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};
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);
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};
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);
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};
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);
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);
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
; };
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);
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
;
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);
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};
409 std::array
<int, 8> out
;
410 int numberOfComp
= 0;
411 int numberOfProj
= 0;
412 auto result
= std::ranges::unique_copy(
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)));
426 std::array
<int, 8> out
;
427 int numberOfComp
= 0;
428 int numberOfProj
= 0;
429 auto result
= std::ranges::unique_copy(
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)));
444 int main(int, char**) {
446 static_assert(test());