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// UNSUPPORTED: c++03, c++11, c++14, c++17
10
11// constexpr reverse_iterator<iterator_t<V>> begin();
12// constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
13// constexpr auto begin() const requires common_range<const V>;
14
15#include <ranges>
16#include <cassert>
17
18#include "test_macros.h"
19#include "types.h"
20
21static int globalCount = 0;
22
23struct CountedIter {
24 typedef std::bidirectional_iterator_tag iterator_category;
25 typedef int value_type;
26 typedef std::ptrdiff_t difference_type;
27 typedef int* pointer;
28 typedef int& reference;
29 typedef CountedIter self;
30
31 pointer ptr_;
32 CountedIter(pointer ptr) : ptr_(ptr) {}
33 CountedIter() = default;
34
35 reference operator*() const;
36 pointer operator->() const;
37 auto operator<=>(const self&) const = default;
38
39 self& operator++() { globalCount++; ++ptr_; return *this; }
40 self operator++(int) {
41 auto tmp = *this;
42 ++*this;
43 return tmp;
44 }
45
46 self& operator--();
47 self operator--(int);
48};
49
50struct CountedView : std::ranges::view_base {
51 int* begin_;
52 int* end_;
53
54 CountedView(int* b, int* e) : begin_(b), end_(e) { }
55
56 auto begin() { return CountedIter(begin_); }
57 auto begin() const { return CountedIter(begin_); }
58 auto end() { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
59 auto end() const { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
60};
61
62struct RASentRange : std::ranges::view_base {
63 using sent_t = sentinel_wrapper<random_access_iterator<int*>>;
64 using sent_const_t = sentinel_wrapper<random_access_iterator<const int*>>;
65
66 int* begin_;
67 int* end_;
68
69 constexpr RASentRange(int* b, int* e) : begin_(b), end_(e) { }
70
71 constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
72 constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
73 constexpr sent_t end() { return sent_t{random_access_iterator<int*>{end_}}; }
74 constexpr sent_const_t end() const { return sent_const_t{random_access_iterator<const int*>{end_}}; }
75};
76
77template<class T>
78concept BeginInvocable = requires(T t) { t.begin(); };
79
80constexpr bool test() {
81 int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
82
83 // Common bidirectional range.
84 {
85 auto rev = std::ranges::reverse_view(BidirRange{buffer, buffer + 8});
86 assert(base(rev.begin().base()) == buffer + 8);
87 assert(base(std::move(rev).begin().base()) == buffer + 8);
88
89 ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
90 ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
91 }
92 // Const common bidirectional range.
93 {
94 const auto rev = std::ranges::reverse_view(BidirRange{buffer, buffer + 8});
95 assert(base(rev.begin().base()) == buffer + 8);
96 assert(base(std::move(rev).begin().base()) == buffer + 8);
97
98 ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
99 ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
100 }
101 // Non-common, non-const (move only) bidirectional range.
102 {
103 auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer, buffer + 8});
104 assert(base(std::move(rev).begin().base()) == buffer + 8);
105
106 ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
107 }
108 // Non-common, non-const bidirectional range.
109 {
110 auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer, buffer + 8});
111 assert(base(rev.begin().base()) == buffer + 8);
112 assert(base(std::move(rev).begin().base()) == buffer + 8);
113
114 ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
115 ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
116 }
117 // Non-common random access range.
118 // Note: const overload invalid for non-common ranges, though it would not be impossible
119 // to implement for random access ranges.
120 {
121 auto rev = std::ranges::reverse_view(RASentRange{buffer, buffer + 8});
122 assert(base(rev.begin().base()) == buffer + 8);
123 assert(base(std::move(rev).begin().base()) == buffer + 8);
124
125 ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<random_access_iterator<int*>>);
126 ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<random_access_iterator<int*>>);
127 }
128 {
129 static_assert( BeginInvocable< std::ranges::reverse_view<BidirSentRange<Copyable>>>);
130 static_assert(!BeginInvocable<const std::ranges::reverse_view<BidirSentRange<Copyable>>>);
131 }
132
133 return true;
134}
135
136int main(int, char**) {
137 test();
138 static_assert(test());
139
140 {
141 // Make sure we cache begin.
142 int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
143 CountedView view{buffer, buffer + 8};
144 std::ranges::reverse_view rev(view);
145 assert(rev.begin().base().ptr_ == buffer + 8);
146 assert(globalCount == 8);
147 assert(rev.begin().base().ptr_ == buffer + 8);
148 assert(globalCount == 8);
149 }
150
151 return 0;
152}
153

source code of libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp