xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.reverse/begin.pass.cpp (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
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