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