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