1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
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 = {});
27 #include "almost_satisfies_types.h"
28 #include "test_iterators.h"
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
>);
43 static_assert(!HasCountIfIt
<int*, int>);
44 static_assert(!HasCountIfIt
<int, int*>);
47 concept HasCountIfPred
= requires(int* it
, Pred pred
) {std::ranges::count_if(it
, it
, pred
); };
49 static_assert(!HasCountIfPred
<IndirectUnaryPredicateNotCopyConstructible
>);
50 static_assert(!HasCountIfPred
<IndirectUnaryPredicateNotPredicate
>);
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
>);
62 template <class It
, class Sent
= It
>
63 constexpr void test_iterators() {
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; });
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; });
82 // check that an empty range works
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; });
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; });
97 // check that a range with a single element works
100 auto ret
= std::ranges::count_if(It(a
.data()), Sent(It(a
.data() + a
.size())), [](int i
) { return i
== 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; });
112 // check that 0 is returned with no match
115 auto ret
= std::ranges::count_if(It(a
), Sent(It(a
+ 3)), [](int) { return false; });
120 auto range
= std::ranges::subrange(It(a
), Sent(It(a
+ 3)));
121 auto ret
= std::ranges::count_if(range
, [](int){ return false; });
127 // check that more than one element is counted
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; });
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; });
142 // check that all elements are counted
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; });
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; });
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*>>();
167 // check that projections are used properly and that they are called with the iterator directly
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
; });
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
; });
181 // check that std::invoke is used
187 S a
[] = { {0, 0}, {0, 2}, {0, 1} };
188 auto ret
= std::ranges::count_if(a
, [](int i
){ return i
== 0; }, &S::comp
);
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
);
203 // check projection and predicate invocation count
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
; });
212 assert(predicate_count
== 4);
213 assert(projection_count
== 4);
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
; });
223 assert(predicate_count
== 4);
224 assert(projection_count
== 4);
229 // check that an immobile type works
231 NonMovable(const NonMovable
&) = delete;
232 NonMovable(NonMovable
&&) = delete;
233 constexpr NonMovable(int i_
) : i(i_
) {}
236 bool operator==(const NonMovable
&) const = default;
239 NonMovable a
[] = {9, 8, 4, 3};
240 auto ret
= std::ranges::count_if(a
, a
+ 4, [](const NonMovable
& i
) { return i
== NonMovable(8); });
244 NonMovable a
[] = {9, 8, 4, 3};
245 auto ret
= std::ranges::count_if(a
, [](const NonMovable
& i
) { return i
== NonMovable(8); });
251 // check that difference_type is used
252 struct DiffTypeIterator
{
253 using difference_type
= signed char;
254 using value_type
= int;
258 constexpr DiffTypeIterator() = default;
259 constexpr DiffTypeIterator(int* i
) : it(i
) {}
261 constexpr int& operator*() const { return *it
; }
262 constexpr DiffTypeIterator
& operator++() { ++it
; return *this; }
263 constexpr void operator++(int) { ++it
; }
265 bool operator==(const DiffTypeIterator
&) const = default;
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; });
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; });
283 // check that the predicate can take the argument by lvalue ref
285 int a
[] = {9, 8, 4, 3};
286 auto ret
= std::ranges::count_if(a
, a
+ 4, [](int& i
) { return i
== 8; });
290 int a
[] = {9, 8, 4, 3};
291 auto ret
= std::ranges::count_if(a
, [](int& i
) { return i
== 8; });
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; }
303 int a
[] = {9, 8, 4, 3};
304 auto ret
= std::ranges::count_if(a
, a
+ 4, MutablePredicate
{});
308 int a
[] = {9, 8, 4, 3};
309 auto ret
= std::ranges::count_if(a
, MutablePredicate
{});
317 int main(int, char**) {
319 static_assert(test());