1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
14 // indirect_unary_predicate<projected<I, Proj>> Pred>
15 // requires indirectly_copyable<I, O>
16 // constexpr ranges::copy_if_result<I, O>
17 // ranges::copy_if(I first, S last, O result, Pred pred, Proj proj = {});
18 // template<input_range R, weakly_incrementable O, class Proj = identity,
19 // indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
20 // requires indirectly_copyable<iterator_t<R>, O>
21 // constexpr ranges::copy_if_result<borrowed_iterator_t<R>, O>
22 // ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {});
29 #include "almost_satisfies_types.h"
30 #include "test_iterators.h"
36 template <class In
, class Out
= In
, class Sent
= sentinel_wrapper
<In
>, class Func
= Functor
>
37 concept HasCopyIfIt
= requires(In first
, Sent last
, Out result
) { std::ranges::copy_if(first
, last
, result
, Func
{}); };
39 static_assert(HasCopyIfIt
<int*>);
40 static_assert(!HasCopyIfIt
<InputIteratorNotDerivedFrom
>);
41 static_assert(!HasCopyIfIt
<InputIteratorNotIndirectlyReadable
>);
42 static_assert(!HasCopyIfIt
<InputIteratorNotInputOrOutputIterator
>);
43 static_assert(!HasCopyIfIt
<int*, WeaklyIncrementableNotMovable
>);
44 struct NotIndirectlyCopyable
{};
45 static_assert(!HasCopyIfIt
<int*, NotIndirectlyCopyable
*>);
46 static_assert(!HasCopyIfIt
<int*, int*, SentinelForNotSemiregular
>);
47 static_assert(!HasCopyIfIt
<int*, int*, SentinelForNotWeaklyEqualityComparableWith
>);
49 static_assert(!HasCopyIfIt
<int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible
>);
50 static_assert(!HasCopyIfIt
<int*, int*, int*, IndirectUnaryPredicateNotPredicate
>);
52 template <class Range
, class Out
, class Func
= Functor
>
53 concept HasCopyIfR
= requires(Range range
, Out out
) { std::ranges::copy_if(range
, out
, Func
{}); };
55 static_assert(HasCopyIfR
<std::array
<int, 10>, int*>);
56 static_assert(!HasCopyIfR
<InputRangeNotDerivedFrom
, int*>);
57 static_assert(!HasCopyIfR
<InputRangeNotIndirectlyReadable
, int*>);
58 static_assert(!HasCopyIfR
<InputRangeNotInputOrOutputIterator
, int*>);
59 static_assert(!HasCopyIfR
<WeaklyIncrementableNotMovable
, int*>);
60 static_assert(!HasCopyIfR
<UncheckedRange
<NotIndirectlyCopyable
*>, int*>);
61 static_assert(!HasCopyIfR
<InputRangeNotSentinelSemiregular
, int*>);
62 static_assert(!HasCopyIfR
<InputRangeNotSentinelEqualityComparableWith
, int*>);
64 static_assert(std::is_same_v
<std::ranges::copy_if_result
<int, long>, std::ranges::in_out_result
<int, long>>);
66 template <class In
, class Out
, class Sent
= In
>
67 constexpr void test_iterators() {
70 std::array in
= {1, 2, 3, 4};
71 std::array
<int, 4> out
;
72 std::same_as
<std::ranges::copy_if_result
<In
, Out
>> auto ret
=
73 std::ranges::copy_if(In(in
.data()),
74 Sent(In(in
.data() + in
.size())),
76 [](int) { return true; });
78 assert(base(ret
.in
) == in
.data() + in
.size());
79 assert(base(ret
.out
) == out
.data() + out
.size());
82 std::array in
= {1, 2, 3, 4};
83 std::array
<int, 4> out
;
84 auto range
= std::ranges::subrange(In(in
.data()), Sent(In(in
.data() + in
.size())));
85 std::same_as
<std::ranges::copy_if_result
<In
, Out
>> auto ret
=
86 std::ranges::copy_if(range
, Out(out
.data()), [](int) { return true; });
88 assert(base(ret
.in
) == in
.data() + in
.size());
89 assert(base(ret
.out
) == out
.data() + out
.size());
93 { // check that an empty range works
95 std::array
<int, 0> in
;
96 std::array
<int, 0> out
;
97 auto ret
= std::ranges::copy_if(In(in
.data()), Sent(In(in
.data())), Out(out
.data()), [](int) { return true; });
98 assert(base(ret
.in
) == in
.data());
99 assert(base(ret
.out
) == out
.data());
102 std::array
<int, 0> in
;
103 std::array
<int, 0> out
;
104 auto range
= std::ranges::subrange(In(in
.data()), Sent(In(in
.data())));
105 auto ret
= std::ranges::copy_if(range
, Out(out
.data()), [](int) { return true; });
106 assert(base(ret
.in
) == in
.data());
107 assert(base(ret
.out
) == out
.data());
111 { // check that the predicate is used
113 std::array in
= {4, 6, 87, 3, 88, 44, 45, 9};
114 std::array
<int, 4> out
;
115 auto ret
= std::ranges::copy_if(In(in
.data()),
116 Sent(In(in
.data() + in
.size())),
118 [](int i
) { return i
% 2 == 0; });
119 assert((out
== std::array
{4, 6, 88, 44}));
120 assert(base(ret
.in
) == in
.data() + in
.size());
121 assert(base(ret
.out
) == out
.data() + out
.size());
124 std::array in
= {4, 6, 87, 3, 88, 44, 45, 9};
125 std::array
<int, 4> out
;
126 auto range
= std::ranges::subrange(In(in
.data()), Sent(In(in
.data() + in
.size())));
127 auto ret
= std::ranges::copy_if(range
, Out(out
.data()), [](int i
) { return i
% 2 == 0; });
128 assert((out
== std::array
{4, 6, 88, 44}));
129 assert(base(ret
.in
) == in
.data() + in
.size());
130 assert(base(ret
.out
) == out
.data() + out
.size());
136 constexpr bool test_in_iterators() {
137 test_iterators
<cpp17_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp17_input_iterator
<int*>>>();
138 test_iterators
<cpp20_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp20_input_iterator
<int*>>>();
139 test_iterators
<forward_iterator
<int*>, Out
>();
140 test_iterators
<bidirectional_iterator
<int*>, Out
>();
141 test_iterators
<random_access_iterator
<int*>, Out
>();
142 test_iterators
<contiguous_iterator
<int*>, Out
>();
143 test_iterators
<int*, Out
>();
148 constexpr bool test() {
149 test_in_iterators
<cpp17_output_iterator
<int*>>();
150 test_in_iterators
<cpp20_output_iterator
<int*>>();
151 test_in_iterators
<forward_iterator
<int*>>();
152 test_in_iterators
<bidirectional_iterator
<int*>>();
153 test_in_iterators
<random_access_iterator
<int*>>();
154 test_in_iterators
<contiguous_iterator
<int*>>();
155 test_in_iterators
<int*>();
157 { // check that std::invoke is used
159 struct S
{ int val
; int other
; };
160 std::array
<S
, 4> in
= {{{4, 2}, {1, 3}, {3, 4}, {3, 5}}};
161 std::array
<S
, 2> out
;
162 auto ret
= std::ranges::copy_if(in
.begin(), in
.end(), out
.begin(), [](int i
) { return i
== 3; }, &S::val
);
163 assert(ret
.in
== in
.end());
164 assert(ret
.out
== out
.end());
165 assert(out
[0].val
== 3);
166 assert(out
[0].other
== 4);
167 assert(out
[1].val
== 3);
168 assert(out
[1].other
== 5);
171 struct S
{ int val
; int other
; };
172 std::array
<S
, 4> in
= {{{4, 2}, {1, 3}, {3, 4}, {3, 5}}};
173 std::array
<S
, 2> out
;
174 auto ret
= std::ranges::copy_if(in
, out
.begin(), [](int i
) { return i
== 3; }, &S::val
);
175 assert(ret
.in
== in
.end());
176 assert(ret
.out
== out
.end());
177 assert(out
[0].val
== 3);
178 assert(out
[0].other
== 4);
179 assert(out
[1].val
== 3);
180 assert(out
[1].other
== 5);
184 { // check that the complexity requirements are met
186 int predicateCount
= 0;
187 int projectionCount
= 0;
188 auto pred
= [&](int i
) { ++predicateCount
; return i
!= 0; };
189 auto proj
= [&](int i
) { ++projectionCount
; return i
; };
191 int a
[] = {5, 4, 3, 2, 1};
193 std::ranges::copy_if(a
, a
+ 5, b
, pred
, proj
);
194 assert(predicateCount
== 5);
195 assert(projectionCount
== 5);
198 int predicateCount
= 0;
199 int projectionCount
= 0;
200 auto pred
= [&](int i
) { ++predicateCount
; return i
!= 0; };
201 auto proj
= [&](int i
) { ++projectionCount
; return i
; };
203 int a
[] = {5, 4, 3, 2, 1};
205 std::ranges::copy_if(a
, b
, pred
, proj
);
206 assert(predicateCount
== 5);
207 assert(projectionCount
== 5);
211 { // test proxy iterator
213 std::array in
= {4, 6, 87, 3, 88, 44, 45, 9};
214 std::array
<int, 4> out
;
216 ProxyRange proxyIn
{in
};
217 ProxyRange proxyOut
{out
};
219 std::ranges::copy_if(proxyIn
.begin(), proxyIn
.end(), proxyOut
.begin(),
220 [](auto const& i
) { return i
.data
% 2 == 0; });
221 assert((out
== std::array
{4, 6, 88, 44}));
224 std::array in
= {4, 6, 87, 3, 88, 44, 45, 9};
225 std::array
<int, 4> out
;
227 ProxyRange proxyIn
{in
};
228 ProxyRange proxyOut
{out
};
230 std::ranges::copy_if(proxyIn
, proxyOut
.begin(), [](const auto& i
) { return i
.data
% 2 == 0; });
231 assert((out
== std::array
{4, 6, 88, 44}));
238 int main(int, char**) {
240 static_assert(test());