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
21int globalBuff[8];
22
23template<class T>
24concept ValidRefView = requires { typename std::ranges::ref_view<T>; };
25
26struct Range {
27 int start = 0;
28 friend constexpr int* begin(Range const& range) { return globalBuff + range.start; }
29 friend constexpr int* end(Range const&) { return globalBuff + 8; }
30 friend constexpr int* begin(Range& range) { return globalBuff + range.start; }
31 friend constexpr int* end(Range&) { return globalBuff + 8; }
32};
33
34struct BeginOnly {
35 friend int* begin(BeginOnly const&);
36 friend int* begin(BeginOnly &);
37};
38
39static_assert( ValidRefView<Range>);
40static_assert(!ValidRefView<BeginOnly>);
41static_assert(!ValidRefView<int (&)[4]>);
42static_assert( ValidRefView<int[4]>);
43
44static_assert(std::derived_from<std::ranges::ref_view<Range>, std::ranges::view_interface<std::ranges::ref_view<Range>>>);
45
46struct RangeConvertible {
47 operator Range& ();
48};
49
50struct RValueRangeConvertible {
51 operator Range&& ();
52};
53
54static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, Range&>);
55static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, RangeConvertible>);
56static_assert(!std::is_constructible_v<std::ranges::ref_view<Range>, RValueRangeConvertible>);
57
58struct ConstConvertibleToLValueAndRValue {
59 operator Range& () const;
60 operator Range&& () const;
61};
62static_assert( std::is_convertible_v<RangeConvertible, std::ranges::ref_view<Range>>);
63static_assert(!std::is_convertible_v<RValueRangeConvertible, std::ranges::ref_view<Range>>);
64static_assert(!std::is_convertible_v<ConstConvertibleToLValueAndRValue, std::ranges::ref_view<Range>>);
65
66struct ForwardRange {
67 constexpr forward_iterator<int*> begin() const { return forward_iterator<int*>(globalBuff); }
68 constexpr forward_iterator<int*> end() const { return forward_iterator<int*>(globalBuff + 8); }
69};
70
71struct Cpp17InputRange {
72 struct sentinel {
73 friend constexpr bool operator==(sentinel, cpp17_input_iterator<int*> iter) { return base(iter) == globalBuff + 8; }
74 friend constexpr std::ptrdiff_t operator-(sentinel, cpp17_input_iterator<int*>) { return -8; }
75 friend constexpr std::ptrdiff_t operator-(cpp17_input_iterator<int*>, sentinel) { return 8; }
76 };
77
78 constexpr cpp17_input_iterator<int*> begin() const {
79 return cpp17_input_iterator<int*>(globalBuff);
80 }
81 constexpr sentinel end() const { return {}; }
82};
83
84struct Cpp20InputRange {
85 struct sentinel {
86 friend constexpr bool operator==(sentinel, const cpp20_input_iterator<int*> &iter) { return base(iter) == globalBuff + 8; }
87 friend constexpr std::ptrdiff_t operator-(sentinel, const cpp20_input_iterator<int*>&) { return -8; }
88 };
89
90 constexpr cpp20_input_iterator<int*> begin() const {
91 return cpp20_input_iterator<int*>(globalBuff);
92 }
93 constexpr sentinel end() const { return {}; }
94};
95
96template<>
97inline constexpr bool std::ranges::enable_borrowed_range<Cpp20InputRange> = true;
98
99template<class R>
100concept EmptyIsInvocable = requires (std::ranges::ref_view<R> view) { view.empty(); };
101
102template<class R>
103concept SizeIsInvocable = requires (std::ranges::ref_view<R> view) { view.size(); };
104
105template<class R>
106concept DataIsInvocable = requires (std::ranges::ref_view<R> view) { view.data(); };
107
108// Testing ctad.
109static_assert(std::same_as<decltype(std::ranges::ref_view(std::declval<Range&>())),
110 std::ranges::ref_view<Range>>);
111
112constexpr 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{.start: 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{.start: 8};
177 std::ranges::ref_view<Range> view1 = range1;
178 assert(view1.size() == 0);
179
180 Range range2{.start: 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{.start: 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
203int main(int, char**) {
204 test();
205 static_assert(test());
206
207 return 0;
208}
209

source code of libcxx/test/std/ranges/range.adaptors/range.all/range.ref.view/range.ref.view.pass.cpp