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-no-concepts 11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 12 13 // constexpr reverse_iterator<iterator_t<V>> begin(); 14 // constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>; 15 // constexpr auto begin() const requires common_range<const V>; 16 17 #include <ranges> 18 #include <cassert> 19 20 #include "test_macros.h" 21 #include "types.h" 22 23 static int globalCount = 0; 24 25 struct CountedIter { 26 typedef std::bidirectional_iterator_tag iterator_category; 27 typedef int value_type; 28 typedef std::ptrdiff_t difference_type; 29 typedef int* pointer; 30 typedef int& reference; 31 typedef CountedIter self; 32 33 pointer ptr_; 34 CountedIter(pointer ptr) : ptr_(ptr) {} 35 CountedIter() = default; 36 37 reference operator*() const; 38 pointer operator->() const; 39 auto operator<=>(const self&) const = default; 40 41 self& operator++() { globalCount++; ++ptr_; return *this; } 42 self operator++(int) { 43 auto tmp = *this; 44 ++*this; 45 return tmp; 46 } 47 48 self& operator--(); 49 self operator--(int); 50 }; 51 52 struct CountedView : std::ranges::view_base { 53 int *ptr_; 54 55 CountedView(int *ptr) : ptr_(ptr) {} 56 57 auto begin() { return CountedIter(ptr_); } 58 auto begin() const { return CountedIter(ptr_); } 59 auto end() { return sentinel_wrapper<CountedIter>(CountedIter(ptr_ + 8)); } 60 auto end() const { return sentinel_wrapper<CountedIter>(CountedIter(ptr_ + 8)); } 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 *ptr_; 68 69 constexpr RASentRange(int *ptr) : ptr_(ptr) {} 70 71 constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{ptr_}; } 72 constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{ptr_}; } 73 constexpr sent_t end() { return sent_t{random_access_iterator<int*>{ptr_ + 8}}; } 74 constexpr sent_const_t end() const { return sent_const_t{random_access_iterator<const int*>{ptr_ + 8}}; } 75 }; 76 77 template<class T> 78 concept BeginInvocable = requires(T t) { t.begin(); }; 79 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}); 86 assert(rev.begin().base().base() == buffer + 8); 87 assert(std::move(rev).begin().base().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}); 95 assert(rev.begin().base().base() == buffer + 8); 96 assert(std::move(rev).begin().base().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}); 104 assert(std::move(rev).begin().base().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}); 111 assert(rev.begin().base().base() == buffer + 8); 112 assert(std::move(rev).begin().base().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 imposible 119 // to implement for random access ranges. 120 { 121 auto rev = std::ranges::reverse_view(RASentRange{buffer}); 122 assert(rev.begin().base().base() == buffer + 8); 123 assert(std::move(rev).begin().base().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 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}; 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