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