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 // UNSUPPORTED: libcpp-no-concepts
11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
12 
13 // template<class D>
14 //   requires is_class_v<D> && same_as<D, remove_cv_t<D>>
15 // class view_interface;
16 
17 #include <ranges>
18 
19 #include <cassert>
20 #include "test_macros.h"
21 #include "test_iterators.h"
22 
23 template<class T>
24 concept ValidViewInterfaceType = requires { typename std::ranges::view_interface<T>; };
25 
26 struct Empty { };
27 
28 static_assert(!ValidViewInterfaceType<void>);
29 static_assert(!ValidViewInterfaceType<void*>);
30 static_assert(!ValidViewInterfaceType<Empty*>);
31 static_assert(!ValidViewInterfaceType<Empty const>);
32 static_assert(!ValidViewInterfaceType<Empty &>);
33 static_assert( ValidViewInterfaceType<Empty>);
34 
35 static_assert(std::derived_from<std::ranges::view_interface<Empty>, std::ranges::view_base>);
36 
37 using InputIter = cpp20_input_iterator<const int*>;
38 
39 struct InputRange : std::ranges::view_interface<InputRange> {
40   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
41   constexpr InputIter begin() const { return InputIter(buff); }
42   constexpr InputIter end() const { return InputIter(buff + 8); }
43 };
44 
45 struct NotSizedSentinel {
46   using value_type = int;
47   using difference_type = std::ptrdiff_t;
48   using iterator_concept = std::forward_iterator_tag;
49 
50   explicit NotSizedSentinel() = default;
51   explicit NotSizedSentinel(int*);
52   int& operator*() const;
53   NotSizedSentinel& operator++();
54   NotSizedSentinel operator++(int);
55   bool operator==(NotSizedSentinel const&) const;
56 };
57 static_assert(std::forward_iterator<NotSizedSentinel>);
58 
59 using ForwardIter = forward_iterator<int*>;
60 
61 // So that we conform to sized_sentinel_for.
62 constexpr std::ptrdiff_t operator-(const ForwardIter& x, const ForwardIter& y) {
63     return x.base() - y.base();
64 }
65 
66 struct ForwardRange : std::ranges::view_interface<ForwardRange> {
67   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
68   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
69   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
70 };
71 static_assert(std::ranges::view<ForwardRange>);
72 
73 struct MoveOnlyForwardRange : std::ranges::view_interface<MoveOnlyForwardRange> {
74   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
75   MoveOnlyForwardRange(MoveOnlyForwardRange const&) = delete;
76   MoveOnlyForwardRange(MoveOnlyForwardRange &&) = default;
77   MoveOnlyForwardRange& operator=(MoveOnlyForwardRange &&) = default;
78   MoveOnlyForwardRange() = default;
79   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
80   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
81 };
82 static_assert(std::ranges::view<MoveOnlyForwardRange>);
83 
84 struct EmptyIsTrue : std::ranges::view_interface<EmptyIsTrue> {
85   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
86   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
87   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
88   constexpr bool empty() const { return true; }
89 };
90 static_assert(std::ranges::view<EmptyIsTrue>);
91 
92 struct SizeIsTen : std::ranges::view_interface<SizeIsTen> {
93   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
94   constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
95   constexpr ForwardIter end() const { return ForwardIter(const_cast<int*>(buff) + 8); }
96   constexpr size_t size() const { return 10; }
97 };
98 static_assert(std::ranges::view<SizeIsTen>);
99 
100 using RAIter = random_access_iterator<int*>;
101 
102 struct RARange : std::ranges::view_interface<RARange> {
103   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
104   constexpr RAIter begin() const { return RAIter(const_cast<int*>(buff)); }
105   constexpr RAIter end() const { return RAIter(const_cast<int*>(buff) + 8); }
106 };
107 static_assert(std::ranges::view<RARange>);
108 
109 using ContIter = contiguous_iterator<const int*>;
110 
111 struct ContRange : std::ranges::view_interface<ContRange> {
112   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
113   constexpr ContIter begin() const { return ContIter(buff); }
114   constexpr ContIter end() const { return ContIter(buff + 8); }
115 };
116 static_assert(std::ranges::view<ContRange>);
117 
118 struct DataIsNull : std::ranges::view_interface<DataIsNull> {
119   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
120   constexpr ContIter begin() const { return ContIter(buff); }
121   constexpr ContIter end() const { return ContIter(buff + 8); }
122   constexpr const int *data() const { return nullptr; }
123 };
124 static_assert(std::ranges::view<DataIsNull>);
125 
126 template<bool IsNoexcept>
127 struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison<IsNoexcept>> {
128   struct ResultType {
129     bool value;
130     constexpr operator bool() const noexcept(IsNoexcept) { return value; }
131   };
132 
133   struct SentinelType {
134     int *base_;
135     SentinelType() = default;
136     explicit constexpr SentinelType(int *base) : base_(base) {}
137     friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {iter.base() == sent.base_}; }
138     friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {iter.base() == sent.base_}; }
139     friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {iter.base() != sent.base_}; }
140     friend constexpr ResultType operator!=(SentinelType const& sent, ForwardIter const& iter) noexcept { return {iter.base() != sent.base_}; }
141   };
142 
143   int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
144   constexpr ForwardIter begin() const noexcept { return ForwardIter(const_cast<int*>(buff)); }
145   constexpr SentinelType end() const noexcept { return SentinelType(const_cast<int*>(buff) + 8); }
146 };
147 static_assert(std::ranges::view<BoolConvertibleComparison<true>>);
148 static_assert(std::ranges::view<BoolConvertibleComparison<false>>);
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 
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<true> boolConv;
190   BoolConvertibleComparison<false> boolConv2;
191   static_assert(noexcept(boolConv.empty()));
192   static_assert(!noexcept(boolConv2.empty()));
193 
194   assert(!boolConv.empty());
195   assert(!static_cast<BoolConvertibleComparison<true> const&>(boolConv).empty());
196 
197   assert(boolConv);
198   assert(static_cast<BoolConvertibleComparison<true> const&>(boolConv));
199 
200   assert(!std::ranges::empty(boolConv));
201   assert(!std::ranges::empty(static_cast<BoolConvertibleComparison<true> const&>(boolConv)));
202 
203   return true;
204 }
205 
206 template<class T>
207 concept DataInvocable = requires (T const& obj) { obj.data(); };
208 
209 constexpr bool testData() {
210   static_assert(!DataInvocable<ForwardRange>);
211   static_assert( DataInvocable<ContRange>);
212 
213   ContRange contiguous;
214   assert(contiguous.data() == contiguous.buff);
215   assert(static_cast<ContRange const&>(contiguous).data() == contiguous.buff);
216 
217   assert(std::ranges::data(contiguous) == contiguous.buff);
218   assert(std::ranges::data(static_cast<ContRange const&>(contiguous)) == contiguous.buff);
219 
220   DataIsNull dataNull;
221   assert(dataNull.data() == nullptr);
222   assert(static_cast<DataIsNull const&>(dataNull).data() == nullptr);
223   assert(dataNull.std::ranges::view_interface<DataIsNull>::data() == dataNull.buff);
224 
225   assert(std::ranges::data(dataNull) == nullptr);
226   assert(std::ranges::data(static_cast<DataIsNull const&>(dataNull)) == nullptr);
227 
228   return true;
229 }
230 
231 template<class T>
232 concept SizeInvocable = requires (T const& obj) { obj.size(); };
233 
234 constexpr bool testSize() {
235   static_assert(!SizeInvocable<InputRange>);
236   static_assert(!SizeInvocable<NotSizedSentinel>);
237   static_assert( SizeInvocable<ForwardRange>);
238 
239   ForwardRange forwardRange;
240   assert(forwardRange.size() == 8);
241   assert(static_cast<ForwardRange const&>(forwardRange).size() == 8);
242 
243   assert(std::ranges::size(forwardRange) == 8);
244   assert(std::ranges::size(static_cast<ForwardRange const&>(forwardRange)) == 8);
245 
246   SizeIsTen sizeTen;
247   assert(sizeTen.size() == 10);
248   assert(static_cast<SizeIsTen const&>(sizeTen).size() == 10);
249   assert(sizeTen.std::ranges::view_interface<SizeIsTen>::size() == 8);
250 
251   assert(std::ranges::size(sizeTen) == 10);
252   assert(std::ranges::size(static_cast<SizeIsTen const&>(sizeTen)) == 10);
253 
254   return true;
255 }
256 
257 template<class T>
258 concept SubscriptInvocable = requires (T const& obj, size_t n) { obj[n]; };
259 
260 constexpr bool testSubscript() {
261   static_assert(!SubscriptInvocable<ForwardRange>);
262   static_assert( SubscriptInvocable<RARange>);
263 
264   RARange randomAccess;
265   assert(randomAccess[2] == 2);
266   assert(static_cast<RARange const&>(randomAccess)[2] == 2);
267   randomAccess[2] = 3;
268   assert(randomAccess[2] == 3);
269 
270   return true;
271 }
272 
273 template<class T>
274 concept FrontInvocable = requires (T const& obj) { obj.front(); };
275 
276 template<class T>
277 concept BackInvocable = requires (T const& obj) { obj.back(); };
278 
279 constexpr bool testFrontBack() {
280   static_assert(!FrontInvocable<InputRange>);
281   static_assert( FrontInvocable<ForwardRange>);
282   static_assert(!BackInvocable<ForwardRange>);
283   static_assert( BackInvocable<RARange>);
284 
285   ForwardRange forwardRange;
286   assert(forwardRange.front() == 0);
287   assert(static_cast<ForwardRange const&>(forwardRange).front() == 0);
288   forwardRange.front() = 2;
289   assert(forwardRange.front() == 2);
290 
291   RARange randomAccess;
292   assert(randomAccess.front() == 0);
293   assert(static_cast<RARange const&>(randomAccess).front() == 0);
294   randomAccess.front() = 2;
295   assert(randomAccess.front() == 2);
296 
297   assert(randomAccess.back() == 7);
298   assert(static_cast<RARange const&>(randomAccess).back() == 7);
299   randomAccess.back() = 2;
300   assert(randomAccess.back() == 2);
301 
302   return true;
303 }
304 
305 int main(int, char**) {
306   testEmpty();
307   static_assert(testEmpty());
308 
309   testData();
310   static_assert(testData());
311 
312   testSize();
313   static_assert(testSize());
314 
315   testSubscript();
316   static_assert(testSubscript());
317 
318   testFrontBack();
319   static_assert(testFrontBack());
320 
321   return 0;
322 }
323