1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // <algorithm>
10
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
12 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
13
14 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
15 // indirect_unary_predicate<projected<I, Proj>> Pred>
16 // requires indirectly_copyable<I, O>
17 // constexpr ranges::copy_if_result<I, O>
18 // ranges::copy_if(I first, S last, O result, Pred pred, Proj proj = {});
19 // template<input_range R, weakly_incrementable O, class Proj = identity,
20 // indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
21 // requires indirectly_copyable<iterator_t<R>, O>
22 // constexpr ranges::copy_if_result<borrowed_iterator_t<R>, O>
23 // ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {});
24
25 #include <algorithm>
26 #include <array>
27 #include <cassert>
28 #include <ranges>
29
30 #include "almost_satisfies_types.h"
31 #include "test_iterators.h"
32
33 struct Functor {
34 bool operator()(int);
35 };
36
37 template <class In, class Out = In, class Sent = sentinel_wrapper<In>, class Func = Functor>
38 concept HasCopyIfIt = requires(In first, Sent last, Out result) { std::ranges::copy_if(first, last, result, Func{}); };
39
40 static_assert(HasCopyIfIt<int*>);
41 static_assert(!HasCopyIfIt<InputIteratorNotDerivedFrom>);
42 static_assert(!HasCopyIfIt<InputIteratorNotIndirectlyReadable>);
43 static_assert(!HasCopyIfIt<InputIteratorNotInputOrOutputIterator>);
44 static_assert(!HasCopyIfIt<int*, WeaklyIncrementableNotMovable>);
45 struct NotIndirectlyCopyable {};
46 static_assert(!HasCopyIfIt<int*, NotIndirectlyCopyable*>);
47 static_assert(!HasCopyIfIt<int*, int*, SentinelForNotSemiregular>);
48 static_assert(!HasCopyIfIt<int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
49
50 static_assert(!HasCopyIfIt<int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
51 static_assert(!HasCopyIfIt<int*, int*, int*, IndirectUnaryPredicateNotPredicate>);
52
53 template <class Range, class Out, class Func = Functor>
54 concept HasCopyIfR = requires(Range range, Out out) { std::ranges::copy_if(range, out, Func{}); };
55
56 static_assert(HasCopyIfR<std::array<int, 10>, int*>);
57 static_assert(!HasCopyIfR<InputRangeNotDerivedFrom, int*>);
58 static_assert(!HasCopyIfR<InputRangeNotIndirectlyReadable, int*>);
59 static_assert(!HasCopyIfR<InputRangeNotInputOrOutputIterator, int*>);
60 static_assert(!HasCopyIfR<WeaklyIncrementableNotMovable, int*>);
61 static_assert(!HasCopyIfR<UncheckedRange<NotIndirectlyCopyable*>, int*>);
62 static_assert(!HasCopyIfR<InputRangeNotSentinelSemiregular, int*>);
63 static_assert(!HasCopyIfR<InputRangeNotSentinelEqualityComparableWith, int*>);
64
65 static_assert(std::is_same_v<std::ranges::copy_if_result<int, long>, std::ranges::in_out_result<int, long>>);
66
67 template <class In, class Out, class Sent = In>
test_iterators()68 constexpr void test_iterators() {
69 { // simple test
70 {
71 std::array in = {1, 2, 3, 4};
72 std::array<int, 4> out;
73 std::same_as<std::ranges::copy_if_result<In, Out>> auto ret =
74 std::ranges::copy_if(In(in.data()),
75 Sent(In(in.data() + in.size())),
76 Out(out.data()),
77 [](int) { return true; });
78 assert(in == out);
79 assert(base(ret.in) == in.data() + in.size());
80 assert(base(ret.out) == out.data() + out.size());
81 }
82 {
83 std::array in = {1, 2, 3, 4};
84 std::array<int, 4> out;
85 auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
86 std::same_as<std::ranges::copy_if_result<In, Out>> auto ret =
87 std::ranges::copy_if(range, Out(out.data()), [](int) { return true; });
88 assert(in == out);
89 assert(base(ret.in) == in.data() + in.size());
90 assert(base(ret.out) == out.data() + out.size());
91 }
92 }
93
94 { // check that an empty range works
95 {
96 std::array<int, 0> in;
97 std::array<int, 0> out;
98 auto ret = std::ranges::copy_if(In(in.data()), Sent(In(in.data())), Out(out.data()), [](int) { return true; });
99 assert(base(ret.in) == in.data());
100 assert(base(ret.out) == out.data());
101 }
102 {
103 std::array<int, 0> in;
104 std::array<int, 0> out;
105 auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data())));
106 auto ret = std::ranges::copy_if(range, Out(out.data()), [](int) { return true; });
107 assert(base(ret.in) == in.data());
108 assert(base(ret.out) == out.data());
109 }
110 }
111
112 { // check that the predicate is used
113 {
114 std::array in = {4, 6, 87, 3, 88, 44, 45, 9};
115 std::array<int, 4> out;
116 auto ret = std::ranges::copy_if(In(in.data()),
117 Sent(In(in.data() + in.size())),
118 Out(out.data()),
119 [](int i) { return i % 2 == 0; });
120 assert((out == std::array{4, 6, 88, 44}));
121 assert(base(ret.in) == in.data() + in.size());
122 assert(base(ret.out) == out.data() + out.size());
123 }
124 {
125 std::array in = {4, 6, 87, 3, 88, 44, 45, 9};
126 std::array<int, 4> out;
127 auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
128 auto ret = std::ranges::copy_if(range, Out(out.data()), [](int i) { return i % 2 == 0; });
129 assert((out == std::array{4, 6, 88, 44}));
130 assert(base(ret.in) == in.data() + in.size());
131 assert(base(ret.out) == out.data() + out.size());
132 }
133 }
134 }
135
136 template <class Out>
test_in_iterators()137 constexpr bool test_in_iterators() {
138 test_iterators<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>();
139 test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
140 test_iterators<forward_iterator<int*>, Out>();
141 test_iterators<bidirectional_iterator<int*>, Out>();
142 test_iterators<random_access_iterator<int*>, Out>();
143 test_iterators<contiguous_iterator<int*>, Out>();
144 test_iterators<int*, Out>();
145
146 return true;
147 }
148
test()149 constexpr bool test() {
150 test_in_iterators<cpp17_output_iterator<int*>>();
151 test_in_iterators<cpp20_output_iterator<int*>>();
152 test_in_iterators<forward_iterator<int*>>();
153 test_in_iterators<bidirectional_iterator<int*>>();
154 test_in_iterators<random_access_iterator<int*>>();
155 test_in_iterators<contiguous_iterator<int*>>();
156 test_in_iterators<int*>();
157
158 { // check that std::invoke is used
159 {
160 struct S { int val; int other; };
161 std::array<S, 4> in = {{{4, 2}, {1, 3}, {3, 4}, {3, 5}}};
162 std::array<S, 2> out;
163 auto ret = std::ranges::copy_if(in.begin(), in.end(), out.begin(), [](int i) { return i == 3; }, &S::val);
164 assert(ret.in == in.end());
165 assert(ret.out == out.end());
166 assert(out[0].val == 3);
167 assert(out[0].other == 4);
168 assert(out[1].val == 3);
169 assert(out[1].other == 5);
170 }
171 {
172 struct S { int val; int other; };
173 std::array<S, 4> in = {{{4, 2}, {1, 3}, {3, 4}, {3, 5}}};
174 std::array<S, 2> out;
175 auto ret = std::ranges::copy_if(in, out.begin(), [](int i) { return i == 3; }, &S::val);
176 assert(ret.in == in.end());
177 assert(ret.out == out.end());
178 assert(out[0].val == 3);
179 assert(out[0].other == 4);
180 assert(out[1].val == 3);
181 assert(out[1].other == 5);
182 }
183 }
184
185 { // check that the complexity requirements are met
186 {
187 int predicateCount = 0;
188 int projectionCount = 0;
189 auto pred = [&](int i) { ++predicateCount; return i != 0; };
190 auto proj = [&](int i) { ++projectionCount; return i; };
191
192 int a[] = {5, 4, 3, 2, 1};
193 int b[5];
194 std::ranges::copy_if(a, a + 5, b, pred, proj);
195 assert(predicateCount == 5);
196 assert(projectionCount == 5);
197 }
198 {
199 int predicateCount = 0;
200 int projectionCount = 0;
201 auto pred = [&](int i) { ++predicateCount; return i != 0; };
202 auto proj = [&](int i) { ++projectionCount; return i; };
203
204 int a[] = {5, 4, 3, 2, 1};
205 int b[5];
206 std::ranges::copy_if(a, b, pred, proj);
207 assert(predicateCount == 5);
208 assert(projectionCount == 5);
209 }
210 }
211
212 { // test proxy iterator
213 {
214 std::array in = {4, 6, 87, 3, 88, 44, 45, 9};
215 std::array<int, 4> out;
216
217 ProxyRange proxyIn{in};
218 ProxyRange proxyOut{out};
219
220 std::ranges::copy_if(proxyIn.begin(), proxyIn.end(), proxyOut.begin(),
221 [](auto const& i) { return i.data % 2 == 0; });
222 assert((out == std::array{4, 6, 88, 44}));
223 }
224 {
225 std::array in = {4, 6, 87, 3, 88, 44, 45, 9};
226 std::array<int, 4> out;
227
228 ProxyRange proxyIn{in};
229 ProxyRange proxyOut{out};
230
231 std::ranges::copy_if(proxyIn, proxyOut.begin(), [](const auto& i) { return i.data % 2 == 0; });
232 assert((out == std::array{4, 6, 88, 44}));
233 }
234 }
235
236 return true;
237 }
238
main(int,char **)239 int main(int, char**) {
240 test();
241 static_assert(test());
242
243 return 0;
244 }
245