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