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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
13*1306b102SNikolas Klauser 
14*1306b102SNikolas Klauser // template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
15*1306b102SNikolas Klauser //   requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
16*1306b102SNikolas Klauser //   constexpr iter_difference_t<I>
17*1306b102SNikolas Klauser //     ranges::count(I first, S last, const T& value, Proj proj = {});
18*1306b102SNikolas Klauser // template<input_range R, class T, class Proj = identity>
19*1306b102SNikolas Klauser //   requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
20*1306b102SNikolas Klauser //   constexpr range_difference_t<R>
21*1306b102SNikolas Klauser //     ranges::count(R&& r, const T& value, Proj proj = {});
22*1306b102SNikolas Klauser 
23*1306b102SNikolas Klauser #include <algorithm>
24*1306b102SNikolas Klauser #include <array>
25*1306b102SNikolas Klauser #include <cassert>
26*1306b102SNikolas Klauser #include <ranges>
27*1306b102SNikolas Klauser 
28*1306b102SNikolas Klauser #include "almost_satisfies_types.h"
29*1306b102SNikolas Klauser #include "test_iterators.h"
30*1306b102SNikolas Klauser 
31*1306b102SNikolas Klauser struct NotEqualityComparable {
32*1306b102SNikolas Klauser   bool operator==(NotEqualityComparable&&) const;
33*1306b102SNikolas Klauser   bool operator==(NotEqualityComparable&) const;
34*1306b102SNikolas Klauser   bool operator==(const NotEqualityComparable&&) const;
35*1306b102SNikolas Klauser };
36*1306b102SNikolas Klauser 
37*1306b102SNikolas Klauser template <class It, class Sent = It>
38*1306b102SNikolas Klauser concept HasCountIt = requires(It it, Sent sent) { std::ranges::count(it, sent, *it); };
39*1306b102SNikolas Klauser static_assert(HasCountIt<int*>);
40*1306b102SNikolas Klauser static_assert(!HasCountIt<NotEqualityComparable*>);
41*1306b102SNikolas Klauser static_assert(!HasCountIt<InputIteratorNotDerivedFrom>);
42*1306b102SNikolas Klauser static_assert(!HasCountIt<InputIteratorNotIndirectlyReadable>);
43*1306b102SNikolas Klauser static_assert(!HasCountIt<InputIteratorNotInputOrOutputIterator>);
44*1306b102SNikolas Klauser static_assert(!HasCountIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
45*1306b102SNikolas Klauser static_assert(!HasCountIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
46*1306b102SNikolas Klauser 
47*1306b102SNikolas Klauser static_assert(!HasCountIt<int*, int>);
48*1306b102SNikolas Klauser static_assert(!HasCountIt<int, int*>);
49*1306b102SNikolas Klauser 
50*1306b102SNikolas Klauser template <class Range, class ValT>
51*1306b102SNikolas Klauser concept HasCountR = requires(Range r) { std::ranges::count(r, ValT{}); };
52*1306b102SNikolas Klauser static_assert(HasCountR<std::array<int, 1>, int>);
53*1306b102SNikolas Klauser static_assert(!HasCountR<int, int>);
54*1306b102SNikolas Klauser static_assert(!HasCountR<std::array<NotEqualityComparable, 1>, NotEqualityComparable>);
55*1306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotDerivedFrom, int>);
56*1306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotIndirectlyReadable, int>);
57*1306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotInputOrOutputIterator, int>);
58*1306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotSentinelSemiregular, int>);
59*1306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotSentinelEqualityComparableWith, int>);
60*1306b102SNikolas Klauser 
61*1306b102SNikolas Klauser template <class It, class Sent = It>
test_iterators()62*1306b102SNikolas Klauser constexpr void test_iterators() {
63*1306b102SNikolas Klauser   {
64*1306b102SNikolas Klauser     // simple test
65*1306b102SNikolas Klauser     {
66*1306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
67*1306b102SNikolas Klauser       std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3);
68*1306b102SNikolas Klauser       assert(ret == 1);
69*1306b102SNikolas Klauser     }
70*1306b102SNikolas Klauser     {
71*1306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
72*1306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));
73*1306b102SNikolas Klauser       std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(range, 3);
74*1306b102SNikolas Klauser       assert(ret == 1);
75*1306b102SNikolas Klauser     }
76*1306b102SNikolas Klauser   }
77*1306b102SNikolas Klauser 
78*1306b102SNikolas Klauser   {
79*1306b102SNikolas Klauser     // check that an empty range works
80*1306b102SNikolas Klauser     {
81*1306b102SNikolas Klauser       std::array<int, 0> a = {};
82*1306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1);
83*1306b102SNikolas Klauser       assert(ret == 0);
84*1306b102SNikolas Klauser     }
85*1306b102SNikolas Klauser     {
86*1306b102SNikolas Klauser       std::array<int, 0> a = {};
87*1306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
88*1306b102SNikolas Klauser       auto ret = std::ranges::count(range, 1);
89*1306b102SNikolas Klauser       assert(ret == 0);
90*1306b102SNikolas Klauser     }
91*1306b102SNikolas Klauser   }
92*1306b102SNikolas Klauser 
93*1306b102SNikolas Klauser   {
94*1306b102SNikolas Klauser     // check that a range with a single element works
95*1306b102SNikolas Klauser     {
96*1306b102SNikolas Klauser       std::array a = {2};
97*1306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2);
98*1306b102SNikolas Klauser       assert(ret == 1);
99*1306b102SNikolas Klauser     }
100*1306b102SNikolas Klauser     {
101*1306b102SNikolas Klauser       std::array a = {2};
102*1306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
103*1306b102SNikolas Klauser       auto ret = std::ranges::count(range, 2);
104*1306b102SNikolas Klauser       assert(ret == 1);
105*1306b102SNikolas Klauser     }
106*1306b102SNikolas Klauser   }
107*1306b102SNikolas Klauser 
108*1306b102SNikolas Klauser   {
109*1306b102SNikolas Klauser     // check that 0 is returned with no match
110*1306b102SNikolas Klauser     {
111*1306b102SNikolas Klauser       std::array a = {1, 1, 1};
112*1306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0);
113*1306b102SNikolas Klauser       assert(ret == 0);
114*1306b102SNikolas Klauser     }
115*1306b102SNikolas Klauser     {
116*1306b102SNikolas Klauser       std::array a = {1, 1, 1};
117*1306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
118*1306b102SNikolas Klauser       auto ret = std::ranges::count(range, 0);
119*1306b102SNikolas Klauser       assert(ret == 0);
120*1306b102SNikolas Klauser     }
121*1306b102SNikolas Klauser   }
122*1306b102SNikolas Klauser 
123*1306b102SNikolas Klauser   {
124*1306b102SNikolas Klauser     // check that more than one element is counted
125*1306b102SNikolas Klauser     {
126*1306b102SNikolas Klauser       std::array a = {3, 3, 4, 3, 3};
127*1306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3);
128*1306b102SNikolas Klauser       assert(ret == 4);
129*1306b102SNikolas Klauser     }
130*1306b102SNikolas Klauser     {
131*1306b102SNikolas Klauser       std::array a = {3, 3, 4, 3, 3};
132*1306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
133*1306b102SNikolas Klauser       auto ret = std::ranges::count(range, 3);
134*1306b102SNikolas Klauser       assert(ret == 4);
135*1306b102SNikolas Klauser     }
136*1306b102SNikolas Klauser   }
137*1306b102SNikolas Klauser 
138*1306b102SNikolas Klauser   {
139*1306b102SNikolas Klauser     // check that all elements are counted
140*1306b102SNikolas Klauser     {
141*1306b102SNikolas Klauser       std::array a = {5, 5, 5, 5};
142*1306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5);
143*1306b102SNikolas Klauser       assert(ret == 4);
144*1306b102SNikolas Klauser     }
145*1306b102SNikolas Klauser     {
146*1306b102SNikolas Klauser       std::array a = {5, 5, 5, 5};
147*1306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
148*1306b102SNikolas Klauser       auto ret = std::ranges::count(range, 5);
149*1306b102SNikolas Klauser       assert(ret == 4);
150*1306b102SNikolas Klauser     }
151*1306b102SNikolas Klauser   }
152*1306b102SNikolas Klauser }
153*1306b102SNikolas Klauser 
test()154*1306b102SNikolas Klauser constexpr bool test() {
155*1306b102SNikolas Klauser   test_iterators<int*>();
156*1306b102SNikolas Klauser   test_iterators<const int*>();
157*1306b102SNikolas Klauser   test_iterators<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
158*1306b102SNikolas Klauser   test_iterators<bidirectional_iterator<int*>>();
159*1306b102SNikolas Klauser   test_iterators<forward_iterator<int*>>();
160*1306b102SNikolas Klauser   test_iterators<random_access_iterator<int*>>();
161*1306b102SNikolas Klauser   test_iterators<contiguous_iterator<int*>>();
162*1306b102SNikolas Klauser 
163*1306b102SNikolas Klauser   {
164*1306b102SNikolas Klauser     // check that projections are used properly and that they are called with the iterator directly
165*1306b102SNikolas Klauser     {
166*1306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
167*1306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; });
168*1306b102SNikolas Klauser       assert(ret == 1);
169*1306b102SNikolas Klauser     }
170*1306b102SNikolas Klauser     {
171*1306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
172*1306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; });
173*1306b102SNikolas Klauser       assert(ret == 1);
174*1306b102SNikolas Klauser     }
175*1306b102SNikolas Klauser   }
176*1306b102SNikolas Klauser 
177*1306b102SNikolas Klauser   {
178*1306b102SNikolas Klauser     // check that std::invoke is used
179*1306b102SNikolas Klauser     struct S { int i; };
180*1306b102SNikolas Klauser     S a[] = { S{1}, S{3}, S{2} };
181*1306b102SNikolas Klauser     std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(a, 4, &S::i);
182*1306b102SNikolas Klauser     assert(ret == 0);
183*1306b102SNikolas Klauser   }
184*1306b102SNikolas Klauser 
185*1306b102SNikolas Klauser   {
186*1306b102SNikolas Klauser     // count invocations of the projection
187*1306b102SNikolas Klauser     {
188*1306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
189*1306b102SNikolas Klauser       int projection_count = 0;
190*1306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; });
191*1306b102SNikolas Klauser       assert(ret == 1);
192*1306b102SNikolas Klauser       assert(projection_count == 4);
193*1306b102SNikolas Klauser     }
194*1306b102SNikolas Klauser     {
195*1306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
196*1306b102SNikolas Klauser       int projection_count = 0;
197*1306b102SNikolas Klauser       auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; });
198*1306b102SNikolas Klauser       assert(ret == 1);
199*1306b102SNikolas Klauser       assert(projection_count == 4);
200*1306b102SNikolas Klauser     }
201*1306b102SNikolas Klauser   }
202*1306b102SNikolas Klauser 
203*1306b102SNikolas Klauser   {
204*1306b102SNikolas Klauser     // check that an immobile type works
205*1306b102SNikolas Klauser     struct NonMovable {
206*1306b102SNikolas Klauser       NonMovable(const NonMovable&) = delete;
207*1306b102SNikolas Klauser       NonMovable(NonMovable&&) = delete;
208*1306b102SNikolas Klauser       constexpr NonMovable(int i_) : i(i_) {}
209*1306b102SNikolas Klauser       int i;
210*1306b102SNikolas Klauser 
211*1306b102SNikolas Klauser       bool operator==(const NonMovable&) const = default;
212*1306b102SNikolas Klauser     };
213*1306b102SNikolas Klauser     {
214*1306b102SNikolas Klauser       NonMovable a[] = {9, 8, 4, 3};
215*1306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 4, NonMovable(8));
216*1306b102SNikolas Klauser       assert(ret == 1);
217*1306b102SNikolas Klauser     }
218*1306b102SNikolas Klauser     {
219*1306b102SNikolas Klauser       NonMovable a[] = {9, 8, 4, 3};
220*1306b102SNikolas Klauser       auto ret = std::ranges::count(a, NonMovable(8));
221*1306b102SNikolas Klauser       assert(ret == 1);
222*1306b102SNikolas Klauser     }
223*1306b102SNikolas Klauser   }
224*1306b102SNikolas Klauser 
225*1306b102SNikolas Klauser   {
226*1306b102SNikolas Klauser     // check that difference_type is used
227*1306b102SNikolas Klauser     struct DiffTypeIterator {
228*1306b102SNikolas Klauser       using difference_type = signed char;
229*1306b102SNikolas Klauser       using value_type = int;
230*1306b102SNikolas Klauser 
231*1306b102SNikolas Klauser       int* it = nullptr;
232*1306b102SNikolas Klauser 
233*1306b102SNikolas Klauser       constexpr DiffTypeIterator() = default;
234*1306b102SNikolas Klauser       constexpr DiffTypeIterator(int* i) : it(i) {}
235*1306b102SNikolas Klauser 
236*1306b102SNikolas Klauser       constexpr int& operator*() const { return *it; }
237*1306b102SNikolas Klauser       constexpr DiffTypeIterator& operator++() { ++it; return *this; }
238*1306b102SNikolas Klauser       constexpr void operator++(int) { ++it; }
239*1306b102SNikolas Klauser 
240*1306b102SNikolas Klauser       bool operator==(const DiffTypeIterator&) const = default;
241*1306b102SNikolas Klauser     };
242*1306b102SNikolas Klauser 
243*1306b102SNikolas Klauser     {
244*1306b102SNikolas Klauser       int a[] = {5, 5, 4, 3, 2, 1};
245*1306b102SNikolas Klauser       std::same_as<signed char> decltype(auto) ret =
246*1306b102SNikolas Klauser           std::ranges::count(DiffTypeIterator(a), DiffTypeIterator(a + 6), 4);
247*1306b102SNikolas Klauser       assert(ret == 1);
248*1306b102SNikolas Klauser     }
249*1306b102SNikolas Klauser     {
250*1306b102SNikolas Klauser       int a[] = {5, 5, 4, 3, 2, 1};
251*1306b102SNikolas Klauser       auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6));
252*1306b102SNikolas Klauser       std::same_as<signed char> decltype(auto) ret = std::ranges::count(range, 4);
253*1306b102SNikolas Klauser       assert(ret == 1);
254*1306b102SNikolas Klauser     }
255*1306b102SNikolas Klauser   }
256*1306b102SNikolas Klauser 
257*1306b102SNikolas Klauser   return true;
258*1306b102SNikolas Klauser }
259*1306b102SNikolas Klauser 
main(int,char **)260*1306b102SNikolas Klauser int main(int, char**) {
261*1306b102SNikolas Klauser   test();
262*1306b102SNikolas Klauser   static_assert(test());
263*1306b102SNikolas Klauser 
264*1306b102SNikolas Klauser   return 0;
265*1306b102SNikolas Klauser }
266