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

source code of libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp