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