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
21 struct SimpleView : std::ranges::view_base {
22 int* begin() const;
23 int* end() const;
24 };
25
26 struct NonSimpleView : std::ranges::view_base {
27 char* begin();
28 char* end();
29 int* begin() const;
30 int* end() const;
31 };
32
33 struct NonConstView : std::ranges::view_base {
34 char* begin();
35 char* end();
36 };
37
38 template <class T>
39 concept HasBegin = requires(T t) { t.begin(); };
40
41 static_assert(HasBegin<std::ranges::as_rvalue_view<SimpleView>>);
42 static_assert(HasBegin<const std::ranges::as_rvalue_view<SimpleView>>);
43 static_assert(HasBegin<std::ranges::as_rvalue_view<NonSimpleView>>);
44 static_assert(HasBegin<const std::ranges::as_rvalue_view<NonSimpleView>>);
45 static_assert(HasBegin<std::ranges::as_rvalue_view<NonConstView>>);
46 static_assert(!HasBegin<const std::ranges::as_rvalue_view<NonConstView>>);
47
48 template <class Iter, class Sent>
test_range()49 constexpr 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
57 template <class Iter, class Sent>
58 class WrapRange {
59 Iter iter_;
60 Sent sent_;
61
62 public:
WrapRange(Iter iter,Sent sent)63 constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {}
64
begin() const65 constexpr Iter begin() const { return iter_; }
end() const66 constexpr Sent end() const { return sent_; }
67 };
68
69 template <class Iter, class Sent>
70 WrapRange(Iter, Sent) -> WrapRange<Iter, Sent>;
71
72 template <class Iter, class Sent>
test_const_range()73 constexpr 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
81 struct move_iterator_view : std::ranges::view_base {
beginmove_iterator_view82 constexpr std::move_iterator<int*> begin() const { return {}; }
endmove_iterator_view83 constexpr std::move_iterator<int*> end() const { return {}; }
84 };
85
test()86 constexpr 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
main(int,char **)109 int main(int, char**) {
110 test();
111 static_assert(test());
112
113 return 0;
114 }
115