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<class D>
12 // requires is_class_v<D> && same_as<D, remove_cv_t<D>>
13 // class view_interface;
14
15 #include <ranges>
16
17 #include <cassert>
18 #include <utility>
19 #include "test_macros.h"
20 #include "test_iterators.h"
21
22 template<class T>
23 concept ValidViewInterfaceType = requires { typename std::ranges::view_interface<T>; };
24
25 struct Empty { };
26
27 static_assert(!ValidViewInterfaceType<void>);
28 static_assert(!ValidViewInterfaceType<void*>);
29 static_assert(!ValidViewInterfaceType<Empty*>);
30 static_assert(!ValidViewInterfaceType<Empty const>);
31 static_assert(!ValidViewInterfaceType<Empty &>);
32 static_assert( ValidViewInterfaceType<Empty>);
33
34 using InputIter = cpp20_input_iterator<const int*>;
35
36 struct InputRange : std::ranges::view_interface<InputRange> {
37 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginInputRange38 constexpr InputIter begin() const { return InputIter(buff); }
endInputRange39 constexpr InputIter end() const { return InputIter(buff + 8); }
40 };
41
42 struct NotSizedSentinel {
43 using value_type = int;
44 using difference_type = std::ptrdiff_t;
45 using iterator_concept = std::forward_iterator_tag;
46
47 explicit NotSizedSentinel() = default;
48 explicit NotSizedSentinel(int*);
49 int& operator*() const;
50 NotSizedSentinel& operator++();
51 NotSizedSentinel operator++(int);
52 bool operator==(NotSizedSentinel const&) const;
53 };
54 static_assert(std::forward_iterator<NotSizedSentinel>);
55
56 using ForwardIter = forward_iterator<int*>;
57
58 // So that we conform to sized_sentinel_for.
operator -(const ForwardIter & x,const ForwardIter & y)59 constexpr std::ptrdiff_t operator-(const ForwardIter& x, const ForwardIter& y) {
60 return base(x) - base(y);
61 }
62
63 struct ForwardRange : std::ranges::view_interface<ForwardRange> {
64 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginForwardRange65 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endForwardRange66 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
67 };
68 static_assert(std::ranges::view<ForwardRange>);
69
70 struct MoveOnlyForwardRange : std::ranges::view_interface<MoveOnlyForwardRange> {
71 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
72 MoveOnlyForwardRange(MoveOnlyForwardRange const&) = delete;
73 MoveOnlyForwardRange(MoveOnlyForwardRange &&) = default;
74 MoveOnlyForwardRange& operator=(MoveOnlyForwardRange &&) = default;
75 MoveOnlyForwardRange() = default;
beginMoveOnlyForwardRange76 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endMoveOnlyForwardRange77 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
78 };
79 static_assert(std::ranges::view<MoveOnlyForwardRange>);
80
81 struct MI : std::ranges::view_interface<InputRange>,
82 std::ranges::view_interface<MoveOnlyForwardRange> {
83 };
84 static_assert(!std::ranges::view<MI>);
85
86 struct EmptyIsTrue : std::ranges::view_interface<EmptyIsTrue> {
87 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginEmptyIsTrue88 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endEmptyIsTrue89 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
emptyEmptyIsTrue90 constexpr bool empty() const { return true; }
91 };
92 static_assert(std::ranges::view<EmptyIsTrue>);
93
94 struct SizeIsTen : std::ranges::view_interface<SizeIsTen> {
95 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginSizeIsTen96 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endSizeIsTen97 constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
sizeSizeIsTen98 constexpr std::size_t size() const { return 10; }
99 };
100 static_assert(std::ranges::view<SizeIsTen>);
101
102 using RAIter = random_access_iterator<int*>;
103
104 struct RARange : std::ranges::view_interface<RARange> {
105 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginRARange106 constexpr RAIter begin() const { return RAIter(const_cast<int*>(buff)); }
endRARange107 constexpr RAIter end() const { return RAIter(const_cast<int*>(buff) + 8); }
108 };
109 static_assert(std::ranges::view<RARange>);
110
111 using ContIter = contiguous_iterator<const int*>;
112
113 struct ContRange : std::ranges::view_interface<ContRange> {
114 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginContRange115 constexpr ContIter begin() const { return ContIter(buff); }
endContRange116 constexpr ContIter end() const { return ContIter(buff + 8); }
117 };
118 static_assert(std::ranges::view<ContRange>);
119
120 struct DataIsNull : std::ranges::view_interface<DataIsNull> {
121 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginDataIsNull122 constexpr ContIter begin() const { return ContIter(buff); }
endDataIsNull123 constexpr ContIter end() const { return ContIter(buff + 8); }
dataDataIsNull124 constexpr const int *data() const { return nullptr; }
125 };
126 static_assert(std::ranges::view<DataIsNull>);
127
128 struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison> {
129 struct ResultType {
130 bool value;
operator boolBoolConvertibleComparison::ResultType131 constexpr operator bool() const { return value; }
132 };
133
134 struct SentinelType {
135 int *base_;
136 explicit SentinelType() = default;
SentinelTypeBoolConvertibleComparison::SentinelType137 constexpr explicit SentinelType(int *base) : base_(base) {}
operator ==BoolConvertibleComparison138 friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) == sent.base_}; }
operator ==BoolConvertibleComparison139 friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) == sent.base_}; }
operator !=BoolConvertibleComparison140 friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) != sent.base_}; }
operator !=BoolConvertibleComparison141 friend constexpr ResultType operator!=(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) != sent.base_}; }
142 };
143
144 int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginBoolConvertibleComparison145 constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endBoolConvertibleComparison146 constexpr SentinelType end() const { return SentinelType(const_cast<int*>(buff) + 8); }
147 };
148 static_assert(std::ranges::view<BoolConvertibleComparison>);
149
150 template<class T>
151 concept EmptyInvocable = requires (T const& obj) { obj.empty(); };
152
153 template<class T>
154 concept BoolOpInvocable = requires (T const& obj) { bool(obj); };
155
testEmpty()156 constexpr bool testEmpty() {
157 static_assert(!EmptyInvocable<InputRange>);
158 static_assert( EmptyInvocable<ForwardRange>);
159
160 static_assert(!BoolOpInvocable<InputRange>);
161 static_assert( BoolOpInvocable<ForwardRange>);
162
163 ForwardRange forwardRange;
164 assert(!forwardRange.empty());
165 assert(!static_cast<ForwardRange const&>(forwardRange).empty());
166
167 assert(forwardRange);
168 assert(static_cast<ForwardRange const&>(forwardRange));
169
170 assert(!std::ranges::empty(forwardRange));
171 assert(!std::ranges::empty(static_cast<ForwardRange const&>(forwardRange)));
172
173 EmptyIsTrue emptyTrue;
174 assert(emptyTrue.empty());
175 assert(static_cast<EmptyIsTrue const&>(emptyTrue).empty());
176 assert(!emptyTrue.std::ranges::view_interface<EmptyIsTrue>::empty());
177
178 assert(!emptyTrue);
179 assert(!static_cast<EmptyIsTrue const&>(emptyTrue));
180 assert(!emptyTrue.std::ranges::view_interface<EmptyIsTrue>::operator bool());
181
182 assert(std::ranges::empty(emptyTrue));
183 assert(std::ranges::empty(static_cast<EmptyIsTrue const&>(emptyTrue)));
184
185 // Try calling empty on an rvalue.
186 MoveOnlyForwardRange moveOnly;
187 assert(!std::move(moveOnly).empty());
188
189 BoolConvertibleComparison boolConv;
190 ASSERT_NOT_NOEXCEPT(boolConv.empty());
191
192 assert(!boolConv.empty());
193 assert(!static_cast<const BoolConvertibleComparison&>(boolConv).empty());
194
195 assert(boolConv);
196 assert(static_cast<const BoolConvertibleComparison&>(boolConv));
197
198 assert(!std::ranges::empty(boolConv));
199 assert(!std::ranges::empty(static_cast<const BoolConvertibleComparison&>(boolConv)));
200
201 return true;
202 }
203
204 template<class T>
205 concept DataInvocable = requires (T const& obj) { obj.data(); };
206
testData()207 constexpr bool testData() {
208 static_assert(!DataInvocable<ForwardRange>);
209 static_assert( DataInvocable<ContRange>);
210
211 ContRange contiguous;
212 assert(contiguous.data() == contiguous.buff);
213 assert(static_cast<ContRange const&>(contiguous).data() == contiguous.buff);
214
215 assert(std::ranges::data(contiguous) == contiguous.buff);
216 assert(std::ranges::data(static_cast<ContRange const&>(contiguous)) == contiguous.buff);
217
218 DataIsNull dataNull;
219 assert(dataNull.data() == nullptr);
220 assert(static_cast<DataIsNull const&>(dataNull).data() == nullptr);
221 assert(dataNull.std::ranges::view_interface<DataIsNull>::data() == dataNull.buff);
222
223 assert(std::ranges::data(dataNull) == nullptr);
224 assert(std::ranges::data(static_cast<DataIsNull const&>(dataNull)) == nullptr);
225
226 return true;
227 }
228
229 template<class T>
230 concept SizeInvocable = requires (T const& obj) { obj.size(); };
231
testSize()232 constexpr bool testSize() {
233 static_assert(!SizeInvocable<InputRange>);
234 static_assert(!SizeInvocable<NotSizedSentinel>);
235 static_assert( SizeInvocable<ForwardRange>);
236
237 // Test the test.
238 static_assert(std::same_as<decltype(std::declval<ForwardIter>() - std::declval<ForwardIter>()), std::ptrdiff_t>);
239 using UnsignedSize = std::make_unsigned_t<std::ptrdiff_t>;
240 using SignedSize = std::common_type_t<std::ptrdiff_t, std::make_signed_t<UnsignedSize>>;
241 ForwardRange forwardRange;
242 assert(forwardRange.size() == 8);
243 assert(static_cast<ForwardRange const&>(forwardRange).size() == 8);
244
245 assert(std::ranges::size(forwardRange) == 8);
246 static_assert(std::same_as<decltype(std::ranges::size(std::declval<ForwardRange>())), UnsignedSize>);
247 static_assert(std::same_as<decltype(std::ranges::ssize(std::declval<ForwardRange>())), SignedSize>);
248
249 assert(std::ranges::size(static_cast<ForwardRange const&>(forwardRange)) == 8);
250 static_assert(std::same_as<decltype(std::ranges::size(std::declval<ForwardRange const>())), UnsignedSize>);
251 static_assert(std::same_as<decltype(std::ranges::ssize(std::declval<ForwardRange const>())), SignedSize>);
252
253 SizeIsTen sizeTen;
254 assert(sizeTen.size() == 10);
255 assert(static_cast<SizeIsTen const&>(sizeTen).size() == 10);
256 assert(sizeTen.std::ranges::view_interface<SizeIsTen>::size() == 8);
257
258 assert(std::ranges::size(sizeTen) == 10);
259 assert(std::ranges::size(static_cast<SizeIsTen const&>(sizeTen)) == 10);
260
261 return true;
262 }
263
264 template<class T>
265 concept SubscriptInvocable = requires (T const& obj, std::size_t n) { obj[n]; };
266
testSubscript()267 constexpr bool testSubscript() {
268 static_assert(!SubscriptInvocable<ForwardRange>);
269 static_assert( SubscriptInvocable<RARange>);
270
271 RARange randomAccess;
272 assert(randomAccess[2] == 2);
273 assert(static_cast<RARange const&>(randomAccess)[2] == 2);
274 randomAccess[2] = 3;
275 assert(randomAccess[2] == 3);
276
277 return true;
278 }
279
280 template<class T>
281 concept FrontInvocable = requires (T const& obj) { obj.front(); };
282
283 template<class T>
284 concept BackInvocable = requires (T const& obj) { obj.back(); };
285
testFrontBack()286 constexpr bool testFrontBack() {
287 static_assert(!FrontInvocable<InputRange>);
288 static_assert( FrontInvocable<ForwardRange>);
289 static_assert(!BackInvocable<ForwardRange>);
290 static_assert( BackInvocable<RARange>);
291
292 ForwardRange forwardRange;
293 assert(forwardRange.front() == 0);
294 assert(static_cast<ForwardRange const&>(forwardRange).front() == 0);
295 forwardRange.front() = 2;
296 assert(forwardRange.front() == 2);
297
298 RARange randomAccess;
299 assert(randomAccess.front() == 0);
300 assert(static_cast<RARange const&>(randomAccess).front() == 0);
301 randomAccess.front() = 2;
302 assert(randomAccess.front() == 2);
303
304 assert(randomAccess.back() == 7);
305 assert(static_cast<RARange const&>(randomAccess).back() == 7);
306 randomAccess.back() = 2;
307 assert(randomAccess.back() == 2);
308
309 return true;
310 }
311
312 struct V1 : std::ranges::view_interface<V1> { };
313 struct V2 : std::ranges::view_interface<V2> { V1 base_; };
314 static_assert(sizeof(V2) == sizeof(V1));
315
main(int,char **)316 int main(int, char**) {
317 testEmpty();
318 static_assert(testEmpty());
319
320 testData();
321 static_assert(testData());
322
323 testSize();
324 static_assert(testSize());
325
326 testSubscript();
327 static_assert(testSubscript());
328
329 testFrontBack();
330 static_assert(testFrontBack());
331
332 return 0;
333 }
334