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