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, c++20
10
11// constexpr auto begin()
12// constexpr auto begin() const
13
14#include <array>
15#include <cassert>
16#include <concepts>
17#include <ranges>
18
19#include "test_iterators.h"
20
21struct SimpleView : std::ranges::view_base {
22 int* begin() const;
23 int* end() const;
24};
25
26struct NonSimpleView : std::ranges::view_base {
27 char* begin();
28 char* end();
29 int* begin() const;
30 int* end() const;
31};
32
33struct NonConstView : std::ranges::view_base {
34 char* begin();
35 char* end();
36};
37
38template <class T>
39concept HasBegin = requires(T t) { t.begin(); };
40
41static_assert(HasBegin<std::ranges::as_rvalue_view<SimpleView>>);
42static_assert(HasBegin<const std::ranges::as_rvalue_view<SimpleView>>);
43static_assert(HasBegin<std::ranges::as_rvalue_view<NonSimpleView>>);
44static_assert(HasBegin<const std::ranges::as_rvalue_view<NonSimpleView>>);
45static_assert(HasBegin<std::ranges::as_rvalue_view<NonConstView>>);
46static_assert(!HasBegin<const std::ranges::as_rvalue_view<NonConstView>>);
47
48template <class Iter, class Sent>
49constexpr void test_range() {
50 int a[] = {1, 2};
51 std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a))));
52 std::ranges::as_rvalue_view view(std::move(range));
53 std::same_as<std::move_iterator<Iter>> decltype(auto) iter = view.begin();
54 assert(base(iter.base()) == std::begin(a));
55}
56
57template <class Iter, class Sent>
58class WrapRange {
59 Iter iter_;
60 Sent sent_;
61
62public:
63 constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {}
64
65 constexpr Iter begin() const { return iter_; }
66 constexpr Sent end() const { return sent_; }
67};
68
69template <class Iter, class Sent>
70WrapRange(Iter, Sent) -> WrapRange<Iter, Sent>;
71
72template <class Iter, class Sent>
73constexpr void test_const_range() {
74 int a[] = {1, 2};
75 auto range = WrapRange{Iter(a), Sent(Iter(a + 2))};
76 const std::ranges::as_rvalue_view view(std::views::all(range));
77 std::same_as<std::move_iterator<Iter>> decltype(auto) iter = view.begin();
78 assert(base(iter.base()) == std::begin(a));
79}
80
81struct move_iterator_view : std::ranges::view_base {
82 constexpr std::move_iterator<int*> begin() const { return {}; }
83 constexpr std::move_iterator<int*> end() const { return {}; }
84};
85
86constexpr bool test() {
87 types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter> {
88 if constexpr (std::sentinel_for<Iter, Iter>)
89 test_range<Iter, Iter>();
90 test_range<Iter, sentinel_wrapper<Iter>>();
91 test_range<Iter, sized_sentinel<Iter>>();
92 });
93
94 types::for_each(types::forward_iterator_list<const int*>{}, []<class Iter> {
95 test_const_range<Iter, Iter>();
96 test_const_range<Iter, sentinel_wrapper<Iter>>();
97 test_const_range<Iter, sized_sentinel<Iter>>();
98 });
99
100 { // check that with a std::move_iterator begin() doesn't return move_iterator<move_iterator<T>>
101 std::ranges::as_rvalue_view view{move_iterator_view{}};
102 std::same_as<std::move_iterator<int*>> decltype(auto) it = view.begin();
103 assert(it == std::move_iterator<int*>{});
104 }
105
106 return true;
107}
108
109int main(int, char**) {
110 test();
111 static_assert(test());
112
113 return 0;
114}
115

source code of libcxx/test/std/ranges/range.adaptors/range.as.rvalue/begin.pass.cpp