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// requires ref-is-glvalue && bidirectional_range<Base> &&
15// bidirectional-common<InnerBase> && bidirectional-common<PatternBase>;
16// constexpr iterator operator--(int)
17// requires ref-is-glvalue && bidirectional_range<Base> &&
18// bidirectional-common<InnerBase> && bidirectional-common<PatternBase>;
19
20#include <ranges>
21
22#include <algorithm>
23#include <array>
24#include <cassert>
25#include <forward_list>
26#include <string>
27#include <string_view>
28#include <vector>
29
30#include "../types.h"
31
32template <class I>
33concept CanPreDecrement = requires(I& i) {
34 { --i } -> std::same_as<I&>;
35};
36
37template <class I>
38concept CanPostDecrement = requires(I& i) {
39 { i-- } -> std::same_as<I>;
40};
41
42template <class I>
43concept CanDecrement = CanPreDecrement<I> && CanPostDecrement<I>;
44
45constexpr bool test() {
46 { // `V` and `Pattern` are not empty. Test return type too.
47 using V = std::ranges::owning_view<std::vector<std::string>>;
48 using Pattern = std::ranges::single_view<char>;
49 using JWV = std::ranges::join_with_view<V, Pattern>;
50
51 using Iter = std::ranges::iterator_t<JWV>;
52 using CIter = std::ranges::iterator_t<const JWV>;
53 static_assert(CanDecrement<Iter>);
54 static_assert(CanDecrement<CIter>);
55
56 JWV jwv(V{{"01", "23", "45"}}, Pattern{'_'});
57
58 {
59 auto it = jwv.end();
60 std::same_as<Iter&> decltype(auto) it_ref = --it;
61 assert(it_ref == it);
62 assert(*it == '5');
63 std::same_as<Iter> decltype(auto) it_copy = it--;
64 assert(--it_copy == it);
65 --it;
66 assert(*it == '_');
67 it--;
68 assert(*it == '3');
69 --it;
70 it--;
71 assert(*it == '_');
72 }
73
74 {
75 auto cit = std::as_const(jwv).end();
76 std::same_as<CIter&> decltype(auto) cit_ref = --cit;
77 assert(cit_ref == cit);
78 assert(*cit == '5');
79 std::same_as<CIter> decltype(auto) cit_copy = cit--;
80 assert(--cit_copy == cit);
81 --cit;
82 assert(*cit == '_');
83 cit--;
84 assert(*cit == '3');
85 --cit;
86 cit--;
87 assert(*cit == '_');
88 }
89
90 assert(std::ranges::equal(std::views::reverse(std::move(jwv)), std::string_view{"54_32_10"}));
91 }
92
93 { // `Pattern` is empty, `V` is not.
94 using Inner = std::array<int, 1>;
95 using V = std::ranges::owning_view<std::array<Inner, 3>>;
96 using Pattern = std::ranges::owning_view<std::array<int, 0>>;
97 using JWV = std::ranges::join_with_view<V, Pattern>;
98
99 JWV jwv(V{{Inner{-9}, Inner{-99}, Inner{-999}}}, Pattern{});
100
101 {
102 auto it = jwv.end();
103 --it;
104 assert(*it == -999);
105 it--;
106 assert(*it == -99);
107 --it;
108 assert(*it == -9);
109 assert(it == jwv.begin());
110 }
111
112 {
113 auto cit = std::as_const(jwv).end();
114 --cit;
115 assert(*cit == -999);
116 cit--;
117 assert(*cit == -99);
118 --cit;
119 assert(*cit == -9);
120 assert(cit == std::as_const(jwv).begin());
121 }
122 }
123
124#if !defined(TEST_COMPILER_GCC) // GCC c++/101777
125 { // `V` has empty subrange in the middle, `Pattern` is not empty. Try to go back and forth.
126 using V = std::array<std::vector<int>, 3>;
127 using Pattern = std::ranges::single_view<int>;
128 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;
129
130 JWV jwv(V{{{5}, {}, {125}}}, Pattern{1});
131
132 {
133 auto it = jwv.end();
134 --it;
135 assert(*it == 125);
136 it--;
137 assert(*it == 1);
138 --it;
139 assert(*it == 1);
140 it--;
141 assert(*it == 5);
142 ++it;
143 assert(*it == 1);
144 --it;
145 assert(*it == 5);
146 std::ranges::advance(it, 4);
147 it--;
148 assert(*it == 125);
149 }
150
151 {
152 auto cit = std::as_const(jwv).end();
153 --cit;
154 assert(*cit == 125);
155 cit--;
156 assert(*cit == 1);
157 --cit;
158 assert(*cit == 1);
159 cit--;
160 assert(*cit == 5);
161 ++cit;
162 assert(*cit == 1);
163 --cit;
164 assert(*cit == 5);
165 std::ranges::advance(cit, 4);
166 cit--;
167 assert(*cit == 125);
168 }
169 }
170
171 { // Only first element of `V` is not empty. `Pattern` is empty. Try to go back and forth.
172 using Inner = std::vector<int>;
173 using V = std::ranges::owning_view<std::array<Inner, 3>>;
174 using Pattern = std::ranges::empty_view<int>;
175 using JWV = std::ranges::join_with_view<V, Pattern>;
176
177 JWV jwv(V{{Inner{999}, {}, {}}}, Pattern{});
178
179 {
180 auto it = jwv.end();
181 --it;
182 assert(*it == 999);
183 ++it;
184 assert(it == jwv.end());
185 it--;
186 assert(*it == 999);
187 }
188
189 {
190 auto cit = std::as_const(jwv).end();
191 --cit;
192 assert(*cit == 999);
193 ++cit;
194 assert(cit == std::as_const(jwv).end());
195 cit--;
196 assert(*cit == 999);
197 }
198 }
199#endif // !defined(TEST_COMPILER_GCC)
200
201 { // `ref-is-glvalue` is false
202 using V = RvalueVector<std::vector<int>>;
203 using Pattern = std::ranges::empty_view<int>;
204 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;
205 using Iter = std::ranges::iterator_t<JWV>;
206 static_assert(!CanPreDecrement<Iter>);
207 static_assert(!CanPostDecrement<Iter>);
208 }
209
210 { // `Base` does not model bidirectional range
211 using V = std::ranges::owning_view<std::forward_list<std::vector<int>>>;
212 using Pattern = std::ranges::single_view<int>;
213 using JWV = std::ranges::join_with_view<V, Pattern>;
214 using Iter = std::ranges::iterator_t<JWV>;
215 using CIter = std::ranges::iterator_t<const JWV>;
216 static_assert(!CanPreDecrement<Iter>);
217 static_assert(!CanPostDecrement<Iter>);
218 static_assert(!CanPreDecrement<CIter>);
219 static_assert(!CanPostDecrement<CIter>);
220 }
221
222 { // InnerBase does not model bidirectional-common
223 { // InnerBase does not model bidirectional range
224 using V = std::ranges::owning_view<std::vector<std::forward_list<int>>>;
225 using Pattern = std::ranges::single_view<int>;
226 using JWV = std::ranges::join_with_view<V, Pattern>;
227 using Iter = std::ranges::iterator_t<JWV>;
228 using CIter = std::ranges::iterator_t<const JWV>;
229 static_assert(!CanPreDecrement<Iter>);
230 static_assert(!CanPostDecrement<Iter>);
231 static_assert(!CanPreDecrement<CIter>);
232 static_assert(!CanPostDecrement<CIter>);
233 }
234
235 { // InnerBase does not model common range
236 using InnerBase = BasicVectorView<int, ViewProperties{.common = false}, bidirectional_iterator>;
237 using V = std::ranges::owning_view<std::vector<InnerBase>>;
238 using Pattern = std::ranges::single_view<int>;
239 using JWV = std::ranges::join_with_view<V, Pattern>;
240 using Iter = std::ranges::iterator_t<JWV>;
241 using CIter = std::ranges::iterator_t<const JWV>;
242 static_assert(!CanPreDecrement<Iter>);
243 static_assert(!CanPostDecrement<Iter>);
244 static_assert(!CanPreDecrement<CIter>);
245 static_assert(!CanPostDecrement<CIter>);
246 }
247 }
248
249 { // PatternBase does not model bidirectional-common
250 { // PatternBase does not model bidirectional range
251 using V = std::ranges::owning_view<std::vector<std::vector<int>>>;
252 using Pattern = std::ranges::owning_view<std::forward_list<int>>;
253 using JWV = std::ranges::join_with_view<V, Pattern>;
254 using Iter = std::ranges::iterator_t<JWV>;
255 using CIter = std::ranges::iterator_t<const JWV>;
256 static_assert(!CanPreDecrement<Iter>);
257 static_assert(!CanPostDecrement<Iter>);
258 static_assert(!CanPreDecrement<CIter>);
259 static_assert(!CanPostDecrement<CIter>);
260 }
261
262 { // PatternBase does not model common range
263 using V = std::ranges::owning_view<std::vector<std::vector<int>>>;
264 using Pattern = BasicVectorView<int, ViewProperties{.common = false}, bidirectional_iterator>;
265 using JWV = std::ranges::join_with_view<V, Pattern>;
266 using Iter = std::ranges::iterator_t<JWV>;
267 using CIter = std::ranges::iterator_t<const JWV>;
268 static_assert(!CanPreDecrement<Iter>);
269 static_assert(!CanPostDecrement<Iter>);
270 static_assert(!CanPreDecrement<CIter>);
271 static_assert(!CanPostDecrement<CIter>);
272 }
273 }
274
275 return true;
276}
277
278int main(int, char**) {
279 test();
280 static_assert(test());
281
282 return 0;
283}
284

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