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
13 // template<input_iterator I, sentinel_for<I> S, class Proj = identity,
14 // indirect_unary_predicate<projected<I, Proj>> Pred>
15 // constexpr iter_difference_t<I>
16 // ranges::count_if(I first, S last, Pred pred, Proj proj = {});
17 // template<input_range R, class Proj = identity,
18 // indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
19 // constexpr range_difference_t<R>
20 // ranges::count_if(R&& r, Pred pred, Proj proj = {});
21
22 #include <algorithm>
23 #include <array>
24 #include <cassert>
25 #include <ranges>
26
27 #include "almost_satisfies_types.h"
28 #include "test_iterators.h"
29
30 struct Predicate {
31 bool operator()(int);
32 };
33
34 template <class It, class Sent = It>
35 concept HasCountIfIt = requires(It it, Sent sent) { std::ranges::count_if(it, sent, Predicate{}); };
36 static_assert(HasCountIfIt<int*>);
37 static_assert(!HasCountIfIt<InputIteratorNotDerivedFrom>);
38 static_assert(!HasCountIfIt<InputIteratorNotIndirectlyReadable>);
39 static_assert(!HasCountIfIt<InputIteratorNotInputOrOutputIterator>);
40 static_assert(!HasCountIfIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
41 static_assert(!HasCountIfIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
42
43 static_assert(!HasCountIfIt<int*, int>);
44 static_assert(!HasCountIfIt<int, int*>);
45
46 template <class Pred>
47 concept HasCountIfPred = requires(int* it, Pred pred) {std::ranges::count_if(it, it, pred); };
48
49 static_assert(!HasCountIfPred<IndirectUnaryPredicateNotCopyConstructible>);
50 static_assert(!HasCountIfPred<IndirectUnaryPredicateNotPredicate>);
51
52 template <class R>
53 concept HasCountIfR = requires(R r) { std::ranges::count_if(r, Predicate{}); };
54 static_assert(HasCountIfR<std::array<int, 0>>);
55 static_assert(!HasCountIfR<int>);
56 static_assert(!HasCountIfR<InputRangeNotDerivedFrom>);
57 static_assert(!HasCountIfR<InputRangeNotIndirectlyReadable>);
58 static_assert(!HasCountIfR<InputRangeNotInputOrOutputIterator>);
59 static_assert(!HasCountIfR<InputRangeNotSentinelSemiregular>);
60 static_assert(!HasCountIfR<InputRangeNotSentinelEqualityComparableWith>);
61
62 template <class It, class Sent = It>
test_iterators()63 constexpr void test_iterators() {
64 {
65 // simple test
66 {
67 int a[] = {1, 2, 3, 4};
68 std::same_as<std::ptrdiff_t> auto ret =
69 std::ranges::count_if(It(a), Sent(It(a + 4)), [](int x) { return x == 4; });
70 assert(ret == 1);
71 }
72 {
73 int a[] = {1, 2, 3, 4};
74 auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));
75 std::same_as<std::ptrdiff_t> auto ret =
76 std::ranges::count_if(range, [](int x) { return x == 4; });
77 assert(ret == 1);
78 }
79 }
80
81 {
82 // check that an empty range works
83 {
84 std::array<int, 0> a = {};
85 auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int) { return true; });
86 assert(ret == 0);
87 }
88 {
89 std::array<int, 0> a = {};
90 auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
91 auto ret = std::ranges::count_if(range, [](int) { return true; });
92 assert(ret == 0);
93 }
94 }
95
96 {
97 // check that a range with a single element works
98 {
99 std::array a = {2};
100 auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int i) { return i == 2; });
101 assert(ret == 1);
102 }
103 {
104 std::array a = {2};
105 auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
106 auto ret = std::ranges::count_if(range, [](int i) { return i == 2; });
107 assert(ret == 1);
108 }
109 }
110
111 {
112 // check that 0 is returned with no match
113 {
114 int a[] = {1, 1, 1};
115 auto ret = std::ranges::count_if(It(a), Sent(It(a + 3)), [](int) { return false; });
116 assert(ret == 0);
117 }
118 {
119 int a[] = {1, 1, 1};
120 auto range = std::ranges::subrange(It(a), Sent(It(a + 3)));
121 auto ret = std::ranges::count_if(range, [](int){ return false; });
122 assert(ret == 0);
123 }
124 }
125
126 {
127 // check that more than one element is counted
128 {
129 std::array a = {3, 3, 4, 3, 3};
130 auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int i) { return i == 3; });
131 assert(ret == 4);
132 }
133 {
134 std::array a = {3, 3, 4, 3, 3};
135 auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
136 auto ret = std::ranges::count_if(range, [](int i) { return i == 3; });
137 assert(ret == 4);
138 }
139 }
140
141 {
142 // check that all elements are counted
143 {
144 std::array a = {5, 5, 5, 5};
145 auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int) { return true; });
146 assert(ret == 4);
147 }
148 {
149 std::array a = {5, 5, 5, 5};
150 auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
151 auto ret = std::ranges::count_if(range, [](int) { return true; });
152 assert(ret == 4);
153 }
154 }
155 }
156
test()157 constexpr bool test() {
158 test_iterators<int*>();
159 test_iterators<const int*>();
160 test_iterators<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
161 test_iterators<bidirectional_iterator<int*>>();
162 test_iterators<forward_iterator<int*>>();
163 test_iterators<random_access_iterator<int*>>();
164 test_iterators<contiguous_iterator<int*>>();
165
166 {
167 // check that projections are used properly and that they are called with the iterator directly
168 {
169 int a[] = {1, 2, 3, 4};
170 auto ret = std::ranges::count_if(a, a + 4, [&](int* i) { return i == a + 3; }, [](int& i) { return &i; });
171 assert(ret == 1);
172 }
173 {
174 int a[] = {1, 2, 3, 4};
175 auto ret = std::ranges::count_if(a, [&](int* i) { return i == a + 3; }, [](int& i) { return &i; });
176 assert(ret == 1);
177 }
178 }
179
180 {
181 // check that std::invoke is used
182 {
183 struct S {
184 int comp;
185 int other;
186 };
187 S a[] = { {0, 0}, {0, 2}, {0, 1} };
188 auto ret = std::ranges::count_if(a, [](int i){ return i == 0; }, &S::comp);
189 assert(ret == 3);
190 }
191 {
192 struct S {
193 int comp;
194 int other;
195 };
196 S a[] = { {0, 0}, {0, 2}, {0, 1} };
197 auto ret = std::ranges::count_if(a, a + 3, [](int i) { return i == 0; }, &S::comp);
198 assert(ret == 3);
199 }
200 }
201
202 {
203 // check projection and predicate invocation count
204 {
205 int a[] = {1, 2, 3, 4};
206 int predicate_count = 0;
207 int projection_count = 0;
208 auto ret = std::ranges::count_if(a, a + 4,
209 [&](int i) { ++predicate_count; return i == 2; },
210 [&](int i) { ++projection_count; return i; });
211 assert(ret == 1);
212 assert(predicate_count == 4);
213 assert(projection_count == 4);
214 }
215 {
216 int a[] = {1, 2, 3, 4};
217 int predicate_count = 0;
218 int projection_count = 0;
219 auto ret = std::ranges::count_if(a,
220 [&](int i) { ++predicate_count; return i == 2; },
221 [&](int i) { ++projection_count; return i; });
222 assert(ret == 1);
223 assert(predicate_count == 4);
224 assert(projection_count == 4);
225 }
226 }
227
228 {
229 // check that an immobile type works
230 struct NonMovable {
231 NonMovable(const NonMovable&) = delete;
232 NonMovable(NonMovable&&) = delete;
233 constexpr NonMovable(int i_) : i(i_) {}
234 int i;
235
236 bool operator==(const NonMovable&) const = default;
237 };
238 {
239 NonMovable a[] = {9, 8, 4, 3};
240 auto ret = std::ranges::count_if(a, a + 4, [](const NonMovable& i) { return i == NonMovable(8); });
241 assert(ret == 1);
242 }
243 {
244 NonMovable a[] = {9, 8, 4, 3};
245 auto ret = std::ranges::count_if(a, [](const NonMovable& i) { return i == NonMovable(8); });
246 assert(ret == 1);
247 }
248 }
249
250 {
251 // check that difference_type is used
252 struct DiffTypeIterator {
253 using difference_type = signed char;
254 using value_type = int;
255
256 int* it = nullptr;
257
258 constexpr DiffTypeIterator() = default;
259 constexpr DiffTypeIterator(int* i) : it(i) {}
260
261 constexpr int& operator*() const { return *it; }
262 constexpr DiffTypeIterator& operator++() { ++it; return *this; }
263 constexpr void operator++(int) { ++it; }
264
265 bool operator==(const DiffTypeIterator&) const = default;
266 };
267
268 {
269 int a[] = {5, 5, 4, 3, 2, 1};
270 std::same_as<signed char> auto ret =
271 std::ranges::count_if(DiffTypeIterator(a), DiffTypeIterator(a + 6), [](int& i) { return i == 4; });
272 assert(ret == 1);
273 }
274 {
275 int a[] = {5, 5, 4, 3, 2, 1};
276 auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6));
277 std::same_as<signed char> auto ret = std::ranges::count_if(range, [](int& i) { return i == 4; });
278 assert(ret == 1);
279 }
280 }
281
282 {
283 // check that the predicate can take the argument by lvalue ref
284 {
285 int a[] = {9, 8, 4, 3};
286 auto ret = std::ranges::count_if(a, a + 4, [](int& i) { return i == 8; });
287 assert(ret == 1);
288 }
289 {
290 int a[] = {9, 8, 4, 3};
291 auto ret = std::ranges::count_if(a, [](int& i) { return i == 8; });
292 assert(ret == 1);
293 }
294 }
295
296 {
297 // check that the predicate isn't made const
298 struct MutablePredicate {
299 constexpr bool operator()(int i) & { return i == 8; }
300 constexpr bool operator()(int i) && { return i == 8; }
301 };
302 {
303 int a[] = {9, 8, 4, 3};
304 auto ret = std::ranges::count_if(a, a + 4, MutablePredicate{});
305 assert(ret == 1);
306 }
307 {
308 int a[] = {9, 8, 4, 3};
309 auto ret = std::ranges::count_if(a, MutablePredicate{});
310 assert(ret == 1);
311 }
312 }
313
314 return true;
315 }
316
main(int,char **)317 int main(int, char**) {
318 test();
319 static_assert(test());
320
321 return 0;
322 }
323