//===----------------------------------------------------------------------===// // // 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_unary_predicate> Pred> // requires indirectly_copyable // constexpr remove_copy_if_result // remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {}); // Since C++20 // // template, Proj>> Pred> // requires indirectly_copyable, O> // constexpr remove_copy_if_result, O> // remove_copy_if(R&& r, O result, Pred pred, Proj proj = {}); // Since C++20 #include #include #include #include #include #include #include #include "almost_satisfies_types.h" #include "counting_predicates.h" #include "counting_projection.h" #include "test_iterators.h" struct AlwaysTrue { constexpr bool operator()(auto&&...) const { return true; } }; template < class I, class S = sentinel_wrapper>, class O = int*, class Pred = AlwaysTrue> concept HasRemoveCopyIfIter = requires(I&& iter, S&& sent, O&& out, Pred&& pred) { std::ranges::remove_copy_if(std::forward(iter), std::forward(sent), std::forward(out), std::forward(pred)); }; static_assert(HasRemoveCopyIfIter); // !input_iterator static_assert(!HasRemoveCopyIfIter); static_assert(!HasRemoveCopyIfIter>); // !sentinel_for static_assert(!HasRemoveCopyIfIter); static_assert(!HasRemoveCopyIfIter); // !weakly_incrementable static_assert(!HasRemoveCopyIfIter); // !indirect_unary_predicate> static_assert(!HasRemoveCopyIfIter); static_assert(!HasRemoveCopyIfIter); // !indirectly_copyable static_assert(!HasRemoveCopyIfIter); static_assert(!HasRemoveCopyIfIter); template < class R, class O = int*, class Pred = AlwaysTrue, class Proj = std::identity> concept HasRemoveCopyIfRange = requires(R&& r, O&& out, Pred&& pred, Proj&& proj) { std::ranges::remove_copy_if( std::forward(r), std::forward(out), std::forward(pred), std::forward(proj)); }; template using R = UncheckedRange; static_assert(HasRemoveCopyIfRange>); // !input_range static_assert(!HasRemoveCopyIfRange>); static_assert(!HasRemoveCopyIfRange>>); // !weakly_incrementable static_assert(!HasRemoveCopyIfRange, WeaklyIncrementableNotMovable>); // !indirect_unary_predicate, Proj>> static_assert(!HasRemoveCopyIfRange, int*, IndirectUnaryPredicateNotPredicate>); static_assert(!HasRemoveCopyIfRange, int*, IndirectUnaryPredicateNotCopyConstructible>); // !indirectly_copyable, O> static_assert(!HasRemoveCopyIfRange, OutputIteratorNotIndirectlyWritable>); static_assert(!HasRemoveCopyIfRange, const int*>); template class SentWrapper, std::size_t N1, std::size_t N2, class Pred> constexpr void testRemoveCopyIfImpl(std::array in, std::array expected, Pred pred) { using Sent = SentWrapper; using Result = std::ranges::remove_copy_if_result; // iterator overload { std::array out; std::same_as decltype(auto) result = std::ranges::remove_copy_if(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.data()}, pred); 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::remove_copy_if(r, OutIter{out.data()}, pred); 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() { // remove multiple elements { std::array in{1, 2, 3, 2, 1}; std::array expected{1, 3, 1}; auto pred = [](int i) { return i == 2; }; testRemoveCopyIfImpl(in, expected, pred); } // remove single elements { std::array in{1, 2, 3, 2, 1}; std::array expected{1, 2, 2, 1}; auto pred = [](int i) { return i == 3; }; testRemoveCopyIfImpl(in, expected, pred); } // nothing removed { std::array in{1, 2, 3, 2, 1}; std::array expected{1, 2, 3, 2, 1}; auto pred = [](int) { return false; }; testRemoveCopyIfImpl(in, expected, pred); } // all removed { std::array in{1, 2, 3, 2, 1}; std::array expected{}; auto pred = [](int) { return true; }; testRemoveCopyIfImpl(in, expected, pred); } // remove first { std::array in{1, 2, 3, 2}; std::array expected{2, 3, 2}; auto pred = [](int i) { return i < 2; }; testRemoveCopyIfImpl(in, expected, pred); } // remove last { std::array in{1, 2, 3, 2, 5}; std::array expected{1, 2, 3, 2}; auto pred = [](int i) { return i > 3; }; testRemoveCopyIfImpl(in, expected, pred); } // stable { std::array in{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; std::array expected{6, 7, 8, 9, 10}; auto pred = [](int i) { return i < 6; }; testRemoveCopyIfImpl(in, expected, pred); } // empty range { std::array in{}; std::array expected{}; auto pred = [](int) { return false; }; testRemoveCopyIfImpl(in, expected, pred); } // one element range { std::array in{1}; std::array expected{}; auto pred = [](int i) { return i == 1; }; testRemoveCopyIfImpl(in, expected, pred); } } template class SentWrapper> constexpr void withAllPermutationsOfInIter() { testImpl, OutIter, sentinel_wrapper>(); testImpl, OutIter, SentWrapper>(); testImpl, OutIter, SentWrapper>(); testImpl, OutIter, SentWrapper>(); testImpl, OutIter, SentWrapper>(); testImpl(); } template