xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.all/range.ref.view/range.ref.view.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<range R>
12 //  requires is_object_v<R>
13 // class ref_view;
14 
15 #include <ranges>
16 
17 #include <cassert>
18 #include "test_macros.h"
19 #include "test_iterators.h"
20 
21 int globalBuff[8];
22 
23 template<class T>
24 concept ValidRefView = requires { typename std::ranges::ref_view<T>; };
25 
26 struct Range {
27   int start = 0;
begin(Range const & range)28   friend constexpr int* begin(Range const& range) { return globalBuff + range.start; }
end(Range const &)29   friend constexpr int* end(Range const&) { return globalBuff + 8; }
begin(Range & range)30   friend constexpr int* begin(Range& range) { return globalBuff + range.start; }
end(Range &)31   friend constexpr int* end(Range&) { return globalBuff + 8; }
32 };
33 
34 struct BeginOnly {
35   friend int* begin(BeginOnly const&);
36   friend int* begin(BeginOnly &);
37 };
38 
39 static_assert( ValidRefView<Range>);
40 static_assert(!ValidRefView<BeginOnly>);
41 static_assert(!ValidRefView<int (&)[4]>);
42 static_assert( ValidRefView<int[4]>);
43 
44 static_assert(std::derived_from<std::ranges::ref_view<Range>, std::ranges::view_interface<std::ranges::ref_view<Range>>>);
45 
46 struct RangeConvertible {
47   operator Range& ();
48 };
49 
50 struct RValueRangeConvertible {
51   operator Range&& ();
52 };
53 
54 static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, Range&>);
55 static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, RangeConvertible>);
56 static_assert(!std::is_constructible_v<std::ranges::ref_view<Range>, RValueRangeConvertible>);
57 
58 struct ConstConvertibleToLValueAndRValue {
59   operator Range& () const;
60   operator Range&& () const;
61 };
62 static_assert( std::is_convertible_v<RangeConvertible, std::ranges::ref_view<Range>>);
63 static_assert(!std::is_convertible_v<RValueRangeConvertible, std::ranges::ref_view<Range>>);
64 static_assert(!std::is_convertible_v<ConstConvertibleToLValueAndRValue, std::ranges::ref_view<Range>>);
65 
66 struct ForwardRange {
beginForwardRange67   constexpr forward_iterator<int*> begin() const { return forward_iterator<int*>(globalBuff); }
endForwardRange68   constexpr forward_iterator<int*> end() const { return forward_iterator<int*>(globalBuff + 8); }
69 };
70 
71 struct Cpp17InputRange {
72   struct sentinel {
operator ==Cpp17InputRange73     friend constexpr bool operator==(sentinel, cpp17_input_iterator<int*> iter) { return base(iter) == globalBuff + 8; }
operator -Cpp17InputRange74     friend constexpr std::ptrdiff_t operator-(sentinel, cpp17_input_iterator<int*>) { return -8; }
operator -Cpp17InputRange75     friend constexpr std::ptrdiff_t operator-(cpp17_input_iterator<int*>, sentinel) { return 8; }
76   };
77 
beginCpp17InputRange78   constexpr cpp17_input_iterator<int*> begin() const {
79     return cpp17_input_iterator<int*>(globalBuff);
80   }
endCpp17InputRange81   constexpr sentinel end() const { return {}; }
82 };
83 
84 struct Cpp20InputRange {
85   struct sentinel {
operator ==Cpp20InputRange86     friend constexpr bool operator==(sentinel, const cpp20_input_iterator<int*> &iter) { return base(iter) == globalBuff + 8; }
operator -Cpp20InputRange87     friend constexpr std::ptrdiff_t operator-(sentinel, const cpp20_input_iterator<int*>&) { return -8; }
88   };
89 
beginCpp20InputRange90   constexpr cpp20_input_iterator<int*> begin() const {
91     return cpp20_input_iterator<int*>(globalBuff);
92   }
endCpp20InputRange93   constexpr sentinel end() const { return {}; }
94 };
95 
96 template<>
97 inline constexpr bool std::ranges::enable_borrowed_range<Cpp20InputRange> = true;
98 
99 template<class R>
100 concept EmptyIsInvocable = requires (std::ranges::ref_view<R> view) { view.empty(); };
101 
102 template<class R>
103 concept SizeIsInvocable = requires (std::ranges::ref_view<R> view) { view.size(); };
104 
105 template<class R>
106 concept DataIsInvocable = requires (std::ranges::ref_view<R> view) { view.data(); };
107 
108 // Testing ctad.
109 static_assert(std::same_as<decltype(std::ranges::ref_view(std::declval<Range&>())),
110               std::ranges::ref_view<Range>>);
111 
test()112 constexpr bool test() {
113   {
114     // ref_view::base
115     Range range;
116     std::ranges::ref_view<Range> view{range};
117     assert(view.begin() == globalBuff);
118     view.base() = Range{2};
119     assert(view.begin() == globalBuff + 2);
120   }
121 
122   {
123     // ref_view::begin
124     Range range1;
125     std::ranges::ref_view<Range> view1 = range1;
126     assert(view1.begin() == globalBuff);
127 
128     ForwardRange range2;
129     std::ranges::ref_view<ForwardRange> view2 = range2;
130     assert(base(view2.begin()) == globalBuff);
131 
132     Cpp17InputRange range3;
133     std::ranges::ref_view<Cpp17InputRange> view3 = range3;
134     assert(base(view3.begin()) == globalBuff);
135 
136     Cpp20InputRange range4;
137     std::ranges::ref_view<Cpp20InputRange> view4 = range4;
138     assert(base(view4.begin()) == globalBuff);
139   }
140 
141   {
142     // ref_view::end
143     Range range1;
144     std::ranges::ref_view<Range> view1 = range1;
145     assert(view1.end() == globalBuff + 8);
146 
147     ForwardRange range2;
148     std::ranges::ref_view<ForwardRange> view2 = range2;
149     assert(base(view2.end()) == globalBuff + 8);
150 
151     Cpp17InputRange range3;
152     std::ranges::ref_view<Cpp17InputRange> view3 = range3;
153     assert(view3.end() == cpp17_input_iterator(globalBuff + 8));
154 
155     Cpp20InputRange range4;
156     std::ranges::ref_view<Cpp20InputRange> view4 = range4;
157     assert(view4.end() == cpp20_input_iterator(globalBuff + 8));
158   }
159 
160   {
161     // ref_view::empty
162     Range range{8};
163     std::ranges::ref_view<Range> view1 = range;
164     assert(view1.empty());
165 
166     ForwardRange range2;
167     std::ranges::ref_view<ForwardRange> view2 = range2;
168     assert(!view2.empty());
169 
170     static_assert(!EmptyIsInvocable<Cpp17InputRange>);
171     static_assert(!EmptyIsInvocable<Cpp20InputRange>);
172   }
173 
174   {
175     // ref_view::size
176     Range range1{8};
177     std::ranges::ref_view<Range> view1 = range1;
178     assert(view1.size() == 0);
179 
180     Range range2{2};
181     std::ranges::ref_view<Range> view2 = range2;
182     assert(view2.size() == 6);
183 
184     static_assert(!SizeIsInvocable<ForwardRange>);
185   }
186 
187   {
188     // ref_view::data
189     Range range1;
190     std::ranges::ref_view<Range> view1 = range1;
191     assert(view1.data() == globalBuff);
192 
193     Range range2{2};
194     std::ranges::ref_view<Range> view2 = range2;
195     assert(view2.data() == globalBuff + 2);
196 
197     static_assert(!DataIsInvocable<ForwardRange>);
198   }
199 
200   return true;
201 }
202 
main(int,char **)203 int main(int, char**) {
204   test();
205   static_assert(test());
206 
207   return 0;
208 }
209