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
10
11 // template<range R>
12 // requires is_object_v<R>
13 // class ref_view;
14
15 #include <ranges>
16
17 #include <cassert>
18 #include "test_macros.h"
19 #include "test_iterators.h"
20
21 int globalBuff[8];
22
23 template<class T>
24 concept ValidRefView = requires { typename std::ranges::ref_view<T>; };
25
26 struct Range {
27 int start = 0;
begin(Range const & range)28 friend constexpr int* begin(Range const& range) { return globalBuff + range.start; }
end(Range const &)29 friend constexpr int* end(Range const&) { return globalBuff + 8; }
begin(Range & range)30 friend constexpr int* begin(Range& range) { return globalBuff + range.start; }
end(Range &)31 friend constexpr int* end(Range&) { return globalBuff + 8; }
32 };
33
34 struct BeginOnly {
35 friend int* begin(BeginOnly const&);
36 friend int* begin(BeginOnly &);
37 };
38
39 static_assert( ValidRefView<Range>);
40 static_assert(!ValidRefView<BeginOnly>);
41 static_assert(!ValidRefView<int (&)[4]>);
42 static_assert( ValidRefView<int[4]>);
43
44 static_assert(std::derived_from<std::ranges::ref_view<Range>, std::ranges::view_interface<std::ranges::ref_view<Range>>>);
45
46 struct RangeConvertible {
47 operator Range& ();
48 };
49
50 struct RValueRangeConvertible {
51 operator Range&& ();
52 };
53
54 static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, Range&>);
55 static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, RangeConvertible>);
56 static_assert(!std::is_constructible_v<std::ranges::ref_view<Range>, RValueRangeConvertible>);
57
58 struct ConstConvertibleToLValueAndRValue {
59 operator Range& () const;
60 operator Range&& () const;
61 };
62 static_assert( std::is_convertible_v<RangeConvertible, std::ranges::ref_view<Range>>);
63 static_assert(!std::is_convertible_v<RValueRangeConvertible, std::ranges::ref_view<Range>>);
64 static_assert(!std::is_convertible_v<ConstConvertibleToLValueAndRValue, std::ranges::ref_view<Range>>);
65
66 struct ForwardRange {
beginForwardRange67 constexpr forward_iterator<int*> begin() const { return forward_iterator<int*>(globalBuff); }
endForwardRange68 constexpr forward_iterator<int*> end() const { return forward_iterator<int*>(globalBuff + 8); }
69 };
70
71 struct Cpp17InputRange {
72 struct sentinel {
operator ==Cpp17InputRange73 friend constexpr bool operator==(sentinel, cpp17_input_iterator<int*> iter) { return base(iter) == globalBuff + 8; }
operator -Cpp17InputRange74 friend constexpr std::ptrdiff_t operator-(sentinel, cpp17_input_iterator<int*>) { return -8; }
operator -Cpp17InputRange75 friend constexpr std::ptrdiff_t operator-(cpp17_input_iterator<int*>, sentinel) { return 8; }
76 };
77
beginCpp17InputRange78 constexpr cpp17_input_iterator<int*> begin() const {
79 return cpp17_input_iterator<int*>(globalBuff);
80 }
endCpp17InputRange81 constexpr sentinel end() const { return {}; }
82 };
83
84 struct Cpp20InputRange {
85 struct sentinel {
operator ==Cpp20InputRange86 friend constexpr bool operator==(sentinel, const cpp20_input_iterator<int*> &iter) { return base(iter) == globalBuff + 8; }
operator -Cpp20InputRange87 friend constexpr std::ptrdiff_t operator-(sentinel, const cpp20_input_iterator<int*>&) { return -8; }
88 };
89
beginCpp20InputRange90 constexpr cpp20_input_iterator<int*> begin() const {
91 return cpp20_input_iterator<int*>(globalBuff);
92 }
endCpp20InputRange93 constexpr sentinel end() const { return {}; }
94 };
95
96 template<>
97 inline constexpr bool std::ranges::enable_borrowed_range<Cpp20InputRange> = true;
98
99 template<class R>
100 concept EmptyIsInvocable = requires (std::ranges::ref_view<R> view) { view.empty(); };
101
102 template<class R>
103 concept SizeIsInvocable = requires (std::ranges::ref_view<R> view) { view.size(); };
104
105 template<class R>
106 concept DataIsInvocable = requires (std::ranges::ref_view<R> view) { view.data(); };
107
108 // Testing ctad.
109 static_assert(std::same_as<decltype(std::ranges::ref_view(std::declval<Range&>())),
110 std::ranges::ref_view<Range>>);
111
test()112 constexpr bool test() {
113 {
114 // ref_view::base
115 Range range;
116 std::ranges::ref_view<Range> view{range};
117 assert(view.begin() == globalBuff);
118 view.base() = Range{2};
119 assert(view.begin() == globalBuff + 2);
120 }
121
122 {
123 // ref_view::begin
124 Range range1;
125 std::ranges::ref_view<Range> view1 = range1;
126 assert(view1.begin() == globalBuff);
127
128 ForwardRange range2;
129 std::ranges::ref_view<ForwardRange> view2 = range2;
130 assert(base(view2.begin()) == globalBuff);
131
132 Cpp17InputRange range3;
133 std::ranges::ref_view<Cpp17InputRange> view3 = range3;
134 assert(base(view3.begin()) == globalBuff);
135
136 Cpp20InputRange range4;
137 std::ranges::ref_view<Cpp20InputRange> view4 = range4;
138 assert(base(view4.begin()) == globalBuff);
139 }
140
141 {
142 // ref_view::end
143 Range range1;
144 std::ranges::ref_view<Range> view1 = range1;
145 assert(view1.end() == globalBuff + 8);
146
147 ForwardRange range2;
148 std::ranges::ref_view<ForwardRange> view2 = range2;
149 assert(base(view2.end()) == globalBuff + 8);
150
151 Cpp17InputRange range3;
152 std::ranges::ref_view<Cpp17InputRange> view3 = range3;
153 assert(view3.end() == cpp17_input_iterator(globalBuff + 8));
154
155 Cpp20InputRange range4;
156 std::ranges::ref_view<Cpp20InputRange> view4 = range4;
157 assert(view4.end() == cpp20_input_iterator(globalBuff + 8));
158 }
159
160 {
161 // ref_view::empty
162 Range range{8};
163 std::ranges::ref_view<Range> view1 = range;
164 assert(view1.empty());
165
166 ForwardRange range2;
167 std::ranges::ref_view<ForwardRange> view2 = range2;
168 assert(!view2.empty());
169
170 static_assert(!EmptyIsInvocable<Cpp17InputRange>);
171 static_assert(!EmptyIsInvocable<Cpp20InputRange>);
172 }
173
174 {
175 // ref_view::size
176 Range range1{8};
177 std::ranges::ref_view<Range> view1 = range1;
178 assert(view1.size() == 0);
179
180 Range range2{2};
181 std::ranges::ref_view<Range> view2 = range2;
182 assert(view2.size() == 6);
183
184 static_assert(!SizeIsInvocable<ForwardRange>);
185 }
186
187 {
188 // ref_view::data
189 Range range1;
190 std::ranges::ref_view<Range> view1 = range1;
191 assert(view1.data() == globalBuff);
192
193 Range range2{2};
194 std::ranges::ref_view<Range> view2 = range2;
195 assert(view2.data() == globalBuff + 2);
196
197 static_assert(!DataIsInvocable<ForwardRange>);
198 }
199
200 return true;
201 }
202
main(int,char **)203 int main(int, char**) {
204 test();
205 static_assert(test());
206
207 return 0;
208 }
209