xref: /llvm-project/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp (revision e99c4906e44ae3f921fa05356909d006cda8d954)
11306b102SNikolas Klauser //===----------------------------------------------------------------------===//
21306b102SNikolas Klauser //
31306b102SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41306b102SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
51306b102SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61306b102SNikolas Klauser //
71306b102SNikolas Klauser //===----------------------------------------------------------------------===//
81306b102SNikolas Klauser 
91306b102SNikolas Klauser // <algorithm>
101306b102SNikolas Klauser 
111306b102SNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
121306b102SNikolas Klauser 
13a9138cdbSNikolas Klauser // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
1407b18c5eSNikolas Klauser // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000
15a9138cdbSNikolas Klauser 
161306b102SNikolas Klauser // template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
171306b102SNikolas Klauser //   requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
181306b102SNikolas Klauser //   constexpr iter_difference_t<I>
191306b102SNikolas Klauser //     ranges::count(I first, S last, const T& value, Proj proj = {});
201306b102SNikolas Klauser // template<input_range R, class T, class Proj = identity>
211306b102SNikolas Klauser //   requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
221306b102SNikolas Klauser //   constexpr range_difference_t<R>
231306b102SNikolas Klauser //     ranges::count(R&& r, const T& value, Proj proj = {});
241306b102SNikolas Klauser 
251306b102SNikolas Klauser #include <algorithm>
261306b102SNikolas Klauser #include <array>
271306b102SNikolas Klauser #include <cassert>
28*e99c4906SNikolas Klauser #include <cstddef>
291306b102SNikolas Klauser #include <ranges>
30a9138cdbSNikolas Klauser #include <vector>
311306b102SNikolas Klauser 
321306b102SNikolas Klauser #include "almost_satisfies_types.h"
331306b102SNikolas Klauser #include "test_iterators.h"
341306b102SNikolas Klauser 
351306b102SNikolas Klauser struct NotEqualityComparable {
361306b102SNikolas Klauser   bool operator==(NotEqualityComparable&&) const;
371306b102SNikolas Klauser   bool operator==(NotEqualityComparable&) const;
381306b102SNikolas Klauser   bool operator==(const NotEqualityComparable&&) const;
391306b102SNikolas Klauser };
401306b102SNikolas Klauser 
411306b102SNikolas Klauser template <class It, class Sent = It>
421306b102SNikolas Klauser concept HasCountIt = requires(It it, Sent sent) { std::ranges::count(it, sent, *it); };
431306b102SNikolas Klauser static_assert(HasCountIt<int*>);
441306b102SNikolas Klauser static_assert(!HasCountIt<NotEqualityComparable*>);
451306b102SNikolas Klauser static_assert(!HasCountIt<InputIteratorNotDerivedFrom>);
461306b102SNikolas Klauser static_assert(!HasCountIt<InputIteratorNotIndirectlyReadable>);
471306b102SNikolas Klauser static_assert(!HasCountIt<InputIteratorNotInputOrOutputIterator>);
481306b102SNikolas Klauser static_assert(!HasCountIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
491306b102SNikolas Klauser static_assert(!HasCountIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
501306b102SNikolas Klauser 
511306b102SNikolas Klauser static_assert(!HasCountIt<int*, int>);
521306b102SNikolas Klauser static_assert(!HasCountIt<int, int*>);
531306b102SNikolas Klauser 
541306b102SNikolas Klauser template <class Range, class ValT>
551306b102SNikolas Klauser concept HasCountR = requires(Range r) { std::ranges::count(r, ValT{}); };
561306b102SNikolas Klauser static_assert(HasCountR<std::array<int, 1>, int>);
571306b102SNikolas Klauser static_assert(!HasCountR<int, int>);
581306b102SNikolas Klauser static_assert(!HasCountR<std::array<NotEqualityComparable, 1>, NotEqualityComparable>);
591306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotDerivedFrom, int>);
601306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotIndirectlyReadable, int>);
611306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotInputOrOutputIterator, int>);
621306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotSentinelSemiregular, int>);
631306b102SNikolas Klauser static_assert(!HasCountR<InputRangeNotSentinelEqualityComparableWith, int>);
641306b102SNikolas Klauser 
651306b102SNikolas Klauser template <class It, class Sent = It>
661306b102SNikolas Klauser constexpr void test_iterators() {
671306b102SNikolas Klauser   {
681306b102SNikolas Klauser     // simple test
691306b102SNikolas Klauser     {
701306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
711306b102SNikolas Klauser       std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3);
721306b102SNikolas Klauser       assert(ret == 1);
731306b102SNikolas Klauser     }
741306b102SNikolas Klauser     {
751306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
761306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));
771306b102SNikolas Klauser       std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(range, 3);
781306b102SNikolas Klauser       assert(ret == 1);
791306b102SNikolas Klauser     }
801306b102SNikolas Klauser   }
811306b102SNikolas Klauser 
821306b102SNikolas Klauser   {
831306b102SNikolas Klauser     // check that an empty range works
841306b102SNikolas Klauser     {
851306b102SNikolas Klauser       std::array<int, 0> a = {};
861306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1);
871306b102SNikolas Klauser       assert(ret == 0);
881306b102SNikolas Klauser     }
891306b102SNikolas Klauser     {
901306b102SNikolas Klauser       std::array<int, 0> a = {};
911306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
921306b102SNikolas Klauser       auto ret = std::ranges::count(range, 1);
931306b102SNikolas Klauser       assert(ret == 0);
941306b102SNikolas Klauser     }
951306b102SNikolas Klauser   }
961306b102SNikolas Klauser 
971306b102SNikolas Klauser   {
981306b102SNikolas Klauser     // check that a range with a single element works
991306b102SNikolas Klauser     {
1001306b102SNikolas Klauser       std::array a = {2};
1011306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2);
1021306b102SNikolas Klauser       assert(ret == 1);
1031306b102SNikolas Klauser     }
1041306b102SNikolas Klauser     {
1051306b102SNikolas Klauser       std::array a = {2};
1061306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
1071306b102SNikolas Klauser       auto ret = std::ranges::count(range, 2);
1081306b102SNikolas Klauser       assert(ret == 1);
1091306b102SNikolas Klauser     }
1101306b102SNikolas Klauser   }
1111306b102SNikolas Klauser 
1121306b102SNikolas Klauser   {
1131306b102SNikolas Klauser     // check that 0 is returned with no match
1141306b102SNikolas Klauser     {
1151306b102SNikolas Klauser       std::array a = {1, 1, 1};
1161306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0);
1171306b102SNikolas Klauser       assert(ret == 0);
1181306b102SNikolas Klauser     }
1191306b102SNikolas Klauser     {
1201306b102SNikolas Klauser       std::array a = {1, 1, 1};
1211306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
1221306b102SNikolas Klauser       auto ret = std::ranges::count(range, 0);
1231306b102SNikolas Klauser       assert(ret == 0);
1241306b102SNikolas Klauser     }
1251306b102SNikolas Klauser   }
1261306b102SNikolas Klauser 
1271306b102SNikolas Klauser   {
1281306b102SNikolas Klauser     // check that more than one element is counted
1291306b102SNikolas Klauser     {
1301306b102SNikolas Klauser       std::array a = {3, 3, 4, 3, 3};
1311306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3);
1321306b102SNikolas Klauser       assert(ret == 4);
1331306b102SNikolas Klauser     }
1341306b102SNikolas Klauser     {
1351306b102SNikolas Klauser       std::array a = {3, 3, 4, 3, 3};
1361306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
1371306b102SNikolas Klauser       auto ret = std::ranges::count(range, 3);
1381306b102SNikolas Klauser       assert(ret == 4);
1391306b102SNikolas Klauser     }
1401306b102SNikolas Klauser   }
1411306b102SNikolas Klauser 
1421306b102SNikolas Klauser   {
1431306b102SNikolas Klauser     // check that all elements are counted
1441306b102SNikolas Klauser     {
1451306b102SNikolas Klauser       std::array a = {5, 5, 5, 5};
1461306b102SNikolas Klauser       auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5);
1471306b102SNikolas Klauser       assert(ret == 4);
1481306b102SNikolas Klauser     }
1491306b102SNikolas Klauser     {
1501306b102SNikolas Klauser       std::array a = {5, 5, 5, 5};
1511306b102SNikolas Klauser       auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size())));
1521306b102SNikolas Klauser       auto ret = std::ranges::count(range, 5);
1531306b102SNikolas Klauser       assert(ret == 4);
1541306b102SNikolas Klauser     }
1551306b102SNikolas Klauser   }
1561306b102SNikolas Klauser }
1571306b102SNikolas Klauser 
1581306b102SNikolas Klauser constexpr bool test() {
1591306b102SNikolas Klauser   test_iterators<int*>();
1601306b102SNikolas Klauser   test_iterators<const int*>();
1611306b102SNikolas Klauser   test_iterators<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
1621306b102SNikolas Klauser   test_iterators<bidirectional_iterator<int*>>();
1631306b102SNikolas Klauser   test_iterators<forward_iterator<int*>>();
1641306b102SNikolas Klauser   test_iterators<random_access_iterator<int*>>();
1651306b102SNikolas Klauser   test_iterators<contiguous_iterator<int*>>();
1661306b102SNikolas Klauser 
1671306b102SNikolas Klauser   {
1681306b102SNikolas Klauser     // check that projections are used properly and that they are called with the iterator directly
1691306b102SNikolas Klauser     {
1701306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
1711306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; });
1721306b102SNikolas Klauser       assert(ret == 1);
1731306b102SNikolas Klauser     }
1741306b102SNikolas Klauser     {
1751306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
1761306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; });
1771306b102SNikolas Klauser       assert(ret == 1);
1781306b102SNikolas Klauser     }
1791306b102SNikolas Klauser   }
1801306b102SNikolas Klauser 
1811306b102SNikolas Klauser   {
1821306b102SNikolas Klauser     // check that std::invoke is used
1831306b102SNikolas Klauser     struct S { int i; };
1841306b102SNikolas Klauser     S a[] = { S{1}, S{3}, S{2} };
1851306b102SNikolas Klauser     std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(a, 4, &S::i);
1861306b102SNikolas Klauser     assert(ret == 0);
1871306b102SNikolas Klauser   }
1881306b102SNikolas Klauser 
1891306b102SNikolas Klauser   {
1901306b102SNikolas Klauser     // count invocations of the projection
1911306b102SNikolas Klauser     {
1921306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
1931306b102SNikolas Klauser       int projection_count = 0;
1941306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; });
1951306b102SNikolas Klauser       assert(ret == 1);
1961306b102SNikolas Klauser       assert(projection_count == 4);
1971306b102SNikolas Klauser     }
1981306b102SNikolas Klauser     {
1991306b102SNikolas Klauser       int a[] = {1, 2, 3, 4};
2001306b102SNikolas Klauser       int projection_count = 0;
2011306b102SNikolas Klauser       auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; });
2021306b102SNikolas Klauser       assert(ret == 1);
2031306b102SNikolas Klauser       assert(projection_count == 4);
2041306b102SNikolas Klauser     }
2051306b102SNikolas Klauser   }
2061306b102SNikolas Klauser 
2071306b102SNikolas Klauser   {
2081306b102SNikolas Klauser     // check that an immobile type works
2091306b102SNikolas Klauser     struct NonMovable {
2101306b102SNikolas Klauser       NonMovable(const NonMovable&) = delete;
2111306b102SNikolas Klauser       NonMovable(NonMovable&&) = delete;
2121306b102SNikolas Klauser       constexpr NonMovable(int i_) : i(i_) {}
2131306b102SNikolas Klauser       int i;
2141306b102SNikolas Klauser 
2151306b102SNikolas Klauser       bool operator==(const NonMovable&) const = default;
2161306b102SNikolas Klauser     };
2171306b102SNikolas Klauser     {
2181306b102SNikolas Klauser       NonMovable a[] = {9, 8, 4, 3};
2191306b102SNikolas Klauser       auto ret = std::ranges::count(a, a + 4, NonMovable(8));
2201306b102SNikolas Klauser       assert(ret == 1);
2211306b102SNikolas Klauser     }
2221306b102SNikolas Klauser     {
2231306b102SNikolas Klauser       NonMovable a[] = {9, 8, 4, 3};
2241306b102SNikolas Klauser       auto ret = std::ranges::count(a, NonMovable(8));
2251306b102SNikolas Klauser       assert(ret == 1);
2261306b102SNikolas Klauser     }
2271306b102SNikolas Klauser   }
2281306b102SNikolas Klauser 
2291306b102SNikolas Klauser   {
2301306b102SNikolas Klauser     // check that difference_type is used
2311306b102SNikolas Klauser     struct DiffTypeIterator {
2321306b102SNikolas Klauser       using difference_type = signed char;
2331306b102SNikolas Klauser       using value_type = int;
2341306b102SNikolas Klauser 
2351306b102SNikolas Klauser       int* it = nullptr;
2361306b102SNikolas Klauser 
2371306b102SNikolas Klauser       constexpr DiffTypeIterator() = default;
2381306b102SNikolas Klauser       constexpr DiffTypeIterator(int* i) : it(i) {}
2391306b102SNikolas Klauser 
2401306b102SNikolas Klauser       constexpr int& operator*() const { return *it; }
2411306b102SNikolas Klauser       constexpr DiffTypeIterator& operator++() { ++it; return *this; }
2421306b102SNikolas Klauser       constexpr void operator++(int) { ++it; }
2431306b102SNikolas Klauser 
2441306b102SNikolas Klauser       bool operator==(const DiffTypeIterator&) const = default;
2451306b102SNikolas Klauser     };
2461306b102SNikolas Klauser 
2471306b102SNikolas Klauser     {
2481306b102SNikolas Klauser       int a[] = {5, 5, 4, 3, 2, 1};
2491306b102SNikolas Klauser       std::same_as<signed char> decltype(auto) ret =
2501306b102SNikolas Klauser           std::ranges::count(DiffTypeIterator(a), DiffTypeIterator(a + 6), 4);
2511306b102SNikolas Klauser       assert(ret == 1);
2521306b102SNikolas Klauser     }
2531306b102SNikolas Klauser     {
2541306b102SNikolas Klauser       int a[] = {5, 5, 4, 3, 2, 1};
2551306b102SNikolas Klauser       auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6));
2561306b102SNikolas Klauser       std::same_as<signed char> decltype(auto) ret = std::ranges::count(range, 4);
2571306b102SNikolas Klauser       assert(ret == 1);
2581306b102SNikolas Klauser     }
2591306b102SNikolas Klauser   }
2601306b102SNikolas Klauser 
261a9138cdbSNikolas Klauser   { // check that __bit_iterator optimizations work as expected
262a9138cdbSNikolas Klauser     std::vector<bool> vec(256 + 64);
263a9138cdbSNikolas Klauser     for (ptrdiff_t i = 0; i != 256; ++i) {
264a9138cdbSNikolas Klauser       for (size_t offset = 0; offset != 64; ++offset) {
265a9138cdbSNikolas Klauser         std::fill(vec.begin(), vec.end(), false);
266a9138cdbSNikolas Klauser         std::fill(vec.begin() + offset, vec.begin() + i + offset, true);
267a9138cdbSNikolas Klauser         assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, true) == i);
268a9138cdbSNikolas Klauser         assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, false) == 256 - i);
269a9138cdbSNikolas Klauser       }
270a9138cdbSNikolas Klauser     }
271a9138cdbSNikolas Klauser   }
272a9138cdbSNikolas Klauser 
2731306b102SNikolas Klauser   return true;
2741306b102SNikolas Klauser }
2751306b102SNikolas Klauser 
2761306b102SNikolas Klauser int main(int, char**) {
2771306b102SNikolas Klauser   test();
2781306b102SNikolas Klauser   static_assert(test());
2791306b102SNikolas Klauser 
2801306b102SNikolas Klauser   return 0;
2811306b102SNikolas Klauser }
282