File: begin.pass.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 1,998,492 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (152 lines) | stat: -rw-r--r-- 5,618 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17

// constexpr reverse_iterator<iterator_t<V>> begin();
// constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
// constexpr auto begin() const requires common_range<const V>;

#include <ranges>
#include <cassert>

#include "test_macros.h"
#include "types.h"

static int globalCount = 0;

struct CountedIter {
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef int                             value_type;
    typedef std::ptrdiff_t                  difference_type;
    typedef int*                            pointer;
    typedef int&                            reference;
    typedef CountedIter                     self;

    pointer ptr_;
    CountedIter(pointer ptr) : ptr_(ptr) {}
    CountedIter() = default;

    reference operator*() const;
    pointer operator->() const;
    auto operator<=>(const self&) const = default;

    self& operator++() { globalCount++; ++ptr_; return *this; }
    self operator++(int) {
      auto tmp = *this;
      ++*this;
      return tmp;
    }

    self& operator--();
    self operator--(int);
};

struct CountedView : std::ranges::view_base {
  int* begin_;
  int* end_;

  CountedView(int* b, int* e) : begin_(b), end_(e) { }

  auto begin() { return CountedIter(begin_); }
  auto begin() const { return CountedIter(begin_); }
  auto end() { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
  auto end() const { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
};

struct RASentRange : std::ranges::view_base {
  using sent_t = sentinel_wrapper<random_access_iterator<int*>>;
  using sent_const_t = sentinel_wrapper<random_access_iterator<const int*>>;

  int* begin_;
  int* end_;

  constexpr RASentRange(int* b, int* e) : begin_(b), end_(e) { }

  constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
  constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
  constexpr sent_t end() { return sent_t{random_access_iterator<int*>{end_}}; }
  constexpr sent_const_t end() const { return sent_const_t{random_access_iterator<const int*>{end_}}; }
};

template<class T>
concept BeginInvocable = requires(T t) { t.begin(); };

constexpr bool test() {
  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};

  // Common bidirectional range.
  {
    auto rev = std::ranges::reverse_view(BidirRange{buffer, buffer + 8});
    assert(base(rev.begin().base()) == buffer + 8);
    assert(base(std::move(rev).begin().base()) == buffer + 8);

    ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
    ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
  }
  // Const common bidirectional range.
  {
    const auto rev = std::ranges::reverse_view(BidirRange{buffer, buffer + 8});
    assert(base(rev.begin().base()) == buffer + 8);
    assert(base(std::move(rev).begin().base()) == buffer + 8);

    ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
    ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
  }
  // Non-common, non-const (move only) bidirectional range.
  {
    auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer, buffer + 8});
    assert(base(std::move(rev).begin().base()) == buffer + 8);

    ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
  }
  // Non-common, non-const bidirectional range.
  {
    auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer, buffer + 8});
    assert(base(rev.begin().base()) == buffer + 8);
    assert(base(std::move(rev).begin().base()) == buffer + 8);

    ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
    ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
  }
  // Non-common random access range.
  // Note: const overload invalid for non-common ranges, though it would not be impossible
  // to implement for random access ranges.
  {
    auto rev = std::ranges::reverse_view(RASentRange{buffer, buffer + 8});
    assert(base(rev.begin().base()) == buffer + 8);
    assert(base(std::move(rev).begin().base()) == buffer + 8);

    ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<random_access_iterator<int*>>);
    ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<random_access_iterator<int*>>);
  }
  {
    static_assert( BeginInvocable<      std::ranges::reverse_view<BidirSentRange<Copyable>>>);
    static_assert(!BeginInvocable<const std::ranges::reverse_view<BidirSentRange<Copyable>>>);
  }

  return true;
}

int main(int, char**) {
  test();
  static_assert(test());

  {
    // Make sure we cache begin.
    int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    CountedView view{buffer, buffer + 8};
    std::ranges::reverse_view rev(view);
    assert(rev.begin().base().ptr_ == buffer + 8);
    assert(globalCount == 8);
    assert(rev.begin().base().ptr_ == buffer + 8);
    assert(globalCount == 8);
  }

  return 0;
}