xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
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 
21 static int globalCount = 0;
22 
23 struct 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_;
CountedIterCountedIter32     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 
operator ++CountedIter39     self& operator++() { globalCount++; ++ptr_; return *this; }
operator ++CountedIter40     self operator++(int) {
41       auto tmp = *this;
42       ++*this;
43       return tmp;
44     }
45 
46     self& operator--();
47     self operator--(int);
48 };
49 
50 struct CountedView : std::ranges::view_base {
51   int* begin_;
52   int* end_;
53 
CountedViewCountedView54   CountedView(int* b, int* e) : begin_(b), end_(e) { }
55 
beginCountedView56   auto begin() { return CountedIter(begin_); }
beginCountedView57   auto begin() const { return CountedIter(begin_); }
endCountedView58   auto end() { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
endCountedView59   auto end() const { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
60 };
61 
62 struct 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 
RASentRangeRASentRange69   constexpr RASentRange(int* b, int* e) : begin_(b), end_(e) { }
70 
beginRASentRange71   constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
beginRASentRange72   constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
endRASentRange73   constexpr sent_t end() { return sent_t{random_access_iterator<int*>{end_}}; }
endRASentRange74   constexpr sent_const_t end() const { return sent_const_t{random_access_iterator<const int*>{end_}}; }
75 };
76 
77 template<class T>
78 concept BeginInvocable = requires(T t) { t.begin(); };
79 
test()80 constexpr 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 
main(int,char **)136 int 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