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 T,
1473ebcabfSKonstantin Varlamov // class Proj = identity>
1573ebcabfSKonstantin Varlamov // requires indirectly_copyable<I, O> &&
1673ebcabfSKonstantin Varlamov // indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
1773ebcabfSKonstantin Varlamov // constexpr remove_copy_result<I, O>
1873ebcabfSKonstantin Varlamov // remove_copy(I first, S last, O result, const T& value, Proj proj = {}); // Since C++20
1973ebcabfSKonstantin Varlamov //
2073ebcabfSKonstantin Varlamov // template<input_range R, weakly_incrementable O, class T, class Proj = identity>
2173ebcabfSKonstantin Varlamov // requires indirectly_copyable<iterator_t<R>, O> &&
2273ebcabfSKonstantin Varlamov // indirect_binary_predicate<ranges::equal_to,
2373ebcabfSKonstantin Varlamov // projected<iterator_t<R>, Proj>, const T*>
2473ebcabfSKonstantin Varlamov // constexpr remove_copy_result<borrowed_iterator_t<R>, O>
2573ebcabfSKonstantin Varlamov // remove_copy(R&& r, O result, const T& value, Proj proj = {}); // Since C++20
2673ebcabfSKonstantin Varlamov
2773ebcabfSKonstantin Varlamov #include <algorithm>
2873ebcabfSKonstantin Varlamov #include <array>
2973ebcabfSKonstantin Varlamov #include <concepts>
3073ebcabfSKonstantin Varlamov #include <functional>
3173ebcabfSKonstantin Varlamov #include <ranges>
32*760d2b46SNikolas Klauser #include <utility>
3373ebcabfSKonstantin Varlamov
3473ebcabfSKonstantin Varlamov #include "almost_satisfies_types.h"
35*760d2b46SNikolas Klauser #include "counting_projection.h"
3673ebcabfSKonstantin Varlamov #include "test_iterators.h"
3773ebcabfSKonstantin Varlamov
38*760d2b46SNikolas Klauser struct ToPtr {
39*760d2b46SNikolas Klauser int* operator()(int) const;
40*760d2b46SNikolas Klauser };
41*760d2b46SNikolas Klauser
42*760d2b46SNikolas Klauser template <class Iter = int*, class Sent = int*, class OutIter = int*, class Proj = std::identity>
43*760d2b46SNikolas Klauser concept HasRemoveCopyIter =
44*760d2b46SNikolas Klauser requires(Iter&& iter, Sent&& sent, OutIter&& out, Proj&& proj) {
45*760d2b46SNikolas Klauser std::ranges::remove_copy(
46*760d2b46SNikolas Klauser std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<OutIter>(out), 0, std::forward<Proj>(proj));
47*760d2b46SNikolas Klauser };
48*760d2b46SNikolas Klauser
49*760d2b46SNikolas Klauser static_assert(HasRemoveCopyIter<int*>);
50*760d2b46SNikolas Klauser
51*760d2b46SNikolas Klauser // !input_iterator<I>
52*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<InputIteratorNotDerivedFrom>);
53*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<cpp20_output_iterator<int*>>);
54*760d2b46SNikolas Klauser
55*760d2b46SNikolas Klauser // !sentinel_for<S, I>
56*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
57*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<int*, SentinelForNotSemiregular>);
58*760d2b46SNikolas Klauser
59*760d2b46SNikolas Klauser // !weakly_incrementable<O>
60*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
61*760d2b46SNikolas Klauser
62*760d2b46SNikolas Klauser // !indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
63*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<int*, int*, int*, ToPtr>);
64*760d2b46SNikolas Klauser
65*760d2b46SNikolas Klauser // !indirectly_copyable<I, O>
66*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<int*, int*, OutputIteratorNotIndirectlyWritable>);
67*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyIter<const int*, const int*, const int*>);
68*760d2b46SNikolas Klauser
69*760d2b46SNikolas Klauser template <class Range, class OutIter = int*, class Proj = std::identity>
70*760d2b46SNikolas Klauser concept HasRemoveCopyRange =
71*760d2b46SNikolas Klauser requires(Range&& range, OutIter&& out, Proj&& proj) {
72*760d2b46SNikolas Klauser std::ranges::remove_copy(
73*760d2b46SNikolas Klauser std::forward<Range>(range), std::forward<OutIter>(out), 0, std::forward<Proj>(proj));
74*760d2b46SNikolas Klauser };
75*760d2b46SNikolas Klauser
76*760d2b46SNikolas Klauser template <class T>
77*760d2b46SNikolas Klauser using R = UncheckedRange<T>;
78*760d2b46SNikolas Klauser
79*760d2b46SNikolas Klauser static_assert(HasRemoveCopyRange<R<int*>>);
80*760d2b46SNikolas Klauser
81*760d2b46SNikolas Klauser // !input_range<R>
82*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<InputRangeNotDerivedFrom>);
83*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<InputRangeNotIndirectlyReadable>);
84*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<InputRangeNotInputOrOutputIterator>);
85*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<InputRangeNotSentinelSemiregular>);
86*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<InputRangeNotSentinelEqualityComparableWith>);
87*760d2b46SNikolas Klauser
88*760d2b46SNikolas Klauser // !weakly_incrementable<O>
89*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<R<int*>, WeaklyIncrementableNotMovable>);
90*760d2b46SNikolas Klauser
91*760d2b46SNikolas Klauser // !indirect_binary_predicate<ranges::equal_to, projected<iterator_t<I>, Proj>, const T*>
92*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<R<int*>, int*, ToPtr>);
93*760d2b46SNikolas Klauser
94*760d2b46SNikolas Klauser // !indirectly_copyable<I, O>
95*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<R<int*>, int*, OutputIteratorNotIndirectlyWritable>);
96*760d2b46SNikolas Klauser static_assert(!HasRemoveCopyRange<const int*, const int*, const int*>);
97*760d2b46SNikolas Klauser
98*760d2b46SNikolas Klauser template <int N, int M>
99*760d2b46SNikolas Klauser struct Data {
100*760d2b46SNikolas Klauser std::array<int, N> input;
101*760d2b46SNikolas Klauser std::array<int, M> expected;
102*760d2b46SNikolas Klauser int val;
103*760d2b46SNikolas Klauser };
104*760d2b46SNikolas Klauser
105*760d2b46SNikolas Klauser template <class InIter, class Sent, class OutIter, int N, int M>
test(Data<N,M> d)106*760d2b46SNikolas Klauser constexpr void test(Data<N, M> d) {
107*760d2b46SNikolas Klauser using Result = std::ranges::remove_copy_result<InIter, OutIter>;
108*760d2b46SNikolas Klauser
109*760d2b46SNikolas Klauser { // iterator overload
110*760d2b46SNikolas Klauser std::array<int, M> output;
111*760d2b46SNikolas Klauser
112*760d2b46SNikolas Klauser std::same_as<Result> decltype(auto) ret = std::ranges::remove_copy(
113*760d2b46SNikolas Klauser InIter(d.input.data()), Sent(InIter(d.input.data() + d.input.size())), OutIter(output.data()), d.val);
114*760d2b46SNikolas Klauser
115*760d2b46SNikolas Klauser assert(base(ret.in) == d.input.data() + N);
116*760d2b46SNikolas Klauser assert(base(ret.out) == output.data() + M);
117*760d2b46SNikolas Klauser assert(d.expected == output);
118*760d2b46SNikolas Klauser }
119*760d2b46SNikolas Klauser
120*760d2b46SNikolas Klauser { // range overload
121*760d2b46SNikolas Klauser std::array<int, M> output;
122*760d2b46SNikolas Klauser auto range = std::ranges::subrange(InIter(d.input.data()), Sent(InIter(d.input.data() + d.input.size())));
123*760d2b46SNikolas Klauser
124*760d2b46SNikolas Klauser std::same_as<Result> decltype(auto) ret =
125*760d2b46SNikolas Klauser std::ranges::remove_copy(range, OutIter(output.data()), d.val);
126*760d2b46SNikolas Klauser
127*760d2b46SNikolas Klauser assert(base(ret.in) == d.input.data() + N);
128*760d2b46SNikolas Klauser assert(base(ret.out) == output.data() + M);
129*760d2b46SNikolas Klauser assert(d.expected == output);
130*760d2b46SNikolas Klauser }
131*760d2b46SNikolas Klauser }
132*760d2b46SNikolas Klauser
133*760d2b46SNikolas Klauser template <class Iter, class Sent, class OutIter>
tests()134*760d2b46SNikolas Klauser constexpr void tests() {
135*760d2b46SNikolas Klauser // simple test
136*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 6, 5>({.input = {1, 2, 3, 4, 5, 6}, .expected = {1, 2, 3, 4, 6}, .val = 5});
137*760d2b46SNikolas Klauser // empty range
138*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 0, 0>({});
139*760d2b46SNikolas Klauser // single element range - match
140*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 1, 0>({.input = {1}, .expected = {}, .val = 1});
141*760d2b46SNikolas Klauser // single element range - no match
142*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 1, 1>({.input = {1}, .expected = {1}, .val = 2});
143*760d2b46SNikolas Klauser // two element range - same order
144*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 2, 1>({.input = {1, 2}, .expected = {1}, .val = 2});
145*760d2b46SNikolas Klauser // two element range - reversed order
146*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 2, 1>({.input = {1, 2}, .expected = {2}, .val = 1});
147*760d2b46SNikolas Klauser // all elements match
148*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 5, 0>({.input = {1, 1, 1, 1, 1}, .expected = {}, .val = 1});
149*760d2b46SNikolas Klauser // the relative order of elements isn't changed
150*760d2b46SNikolas Klauser test<Iter, Sent, OutIter, 8, 5>({.input = {1, 2, 3, 2, 3, 4, 2, 5}, .expected = {1, 3, 3, 4, 5}, .val = 2});
151*760d2b46SNikolas Klauser }
152*760d2b46SNikolas Klauser
153*760d2b46SNikolas Klauser template <class InIter, class Sent>
test_output_iterators()154*760d2b46SNikolas Klauser constexpr void test_output_iterators() {
155*760d2b46SNikolas Klauser tests<InIter, Sent, cpp17_output_iterator<int*>>();
156*760d2b46SNikolas Klauser tests<InIter, Sent, forward_iterator<int*>>();
157*760d2b46SNikolas Klauser tests<InIter, Sent, bidirectional_iterator<int*>>();
158*760d2b46SNikolas Klauser tests<InIter, Sent, random_access_iterator<int*>>();
159*760d2b46SNikolas Klauser tests<InIter, Sent, contiguous_iterator<int*>>();
160*760d2b46SNikolas Klauser tests<InIter, Sent, int*>();
161*760d2b46SNikolas Klauser }
162*760d2b46SNikolas Klauser
163*760d2b46SNikolas Klauser template <class Iter>
test_sentinels()164*760d2b46SNikolas Klauser constexpr void test_sentinels() {
165*760d2b46SNikolas Klauser test_output_iterators<Iter, Iter>();
166*760d2b46SNikolas Klauser test_output_iterators<Iter, sentinel_wrapper<Iter>>();
167*760d2b46SNikolas Klauser test_output_iterators<Iter, sized_sentinel<Iter>>();
168*760d2b46SNikolas Klauser }
16973ebcabfSKonstantin Varlamov
test()17073ebcabfSKonstantin Varlamov constexpr bool test() {
171*760d2b46SNikolas Klauser test_output_iterators<cpp17_input_iterator<int*>, sentinel_wrapper<cpp17_input_iterator<int*>>>();
172*760d2b46SNikolas Klauser test_output_iterators<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>();
173*760d2b46SNikolas Klauser test_output_iterators<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
174*760d2b46SNikolas Klauser test_output_iterators<cpp20_input_iterator<int*>, sized_sentinel<cpp20_input_iterator<int*>>>();
175*760d2b46SNikolas Klauser test_sentinels<forward_iterator<int*>>();
176*760d2b46SNikolas Klauser test_sentinels<bidirectional_iterator<int*>>();
177*760d2b46SNikolas Klauser test_sentinels<random_access_iterator<int*>>();
178*760d2b46SNikolas Klauser test_sentinels<contiguous_iterator<int*>>();
179*760d2b46SNikolas Klauser test_sentinels<int*>();
180*760d2b46SNikolas Klauser
181*760d2b46SNikolas Klauser { // check that passing a different type works
182*760d2b46SNikolas Klauser struct S {
183*760d2b46SNikolas Klauser constexpr operator int() const { return 3; }
184*760d2b46SNikolas Klauser };
185*760d2b46SNikolas Klauser
186*760d2b46SNikolas Klauser { // iterator overload
187*760d2b46SNikolas Klauser int a[] = {1, 2, 3, 4};
188*760d2b46SNikolas Klauser int b[3];
189*760d2b46SNikolas Klauser std::ranges::remove_copy(std::begin(a), std::end(a), std::begin(b), S{});
190*760d2b46SNikolas Klauser }
191*760d2b46SNikolas Klauser
192*760d2b46SNikolas Klauser { // range overload
193*760d2b46SNikolas Klauser int a[] = {1, 2, 3, 4};
194*760d2b46SNikolas Klauser int b[3];
195*760d2b46SNikolas Klauser std::ranges::remove_copy(a, std::begin(b), S{});
196*760d2b46SNikolas Klauser }
197*760d2b46SNikolas Klauser }
198*760d2b46SNikolas Klauser
199*760d2b46SNikolas Klauser { // check that a custom projection works
200*760d2b46SNikolas Klauser struct S {
201*760d2b46SNikolas Klauser constexpr operator int() const { return 3; }
202*760d2b46SNikolas Klauser };
203*760d2b46SNikolas Klauser
204*760d2b46SNikolas Klauser { // iterator overload
205*760d2b46SNikolas Klauser int a[] = {1, 2, 3, 4};
206*760d2b46SNikolas Klauser int b[3];
207*760d2b46SNikolas Klauser std::ranges::remove_copy(std::begin(a), std::end(a), std::begin(b), S{});
208*760d2b46SNikolas Klauser
209*760d2b46SNikolas Klauser }
210*760d2b46SNikolas Klauser { // range overload
211*760d2b46SNikolas Klauser int a[] = {1, 2, 3, 4};
212*760d2b46SNikolas Klauser int b[3];
213*760d2b46SNikolas Klauser std::ranges::remove_copy(a, std::begin(b), S{});
214*760d2b46SNikolas Klauser }
215*760d2b46SNikolas Klauser }
216*760d2b46SNikolas Klauser
217*760d2b46SNikolas Klauser // Complexity: Exactly last - first applications of the corresponding predicate and any projection.
218*760d2b46SNikolas Klauser
219*760d2b46SNikolas Klauser {
220*760d2b46SNikolas Klauser std::array in{4, 4, 5, 6};
221*760d2b46SNikolas Klauser std::array expected{5, 6};
222*760d2b46SNikolas Klauser
223*760d2b46SNikolas Klauser // iterator overload
224*760d2b46SNikolas Klauser {
225*760d2b46SNikolas Klauser int numberOfProj = 0;
226*760d2b46SNikolas Klauser std::array<int, 2> out;
227*760d2b46SNikolas Klauser std::ranges::remove_copy(
228*760d2b46SNikolas Klauser in.begin(),
229*760d2b46SNikolas Klauser in.end(),
230*760d2b46SNikolas Klauser out.begin(),
231*760d2b46SNikolas Klauser 4,
232*760d2b46SNikolas Klauser counting_projection(numberOfProj));
233*760d2b46SNikolas Klauser
234*760d2b46SNikolas Klauser assert(numberOfProj == static_cast<int>(in.size()));
235*760d2b46SNikolas Klauser
236*760d2b46SNikolas Klauser assert(std::ranges::equal(out, expected));
237*760d2b46SNikolas Klauser }
238*760d2b46SNikolas Klauser
239*760d2b46SNikolas Klauser // range overload
240*760d2b46SNikolas Klauser {
241*760d2b46SNikolas Klauser int numberOfProj = 0;
242*760d2b46SNikolas Klauser std::array<int, 2> out;
243*760d2b46SNikolas Klauser std::ranges::remove_copy(
244*760d2b46SNikolas Klauser in, out.begin(), 4, counting_projection(numberOfProj));
245*760d2b46SNikolas Klauser assert(numberOfProj == static_cast<int>(in.size()));
246*760d2b46SNikolas Klauser assert(std::ranges::equal(out, expected));
247*760d2b46SNikolas Klauser }
248*760d2b46SNikolas Klauser }
24973ebcabfSKonstantin Varlamov
25073ebcabfSKonstantin Varlamov return true;
25173ebcabfSKonstantin Varlamov }
25273ebcabfSKonstantin Varlamov
main(int,char **)25373ebcabfSKonstantin Varlamov int main(int, char**) {
25473ebcabfSKonstantin Varlamov test();
25573ebcabfSKonstantin Varlamov static_assert(test());
25673ebcabfSKonstantin Varlamov
25773ebcabfSKonstantin Varlamov return 0;
25873ebcabfSKonstantin Varlamov }
259