Skip to content

Commit 397227f

Browse files
fix test
1 parent 148961f commit 397227f

File tree

7 files changed

+350
-63
lines changed

7 files changed

+350
-63
lines changed

libcxx/include/__ranges/concat_view.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,8 @@ class concat_view<_Views...>::__iterator : public __concat_view_iterator_categor
491491
}
492492

493493
_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
494-
requires((random_access_range<__maybe_const<_Const, _Views>> && ...) &&
495-
(three_way_comparable<__maybe_const<_Const, _Views>> && ...))
494+
requires((__all_random_access<_Const, _Views> && ...) &&
495+
(three_way_comparable<iterator_t<__maybe_const<_Const, _Views>>> && ...))
496496
{
497497
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__x.__it_.valueless_by_exception() && !__y.__it_.valueless_by_exception(),
498498
"Trying to compare a valueless iterator of concat_view.");

libcxx/test/std/ranges/range.adaptors/range.concat/constraints.pass.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,46 @@
1111
#include <cassert>
1212
#include <list>
1313
#include <ranges>
14+
#include <type_traits>
1415
#include <vector>
1516
#include "test_iterators.h"
1617
#include "test_macros.h"
1718

18-
// This tests https://cplusplus.github.io/LWG/issue4082
19-
// views::concat(r) is well-formed when r is an output_range
19+
// test concept constraints
2020

2121
template<typename T>
2222
concept WellFormedView = requires(T& a) {
2323
std::views::concat(a);
2424
};
2525

26+
struct X {};
27+
28+
struct BadIter {
29+
using value_type = int;
30+
int* p;
31+
32+
BadIter() = default;
33+
explicit BadIter(int* q) : p(q) {}
34+
35+
int& operator*() const { return *p; }
36+
BadIter& operator++() {
37+
++p;
38+
return *this;
39+
}
40+
void operator++(int) { ++p; }
41+
42+
friend bool operator==(const BadIter& a, const BadIter& b) { return a.p == b.p; }
43+
friend bool operator!=(const BadIter& a, const BadIter& b) { return !(a == b); }
44+
45+
friend X iter_move(const BadIter&) { return X{}; }
46+
};
47+
48+
struct BadView : std::ranges::view_base {
49+
int buf_[1] = {0};
50+
BadIter begin() const { return BadIter(const_cast<int*>(buf_)); }
51+
BadIter end() const { return BadIter(const_cast<int*>(buf_ + 1)); }
52+
};
53+
2654
struct InputRange {
2755
using Iterator = cpp17_input_iterator<int*>;
2856
using Sentinel = sentinel_wrapper<Iterator>;
@@ -84,5 +112,20 @@ int main(int, char**) {
84112
static_assert(!ConcatViewConstraintsPass<std::vector<int>, std::vector<std::string>>);
85113
}
86114

115+
{
116+
// test concept concatable
117+
{
118+
// concat-reference-t is ill-formed
119+
// no common reference between int and string
120+
static_assert(!ConcatViewConstraintsPass<std::array<int, 1>, std::array<std::string, 1>>);
121+
}
122+
123+
{
124+
// concat-indirectly-readable is ill-formed
125+
// since iter_move of BadIter returns an unrelated type
126+
static_assert(!ConcatViewConstraintsPass<BadView, BadView>);
127+
}
128+
}
129+
87130
return 0;
88131
}

libcxx/test/std/ranges/range.adaptors/range.concat/iterator/arithmetic.pass.cpp

Lines changed: 133 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,20 @@
88

99
// REQUIRES: std-at-least-c++26
1010

11-
// friend constexpr iterator operator-(const iterator& it, difference_type n)
12-
// requires concat-is-random-access<Const, Views...>;
13-
14-
// friend constexpr difference_type operator-(const iterator& x, const iterator& y)
15-
// requires concat-is-random-access<Const, Views...>;
16-
17-
// friend constexpr difference_type operator-(default_sentinel_t, const __iterator& __x)
18-
// requires(sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_Const, _Views>>> &&
19-
// ...) &&
20-
// (__all_but_first_model_sized_range<_Const, _Views...>::value)
21-
22-
// friend constexpr difference_type operator-(const __iterator& __x, default_sentinel_t)
23-
// requires(sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_Const, _Views>>> &&
24-
// ...) &&
25-
// (__all_but_first_model_sized_range<_Const, _Views...>::value)
11+
// operator-(x, y)
12+
// operator-(x, sentinel)
13+
// operator-(sentinel, x)
14+
// operator-(x, n)
15+
// operator+(x, n)
16+
// operator+=(x, n)
17+
// operator-=(x, n)
18+
// operator<(x, y)
19+
// operator<=(x, y)
20+
// operator>=(x, y)
21+
// operator>(x, y)
22+
// operator<=>(x, y)
23+
// operator==(x, y)
24+
// operator==(x, sentinel)
2625

2726
#include <array>
2827
#include <concepts>
@@ -182,6 +181,125 @@ constexpr bool test() {
182181
}
183182
}
184183

184+
{
185+
// operator <, <=, >, >=
186+
std::array<int, 4> arr_a{1, 2, 3, 4};
187+
std::array<int, 3> arr_b{5, 6, 7};
188+
std::span<const int> s1{arr_a};
189+
std::span<const int> s2{arr_b};
190+
auto v = std::views::concat(s1, s2);
191+
using Iter = decltype(v.begin());
192+
using CIter = decltype(std::as_const(v).begin());
193+
auto i = v.begin();
194+
auto j = v.begin();
195+
std::ranges::advance(j, arr_a.size());
196+
197+
assert(i < j);
198+
assert(i <= j);
199+
assert(!(i > j));
200+
assert(!(i >= j));
201+
auto ord1 = (i <=> j);
202+
assert(ord1 < 0);
203+
assert((j <=> i) > 0);
204+
205+
auto k = j;
206+
assert(!(j < k));
207+
assert(j <= k);
208+
assert(!(j > k));
209+
assert(j >= k);
210+
auto ord2 = (j <=> k);
211+
assert(ord2 == 0);
212+
213+
// const-iterator
214+
const auto& cv = v;
215+
auto ci = cv.begin();
216+
auto cj = cv.begin();
217+
std::ranges::advance(cj, arr_a.size());
218+
assert(ci < cj);
219+
assert((ci <=> cj) < 0);
220+
}
221+
222+
{
223+
// operator==(x, sentinel)
224+
std::array<int, 2> arr_a{1, 2};
225+
std::array<int, 2> arr_b{3, 4};
226+
std::span<const int> s1{arr_a};
227+
std::span<const int> s2{arr_b};
228+
auto v = std::views::concat(s1, s2);
229+
230+
auto it = v.begin();
231+
assert(!(it == std::default_sentinel_t{}));
232+
233+
it++;
234+
it++;
235+
it++;
236+
it++;
237+
assert(it == std::default_sentinel_t{});
238+
239+
// const-iterator
240+
const auto& cv = v;
241+
auto cit = cv.begin();
242+
++cit;
243+
++cit;
244+
++cit;
245+
++cit;
246+
assert(cit == std::default_sentinel_t{});
247+
}
248+
249+
{
250+
// operator+(x, n) and operator+(n, x), where n is negative
251+
std::array<int, 4> arr_a{1, 2, 3, 4};
252+
std::array<int, 3> arr_b{5, 6, 7};
253+
std::span<const int> s1{arr_a};
254+
std::span<const int> s2{arr_b};
255+
auto v = std::views::concat(s1, s2);
256+
257+
auto i = v.begin();
258+
std::ranges::advance(i, arr_a.size());
259+
260+
auto j = i;
261+
auto j_1 = j + (-1);
262+
assert(*j_1 == arr_a.back());
263+
auto j_3 = j + (-3);
264+
assert(*j_3 == arr_a[1]);
265+
266+
// n + x (negative)
267+
auto k = (-1) + j;
268+
assert(*k == arr_a.back());
269+
270+
// const-iterator
271+
auto ci = std::as_const(v).begin();
272+
std::ranges::advance(ci, arr_a.size());
273+
auto cj = ci;
274+
auto cj_2 = cj + (-2);
275+
assert(*cj_2 == arr_a[2]);
276+
auto cjn = (-1) + cj;
277+
assert(*cjn == arr_a.back());
278+
}
279+
280+
{
281+
// operator-(x, n), where n is negative
282+
std::array<int, 4> arr_a{1, 2, 3, 4};
283+
std::array<int, 3> arr_b{5, 6, 7};
284+
std::span<const int> s1{arr_a};
285+
std::span<const int> s2{arr_b};
286+
auto v = std::views::concat(s1, s2);
287+
288+
auto i = v.begin();
289+
290+
auto j = i;
291+
auto j_1 = j - (-1);
292+
assert(*j_1 == arr_a[1]);
293+
auto j_3 = j - (-3);
294+
assert(*j_3 == arr_a.back());
295+
296+
// const-iterator
297+
auto ci = std::as_const(v).begin();
298+
auto cj = ci;
299+
auto cj_2 = cj - (-2);
300+
assert(*cj_2 == arr_a[2]);
301+
}
302+
185303
return true;
186304
}
187305

libcxx/test/std/ranges/range.adaptors/range.concat/iterator/decrement.pass.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,11 @@ constexpr bool test() {
126126
{
127127
auto v = std::views::concat(a, b);
128128

129-
// Position at the first element of `b`, then -- to land on a.back().
130129
auto it = v.begin();
131130
it += a.size();
132131
--it;
133132
assert(*it == a.back());
134133

135-
// Post-decrement variant from b[0]; result is old iterator, `it2` moves to a.back().
136134
auto it2 = v.begin();
137135
it2 += a.size();
138136
auto old = it2--;
@@ -165,7 +163,7 @@ constexpr bool test() {
165163
auto v = std::views::concat(a, e, b);
166164

167165
auto it = v.begin();
168-
it += a.size(); // points at beginning of b
166+
it += a.size();
169167
--it; // this skips e
170168
assert(*it == a.back());
171169

@@ -189,7 +187,7 @@ constexpr bool test() {
189187
auto v = std::views::concat(a, e1, e2, b);
190188

191189
auto it = v.begin();
192-
it += a.size(); // points to b[0]
190+
it += a.size();
193191
--it; // skip e2 and e1
194192
assert(*it == a.back());
195193
}

libcxx/test/std/ranges/range.adaptors/range.concat/iterator/increment.pass.cpp

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88

99
// REQUIRES: std-at-least-c++26
1010

11-
// friend constexpr __iterator operator+(const __iterator& __it, difference_type __n)
12-
// requires __concat_is_random_access<_Const, _Views...>
11+
// constexpr __iterator& operator++()
1312

14-
// friend constexpr __iterator operator+(difference_type __n, const __iterator& __it)
15-
// requires __concat_is_random_access<_Const, _Views...>
13+
// constexpr void operator++(int)
1614

1715
#include <array>
1816
#include <cassert>
@@ -100,6 +98,81 @@ constexpr bool test() {
10098
assert(*it == a[3]);
10199
}
102100

101+
// Different underlying range types; ++ crosses from end of first into start of second.
102+
{
103+
std::span<const int> sa{a};
104+
auto sb = std::ranges::subrange{b.data(), b.data() + b.size()};
105+
auto v = std::views::concat(sa, sb);
106+
107+
auto it = v.begin();
108+
for (size_t i = 1; i < a.size(); i++) {
109+
++it;
110+
}
111+
assert(*it == a.back());
112+
113+
++it;
114+
assert(*it == b.front());
115+
116+
auto it2 = v.begin();
117+
for (size_t i = 1; i < a.size(); i++) {
118+
++it2;
119+
}
120+
auto old = it2++;
121+
assert(*old == a.back());
122+
assert(*it2 == b.front());
123+
124+
// Same with a const-iterator.
125+
const auto& cv = v;
126+
auto cit = cv.begin();
127+
for (size_t i = 1; i < a.size(); i++) {
128+
++cit;
129+
}
130+
++cit;
131+
assert(*cit == b.front());
132+
}
133+
134+
// ++ crosses into next range when that next range is empty.
135+
{
136+
std::array<int, 0> e{};
137+
auto v = std::views::concat(a, e, b);
138+
139+
auto it = v.begin();
140+
for (size_t i = 1; i < a.size(); i++) {
141+
++it;
142+
}
143+
++it; // skip e
144+
assert(*it == b.front());
145+
146+
auto it2 = v.begin();
147+
for (size_t i = 1; i < a.size(); i++)
148+
++it2;
149+
auto old = it2++;
150+
assert(*old == a.back());
151+
assert(*it2 == b.front());
152+
153+
// Const-iterator.
154+
const auto& cv = v;
155+
auto cit = cv.begin();
156+
for (size_t i = 1; i < a.size(); i++)
157+
++cit;
158+
++cit;
159+
assert(*cit == b.front());
160+
}
161+
162+
// Multiple consecutive empty ranges are skipped on ++.
163+
{
164+
std::array<int, 0> e1{}, e2{};
165+
auto v = std::views::concat(a, e1, e2, b);
166+
167+
auto it = v.begin();
168+
for (size_t i = 1; i < a.size(); i++) {
169+
++it;
170+
}
171+
172+
++it; // skip e1 and e2
173+
assert(*it == b.front());
174+
}
175+
103176
return true;
104177
}
105178

0 commit comments

Comments
 (0)