xref: /llvm-project/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count_if.pass.cpp (revision 1306b1025c507ec8c406a975558007e3e94e5cbd)
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>
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 
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 
318 int main(int, char**) {
319   test();
320   static_assert(test());
321 
322   return 0;
323 }
324