brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.9 KiB · df34618 Raw
323 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// <algorithm>10 11// UNSUPPORTED: c++03, c++11, c++14, c++1712 13// template<input_iterator I, sentinel_for<I> S, class Proj = identity,14//          indirect_unary_predicate<projected<I, Proj>> Pred>15//   constexpr iter_difference_t<I>16//     ranges::count_if(I first, S last, Pred pred, Proj proj = {});17// template<input_range R, class Proj = identity,18//          indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>19//   constexpr range_difference_t<R>20//     ranges::count_if(R&& r, Pred pred, 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 30struct Predicate {31  bool operator()(int);32};33 34template <class It, class Sent = It>35concept HasCountIfIt = requires(It it, Sent sent) { std::ranges::count_if(it, sent, Predicate{}); };36static_assert(HasCountIfIt<int*>);37static_assert(!HasCountIfIt<InputIteratorNotDerivedFrom>);38static_assert(!HasCountIfIt<InputIteratorNotIndirectlyReadable>);39static_assert(!HasCountIfIt<InputIteratorNotInputOrOutputIterator>);40static_assert(!HasCountIfIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);41static_assert(!HasCountIfIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);42 43static_assert(!HasCountIfIt<int*, int>);44static_assert(!HasCountIfIt<int, int*>);45 46template <class Pred>47concept HasCountIfPred = requires(int* it, Pred pred) {std::ranges::count_if(it, it, pred); };48 49static_assert(!HasCountIfPred<IndirectUnaryPredicateNotCopyConstructible>);50static_assert(!HasCountIfPred<IndirectUnaryPredicateNotPredicate>);51 52template <class R>53concept HasCountIfR = requires(R r) { std::ranges::count_if(r, Predicate{}); };54static_assert(HasCountIfR<std::array<int, 0>>);55static_assert(!HasCountIfR<int>);56static_assert(!HasCountIfR<InputRangeNotDerivedFrom>);57static_assert(!HasCountIfR<InputRangeNotIndirectlyReadable>);58static_assert(!HasCountIfR<InputRangeNotInputOrOutputIterator>);59static_assert(!HasCountIfR<InputRangeNotSentinelSemiregular>);60static_assert(!HasCountIfR<InputRangeNotSentinelEqualityComparableWith>);61 62template <class It, class Sent = It>63constexpr void test_iterators() {64  {65    // simple test66    {67      int a[] = {1, 2, 3, 4};68      std::same_as<std::ptrdiff_t> auto ret =69        std::ranges::count_if(It(a), Sent(It(a + 4)), [](int x) { return x == 4; });70      assert(ret == 1);71    }72    {73      int a[] = {1, 2, 3, 4};74      auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));75      std::same_as<std::ptrdiff_t> auto ret =76        std::ranges::count_if(range, [](int x) { return x == 4; });77      assert(ret == 1);78    }79  }80 81  {82    // check that an empty range works83    {84      std::array<int, 0> a = {};85      auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int) { return true; });86      assert(ret == 0);87    }88    {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_if(range, [](int) { return true; });92      assert(ret == 0);93    }94  }95 96  {97    // check that a range with a single element works98    {99      std::array a = {2};100      auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int i) { return i == 2; });101      assert(ret == 1);102    }103    {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_if(range, [](int i) { return i == 2; });107      assert(ret == 1);108    }109  }110 111  {112    // check that 0 is returned with no match113    {114      int a[] = {1, 1, 1};115      auto ret = std::ranges::count_if(It(a), Sent(It(a + 3)), [](int) { return false; });116      assert(ret == 0);117    }118    {119      int a[] = {1, 1, 1};120      auto range = std::ranges::subrange(It(a), Sent(It(a + 3)));121      auto ret = std::ranges::count_if(range, [](int){ return false; });122      assert(ret == 0);123    }124  }125 126  {127    // check that more than one element is counted128    {129      std::array a = {3, 3, 4, 3, 3};130      auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int i) { return i == 3; });131      assert(ret == 4);132    }133    {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_if(range, [](int i) { return i == 3; });137      assert(ret == 4);138    }139  }140 141  {142    // check that all elements are counted143    {144      std::array a = {5, 5, 5, 5};145      auto ret = std::ranges::count_if(It(a.data()), Sent(It(a.data() + a.size())), [](int) { return true; });146      assert(ret == 4);147    }148    {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_if(range, [](int) { return true; });152      assert(ret == 4);153    }154  }155}156 157constexpr 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*>>();165 166  {167    // check that projections are used properly and that they are called with the iterator directly168    {169      int a[] = {1, 2, 3, 4};170      auto ret = std::ranges::count_if(a, a + 4, [&](int* i) { return i == a + 3; }, [](int& i) { return &i; });171      assert(ret == 1);172    }173    {174      int a[] = {1, 2, 3, 4};175      auto ret = std::ranges::count_if(a, [&](int* i) { return i == a + 3; }, [](int& i) { return &i; });176      assert(ret == 1);177    }178  }179 180  {181    // check that std::invoke is used182    {183      struct S {184        int comp;185        int other;186      };187      S a[] = { {0, 0}, {0, 2}, {0, 1} };188      auto ret = std::ranges::count_if(a, [](int i){ return i == 0; }, &S::comp);189      assert(ret == 3);190    }191    {192      struct S {193        int comp;194        int other;195      };196      S a[] = { {0, 0}, {0, 2}, {0, 1} };197      auto ret = std::ranges::count_if(a, a + 3, [](int i) { return i == 0; }, &S::comp);198      assert(ret == 3);199    }200  }201 202  {203    // check projection and predicate invocation count204    {205      int a[] = {1, 2, 3, 4};206      int predicate_count = 0;207      int projection_count = 0;208      auto ret = std::ranges::count_if(a, a + 4,209                                       [&](int i) { ++predicate_count; return i == 2; },210                                       [&](int i) { ++projection_count; return i; });211      assert(ret == 1);212      assert(predicate_count == 4);213      assert(projection_count == 4);214    }215    {216      int a[] = {1, 2, 3, 4};217      int predicate_count = 0;218      int projection_count = 0;219      auto ret = std::ranges::count_if(a,220                                       [&](int i) { ++predicate_count; return i == 2; },221                                       [&](int i) { ++projection_count; return i; });222      assert(ret == 1);223      assert(predicate_count == 4);224      assert(projection_count == 4);225    }226  }227 228  {229    // check that an immobile type works230    struct NonMovable {231      NonMovable(const NonMovable&) = delete;232      NonMovable(NonMovable&&) = delete;233      constexpr NonMovable(int i_) : i(i_) {}234      int i;235 236      bool operator==(const NonMovable&) const = default;237    };238    {239      NonMovable a[] = {9, 8, 4, 3};240      auto ret = std::ranges::count_if(a, a + 4, [](const NonMovable& i) { return i == NonMovable(8); });241      assert(ret == 1);242    }243    {244      NonMovable a[] = {9, 8, 4, 3};245      auto ret = std::ranges::count_if(a, [](const NonMovable& i) { return i == NonMovable(8); });246      assert(ret == 1);247    }248  }249 250  {251    // check that difference_type is used252    struct DiffTypeIterator {253      using difference_type = signed char;254      using value_type = int;255 256      int* it = nullptr;257 258      constexpr DiffTypeIterator() = default;259      constexpr DiffTypeIterator(int* i) : it(i) {}260 261      constexpr int& operator*() const { return *it; }262      constexpr DiffTypeIterator& operator++() { ++it; return *this; }263      constexpr void operator++(int) { ++it; }264 265      bool operator==(const DiffTypeIterator&) const = default;266    };267 268    {269      int a[] = {5, 5, 4, 3, 2, 1};270      std::same_as<signed char> auto ret =271          std::ranges::count_if(DiffTypeIterator(a), DiffTypeIterator(a + 6), [](int& i) { return i == 4; });272      assert(ret == 1);273    }274    {275      int a[] = {5, 5, 4, 3, 2, 1};276      auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6));277      std::same_as<signed char> auto ret = std::ranges::count_if(range, [](int& i) { return i == 4; });278      assert(ret == 1);279    }280  }281 282  {283    // check that the predicate can take the argument by lvalue ref284    {285      int a[] = {9, 8, 4, 3};286      auto ret = std::ranges::count_if(a, a + 4, [](int& i) { return i == 8; });287      assert(ret == 1);288    }289    {290      int a[] = {9, 8, 4, 3};291      auto ret = std::ranges::count_if(a, [](int& i) { return i == 8; });292      assert(ret == 1);293    }294  }295 296  {297    // check that the predicate isn't made const298    struct MutablePredicate {299      constexpr bool operator()(int i) & { return i == 8; }300      constexpr bool operator()(int i) && { return i == 8; }301    };302    {303      int a[] = {9, 8, 4, 3};304      auto ret = std::ranges::count_if(a, a + 4, MutablePredicate{});305      assert(ret == 1);306    }307    {308      int a[] = {9, 8, 4, 3};309      auto ret = std::ranges::count_if(a, MutablePredicate{});310      assert(ret == 1);311    }312  }313 314  return true;315}316 317int main(int, char**) {318  test();319  static_assert(test());320 321  return 0;322}323