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