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// REQUIRES: std-at-least-c++23
10
11// <ranges>
12
13// constexpr iterator& operator++();
14// constexpr void operator++(int);
15// constexpr iterator operator++(int)
16// requires ref-is-glvalue && forward_iterator<OuterIter> &&
17// forward_iterator<InnerIter>;
18
19#include <ranges>
20
21#include <array>
22#include <cassert>
23#include <type_traits>
24#include <vector>
25
26#include "../types.h"
27
28template <class I>
29concept CanPreIncrement = requires(I& i) { ++i; };
30
31template <class I>
32concept CanPostIncrement = requires(I& i) { i++; };
33
34template <bool RefIsGlvalue, class Inner>
35using VRange = std::conditional_t<RefIsGlvalue, std::vector<Inner>, RvalueVector<Inner>>;
36
37template <bool RefIsGlvalue>
38constexpr void test_pre_increment() {
39 { // `V` and `Pattern` are not empty. Test return type too.
40 using V = VRange<RefIsGlvalue, std::array<int, 2>>;
41 using Pattern = std::array<int, 2>;
42 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
43
44 JWV jwv(V{{1, 1}, {2, 2}, {3, 3}}, Pattern{0, 0});
45
46 {
47 using Iter = std::ranges::iterator_t<JWV>;
48 static_assert(CanPreIncrement<Iter>);
49 static_assert(!CanPreIncrement<const Iter>);
50
51 auto it = jwv.begin();
52 assert(*it == 1);
53 std::same_as<Iter&> decltype(auto) it_ref = ++it;
54 if constexpr (RefIsGlvalue) {
55 assert(it_ref == it);
56 }
57
58 ++it;
59 assert(*it == 0);
60 ++it_ref;
61 ++it_ref;
62 assert(*it_ref == 2);
63 ++it;
64 ++it_ref;
65 assert(*it == 0);
66 }
67
68 if constexpr (RefIsGlvalue) {
69 using CIter = std::ranges::iterator_t<const JWV>;
70 static_assert(CanPreIncrement<CIter>);
71 static_assert(!CanPreIncrement<const CIter>);
72
73 auto cit = std::as_const(jwv).begin();
74 assert(*cit == 1);
75 std::same_as<CIter&> decltype(auto) cit_ref = ++cit;
76 assert(cit_ref == cit);
77 ++cit;
78 assert(*cit == 0);
79 ++cit_ref;
80 ++cit_ref;
81 assert(*cit_ref == 2);
82 ++cit;
83 ++cit_ref;
84 assert(*cit == 0);
85 }
86 }
87
88 { // `V` and `Pattern` are empty.
89 using V = VRange<RefIsGlvalue, std::ranges::empty_view<int>>;
90 using Pattern = std::ranges::empty_view<int>;
91 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
92
93 JWV jwv = {};
94
95 {
96 auto it = jwv.begin();
97 assert(it == jwv.end());
98 }
99
100 if constexpr (RefIsGlvalue) {
101 auto cit = std::as_const(jwv).begin();
102 assert(cit == std::as_const(jwv).end());
103 }
104 }
105
106 { // `Pattern` is empty, `V` is not.
107 using V = VRange<RefIsGlvalue, std::vector<int>>;
108 using Pattern = std::vector<int>;
109 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
110
111 JWV jwv(V{{{-1}, {-2}, {-3}}}, Pattern{});
112
113 {
114 auto it = jwv.begin();
115 assert(*it == -1);
116 ++it;
117 assert(*it == -2);
118 ++it;
119 assert(*it == -3);
120 ++it;
121 assert(it == jwv.end());
122 }
123
124 if constexpr (RefIsGlvalue) {
125 auto cit = std::as_const(jwv).begin();
126 assert(*cit == -1);
127 ++cit;
128 assert(*cit == -2);
129 ++cit;
130 assert(*cit == -3);
131 ++cit;
132 assert(cit == std::as_const(jwv).end());
133 }
134 }
135
136 { // `V` has empty subrange in the middle, `Pattern` is not empty.
137 using V = VRange<RefIsGlvalue, std::vector<int>>;
138 using Pattern = std::ranges::single_view<int>;
139 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;
140
141 JWV jwv(V{{1}, {}, {3}}, Pattern{0});
142
143 {
144 auto it = jwv.begin();
145 assert(*it == 1);
146 ++it;
147 assert(*it == 0);
148 ++it;
149 assert(*it == 0);
150 ++it;
151 assert(*it == 3);
152 }
153
154 if constexpr (RefIsGlvalue) {
155 auto cit = std::as_const(jwv).begin();
156 assert(*cit == 1);
157 ++cit;
158 assert(*cit == 0);
159 ++cit;
160 assert(*cit == 0);
161 ++cit;
162 assert(*cit == 3);
163 }
164 }
165
166 { // Only last element of `V` is not empty. `Pattern` is not empty.
167 using V = VRange<RefIsGlvalue, std::vector<int>>;
168 using Pattern = std::ranges::single_view<int>;
169 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;
170
171 JWV jwv(V{{}, {}, {555}}, Pattern{1});
172
173 {
174 auto it = jwv.begin();
175 assert(*it == 1);
176 ++it;
177 assert(*it == 1);
178 ++it;
179 assert(*it == 555);
180 ++it;
181 assert(it == jwv.end());
182 }
183
184 if constexpr (RefIsGlvalue) {
185 auto cit = std::as_const(jwv).begin();
186 assert(*cit == 1);
187 ++cit;
188 assert(*cit == 1);
189 ++cit;
190 assert(*cit == 555);
191 ++cit;
192 assert(cit == std::as_const(jwv).end());
193 }
194 }
195
196 { // Only first element of `V` is not empty. `Pattern` is empty.
197 using V = VRange<RefIsGlvalue, std::vector<int>>;
198 using Pattern = std::ranges::empty_view<int>;
199 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;
200
201 JWV jwv(V{{777}, {}, {}}, Pattern{});
202
203 {
204 auto it = jwv.begin();
205 assert(*it == 777);
206 ++it;
207 assert(it == jwv.end());
208 }
209
210 if constexpr (RefIsGlvalue) {
211 auto cit = std::as_const(jwv).begin();
212 assert(*cit == 777);
213 ++cit;
214 assert(cit == std::as_const(jwv).end());
215 }
216 }
217
218 { // Only last element of `V` is not empty. `Pattern` is empty. `V` models input range.
219 using V = BasicView<VRange<RefIsGlvalue, std::string>, ViewProperties{}, DefaultCtorInputIter>;
220 using Pattern = std::ranges::empty_view<char>;
221 using JWV = std::ranges::join_with_view<V, Pattern>;
222
223 JWV jwv(V{{}, {}, {'a'}}, Pattern{});
224
225 auto it = jwv.begin();
226 assert(*it == 'a');
227 ++it;
228 assert(it == jwv.end());
229 }
230
231 { // Only first element of `V` is not empty. `Pattern` is not empty. `V` models input range.
232 using V = BasicView<VRange<RefIsGlvalue, std::string>, ViewProperties{}, DefaultCtorInputIter>;
233 using Pattern = std::ranges::single_view<char>;
234 using JWV = std::ranges::join_with_view<V, Pattern>;
235
236 JWV jwv(V{{'b'}, {}, {}}, Pattern{'.'});
237
238 auto it = jwv.begin();
239 assert(*it == 'b');
240 ++it;
241 assert(*it == '.');
242 ++it;
243 assert(*it == '.');
244 ++it;
245 assert(it == jwv.end());
246 }
247}
248
249constexpr void test_post_increment() {
250 { // `V` and `Pattern` are not empty. Return type should be `iterator`.
251 using V = std::array<std::array<int, 3>, 2>;
252 using Pattern = std::array<int, 1>;
253 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
254
255 using Iter = std::ranges::iterator_t<JWV>;
256 using CIter = std::ranges::iterator_t<const JWV>;
257 static_assert(CanPostIncrement<Iter>);
258 static_assert(!CanPostIncrement<const Iter>);
259 static_assert(CanPostIncrement<CIter>);
260 static_assert(!CanPostIncrement<const CIter>);
261
262 JWV jwv(V{._M_elems: {{6, 5, 4}, {3, 2, 1}}}, Pattern{-5});
263
264 {
265 auto it = jwv.begin();
266 assert(*it == 6);
267 std::same_as<Iter> decltype(auto) it_copy = it++;
268 assert(++it_copy == it);
269 it++;
270 it++;
271 assert(*it == -5);
272 it_copy++;
273 it_copy++;
274 assert(*it_copy == -5);
275 it++;
276 it_copy++;
277 assert(*it == 3);
278 assert(*it_copy == 3);
279 }
280
281 {
282 auto cit = std::as_const(jwv).begin();
283 assert(*cit == 6);
284 std::same_as<CIter> decltype(auto) cit_copy = cit++;
285 assert(++cit_copy == cit);
286 cit++;
287 cit++;
288 assert(*cit == -5);
289 cit_copy++;
290 cit_copy++;
291 assert(*cit_copy == -5);
292 cit++;
293 cit_copy++;
294 assert(*cit == 3);
295 assert(*cit_copy == 3);
296 }
297 }
298
299 { // `Pattern` is empty, `V` is not. Value of `ref-is-glvalue` is false (return type should be `void`).
300 using Inner = std::vector<int>;
301 using V = RvalueVector<Inner>;
302 using Pattern = std::ranges::empty_view<int>;
303 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
304
305 JWV jwv(V{Inner{-3}, Inner{-2}, Inner{-1}}, Pattern{});
306
307 auto it = jwv.begin();
308 assert(*it == -3);
309 it++;
310 assert(*it == -2);
311 it++;
312 assert(*it == -1);
313 it++;
314 assert(it == jwv.end());
315 static_assert(std::is_void_v<decltype(it++)>);
316 }
317
318 { // `V` has empty subrange in the middle, `Pattern` is not empty.
319 // OuterIter does not model forward iterator (return type should be `void`).
320 using Inner = std::vector<int>;
321 using V = BasicVectorView<Inner, ViewProperties{.common = false}, cpp20_input_iterator>;
322 using Pattern = std::ranges::single_view<int>;
323 using JWV = std::ranges::join_with_view<V, Pattern>;
324
325 JWV jwv(V{Inner{7}, {}, Inner{9}}, Pattern{8});
326
327 auto it = jwv.begin();
328 assert(*it == 7);
329 it++;
330 assert(*it == 8);
331 it++;
332 assert(*it == 8);
333 it++;
334 assert(*it == 9);
335 it++;
336 assert(it == jwv.end());
337 static_assert(std::is_void_v<decltype(it++)>);
338 }
339
340#if !defined(TEST_COMPILER_GCC) // GCC c++/101777
341 { // Only first element of `V` is not empty. `Pattern` is empty. InnerIter does not model forward
342 // iterator (return type should be `void`).
343 using Inner = BasicVectorView<char32_t, ViewProperties{.common = false}, cpp17_input_iterator>;
344 using V = std::array<Inner, 3>;
345 using Pattern = std::ranges::empty_view<char32_t>;
346 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;
347
348 JWV jwv(V{Inner{U'?'}, Inner{}, Inner{}}, Pattern{});
349
350 auto it = jwv.begin();
351 assert(*it == U'?');
352 it++;
353 assert(it == jwv.end());
354 static_assert(std::is_void_v<decltype(it++)>);
355 }
356#endif // !defined(TEST_COMPILER_GCC)
357}
358
359constexpr bool test() {
360 test_pre_increment<false>();
361 test_pre_increment<true>();
362 test_post_increment();
363
364 return true;
365}
366
367int main(int, char**) {
368 test();
369 static_assert(test());
370
371 return 0;
372}
373

source code of libcxx/test/std/ranges/range.adaptors/range.join.with/range.join.with.iterator/increment.pass.cpp