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