Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / std / algorithms / alg.nonmodifying / alg.count / ranges.count.pass.cpp
blobb17272ea90cdddcf4d65822334696bb2faf277d3
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 //===----------------------------------------------------------------------===//
9 // <algorithm>
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 = {});
25 #include <algorithm>
26 #include <array>
27 #include <cassert>
28 #include <ranges>
29 #include <vector>
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() {
67 // simple test
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);
71 assert(ret == 1);
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);
77 assert(ret == 1);
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);
86 assert(ret == 0);
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);
92 assert(ret == 0);
97 // check that a range with a single element works
99 std::array a = {2};
100 auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2);
101 assert(ret == 1);
104 std::array a = {2};
105 auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
106 auto ret = std::ranges::count(range, 2);
107 assert(ret == 1);
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);
116 assert(ret == 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);
122 assert(ret == 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);
131 assert(ret == 4);
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);
137 assert(ret == 4);
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);
146 assert(ret == 4);
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);
152 assert(ret == 4);
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; });
171 assert(ret == 1);
174 int a[] = {1, 2, 3, 4};
175 auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; });
176 assert(ret == 1);
181 // check that std::invoke is used
182 struct S { int i; };
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);
185 assert(ret == 0);
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; });
194 assert(ret == 1);
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; });
201 assert(ret == 1);
202 assert(projection_count == 4);
207 // check that an immobile type works
208 struct NonMovable {
209 NonMovable(const NonMovable&) = delete;
210 NonMovable(NonMovable&&) = delete;
211 constexpr NonMovable(int i_) : i(i_) {}
212 int 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));
219 assert(ret == 1);
222 NonMovable a[] = {9, 8, 4, 3};
223 auto ret = std::ranges::count(a, NonMovable(8));
224 assert(ret == 1);
229 // check that difference_type is used
230 struct DiffTypeIterator {
231 using difference_type = signed char;
232 using value_type = int;
234 int* it = nullptr;
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);
250 assert(ret == 1);
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);
256 assert(ret == 1);
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);
272 return true;
275 int main(int, char**) {
276 test();
277 static_assert(test());
279 return 0;