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 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
14 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=70000000
16 // template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
17 // requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
18 // constexpr iter_difference_t<I>
19 // ranges::count(I first, S last, const T& value, Proj proj = {});
20 // template<input_range R, class T, class Proj = identity>
21 // requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
22 // constexpr range_difference_t<R>
23 // ranges::count(R&& r, const T& value, Proj proj = {});
31 #include "almost_satisfies_types.h"
32 #include "test_iterators.h"
34 struct NotEqualityComparable
{
35 bool operator==(NotEqualityComparable
&&) const;
36 bool operator==(NotEqualityComparable
&) const;
37 bool operator==(const NotEqualityComparable
&&) const;
40 template <class It
, class Sent
= It
>
41 concept HasCountIt
= requires(It it
, Sent sent
) { std::ranges::count(it
, sent
, *it
); };
42 static_assert(HasCountIt
<int*>);
43 static_assert(!HasCountIt
<NotEqualityComparable
*>);
44 static_assert(!HasCountIt
<InputIteratorNotDerivedFrom
>);
45 static_assert(!HasCountIt
<InputIteratorNotIndirectlyReadable
>);
46 static_assert(!HasCountIt
<InputIteratorNotInputOrOutputIterator
>);
47 static_assert(!HasCountIt
<cpp20_input_iterator
<int*>, SentinelForNotSemiregular
>);
48 static_assert(!HasCountIt
<cpp20_input_iterator
<int*>, InputRangeNotSentinelEqualityComparableWith
>);
50 static_assert(!HasCountIt
<int*, int>);
51 static_assert(!HasCountIt
<int, int*>);
53 template <class Range
, class ValT
>
54 concept HasCountR
= requires(Range r
) { std::ranges::count(r
, ValT
{}); };
55 static_assert(HasCountR
<std::array
<int, 1>, int>);
56 static_assert(!HasCountR
<int, int>);
57 static_assert(!HasCountR
<std::array
<NotEqualityComparable
, 1>, NotEqualityComparable
>);
58 static_assert(!HasCountR
<InputRangeNotDerivedFrom
, int>);
59 static_assert(!HasCountR
<InputRangeNotIndirectlyReadable
, int>);
60 static_assert(!HasCountR
<InputRangeNotInputOrOutputIterator
, int>);
61 static_assert(!HasCountR
<InputRangeNotSentinelSemiregular
, int>);
62 static_assert(!HasCountR
<InputRangeNotSentinelEqualityComparableWith
, int>);
64 template <class It
, class Sent
= It
>
65 constexpr void test_iterators() {
69 int a
[] = {1, 2, 3, 4};
70 std::same_as
<std::ptrdiff_t> auto ret
= std::ranges::count(It(a
), Sent(It(a
+ 4)), 3);
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
= std::ranges::count(range
, 3);
82 // check that an empty range works
84 std::array
<int, 0> a
= {};
85 auto ret
= std::ranges::count(It(a
.data()), Sent(It(a
.data() + a
.size())), 1);
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(range
, 1);
97 // check that a range with a single element works
100 auto ret
= std::ranges::count(It(a
.data()), Sent(It(a
.data() + a
.size())), 2);
105 auto range
= std::ranges::subrange(It(a
.data()), Sent(It(a
.data() + a
.size())));
106 auto ret
= std::ranges::count(range
, 2);
112 // check that 0 is returned with no match
114 std::array a
= {1, 1, 1};
115 auto ret
= std::ranges::count(It(a
.data()), Sent(It(a
.data() + a
.size())), 0);
119 std::array a
= {1, 1, 1};
120 auto range
= std::ranges::subrange(It(a
.data()), Sent(It(a
.data() + a
.size())));
121 auto ret
= std::ranges::count(range
, 0);
127 // check that more than one element is counted
129 std::array a
= {3, 3, 4, 3, 3};
130 auto ret
= std::ranges::count(It(a
.data()), Sent(It(a
.data() + a
.size())), 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(range
, 3);
142 // check that all elements are counted
144 std::array a
= {5, 5, 5, 5};
145 auto ret
= std::ranges::count(It(a
.data()), Sent(It(a
.data() + a
.size())), 5);
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(range
, 5);
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(a
, a
+ 4, a
+ 3, [](int& i
) { return &i
; });
174 int a
[] = {1, 2, 3, 4};
175 auto ret
= std::ranges::count(a
, a
+ 3, [](int& i
) { return &i
; });
181 // check that std::invoke is used
183 S a
[] = { S
{1}, S
{3}, S
{2} };
184 std::same_as
<std::ptrdiff_t> auto ret
= std::ranges::count(a
, 4, &S::i
);
189 // count invocations of the projection
191 int a
[] = {1, 2, 3, 4};
192 int projection_count
= 0;
193 auto ret
= std::ranges::count(a
, a
+ 4, 2, [&](int i
) { ++projection_count
; return i
; });
195 assert(projection_count
== 4);
198 int a
[] = {1, 2, 3, 4};
199 int projection_count
= 0;
200 auto ret
= std::ranges::count(a
, 2, [&](int i
) { ++projection_count
; return i
; });
202 assert(projection_count
== 4);
207 // check that an immobile type works
209 NonMovable(const NonMovable
&) = delete;
210 NonMovable(NonMovable
&&) = delete;
211 constexpr NonMovable(int i_
) : i(i_
) {}
214 bool operator==(const NonMovable
&) const = default;
217 NonMovable a
[] = {9, 8, 4, 3};
218 auto ret
= std::ranges::count(a
, a
+ 4, NonMovable(8));
222 NonMovable a
[] = {9, 8, 4, 3};
223 auto ret
= std::ranges::count(a
, NonMovable(8));
229 // check that difference_type is used
230 struct DiffTypeIterator
{
231 using difference_type
= signed char;
232 using value_type
= int;
236 constexpr DiffTypeIterator() = default;
237 constexpr DiffTypeIterator(int* i
) : it(i
) {}
239 constexpr int& operator*() const { return *it
; }
240 constexpr DiffTypeIterator
& operator++() { ++it
; return *this; }
241 constexpr void operator++(int) { ++it
; }
243 bool operator==(const DiffTypeIterator
&) const = default;
247 int a
[] = {5, 5, 4, 3, 2, 1};
248 std::same_as
<signed char> decltype(auto) ret
=
249 std::ranges::count(DiffTypeIterator(a
), DiffTypeIterator(a
+ 6), 4);
253 int a
[] = {5, 5, 4, 3, 2, 1};
254 auto range
= std::ranges::subrange(DiffTypeIterator(a
), DiffTypeIterator(a
+ 6));
255 std::same_as
<signed char> decltype(auto) ret
= std::ranges::count(range
, 4);
260 { // check that __bit_iterator optimizations work as expected
261 std::vector
<bool> vec(256 + 64);
262 for (ptrdiff_t i
= 0; i
!= 256; ++i
) {
263 for (size_t offset
= 0; offset
!= 64; ++offset
) {
264 std::fill(vec
.begin(), vec
.end(), false);
265 std::fill(vec
.begin() + offset
, vec
.begin() + i
+ offset
, true);
266 assert(std::ranges::count(vec
.begin() + offset
, vec
.begin() + offset
+ 256, true) == i
);
267 assert(std::ranges::count(vec
.begin() + offset
, vec
.begin() + offset
+ 256, false) == 256 - i
);
275 int main(int, char**) {
277 static_assert(test());