Skip to content

Commit adaf68c

Browse files
Testing: Check c(begin|end) members of C++20 ranges (#3612)
1 parent b37ff31 commit adaf68c

File tree

7 files changed

+294
-0
lines changed

7 files changed

+294
-0
lines changed

Diff for: tests/std/tests/P0896R4_ranges_ref_view/test.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,26 @@ struct instantiator {
8686
STATIC_ASSERT(noexcept(as_const(test_view).end()) == noexcept(wrapped_input.end()));
8787
}
8888

89+
#if _HAS_CXX23
90+
if constexpr (ranges::input_range<R>) { // const iterators (from view_interface)
91+
R wrapped_input{input};
92+
ref_view<R> test_view{wrapped_input};
93+
const same_as<ranges::const_iterator_t<R>> auto cfirst = as_const(test_view).cbegin();
94+
if constexpr (_Is_specialization_v<remove_const_t<decltype(cfirst)>, basic_const_iterator>) {
95+
assert(cfirst.base().peek() == begin(input));
96+
} else {
97+
assert(cfirst.peek() == begin(input));
98+
}
99+
100+
const same_as<ranges::const_sentinel_t<R>> auto clast = as_const(test_view).cend();
101+
if constexpr (_Is_specialization_v<remove_const_t<decltype(clast)>, basic_const_iterator>) {
102+
assert(clast.base().peek() == end(input));
103+
} else {
104+
assert(clast.peek() == end(input));
105+
}
106+
}
107+
#endif // _HAS_CXX23
108+
89109
{ // state
90110
STATIC_ASSERT(can_size<ref_view<R>> == ranges::sized_range<R>);
91111
if constexpr (ranges::sized_range<R>) {

Diff for: tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,15 @@ namespace test_subrange {
10361036
STATIC_ASSERT(HasMemberEmpty<Subrange const>);
10371037
STATIC_ASSERT(!copyable<I> || range<Subrange const&>);
10381038

1039+
#if _HAS_CXX23 // Validate cbegin/cend
1040+
if constexpr (ranges::input_range<Subrange>) {
1041+
STATIC_ASSERT(CanMemberCBegin<Subrange>);
1042+
STATIC_ASSERT(CanMemberCBegin<const Subrange> == ranges::input_range<const Subrange&>);
1043+
STATIC_ASSERT(CanMemberCEnd<Subrange>);
1044+
STATIC_ASSERT(CanMemberCEnd<const Subrange> == ranges::input_range<const Subrange&>);
1045+
}
1046+
#endif // _HAS_CXX23
1047+
10391048
// Validate size
10401049
STATIC_ASSERT(sized == HasMemberSize<Subrange>);
10411050

Diff for: tests/std/tests/P0896R4_views_common/test.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,46 @@ void non_literal_parts(R& r, E& expected) {
6363
}
6464
}
6565
}
66+
67+
#if _HAS_CXX23
68+
using ranges::const_iterator_t;
69+
70+
const same_as<const_iterator_t<R>> auto cfirst = r.cbegin();
71+
if (!is_empty) {
72+
assert(*cfirst == *begin(expected));
73+
}
74+
75+
if constexpr (copyable<V>) {
76+
auto r2 = r;
77+
const same_as<const_iterator_t<R>> auto cfirst2 = r2.cbegin();
78+
if (!is_empty) {
79+
assert(*cfirst2 == *cfirst);
80+
}
81+
}
82+
83+
if constexpr (CanCBegin<const R&>) {
84+
const same_as<const_iterator_t<const R>> auto cfirst3 = as_const(r).cbegin();
85+
if (!is_empty) {
86+
assert(*cfirst3 == *cfirst);
87+
}
88+
}
89+
90+
const same_as<const_iterator_t<R>> auto clast = r.cend();
91+
if constexpr (bidirectional_range<R>) {
92+
if (!is_empty) {
93+
assert(*prev(clast) == *prev(end(expected)));
94+
}
95+
}
96+
97+
if constexpr (CanCEnd<const R&>) {
98+
const same_as<const_iterator_t<const R>> auto clast2 = as_const(r).cend();
99+
if constexpr (bidirectional_range<const R>) {
100+
if (!is_empty) {
101+
assert(*prev(clast2) == *prev(end(expected)));
102+
}
103+
}
104+
}
105+
#endif // _HAS_CXX23
66106
}
67107

68108
template <class Rng, class Expected>

Diff for: tests/std/tests/P0896R4_views_filter/test.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,54 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
201201
STATIC_ASSERT(!CanEnd<const F>);
202202
}
203203

204+
#if _HAS_CXX23
205+
using ranges::const_iterator_t, ranges::const_sentinel_t;
206+
207+
// Validate view_interface::cbegin
208+
STATIC_ASSERT(CanMemberCBegin<F>);
209+
if (forward_range<V>) { // intentionally not if constexpr
210+
// Ditto "let's make some extra calls because memoization"
211+
const same_as<const_iterator_t<F>> auto ci = r.cbegin();
212+
if (!is_empty) {
213+
assert(*ci == *begin(expected));
214+
}
215+
assert(*r.cbegin() == *begin(expected));
216+
assert(*r.cbegin() == *begin(expected));
217+
218+
if constexpr (copy_constructible<V>) {
219+
auto r2 = r;
220+
const same_as<const_iterator_t<F>> auto ci2 = r2.cbegin();
221+
assert(*r2.cbegin() == *ci2);
222+
assert(*r2.cbegin() == *ci2);
223+
if (!is_empty) {
224+
assert(*ci2 == *ci);
225+
}
226+
}
227+
228+
STATIC_ASSERT(!CanMemberCBegin<const F>);
229+
}
230+
231+
// Validate view_interface::cend
232+
STATIC_ASSERT(CanMemberCEnd<F>);
233+
if (!is_empty) {
234+
if constexpr (common_range<V>) {
235+
same_as<const_iterator_t<F>> auto ci = r.cend();
236+
if constexpr (bidirectional_range<V>) {
237+
assert(*prev(ci) == *prev(end(expected)));
238+
}
239+
} else {
240+
[[maybe_unused]] same_as<const_sentinel_t<F>> auto cs = r.cend();
241+
}
242+
243+
if constexpr (bidirectional_range<V> && common_range<V> && copy_constructible<V>) {
244+
auto r2 = r;
245+
assert(*prev(r2.cend()) == *prev(end(expected)));
246+
}
247+
248+
STATIC_ASSERT(!CanMemberCEnd<const F>);
249+
}
250+
#endif // _HAS_CXX23
251+
204252
// Validate view_interface::data
205253
STATIC_ASSERT(!CanData<F>);
206254
STATIC_ASSERT(!CanData<const F>);

Diff for: tests/std/tests/P0896R4_views_join/test.cpp

+71
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,77 @@ constexpr bool test_one(Outer&& rng, Expected&& expected) {
215215
}
216216
}
217217

218+
#if _HAS_CXX23
219+
using ranges::const_iterator_t, ranges::const_sentinel_t;
220+
221+
// Validate view_interface::cbegin
222+
static_assert(CanMemberCBegin<R>);
223+
static_assert(CanMemberCBegin<const R>
224+
== (forward_range<const V> && is_reference_v<range_reference_t<const V>>
225+
&& input_range<range_reference_t<const V>>) );
226+
if (forward_range<R>) { // intentionally not if constexpr
227+
const same_as<const_iterator_t<R>> auto ci = r.cbegin();
228+
if (!is_empty) {
229+
assert(*ci == *begin(expected));
230+
}
231+
232+
if constexpr (copyable<V>) {
233+
auto r2 = r;
234+
const same_as<const_iterator_t<R>> auto ci2 = r2.cbegin();
235+
if (!is_empty) {
236+
assert(*ci2 == *ci);
237+
}
238+
}
239+
240+
static_assert(CanMemberCBegin<const R> == CanCBegin<const R&>);
241+
if constexpr (CanMemberCBegin<const R>) {
242+
const same_as<const_iterator_t<const R>> auto ci2 = as_const(r).cbegin();
243+
if (!is_empty) {
244+
assert(*ci2 == *ci);
245+
}
246+
247+
if constexpr (copyable<V>) {
248+
const auto r2 = r;
249+
const same_as<const_iterator_t<const R>> auto ci3 = r2.cbegin();
250+
if (!is_empty) {
251+
assert(*ci3 == *ci);
252+
}
253+
}
254+
}
255+
}
256+
257+
// Validate view_interface::cend
258+
static_assert(CanMemberCEnd<R>);
259+
static_assert(CanMemberCEnd<const R>
260+
== (forward_range<const V> && is_reference_v<range_reference_t<const V>>
261+
&& input_range<range_reference_t<const V>>) );
262+
const same_as<const_sentinel_t<R>> auto cs = r.end();
263+
if (!is_empty) {
264+
if constexpr (bidirectional_range<R> && common_range<R>) {
265+
assert(*prev(cs) == *prev(end(expected)));
266+
267+
if constexpr (copyable<V>) {
268+
auto r2 = r;
269+
assert(*prev(r2.cend()) == *prev(end(expected)));
270+
}
271+
}
272+
273+
static_assert(CanMemberCEnd<const R> == CanCEnd<const R&>);
274+
if constexpr (CanMemberCEnd<const R>) {
275+
const same_as<const_sentinel_t<const R>> auto cs2 = as_const(r).cend();
276+
if constexpr (bidirectional_range<R> && common_range<R>) {
277+
assert(*prev(cs2) == *prev(end(expected)));
278+
279+
if constexpr (copyable<V>) {
280+
const auto r2 = r;
281+
const same_as<const_sentinel_t<const R>> auto cs3 = r2.cend();
282+
assert(*prev(cs3) == *prev(end(expected)));
283+
}
284+
}
285+
}
286+
}
287+
#endif // _HAS_CXX23
288+
218289
// Validate view_interface::data
219290
static_assert(!CanData<R>);
220291
static_assert(!CanData<const R>);

Diff for: tests/std/tests/P0896R4_views_reverse/test.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,64 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
230230
}
231231
}
232232

233+
#if _HAS_CXX23
234+
// Validate view_interface::cbegin
235+
static_assert(CanMemberCBegin<R>);
236+
{
237+
// Ditto "let's make some extra calls because reverse_view sometimes caches begin"
238+
const same_as<const_iterator<reverse_iterator<iterator_t<V>>>> auto ci = r.cbegin();
239+
if (!is_empty) {
240+
assert(*ci == *begin(expected));
241+
}
242+
243+
if constexpr (copyable<V>) {
244+
auto r2 = r;
245+
const same_as<const_iterator<reverse_iterator<iterator_t<V>>>> auto ci2 = r2.cbegin();
246+
assert(r2.cbegin() == ci2);
247+
assert(r2.cbegin() == ci2);
248+
if (!is_empty) {
249+
assert(*ci2 == *ci);
250+
}
251+
}
252+
253+
static_assert(CanMemberCBegin<const R> == common_range<Rng>);
254+
if constexpr (CanMemberCBegin<const R>) {
255+
const same_as<const_iterator<reverse_iterator<iterator_t<const V>>>> auto ci3 = as_const(r).cbegin();
256+
assert(as_const(r).cbegin() == ci3);
257+
assert(as_const(r).cbegin() == ci3);
258+
if (!is_empty) {
259+
assert(*ci3 == *ci);
260+
}
261+
262+
if constexpr (copyable<V>) {
263+
const auto r2 = r;
264+
const same_as<const_iterator<reverse_iterator<iterator_t<const V>>>> auto ci4 = r2.cbegin();
265+
assert(r2.cbegin() == ci4);
266+
assert(r2.cbegin() == ci4);
267+
if (!is_empty) {
268+
assert(*ci4 == *ci);
269+
}
270+
}
271+
}
272+
}
273+
274+
// Validate view_interface::cend
275+
static_assert(CanMemberCEnd<R>);
276+
if (!is_empty) {
277+
assert(*prev(r.cend()) == *prev(end(expected)));
278+
279+
if constexpr (copyable<V>) {
280+
auto r2 = r;
281+
assert(*prev(r2.cend()) == *prev(end(expected)));
282+
}
283+
284+
static_assert(CanMemberCEnd<const R> == common_range<Rng>);
285+
if constexpr (CanMemberCEnd<const R>) {
286+
assert(*prev(as_const(r).cend()) == *prev(end(expected)));
287+
}
288+
}
289+
#endif // _HAS_CXX23
290+
233291
// Validate view_interface::data
234292
static_assert(!CanData<R>);
235293
static_assert(!CanData<const R>);

Diff for: tests/std/tests/P0896R4_views_transform/test.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,54 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
250250
}
251251
}
252252

253+
#if _HAS_CXX23
254+
using ranges::const_iterator_t, ranges::const_sentinel_t;
255+
256+
// Validate view_interface::cbegin
257+
STATIC_ASSERT(CanMemberCBegin<R>);
258+
STATIC_ASSERT(CanMemberCBegin<const R&> == (range<const V> && const_invocable));
259+
if (forward_range<V>) { // intentionally not if constexpr
260+
const same_as<const_iterator_t<R>> auto ci = r.cbegin();
261+
if (!is_empty) {
262+
assert(*ci == *begin(expected));
263+
}
264+
265+
if constexpr (copy_constructible<V>) {
266+
auto r2 = r;
267+
const same_as<const_iterator_t<R>> auto ci2 = r2.cbegin();
268+
if (!is_empty) {
269+
assert(*ci2 == *ci);
270+
}
271+
}
272+
273+
if constexpr (CanMemberCBegin<const R&>) {
274+
const same_as<const_iterator_t<const R>> auto ci3 = as_const(r).cbegin();
275+
if (!is_empty) {
276+
assert(*ci3 == *ci);
277+
}
278+
}
279+
}
280+
281+
// Validate view_interface::cend
282+
STATIC_ASSERT(CanMemberCEnd<R>);
283+
STATIC_ASSERT(CanMemberCEnd<const R&> == (range<const V> && const_invocable));
284+
if (!is_empty) {
285+
same_as<const_sentinel_t<R>> auto cs = r.cend();
286+
STATIC_ASSERT(is_same_v<const_sentinel_t<R>, const_iterator_t<R>> == common_range<V>);
287+
if constexpr (bidirectional_range<R> && common_range<R>) {
288+
assert(*prev(cs) == *prev(end(expected)));
289+
}
290+
291+
if constexpr (CanMemberCEnd<const R&>) {
292+
same_as<const_sentinel_t<const R>> auto cs2 = as_const(r).cend();
293+
STATIC_ASSERT(is_same_v<const_sentinel_t<const R>, const_iterator_t<const R>> == common_range<const V>);
294+
if constexpr (bidirectional_range<const R> && common_range<const R>) {
295+
assert(*prev(cs2) == *prev(end(expected)));
296+
}
297+
}
298+
}
299+
#endif // _HAS_CXX23
300+
253301
// Validate view_interface::data
254302
STATIC_ASSERT(!CanData<TV>);
255303
STATIC_ASSERT(!CanData<const TV>);

0 commit comments

Comments
 (0)