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