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_; 33 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 40 self& operator++() { globalCount++; ++ptr_; return *this; } 41 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 55 CountedView(int* b, int* e) : begin_(b), end_(e) { } 56 57 auto begin() { return CountedIter(begin_); } 58 auto begin() const { return CountedIter(begin_); } 59 auto end() { return sentinel_wrapper<CountedIter>(CountedIter(end_)); } 60 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 70 constexpr RASentRange(int* b, int* e) : begin_(b), end_(e) { } 71 72 constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; } 73 constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; } 74 constexpr sent_t end() { return sent_t{random_access_iterator<int*>{end_}}; } 75 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 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 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