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