19d982c67Szoecarver //===----------------------------------------------------------------------===//
29d982c67Szoecarver //
39d982c67Szoecarver // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49d982c67Szoecarver // See https://llvm.org/LICENSE.txt for license information.
59d982c67Szoecarver // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69d982c67Szoecarver //
79d982c67Szoecarver //===----------------------------------------------------------------------===//
89d982c67Szoecarver
99d982c67Szoecarver // UNSUPPORTED: c++03, c++11, c++14, c++17
109d982c67Szoecarver
119d982c67Szoecarver // constexpr reverse_iterator<iterator_t<V>> begin();
129d982c67Szoecarver // constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
139d982c67Szoecarver // constexpr auto begin() const requires common_range<const V>;
149d982c67Szoecarver
159d982c67Szoecarver #include <ranges>
169d982c67Szoecarver #include <cassert>
179d982c67Szoecarver
189d982c67Szoecarver #include "test_macros.h"
199d982c67Szoecarver #include "types.h"
209d982c67Szoecarver
219d982c67Szoecarver static int globalCount = 0;
229d982c67Szoecarver
239d982c67Szoecarver struct CountedIter {
249d982c67Szoecarver typedef std::bidirectional_iterator_tag iterator_category;
259d982c67Szoecarver typedef int value_type;
269d982c67Szoecarver typedef std::ptrdiff_t difference_type;
279d982c67Szoecarver typedef int* pointer;
289d982c67Szoecarver typedef int& reference;
299d982c67Szoecarver typedef CountedIter self;
309d982c67Szoecarver
319d982c67Szoecarver pointer ptr_;
CountedIterCountedIter329d982c67Szoecarver CountedIter(pointer ptr) : ptr_(ptr) {}
339d982c67Szoecarver CountedIter() = default;
349d982c67Szoecarver
359d982c67Szoecarver reference operator*() const;
369d982c67Szoecarver pointer operator->() const;
379d982c67Szoecarver auto operator<=>(const self&) const = default;
389d982c67Szoecarver
operator ++CountedIter399d982c67Szoecarver self& operator++() { globalCount++; ++ptr_; return *this; }
operator ++CountedIter409d982c67Szoecarver self operator++(int) {
419d982c67Szoecarver auto tmp = *this;
429d982c67Szoecarver ++*this;
439d982c67Szoecarver return tmp;
449d982c67Szoecarver }
459d982c67Szoecarver
469d982c67Szoecarver self& operator--();
479d982c67Szoecarver self operator--(int);
489d982c67Szoecarver };
499d982c67Szoecarver
509d982c67Szoecarver struct CountedView : std::ranges::view_base {
51a6406ce1SLouis Dionne int* begin_;
52a6406ce1SLouis Dionne int* end_;
539d982c67Szoecarver
CountedViewCountedView54a6406ce1SLouis Dionne CountedView(int* b, int* e) : begin_(b), end_(e) { }
559d982c67Szoecarver
beginCountedView56a6406ce1SLouis Dionne auto begin() { return CountedIter(begin_); }
beginCountedView57a6406ce1SLouis Dionne auto begin() const { return CountedIter(begin_); }
endCountedView58a6406ce1SLouis Dionne auto end() { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
endCountedView59a6406ce1SLouis Dionne auto end() const { return sentinel_wrapper<CountedIter>(CountedIter(end_)); }
609d982c67Szoecarver };
619d982c67Szoecarver
629d982c67Szoecarver struct RASentRange : std::ranges::view_base {
639d982c67Szoecarver using sent_t = sentinel_wrapper<random_access_iterator<int*>>;
649d982c67Szoecarver using sent_const_t = sentinel_wrapper<random_access_iterator<const int*>>;
659d982c67Szoecarver
66a6406ce1SLouis Dionne int* begin_;
67a6406ce1SLouis Dionne int* end_;
689d982c67Szoecarver
RASentRangeRASentRange69a6406ce1SLouis Dionne constexpr RASentRange(int* b, int* e) : begin_(b), end_(e) { }
709d982c67Szoecarver
beginRASentRange71a6406ce1SLouis Dionne constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>{begin_}; }
beginRASentRange72a6406ce1SLouis Dionne constexpr random_access_iterator<const int*> begin() const { return random_access_iterator<const int*>{begin_}; }
endRASentRange73a6406ce1SLouis Dionne constexpr sent_t end() { return sent_t{random_access_iterator<int*>{end_}}; }
endRASentRange74a6406ce1SLouis Dionne constexpr sent_const_t end() const { return sent_const_t{random_access_iterator<const int*>{end_}}; }
759d982c67Szoecarver };
769d982c67Szoecarver
779d982c67Szoecarver template<class T>
789d982c67Szoecarver concept BeginInvocable = requires(T t) { t.begin(); };
799d982c67Szoecarver
test()809d982c67Szoecarver constexpr bool test() {
819d982c67Szoecarver int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
829d982c67Szoecarver
839d982c67Szoecarver // Common bidirectional range.
849d982c67Szoecarver {
85a6406ce1SLouis Dionne auto rev = std::ranges::reverse_view(BidirRange{buffer, buffer + 8});
865f26d863SMark de Wever assert(base(rev.begin().base()) == buffer + 8);
875f26d863SMark de Wever assert(base(std::move(rev).begin().base()) == buffer + 8);
889d982c67Szoecarver
899d982c67Szoecarver ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
909d982c67Szoecarver ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
919d982c67Szoecarver }
929d982c67Szoecarver // Const common bidirectional range.
939d982c67Szoecarver {
94a6406ce1SLouis Dionne const auto rev = std::ranges::reverse_view(BidirRange{buffer, buffer + 8});
955f26d863SMark de Wever assert(base(rev.begin().base()) == buffer + 8);
965f26d863SMark de Wever assert(base(std::move(rev).begin().base()) == buffer + 8);
979d982c67Szoecarver
989d982c67Szoecarver ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
999d982c67Szoecarver ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<const int*>>);
1009d982c67Szoecarver }
1019d982c67Szoecarver // Non-common, non-const (move only) bidirectional range.
1029d982c67Szoecarver {
103a6406ce1SLouis Dionne auto rev = std::ranges::reverse_view(BidirSentRange<MoveOnly>{buffer, buffer + 8});
1045f26d863SMark de Wever assert(base(std::move(rev).begin().base()) == buffer + 8);
1059d982c67Szoecarver
1069d982c67Szoecarver ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
1079d982c67Szoecarver }
1089d982c67Szoecarver // Non-common, non-const bidirectional range.
1099d982c67Szoecarver {
110a6406ce1SLouis Dionne auto rev = std::ranges::reverse_view(BidirSentRange<Copyable>{buffer, buffer + 8});
1115f26d863SMark de Wever assert(base(rev.begin().base()) == buffer + 8);
1125f26d863SMark de Wever assert(base(std::move(rev).begin().base()) == buffer + 8);
1139d982c67Szoecarver
1149d982c67Szoecarver ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
1159d982c67Szoecarver ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<bidirectional_iterator<int*>>);
1169d982c67Szoecarver }
1179d982c67Szoecarver // Non-common random access range.
118*f5832babSStephan T. Lavavej // Note: const overload invalid for non-common ranges, though it would not be impossible
1199d982c67Szoecarver // to implement for random access ranges.
1209d982c67Szoecarver {
121a6406ce1SLouis Dionne auto rev = std::ranges::reverse_view(RASentRange{buffer, buffer + 8});
1225f26d863SMark de Wever assert(base(rev.begin().base()) == buffer + 8);
1235f26d863SMark de Wever assert(base(std::move(rev).begin().base()) == buffer + 8);
1249d982c67Szoecarver
1259d982c67Szoecarver ASSERT_SAME_TYPE(decltype(rev.begin()), std::reverse_iterator<random_access_iterator<int*>>);
1269d982c67Szoecarver ASSERT_SAME_TYPE(decltype(std::move(rev).begin()), std::reverse_iterator<random_access_iterator<int*>>);
1279d982c67Szoecarver }
1289d982c67Szoecarver {
1299d982c67Szoecarver static_assert( BeginInvocable< std::ranges::reverse_view<BidirSentRange<Copyable>>>);
1309d982c67Szoecarver static_assert(!BeginInvocable<const std::ranges::reverse_view<BidirSentRange<Copyable>>>);
1319d982c67Szoecarver }
1329d982c67Szoecarver
1339d982c67Szoecarver return true;
1349d982c67Szoecarver }
1359d982c67Szoecarver
main(int,char **)1369d982c67Szoecarver int main(int, char**) {
1379d982c67Szoecarver test();
1389d982c67Szoecarver static_assert(test());
1399d982c67Szoecarver
1409d982c67Szoecarver {
1419d982c67Szoecarver // Make sure we cache begin.
1429d982c67Szoecarver int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
143a6406ce1SLouis Dionne CountedView view{buffer, buffer + 8};
1449d982c67Szoecarver std::ranges::reverse_view rev(view);
1459d982c67Szoecarver assert(rev.begin().base().ptr_ == buffer + 8);
1469d982c67Szoecarver assert(globalCount == 8);
1479d982c67Szoecarver assert(rev.begin().base().ptr_ == buffer + 8);
1489d982c67Szoecarver assert(globalCount == 8);
1499d982c67Szoecarver }
1509d982c67Szoecarver
1519d982c67Szoecarver return 0;
1529d982c67Szoecarver }
153