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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 13 14 // template<input_iterator I, sentinel_for<I> S, class Proj = identity, 15 // indirect_unary_predicate<projected<I, Proj>> Pred> 16 // constexpr iter_difference_t<I> 17 // ranges::count_if(I first, S last, Pred pred, Proj proj = {}); 18 // template<input_range R, class Proj = identity, 19 // indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred> 20 // constexpr range_difference_t<R> 21 // ranges::count_if(R&& r, Pred pred, Proj proj = {}); 22 23 #include <algorithm> 24 #include <array> 25 #include <cassert> 26 #include <ranges> 27 28 #include "almost_satisfies_types.h" 29 #include "test_iterators.h" 30 31 struct Predicate { 32 bool operator()(int); 33 }; 34 35 template <class It, class Sent = It> 36 concept HasCountIfIt = requires(It it, Sent sent) { std::ranges::count_if(it, sent, Predicate{}); }; 37 static_assert(HasCountIfIt<int*>); 38 static_assert(!HasCountIfIt<InputIteratorNotDerivedFrom>); 39 static_assert(!HasCountIfIt<InputIteratorNotIndirectlyReadable>); 40 static_assert(!HasCountIfIt<InputIteratorNotInputOrOutputIterator>); 41 static_assert(!HasCountIfIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>); 42 static_assert(!HasCountIfIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>); 43 44 static_assert(!HasCountIfIt<int*, int>); 45 static_assert(!HasCountIfIt<int, int*>); 46 47 template <class Pred> 48 concept HasCountIfPred = requires(int* it, Pred pred) {std::ranges::count_if(it, it, pred); }; 49 50 static_assert(!HasCountIfPred<IndirectUnaryPredicateNotCopyConstructible>); 51 static_assert(!HasCountIfPred<IndirectUnaryPredicateNotPredicate>); 52 53 template <class R> 54 concept HasCountIfR = requires(R r) { std::ranges::count_if(r, Predicate{}); }; 55 static_assert(HasCountIfR<std::array<int, 0>>); 56 static_assert(!HasCountIfR<int>); 57 static_assert(!HasCountIfR<InputRangeNotDerivedFrom>); 58 static_assert(!HasCountIfR<InputRangeNotIndirectlyReadable>); 59 static_assert(!HasCountIfR<InputRangeNotInputOrOutputIterator>); 60 static_assert(!HasCountIfR<InputRangeNotSentinelSemiregular>); 61 static_assert(!HasCountIfR<InputRangeNotSentinelEqualityComparableWith>); 62 63 template <class It, class Sent = It> 64 constexpr void test_iterators() { 65 { 66 // simple test 67 { 68 int a[] = {1, 2, 3, 4}; 69 std::same_as<std::ptrdiff_t> auto ret = 70 std::ranges::count_if(It(a), Sent(It(a + 4)), [](int x) { return x == 4; }); 71 assert(ret == 1); 72 } 73 { 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 = 77 std::ranges::count_if(range, [](int x) { return x == 4; }); 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_if(It(a.data()), Sent(It(a.data() + a.size())), [](int) { return true; }); 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_if(range, [](int) { return true; }); 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_if(It(a.data()), Sent(It(a.data() + a.size())), [](int i) { return i == 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_if(range, [](int i) { return i == 2; }); 108 assert(ret == 1); 109 } 110 } 111 112 { 113 // check that 0 is returned with no match 114 { 115 int a[] = {1, 1, 1}; 116 auto ret = std::ranges::count_if(It(a), Sent(It(a + 3)), [](int) { return false; }); 117 assert(ret == 0); 118 } 119 { 120 int a[] = {1, 1, 1}; 121 auto range = std::ranges::subrange(It(a), Sent(It(a + 3))); 122 auto ret = std::ranges::count_if(range, [](int){ return false; }); 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_if(It(a.data()), Sent(It(a.data() + a.size())), [](int i) { return i == 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_if(range, [](int i) { return i == 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_if(It(a.data()), Sent(It(a.data() + a.size())), [](int) { return true; }); 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_if(range, [](int) { return true; }); 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_if(a, a + 4, [&](int* i) { return i == 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_if(a, [&](int* i) { return i == a + 3; }, [](int& i) { return &i; }); 177 assert(ret == 1); 178 } 179 } 180 181 { 182 // check that std::invoke is used 183 { 184 struct S { 185 int comp; 186 int other; 187 }; 188 S a[] = { {0, 0}, {0, 2}, {0, 1} }; 189 auto ret = std::ranges::count_if(a, [](int i){ return i == 0; }, &S::comp); 190 assert(ret == 3); 191 } 192 { 193 struct S { 194 int comp; 195 int other; 196 }; 197 S a[] = { {0, 0}, {0, 2}, {0, 1} }; 198 auto ret = std::ranges::count_if(a, a + 3, [](int i) { return i == 0; }, &S::comp); 199 assert(ret == 3); 200 } 201 } 202 203 { 204 // check projection and predicate invocation count 205 { 206 int a[] = {1, 2, 3, 4}; 207 int predicate_count = 0; 208 int projection_count = 0; 209 auto ret = std::ranges::count_if(a, a + 4, 210 [&](int i) { ++predicate_count; return i == 2; }, 211 [&](int i) { ++projection_count; return i; }); 212 assert(ret == 1); 213 assert(predicate_count == 4); 214 assert(projection_count == 4); 215 } 216 { 217 int a[] = {1, 2, 3, 4}; 218 int predicate_count = 0; 219 int projection_count = 0; 220 auto ret = std::ranges::count_if(a, 221 [&](int i) { ++predicate_count; return i == 2; }, 222 [&](int i) { ++projection_count; return i; }); 223 assert(ret == 1); 224 assert(predicate_count == 4); 225 assert(projection_count == 4); 226 } 227 } 228 229 { 230 // check that an immobile type works 231 struct NonMovable { 232 NonMovable(const NonMovable&) = delete; 233 NonMovable(NonMovable&&) = delete; 234 constexpr NonMovable(int i_) : i(i_) {} 235 int i; 236 237 bool operator==(const NonMovable&) const = default; 238 }; 239 { 240 NonMovable a[] = {9, 8, 4, 3}; 241 auto ret = std::ranges::count_if(a, a + 4, [](const NonMovable& i) { return i == NonMovable(8); }); 242 assert(ret == 1); 243 } 244 { 245 NonMovable a[] = {9, 8, 4, 3}; 246 auto ret = std::ranges::count_if(a, [](const NonMovable& i) { return i == NonMovable(8); }); 247 assert(ret == 1); 248 } 249 } 250 251 { 252 // check that difference_type is used 253 struct DiffTypeIterator { 254 using difference_type = signed char; 255 using value_type = int; 256 257 int* it = nullptr; 258 259 constexpr DiffTypeIterator() = default; 260 constexpr DiffTypeIterator(int* i) : it(i) {} 261 262 constexpr int& operator*() const { return *it; } 263 constexpr DiffTypeIterator& operator++() { ++it; return *this; } 264 constexpr void operator++(int) { ++it; } 265 266 bool operator==(const DiffTypeIterator&) const = default; 267 }; 268 269 { 270 int a[] = {5, 5, 4, 3, 2, 1}; 271 std::same_as<signed char> auto ret = 272 std::ranges::count_if(DiffTypeIterator(a), DiffTypeIterator(a + 6), [](int& i) { return i == 4; }); 273 assert(ret == 1); 274 } 275 { 276 int a[] = {5, 5, 4, 3, 2, 1}; 277 auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6)); 278 std::same_as<signed char> auto ret = std::ranges::count_if(range, [](int& i) { return i == 4; }); 279 assert(ret == 1); 280 } 281 } 282 283 { 284 // check that the predicate can take the argument by lvalue ref 285 { 286 int a[] = {9, 8, 4, 3}; 287 auto ret = std::ranges::count_if(a, a + 4, [](int& i) { return i == 8; }); 288 assert(ret == 1); 289 } 290 { 291 int a[] = {9, 8, 4, 3}; 292 auto ret = std::ranges::count_if(a, [](int& i) { return i == 8; }); 293 assert(ret == 1); 294 } 295 } 296 297 { 298 // check that the predicate isn't made const 299 struct MutablePredicate { 300 constexpr bool operator()(int i) & { return i == 8; } 301 constexpr bool operator()(int i) && { return i == 8; } 302 }; 303 { 304 int a[] = {9, 8, 4, 3}; 305 auto ret = std::ranges::count_if(a, a + 4, MutablePredicate{}); 306 assert(ret == 1); 307 } 308 { 309 int a[] = {9, 8, 4, 3}; 310 auto ret = std::ranges::count_if(a, MutablePredicate{}); 311 assert(ret == 1); 312 } 313 } 314 315 return true; 316 } 317 318 int main(int, char**) { 319 test(); 320 static_assert(test()); 321 322 return 0; 323 } 324