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<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
1473ebcabfSKonstantin Varlamov // indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
1573ebcabfSKonstantin Varlamov // requires indirectly_copyable<I, O> &&
1673ebcabfSKonstantin Varlamov // (forward_iterator<I> ||
1773ebcabfSKonstantin Varlamov // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
1873ebcabfSKonstantin Varlamov // indirectly_copyable_storable<I, O>)
1973ebcabfSKonstantin Varlamov // constexpr unique_copy_result<I, O>
2073ebcabfSKonstantin Varlamov // unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); // Since C++20
2173ebcabfSKonstantin Varlamov //
2273ebcabfSKonstantin Varlamov // template<input_range R, weakly_incrementable O, class Proj = identity,
2373ebcabfSKonstantin Varlamov // indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
2473ebcabfSKonstantin Varlamov // requires indirectly_copyable<iterator_t<R>, O> &&
2573ebcabfSKonstantin Varlamov // (forward_iterator<iterator_t<R>> ||
2673ebcabfSKonstantin Varlamov // (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
2773ebcabfSKonstantin Varlamov // indirectly_copyable_storable<iterator_t<R>, O>)
2873ebcabfSKonstantin Varlamov // constexpr unique_copy_result<borrowed_iterator_t<R>, O>
2973ebcabfSKonstantin Varlamov // unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20
3073ebcabfSKonstantin Varlamov
3173ebcabfSKonstantin Varlamov #include <algorithm>
3273ebcabfSKonstantin Varlamov #include <array>
3373ebcabfSKonstantin Varlamov #include <concepts>
3473ebcabfSKonstantin Varlamov #include <functional>
3573ebcabfSKonstantin Varlamov #include <ranges>
3673ebcabfSKonstantin Varlamov
3773ebcabfSKonstantin Varlamov #include "almost_satisfies_types.h"
3872f57e3aSHui Xie #include "counting_predicates.h"
3972f57e3aSHui Xie #include "counting_projection.h"
4072f57e3aSHui Xie #include "MoveOnly.h"
4173ebcabfSKonstantin Varlamov #include "test_iterators.h"
4273ebcabfSKonstantin Varlamov
4372f57e3aSHui Xie template <
4472f57e3aSHui Xie class InIter = int*,
4572f57e3aSHui Xie class Sent = int*,
4672f57e3aSHui Xie class OutIter = int*,
4772f57e3aSHui Xie class Comp = std::ranges::equal_to,
4872f57e3aSHui Xie class Proj = std::identity>
4972f57e3aSHui Xie concept HasUniqueCopyIter =
5072f57e3aSHui Xie requires(InIter&& in, Sent&& sent, OutIter&& out, Comp&& comp, Proj&& proj) {
5172f57e3aSHui Xie std::ranges::unique_copy(
5272f57e3aSHui Xie std::forward<InIter>(in),
5372f57e3aSHui Xie std::forward<Sent>(sent),
5472f57e3aSHui Xie std::forward<OutIter>(out),
5572f57e3aSHui Xie std::forward<Comp>(comp),
5672f57e3aSHui Xie std::forward<Proj>(proj));
5772f57e3aSHui Xie };
5872f57e3aSHui Xie
5972f57e3aSHui Xie static_assert(HasUniqueCopyIter<int*, int*, int*>);
6072f57e3aSHui Xie
6172f57e3aSHui Xie // !input_iterator<I>
6272f57e3aSHui Xie static_assert(!HasUniqueCopyIter<InputIteratorNotDerivedFrom, sentinel_wrapper<InputIteratorNotDerivedFrom>>);
6372f57e3aSHui Xie
6472f57e3aSHui Xie // !sentinel_for<S, I>
6572f57e3aSHui Xie static_assert(!HasUniqueCopyIter<int*, SentinelForNotSemiregular>);
6672f57e3aSHui Xie
6772f57e3aSHui Xie // !weakly_incrementable<O>
6872f57e3aSHui Xie static_assert(!HasUniqueCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
6972f57e3aSHui Xie
7072f57e3aSHui Xie // !indirect_equivalence_relation<Comp, projected<I, Proj>>
7172f57e3aSHui Xie static_assert(!HasUniqueCopyIter<int*, int*, int*, ComparatorNotCopyable<int>>);
7272f57e3aSHui Xie
7372f57e3aSHui Xie // !indirectly_copyable<I, O>
7472f57e3aSHui Xie static_assert(!HasUniqueCopyIter<const int*, const int*, const int*>);
7572f57e3aSHui Xie
7672f57e3aSHui Xie // forward_iterator<I>
7772f57e3aSHui Xie // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
7872f57e3aSHui Xie // !indirectly_copyable_storable<I, O>
7972f57e3aSHui Xie struct AssignableFromMoveOnly {
8072f57e3aSHui Xie int data;
operator =AssignableFromMoveOnly8172f57e3aSHui Xie constexpr AssignableFromMoveOnly& operator=(MoveOnly const& m) {
8272f57e3aSHui Xie data = m.get();
8372f57e3aSHui Xie return *this;
8472f57e3aSHui Xie }
8572f57e3aSHui Xie };
8672f57e3aSHui Xie static_assert(HasUniqueCopyIter<MoveOnly*, MoveOnly*, AssignableFromMoveOnly*>);
8772f57e3aSHui Xie // because:
8872f57e3aSHui Xie static_assert(std::forward_iterator<MoveOnly*>);
8972f57e3aSHui Xie static_assert(!std::same_as<std::iter_value_t<MoveOnly*>, std::iter_value_t<AssignableFromMoveOnly*>>);
9072f57e3aSHui Xie static_assert(!std::indirectly_copyable_storable<MoveOnly*, AssignableFromMoveOnly*>);
9172f57e3aSHui Xie
9272f57e3aSHui Xie // !forward_iterator<I>
9372f57e3aSHui Xie // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
9472f57e3aSHui Xie // !indirectly_copyable_storable<I, O>
9572f57e3aSHui Xie struct CopyAssignableNotCopyConstructible {
9672f57e3aSHui Xie int data;
CopyAssignableNotCopyConstructibleCopyAssignableNotCopyConstructible9772f57e3aSHui Xie constexpr CopyAssignableNotCopyConstructible(int i = 0) : data(i) {}
9872f57e3aSHui Xie CopyAssignableNotCopyConstructible(const CopyAssignableNotCopyConstructible&) = delete;
9972f57e3aSHui Xie CopyAssignableNotCopyConstructible& operator=(const CopyAssignableNotCopyConstructible&) = default;
10072f57e3aSHui Xie friend constexpr bool
10172f57e3aSHui Xie operator==(CopyAssignableNotCopyConstructible const&, CopyAssignableNotCopyConstructible const&) = default;
10272f57e3aSHui Xie };
10372f57e3aSHui Xie
10472f57e3aSHui Xie using InputAndOutputIterator = cpp17_input_iterator<CopyAssignableNotCopyConstructible*>;
10572f57e3aSHui Xie static_assert(std::input_iterator<InputAndOutputIterator>);
10672f57e3aSHui Xie static_assert(std::output_iterator<InputAndOutputIterator, CopyAssignableNotCopyConstructible>);
10772f57e3aSHui Xie
10872f57e3aSHui Xie static_assert(
10972f57e3aSHui Xie HasUniqueCopyIter<
11072f57e3aSHui Xie cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
11172f57e3aSHui Xie sentinel_wrapper<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
11272f57e3aSHui Xie InputAndOutputIterator>);
11372f57e3aSHui Xie // because:
11472f57e3aSHui Xie static_assert(!std::forward_iterator< cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>);
11572f57e3aSHui Xie static_assert(
11672f57e3aSHui Xie std::input_iterator<InputAndOutputIterator> &&
11772f57e3aSHui Xie std::same_as<std::iter_value_t<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>,
11872f57e3aSHui Xie std::iter_value_t<InputAndOutputIterator>>);
11972f57e3aSHui Xie static_assert(
12072f57e3aSHui Xie !std::indirectly_copyable_storable<
12172f57e3aSHui Xie cpp20_input_iterator<CopyAssignableNotCopyConstructible*>,
12272f57e3aSHui Xie InputAndOutputIterator>);
12372f57e3aSHui Xie
12472f57e3aSHui Xie // !forward_iterator<I>
12572f57e3aSHui Xie // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
12672f57e3aSHui Xie // indirectly_copyable_storable<I, O>
12772f57e3aSHui Xie static_assert(
12872f57e3aSHui Xie HasUniqueCopyIter<
12972f57e3aSHui Xie cpp20_input_iterator<int*>,
13072f57e3aSHui Xie sentinel_wrapper<cpp20_input_iterator<int*>>,
13172f57e3aSHui Xie cpp20_output_iterator<int*>>);
13272f57e3aSHui Xie // because:
13372f57e3aSHui Xie static_assert(!std::forward_iterator<cpp20_input_iterator<int*>>);
13472f57e3aSHui Xie static_assert(!std::input_iterator<cpp20_output_iterator<int*>>);
13572f57e3aSHui Xie static_assert(std::indirectly_copyable_storable<cpp20_input_iterator<int*>, cpp20_output_iterator<int*>>);
13672f57e3aSHui Xie
13772f57e3aSHui Xie // !forward_iterator<I>
13872f57e3aSHui Xie // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
13972f57e3aSHui Xie // !indirectly_copyable_storable<I, O>
14072f57e3aSHui Xie static_assert(
14172f57e3aSHui Xie !HasUniqueCopyIter<
14272f57e3aSHui Xie cpp20_input_iterator<MoveOnly*>,
14372f57e3aSHui Xie sentinel_wrapper<cpp20_input_iterator<MoveOnly*>>,
14472f57e3aSHui Xie cpp20_output_iterator<AssignableFromMoveOnly*>>);
14572f57e3aSHui Xie // because:
14672f57e3aSHui Xie static_assert(!std::forward_iterator<cpp20_input_iterator<MoveOnly*>>);
14772f57e3aSHui Xie static_assert(!std::input_iterator<cpp20_output_iterator<MoveOnly*>>);
14872f57e3aSHui Xie static_assert(
14972f57e3aSHui Xie !std::
15072f57e3aSHui Xie indirectly_copyable_storable<cpp20_input_iterator<MoveOnly*>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
15172f57e3aSHui Xie
15272f57e3aSHui Xie template < class Range, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity>
15372f57e3aSHui Xie concept HasUniqueCopyRange =
15472f57e3aSHui Xie requires(Range&& range, OutIter&& out, Comp&& comp, Proj&& proj) {
15572f57e3aSHui Xie std::ranges::unique_copy(
15672f57e3aSHui Xie std::forward<Range>(range), std::forward<OutIter>(out), std::forward<Comp>(comp), std::forward<Proj>(proj));
15772f57e3aSHui Xie };
15872f57e3aSHui Xie
15972f57e3aSHui Xie template <class T>
16072f57e3aSHui Xie using R = UncheckedRange<T>;
16172f57e3aSHui Xie
16272f57e3aSHui Xie static_assert(HasUniqueCopyRange<R<int*>, int*>);
16372f57e3aSHui Xie
16472f57e3aSHui Xie // !input_range<R>
16572f57e3aSHui Xie static_assert(!HasUniqueCopyRange<R<InputIteratorNotDerivedFrom>>);
16672f57e3aSHui Xie
16772f57e3aSHui Xie // !weakly_incrementable<O>
16872f57e3aSHui Xie static_assert(!HasUniqueCopyIter<R<int*>, WeaklyIncrementableNotMovable>);
16972f57e3aSHui Xie
17072f57e3aSHui Xie // !indirect_equivalence_relation<Comp, projected<I, Proj>>
17172f57e3aSHui Xie static_assert(!HasUniqueCopyIter<R<int*>, int*, ComparatorNotCopyable<int>>);
17272f57e3aSHui Xie
17372f57e3aSHui Xie // !indirectly_copyable<I, O>
17472f57e3aSHui Xie static_assert(!HasUniqueCopyIter<R<const int*>, const int*>);
17572f57e3aSHui Xie
17672f57e3aSHui Xie // !forward_iterator<iterator_t<R>>
17772f57e3aSHui Xie // !(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>)
17872f57e3aSHui Xie // !indirectly_copyable_storable<iterator_t<R>, O>
17972f57e3aSHui Xie static_assert(!HasUniqueCopyIter< R<cpp20_input_iterator<MoveOnly*>>, cpp20_output_iterator<AssignableFromMoveOnly*>>);
18072f57e3aSHui Xie
18172f57e3aSHui Xie template <class InIter, class OutIter, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
testUniqueCopyImpl(std::array<int,N1> in,std::array<int,N2> expected)18272f57e3aSHui Xie constexpr void testUniqueCopyImpl(std::array<int, N1> in, std::array<int, N2> expected) {
18372f57e3aSHui Xie using Sent = SentWrapper<InIter>;
18472f57e3aSHui Xie
18572f57e3aSHui Xie // iterator overload
18672f57e3aSHui Xie {
18772f57e3aSHui Xie std::array<int, N2> out;
18872f57e3aSHui Xie std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
189d05bada5SDuo Wang std::ranges::unique_copy(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.data()});
19072f57e3aSHui Xie assert(std::ranges::equal(out, expected));
19172f57e3aSHui Xie assert(base(result.in) == in.data() + in.size());
19272f57e3aSHui Xie assert(base(result.out) == out.data() + out.size());
19372f57e3aSHui Xie }
19472f57e3aSHui Xie
19572f57e3aSHui Xie // range overload
19672f57e3aSHui Xie {
19772f57e3aSHui Xie std::array<int, N2> out;
19872f57e3aSHui Xie std::ranges::subrange r{InIter{in.data()}, Sent{InIter{in.data() + in.size()}}};
19972f57e3aSHui Xie std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result =
200d05bada5SDuo Wang std::ranges::unique_copy(r, OutIter{out.data()});
20172f57e3aSHui Xie assert(std::ranges::equal(out, expected));
20272f57e3aSHui Xie assert(base(result.in) == in.data() + in.size());
20372f57e3aSHui Xie assert(base(result.out) == out.data() + out.size());
20472f57e3aSHui Xie }
20572f57e3aSHui Xie }
20672f57e3aSHui Xie
20772f57e3aSHui Xie template <class InIter, class OutIter, template <class> class SentWrapper>
testImpl()20872f57e3aSHui Xie constexpr void testImpl() {
20972f57e3aSHui Xie // no consecutive elements
21072f57e3aSHui Xie {
21172f57e3aSHui Xie std::array in{1, 2, 3, 2, 1};
21272f57e3aSHui Xie std::array expected{1, 2, 3, 2, 1};
21372f57e3aSHui Xie testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
21472f57e3aSHui Xie }
21572f57e3aSHui Xie
21672f57e3aSHui Xie // one group of consecutive elements
21772f57e3aSHui Xie {
21872f57e3aSHui Xie std::array in{2, 3, 3, 3, 4, 3};
21972f57e3aSHui Xie std::array expected{2, 3, 4, 3};
22072f57e3aSHui Xie testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
22172f57e3aSHui Xie }
22272f57e3aSHui Xie
22372f57e3aSHui Xie // multiple groups of consecutive elements
22472f57e3aSHui Xie {
22572f57e3aSHui Xie std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5};
22672f57e3aSHui Xie std::array expected{2, 3, 4, 3, 5};
22772f57e3aSHui Xie testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
22872f57e3aSHui Xie }
22972f57e3aSHui Xie
23072f57e3aSHui Xie // all the same
23172f57e3aSHui Xie {
23272f57e3aSHui Xie std::array in{1, 1, 1, 1, 1, 1};
23372f57e3aSHui Xie std::array expected{1};
23472f57e3aSHui Xie testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
23572f57e3aSHui Xie }
23672f57e3aSHui Xie
23772f57e3aSHui Xie // empty range
23872f57e3aSHui Xie {
23972f57e3aSHui Xie std::array<int, 0> in{};
24072f57e3aSHui Xie std::array<int, 0> expected{};
24172f57e3aSHui Xie testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected);
24272f57e3aSHui Xie }
24372f57e3aSHui Xie }
24472f57e3aSHui Xie
24572f57e3aSHui Xie template <class OutIter, template <class> class SentWrapper>
withAllPermutationsOfInIter()24672f57e3aSHui Xie constexpr void withAllPermutationsOfInIter() {
24772f57e3aSHui Xie testImpl<cpp20_input_iterator<int*>, OutIter, sentinel_wrapper>();
24872f57e3aSHui Xie testImpl<forward_iterator<int*>, OutIter, SentWrapper>();
24972f57e3aSHui Xie testImpl<bidirectional_iterator<int*>, OutIter, SentWrapper>();
25072f57e3aSHui Xie testImpl<random_access_iterator<int*>, OutIter, SentWrapper>();
25172f57e3aSHui Xie testImpl<contiguous_iterator<int*>, OutIter, SentWrapper>();
25272f57e3aSHui Xie testImpl<int*, OutIter, SentWrapper>();
25372f57e3aSHui Xie }
25472f57e3aSHui Xie
25572f57e3aSHui Xie template <template <class> class SentWrapper>
withAllPermutationsOfInIterAndOutIter()25672f57e3aSHui Xie constexpr void withAllPermutationsOfInIterAndOutIter() {
25772f57e3aSHui Xie withAllPermutationsOfInIter<cpp20_output_iterator<int*>, SentWrapper>();
25872f57e3aSHui Xie withAllPermutationsOfInIter<forward_iterator<int*>, SentWrapper>();
25972f57e3aSHui Xie withAllPermutationsOfInIter<bidirectional_iterator<int*>, SentWrapper>();
26072f57e3aSHui Xie withAllPermutationsOfInIter<random_access_iterator<int*>, SentWrapper>();
26172f57e3aSHui Xie withAllPermutationsOfInIter<contiguous_iterator<int*>, SentWrapper>();
26272f57e3aSHui Xie withAllPermutationsOfInIter<int*, SentWrapper>();
26372f57e3aSHui Xie }
26473ebcabfSKonstantin Varlamov
test()26573ebcabfSKonstantin Varlamov constexpr bool test() {
26672f57e3aSHui Xie withAllPermutationsOfInIterAndOutIter<std::type_identity_t>();
26772f57e3aSHui Xie withAllPermutationsOfInIterAndOutIter<sentinel_wrapper>();
26873ebcabfSKonstantin Varlamov
26972f57e3aSHui Xie // Test the overload that re-reads from the input iterator
27072f57e3aSHui Xie // forward_iterator<I>
27172f57e3aSHui Xie // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
27272f57e3aSHui Xie // !indirectly_copyable_storable<I, O>
27372f57e3aSHui Xie {
27472f57e3aSHui Xie MoveOnly in[5] = {1, 3, 3, 3, 1};
27572f57e3aSHui Xie // iterator overload
27672f57e3aSHui Xie {
27772f57e3aSHui Xie AssignableFromMoveOnly out[3] = {};
27872f57e3aSHui Xie auto result = std::ranges::unique_copy(in, in + 5, out);
27972f57e3aSHui Xie assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
28072f57e3aSHui Xie assert(result.in == in + 5);
28172f57e3aSHui Xie assert(result.out == out + 3);
28272f57e3aSHui Xie }
28372f57e3aSHui Xie // range overload
28472f57e3aSHui Xie {
28572f57e3aSHui Xie AssignableFromMoveOnly out[3] = {};
28672f57e3aSHui Xie auto result = std::ranges::unique_copy(std::ranges::subrange{in, in + 5}, out);
28772f57e3aSHui Xie assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data));
28872f57e3aSHui Xie assert(result.in == in + 5);
28972f57e3aSHui Xie assert(result.out == out + 3);
29072f57e3aSHui Xie }
29172f57e3aSHui Xie }
29272f57e3aSHui Xie
29372f57e3aSHui Xie // Test the overload that re-reads from the output iterator
29472f57e3aSHui Xie // !forward_iterator<I>
29572f57e3aSHui Xie // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
29672f57e3aSHui Xie // !indirectly_copyable_storable<I, O>
29772f57e3aSHui Xie {
29872f57e3aSHui Xie using InIter = cpp20_input_iterator<CopyAssignableNotCopyConstructible*>;
29972f57e3aSHui Xie using Sent = sentinel_wrapper<InIter>;
30072f57e3aSHui Xie CopyAssignableNotCopyConstructible in[6] = {1, 1, 2, 2, 3, 3};
30172f57e3aSHui Xie // iterator overload
30272f57e3aSHui Xie {
30372f57e3aSHui Xie CopyAssignableNotCopyConstructible out[3];
30472f57e3aSHui Xie auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 6}}, InputAndOutputIterator{out});
30572f57e3aSHui Xie assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
30672f57e3aSHui Xie assert(base(result.in) == in + 6);
30772f57e3aSHui Xie assert(base(result.out) == out + 3);
30872f57e3aSHui Xie }
30972f57e3aSHui Xie // range overload
31072f57e3aSHui Xie {
31172f57e3aSHui Xie CopyAssignableNotCopyConstructible out[3];
31272f57e3aSHui Xie auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 6}});
31372f57e3aSHui Xie auto result = std::ranges::unique_copy(r, InputAndOutputIterator{out});
31472f57e3aSHui Xie assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data));
31572f57e3aSHui Xie assert(base(result.in) == in + 6);
31672f57e3aSHui Xie assert(base(result.out) == out + 3);
31772f57e3aSHui Xie }
31872f57e3aSHui Xie }
31972f57e3aSHui Xie
32072f57e3aSHui Xie // Test the overload that reads from the temporary copy of the value
32172f57e3aSHui Xie // !forward_iterator<I>
32272f57e3aSHui Xie // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>)
32372f57e3aSHui Xie // indirectly_copyable_storable<I, O>
32472f57e3aSHui Xie {
32572f57e3aSHui Xie using InIter = cpp20_input_iterator<int*>;
32672f57e3aSHui Xie using Sent = sentinel_wrapper<InIter>;
32772f57e3aSHui Xie int in[4] = {1, 1, 1, 2};
32872f57e3aSHui Xie // iterator overload
32972f57e3aSHui Xie {
33072f57e3aSHui Xie int out[2];
33172f57e3aSHui Xie auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 4}}, cpp20_output_iterator<int*>{out});
33272f57e3aSHui Xie assert(std::ranges::equal(out, std::array{1, 2}));
33372f57e3aSHui Xie assert(base(result.in) == in + 4);
33472f57e3aSHui Xie assert(base(result.out) == out + 2);
33572f57e3aSHui Xie }
33672f57e3aSHui Xie // range overload
33772f57e3aSHui Xie {
33872f57e3aSHui Xie int out[2];
33972f57e3aSHui Xie auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 4}});
34072f57e3aSHui Xie auto result = std::ranges::unique_copy(r, cpp20_output_iterator<int*>{out});
34172f57e3aSHui Xie assert(std::ranges::equal(out, std::array{1, 2}));
34272f57e3aSHui Xie assert(base(result.in) == in + 4);
34372f57e3aSHui Xie assert(base(result.out) == out + 2);
34472f57e3aSHui Xie }
34572f57e3aSHui Xie }
34672f57e3aSHui Xie
34772f57e3aSHui Xie struct Data {
34872f57e3aSHui Xie int data;
34972f57e3aSHui Xie };
35072f57e3aSHui Xie
35172f57e3aSHui Xie // Test custom comparator
35272f57e3aSHui Xie {
35372f57e3aSHui Xie std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
35472f57e3aSHui Xie std::array expected{Data{4}, Data{8}};
35572f57e3aSHui Xie const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; };
35672f57e3aSHui Xie
35772f57e3aSHui Xie // iterator overload
35872f57e3aSHui Xie {
35972f57e3aSHui Xie std::array<Data, 2> out;
36072f57e3aSHui Xie auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), comp);
36172f57e3aSHui Xie assert(std::ranges::equal(out, expected, comp));
36272f57e3aSHui Xie assert(base(result.in) == in.begin() + 4);
36372f57e3aSHui Xie assert(base(result.out) == out.begin() + 2);
36472f57e3aSHui Xie }
36572f57e3aSHui Xie
36672f57e3aSHui Xie // range overload
36772f57e3aSHui Xie {
36872f57e3aSHui Xie std::array<Data, 2> out;
36972f57e3aSHui Xie auto result = std::ranges::unique_copy(in, out.begin(), comp);
37072f57e3aSHui Xie assert(std::ranges::equal(out, expected, comp));
37172f57e3aSHui Xie assert(base(result.in) == in.begin() + 4);
37272f57e3aSHui Xie assert(base(result.out) == out.begin() + 2);
37372f57e3aSHui Xie }
37472f57e3aSHui Xie }
37572f57e3aSHui Xie
37672f57e3aSHui Xie // Test custom projection
37772f57e3aSHui Xie {
37872f57e3aSHui Xie std::array in{Data{4}, Data{8}, Data{8}, Data{8}};
37972f57e3aSHui Xie std::array expected{Data{4}, Data{8}};
38072f57e3aSHui Xie
38172f57e3aSHui Xie const auto proj = &Data::data;
38272f57e3aSHui Xie
38372f57e3aSHui Xie // iterator overload
38472f57e3aSHui Xie {
38572f57e3aSHui Xie std::array<Data, 2> out;
38672f57e3aSHui Xie auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), {}, proj);
38772f57e3aSHui Xie assert(std::ranges::equal(out, expected, {}, proj, proj));
38872f57e3aSHui Xie assert(base(result.in) == in.begin() + 4);
38972f57e3aSHui Xie assert(base(result.out) == out.begin() + 2);
39072f57e3aSHui Xie }
39172f57e3aSHui Xie
39272f57e3aSHui Xie // range overload
39372f57e3aSHui Xie {
39472f57e3aSHui Xie std::array<Data, 2> out;
39572f57e3aSHui Xie auto result = std::ranges::unique_copy(in, out.begin(), {}, proj);
39672f57e3aSHui Xie assert(std::ranges::equal(out, expected, {}, proj, proj));
39772f57e3aSHui Xie assert(base(result.in) == in.begin() + 4);
39872f57e3aSHui Xie assert(base(result.out) == out.begin() + 2);
39972f57e3aSHui Xie }
40072f57e3aSHui Xie }
40172f57e3aSHui Xie
40272f57e3aSHui Xie // Exactly last - first - 1 applications of the corresponding predicate and no
40372f57e3aSHui Xie // more than twice as many applications of any projection.
40472f57e3aSHui Xie {
40572f57e3aSHui Xie std::array in{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1};
40672f57e3aSHui Xie std::array expected{1, 2, 3, 4, 3, 5, 6, 1};
40772f57e3aSHui Xie // iterator overload
40872f57e3aSHui Xie {
40972f57e3aSHui Xie std::array<int, 8> out;
41072f57e3aSHui Xie int numberOfComp = 0;
41172f57e3aSHui Xie int numberOfProj = 0;
41272f57e3aSHui Xie auto result = std::ranges::unique_copy(
41372f57e3aSHui Xie in.begin(),
41472f57e3aSHui Xie in.end(),
41572f57e3aSHui Xie out.begin(),
41672f57e3aSHui Xie counting_predicate{std::ranges::equal_to{}, numberOfComp},
41772f57e3aSHui Xie counting_projection{numberOfProj});
41872f57e3aSHui Xie assert(std::ranges::equal(out, expected));
41972f57e3aSHui Xie assert(base(result.in) == in.end());
42072f57e3aSHui Xie assert(base(result.out) == out.end());
421*774295caSStephan T. Lavavej assert(numberOfComp == static_cast<int>(in.size() - 1));
42272f57e3aSHui Xie assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
42372f57e3aSHui Xie }
42472f57e3aSHui Xie // range overload
42572f57e3aSHui Xie {
42672f57e3aSHui Xie std::array<int, 8> out;
42772f57e3aSHui Xie int numberOfComp = 0;
42872f57e3aSHui Xie int numberOfProj = 0;
42972f57e3aSHui Xie auto result = std::ranges::unique_copy(
43072f57e3aSHui Xie in,
43172f57e3aSHui Xie out.begin(),
43272f57e3aSHui Xie counting_predicate{std::ranges::equal_to{}, numberOfComp},
43372f57e3aSHui Xie counting_projection{numberOfProj});
43472f57e3aSHui Xie assert(std::ranges::equal(out, expected));
43572f57e3aSHui Xie assert(base(result.in) == in.end());
43672f57e3aSHui Xie assert(base(result.out) == out.end());
437*774295caSStephan T. Lavavej assert(numberOfComp == static_cast<int>(in.size() - 1));
43872f57e3aSHui Xie assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1)));
43972f57e3aSHui Xie }
44072f57e3aSHui Xie }
44173ebcabfSKonstantin Varlamov return true;
44273ebcabfSKonstantin Varlamov }
44373ebcabfSKonstantin Varlamov
main(int,char **)44473ebcabfSKonstantin Varlamov int main(int, char**) {
44573ebcabfSKonstantin Varlamov test();
44673ebcabfSKonstantin Varlamov static_assert(test());
44773ebcabfSKonstantin Varlamov
44873ebcabfSKonstantin Varlamov return 0;
44973ebcabfSKonstantin Varlamov }
450