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