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