brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.6 KiB · 5c8ee52 Raw
183 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// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// constexpr auto begin();12 13#include <array>14#include <cassert>15#include <ranges>16#include <type_traits>17#include <utility>18 19#include "test_iterators.h"20 21struct View : std::ranges::view_base {22  int* begin() const;23  int* end() const;24};25 26// Test that begin is not const27template <class T>28concept HasBegin = requires(T t) { t.begin(); };29 30struct Pred {31  constexpr bool operator()(int i) const { return i < 3; }32};33 34static_assert(HasBegin<std::ranges::drop_while_view<View, Pred>>);35static_assert(!HasBegin<const std::ranges::drop_while_view<View, Pred>>);36 37constexpr auto always = [](auto v) { return [v](auto&&...) { return v; }; };38 39template <class Iter>40constexpr void testOne() {41  using Sent                   = sentinel_wrapper<Iter>;42  using Range                  = std::ranges::subrange<Iter, Sent>;43  constexpr auto make_subrange = []<std::size_t N>(int(&buffer)[N]) {44    return Range{Iter{buffer}, Sent{Iter{buffer + N}}};45  };46 47  // empty48  {49    std::array<int, 0> a;50    Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}};51    std::ranges::drop_while_view dwv{std::move(range), always(false)};52    std::same_as<Iter> decltype(auto) it = dwv.begin();53    assert(base(it) == a.data() + a.size());54  }55 56  // 1 element not dropped57  {58    int buffer[] = {1};59    auto range   = make_subrange(buffer);60    std::ranges::drop_while_view dwv{std::move(range), always(false)};61    std::same_as<Iter> decltype(auto) it = dwv.begin();62    assert(base(it) == buffer);63  }64 65  // 1 element dropped66  {67    int buffer[] = {1};68    auto range   = make_subrange(buffer);69    std::ranges::drop_while_view dwv{std::move(range), always(true)};70    std::same_as<Iter> decltype(auto) it = dwv.begin();71    assert(base(it) == buffer + 1);72  }73 74  // multiple elements. no element dropped75  {76    int buffer[] = {1, 2, 3, 4, 5};77    auto range   = make_subrange(buffer);78    std::ranges::drop_while_view dwv{std::move(range), always(false)};79    std::same_as<Iter> decltype(auto) it = dwv.begin();80    assert(base(it) == buffer);81  }82 83  // multiple elements. all elements dropped84  {85    int buffer[] = {1, 2, 3, 4, 5};86    auto range   = make_subrange(buffer);87    std::ranges::drop_while_view dwv{std::move(range), always(true)};88    std::same_as<Iter> decltype(auto) it = dwv.begin();89    assert(base(it) == buffer + 5);90  }91 92  // multiple elements. some elements dropped93  {94    int buffer[] = {1, 2, 3, 2, 1};95    auto range   = make_subrange(buffer);96    std::ranges::drop_while_view dwv{std::move(range), [](int i) { return i < 3; }};97    std::same_as<Iter> decltype(auto) it = dwv.begin();98    assert(base(it) == buffer + 2);99  }100 101  // Make sure we do not make a copy of the predicate when we call begin()102  {103    struct TrackingPred {104      constexpr explicit TrackingPred(bool* moved, bool* copied) : moved_(moved), copied_(copied) {}105      constexpr TrackingPred(TrackingPred const& other) : moved_(other.moved_), copied_(other.copied_) {106        *copied_ = true;107      }108      constexpr TrackingPred(TrackingPred&& other) : moved_(other.moved_), copied_(other.copied_) { *moved_ = true; }109      TrackingPred& operator=(TrackingPred const&) = default;110      TrackingPred& operator=(TrackingPred&&)      = default;111 112      constexpr bool operator()(int i) const { return i < 3; }113      bool* moved_;114      bool* copied_;115    };116 117    int buffer[] = {1, 2, 3, 2, 1};118    bool moved = false, copied = false;119    auto range = make_subrange(buffer);120    std::ranges::drop_while_view dwv{std::move(range), TrackingPred(&moved, &copied)};121    moved                    = false;122    copied                   = false;123    [[maybe_unused]] auto it = dwv.begin();124    assert(!moved);125    assert(!copied);126  }127 128  // Test with a non-const predicate129  {130    int buffer[] = {1, 2, 3, 2, 1};131    auto range   = make_subrange(buffer);132    std::ranges::drop_while_view dwv{std::move(range), [](int i) mutable { return i < 3; }};133    std::same_as<Iter> decltype(auto) it = dwv.begin();134    assert(base(it) == buffer + 2);135  }136 137  // Test with a predicate that takes by non-const reference138  {139    int buffer[] = {1, 2, 3, 2, 1};140    auto range   = make_subrange(buffer);141    std::ranges::drop_while_view dwv{std::move(range), [](int& i) { return i < 3; }};142    std::same_as<Iter> decltype(auto) it = dwv.begin();143    assert(base(it) == buffer + 2);144  }145 146  if constexpr (std::forward_iterator<Iter>) {147    // Make sure that we cache the result of begin() on subsequent calls148    {149      int buffer[] = {1, 2, 3, 2, 1};150      auto range   = make_subrange(buffer);151 152      int called = 0;153      auto pred  = [&](int i) {154        ++called;155        return i < 3;156      };157      std::ranges::drop_while_view dwv{range, pred};158      for (auto i = 0; i < 10; ++i) {159        std::same_as<Iter> decltype(auto) it = dwv.begin();160        assert(base(it) == buffer + 2);161        assert(called == 3);162      }163    }164  }165}166 167constexpr bool test() {168  testOne<cpp17_input_iterator<int*>>();169  testOne<cpp20_input_iterator<int*>>();170  testOne<forward_iterator<int*>>();171  testOne<bidirectional_iterator<int*>>();172  testOne<random_access_iterator<int*>>();173  testOne<contiguous_iterator<int*>>();174  testOne<int*>();175  return true;176}177 178int main(int, char**) {179  test();180  static_assert(test());181  return 0;182}183