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 SizedInputRange : std::ranges::view_interface<SizedInputRange> {
43   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginSizedInputRange44   constexpr InputIter begin() const { return InputIter(buff); }
endSizedInputRange45   constexpr sentinel_wrapper<InputIter> end() const { return sentinel_wrapper(InputIter(buff + 8)); }
sizeSizedInputRange46   constexpr std::size_t size() const { return 8; }
47 };
48 static_assert(std::ranges::sized_range<SizedInputRange>);
49 
50 struct 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 };
62 static_assert(std::forward_iterator<NotSizedSentinel>);
63 
64 using ForwardIter = forward_iterator<int*>;
65 
66 // So that we conform to sized_sentinel_for.
operator -(const ForwardIter & x,const ForwardIter & y)67 constexpr std::ptrdiff_t operator-(const ForwardIter& x, const ForwardIter& y) {
68     return base(x) - base(y);
69 }
70 
71 struct ForwardRange : std::ranges::view_interface<ForwardRange> {
72   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginForwardRange73   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endForwardRange74   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
75 };
76 static_assert(std::ranges::view<ForwardRange>);
77 
78 struct 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;
beginMoveOnlyForwardRange84   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endMoveOnlyForwardRange85   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
86 };
87 static_assert(std::ranges::view<MoveOnlyForwardRange>);
88 
89 struct MI : std::ranges::view_interface<InputRange>,
90             std::ranges::view_interface<MoveOnlyForwardRange> {
91 };
92 static_assert(!std::ranges::view<MI>);
93 
94 struct EmptyIsTrue : std::ranges::view_interface<EmptyIsTrue> {
95   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginEmptyIsTrue96   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endEmptyIsTrue97   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
emptyEmptyIsTrue98   constexpr bool empty() const { return true; }
99 };
100 static_assert(std::ranges::view<EmptyIsTrue>);
101 
102 struct SizeIsTen : std::ranges::view_interface<SizeIsTen> {
103   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginSizeIsTen104   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endSizeIsTen105   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
sizeSizeIsTen106   constexpr std::size_t size() const { return 10; }
107 };
108 static_assert(std::ranges::view<SizeIsTen>);
109 
110 using RAIter = random_access_iterator<int*>;
111 
112 struct RARange : std::ranges::view_interface<RARange> {
113   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginRARange114   constexpr RAIter begin() const { return RAIter(const_cast<int*>(buff)); }
endRARange115   constexpr RAIter end() const { return RAIter(const_cast<int*>(buff) + 8); }
116 };
117 static_assert(std::ranges::view<RARange>);
118 
119 using ContIter = contiguous_iterator<const int*>;
120 
121 struct ContRange : std::ranges::view_interface<ContRange> {
122   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginContRange123   constexpr ContIter begin() const { return ContIter(buff); }
endContRange124   constexpr ContIter end() const { return ContIter(buff + 8); }
125 };
126 static_assert(std::ranges::view<ContRange>);
127 
128 struct DataIsNull : std::ranges::view_interface<DataIsNull> {
129   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
beginDataIsNull130   constexpr ContIter begin() const { return ContIter(buff); }
endDataIsNull131   constexpr ContIter end() const { return ContIter(buff + 8); }
dataDataIsNull132   constexpr const int *data() const { return nullptr; }
133 };
134 static_assert(std::ranges::view<DataIsNull>);
135 
136 struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison> {
137   struct ResultType {
138     bool value;
operator boolBoolConvertibleComparison::ResultType139     constexpr operator bool() const { return value; }
140   };
141 
142   struct SentinelType {
143     int *base_;
144     explicit SentinelType() = default;
SentinelTypeBoolConvertibleComparison::SentinelType145     constexpr explicit SentinelType(int *base) : base_(base) {}
operator ==BoolConvertibleComparison146     friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) == sent.base_}; }
operator ==BoolConvertibleComparison147     friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {base(iter) == sent.base_}; }
operator !=BoolConvertibleComparison148     friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {base(iter) != sent.base_}; }
operator !=BoolConvertibleComparison149     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};
beginBoolConvertibleComparison153   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
endBoolConvertibleComparison154   constexpr SentinelType end() const { return SentinelType(const_cast<int*>(buff) + 8); }
155 };
156 static_assert(std::ranges::view<BoolConvertibleComparison>);
157 
158 template<class T>
159 concept EmptyInvocable = requires (T const& obj) { obj.empty(); };
160 
161 template<class T>
162 concept BoolOpInvocable = requires (T const& obj) { bool(obj); };
163 
testEmpty()164 constexpr 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 
225 template<class T>
226 concept DataInvocable = requires (T const& obj) { obj.data(); };
227 
testData()228 constexpr 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 
250 template<class T>
251 concept SizeInvocable = requires (T const& obj) { obj.size(); };
252 
testSize()253 constexpr 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 
285 template<class T>
286 concept SubscriptInvocable = requires (T const& obj, std::size_t n) { obj[n]; };
287 
testSubscript()288 constexpr 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 
301 template<class T>
302 concept FrontInvocable = requires (T const& obj) { obj.front(); };
303 
304 template<class T>
305 concept BackInvocable = requires (T const& obj) { obj.back(); };
306 
testFrontBack()307 constexpr 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 
333 struct V1 : std::ranges::view_interface<V1> { };
334 struct V2 : std::ranges::view_interface<V2> { V1 base_; };
335 static_assert(sizeof(V2) == sizeof(V1));
336 
main(int,char **)337 int 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