//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // // template S, weakly_incrementable O, class Proj = identity, // indirect_equivalence_relation> C = ranges::equal_to> // requires indirectly_copyable && // (forward_iterator || // (input_iterator && same_as, iter_value_t>) || // indirectly_copyable_storable) // constexpr unique_copy_result // unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); // Since C++20 // // template, Proj>> C = ranges::equal_to> // requires indirectly_copyable, O> && // (forward_iterator> || // (input_iterator && same_as, iter_value_t>) || // indirectly_copyable_storable, O>) // constexpr unique_copy_result, O> // unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20 #include #include #include #include #include #include "almost_satisfies_types.h" #include "counting_predicates.h" #include "counting_projection.h" #include "MoveOnly.h" #include "test_iterators.h" template < class InIter = int*, class Sent = int*, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity> concept HasUniqueCopyIter = requires(InIter&& in, Sent&& sent, OutIter&& out, Comp&& comp, Proj&& proj) { std::ranges::unique_copy( std::forward(in), std::forward(sent), std::forward(out), std::forward(comp), std::forward(proj)); }; static_assert(HasUniqueCopyIter); // !input_iterator static_assert(!HasUniqueCopyIter>); // !sentinel_for static_assert(!HasUniqueCopyIter); // !weakly_incrementable static_assert(!HasUniqueCopyIter); // !indirect_equivalence_relation> static_assert(!HasUniqueCopyIter>); // !indirectly_copyable static_assert(!HasUniqueCopyIter); // forward_iterator // !(input_iterator && same_as, iter_value_t>) // !indirectly_copyable_storable struct AssignableFromMoveOnly { int data; constexpr AssignableFromMoveOnly& operator=(MoveOnly const& m) { data = m.get(); return *this; } }; static_assert(HasUniqueCopyIter); // because: static_assert(std::forward_iterator); static_assert(!std::same_as, std::iter_value_t>); static_assert(!std::indirectly_copyable_storable); // !forward_iterator // (input_iterator && same_as, iter_value_t>) // !indirectly_copyable_storable struct CopyAssignableNotCopyConstructible { int data; constexpr CopyAssignableNotCopyConstructible(int i = 0) : data(i) {} CopyAssignableNotCopyConstructible(const CopyAssignableNotCopyConstructible&) = delete; CopyAssignableNotCopyConstructible& operator=(const CopyAssignableNotCopyConstructible&) = default; friend constexpr bool operator==(CopyAssignableNotCopyConstructible const&, CopyAssignableNotCopyConstructible const&) = default; }; using InputAndOutputIterator = cpp17_input_iterator; static_assert(std::input_iterator); static_assert(std::output_iterator); static_assert( HasUniqueCopyIter< cpp20_input_iterator, sentinel_wrapper>, InputAndOutputIterator>); // because: static_assert(!std::forward_iterator< cpp20_input_iterator>); static_assert( std::input_iterator && std::same_as>, std::iter_value_t>); static_assert( !std::indirectly_copyable_storable< cpp20_input_iterator, InputAndOutputIterator>); // !forward_iterator // !(input_iterator && same_as, iter_value_t>) // indirectly_copyable_storable static_assert( HasUniqueCopyIter< cpp20_input_iterator, sentinel_wrapper>, cpp20_output_iterator>); // because: static_assert(!std::forward_iterator>); static_assert(!std::input_iterator>); static_assert(std::indirectly_copyable_storable, cpp20_output_iterator>); // !forward_iterator // !(input_iterator && same_as, iter_value_t>) // !indirectly_copyable_storable static_assert( !HasUniqueCopyIter< cpp20_input_iterator, sentinel_wrapper>, cpp20_output_iterator>); // because: static_assert(!std::forward_iterator>); static_assert(!std::input_iterator>); static_assert( !std:: indirectly_copyable_storable, cpp20_output_iterator>); template < class Range, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity> concept HasUniqueCopyRange = requires(Range&& range, OutIter&& out, Comp&& comp, Proj&& proj) { std::ranges::unique_copy( std::forward(range), std::forward(out), std::forward(comp), std::forward(proj)); }; template using R = UncheckedRange; static_assert(HasUniqueCopyRange, int*>); // !input_range static_assert(!HasUniqueCopyRange>); // !weakly_incrementable static_assert(!HasUniqueCopyIter, WeaklyIncrementableNotMovable>); // !indirect_equivalence_relation> static_assert(!HasUniqueCopyIter, int*, ComparatorNotCopyable>); // !indirectly_copyable static_assert(!HasUniqueCopyIter, const int*>); // !forward_iterator> // !(input_iterator && same_as, iter_value_t>) // !indirectly_copyable_storable, O> static_assert(!HasUniqueCopyIter< R>, cpp20_output_iterator>); template class SentWrapper, std::size_t N1, std::size_t N2> constexpr void testUniqueCopyImpl(std::array in, std::array expected) { using Sent = SentWrapper; // iterator overload { std::array out; std::same_as> decltype(auto) result = std::ranges::unique_copy(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.data()}); assert(std::ranges::equal(out, expected)); assert(base(result.in) == in.data() + in.size()); assert(base(result.out) == out.data() + out.size()); } // range overload { std::array out; std::ranges::subrange r{InIter{in.data()}, Sent{InIter{in.data() + in.size()}}}; std::same_as> decltype(auto) result = std::ranges::unique_copy(r, OutIter{out.data()}); assert(std::ranges::equal(out, expected)); assert(base(result.in) == in.data() + in.size()); assert(base(result.out) == out.data() + out.size()); } } template class SentWrapper> constexpr void testImpl() { // no consecutive elements { std::array in{1, 2, 3, 2, 1}; std::array expected{1, 2, 3, 2, 1}; testUniqueCopyImpl(in, expected); } // one group of consecutive elements { std::array in{2, 3, 3, 3, 4, 3}; std::array expected{2, 3, 4, 3}; testUniqueCopyImpl(in, expected); } // multiple groups of consecutive elements { std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5}; std::array expected{2, 3, 4, 3, 5}; testUniqueCopyImpl(in, expected); } // all the same { std::array in{1, 1, 1, 1, 1, 1}; std::array expected{1}; testUniqueCopyImpl(in, expected); } // empty range { std::array in{}; std::array expected{}; testUniqueCopyImpl(in, expected); } } template class SentWrapper> constexpr void withAllPermutationsOfInIter() { testImpl, OutIter, sentinel_wrapper>(); testImpl, OutIter, SentWrapper>(); testImpl, OutIter, SentWrapper>(); testImpl, OutIter, SentWrapper>(); testImpl, OutIter, SentWrapper>(); testImpl(); } template