xref: /llvm-project/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count_if.pass.cpp (revision b8cb1dc9ea87faa8e8e9ab7a31710a8c0bb8b084)
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