Skip to content
20 changes: 20 additions & 0 deletions tests/std/tests/P0896R4_ranges_ref_view/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ struct instantiator {
STATIC_ASSERT(noexcept(as_const(test_view).end()) == noexcept(wrapped_input.end()));
}

#if _HAS_CXX23
if constexpr (ranges::input_range<R>) { // const iterators (from view_interface)
R wrapped_input{input};
ref_view<R> test_view{wrapped_input};
const same_as<ranges::const_iterator_t<R>> auto cfirst = as_const(test_view).cbegin();
if constexpr (_Is_specialization_v<remove_const_t<decltype(cfirst)>, basic_const_iterator>) {
assert(cfirst.base().peek() == begin(input));
} else {
assert(cfirst.peek() == begin(input));
}

const same_as<ranges::const_sentinel_t<R>> auto clast = as_const(test_view).cend();
if constexpr (_Is_specialization_v<remove_const_t<decltype(clast)>, basic_const_iterator>) {
assert(clast.base().peek() == end(input));
} else {
assert(clast.peek() == end(input));
}
}
#endif // _HAS_CXX23

{ // state
STATIC_ASSERT(can_size<ref_view<R>> == ranges::sized_range<R>);
if constexpr (ranges::sized_range<R>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,15 @@ namespace test_subrange {
STATIC_ASSERT(HasMemberEmpty<Subrange const>);
STATIC_ASSERT(!copyable<I> || range<Subrange const&>);

#if _HAS_CXX23 // Validate cbegin/cend
if constexpr (ranges::input_range<Subrange>) {
STATIC_ASSERT(CanMemberCBegin<Subrange>);
STATIC_ASSERT(CanMemberCBegin<const Subrange> == ranges::input_range<const Subrange&>);
STATIC_ASSERT(CanMemberCEnd<Subrange>);
STATIC_ASSERT(CanMemberCEnd<const Subrange> == ranges::input_range<const Subrange&>);
}
#endif // _HAS_CXX23

// Validate size
STATIC_ASSERT(sized == HasMemberSize<Subrange>);

Expand Down
40 changes: 40 additions & 0 deletions tests/std/tests/P0896R4_views_common/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,46 @@ void non_literal_parts(R& r, E& expected) {
}
}
}

#if _HAS_CXX23
using ranges::const_iterator_t;

const same_as<const_iterator_t<R>> auto cfirst = r.cbegin();
if (!is_empty) {
assert(*cfirst == *begin(expected));
}

if constexpr (copyable<V>) {
auto r2 = r;
const same_as<const_iterator_t<R>> auto cfirst2 = r2.cbegin();
if (!is_empty) {
assert(*cfirst2 == *cfirst);
}
}

if constexpr (CanCBegin<const R&>) {
const same_as<const_iterator_t<const R>> auto cfirst3 = as_const(r).cbegin();
if (!is_empty) {
assert(*cfirst3 == *cfirst);
}
}

const same_as<const_iterator_t<R>> auto clast = r.cend();
if constexpr (bidirectional_range<R>) {
if (!is_empty) {
assert(*prev(clast) == *prev(end(expected)));
}
}

if constexpr (CanCEnd<const R&>) {
const same_as<const_iterator_t<const R>> auto clast2 = as_const(r).cend();
if constexpr (bidirectional_range<const R>) {
if (!is_empty) {
assert(*prev(clast2) == *prev(end(expected)));
}
}
}
#endif // _HAS_CXX23
}

template <class Rng, class Expected>
Expand Down
48 changes: 48 additions & 0 deletions tests/std/tests/P0896R4_views_filter/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,54 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
STATIC_ASSERT(!CanEnd<const F>);
}

#if _HAS_CXX23
using ranges::const_iterator_t, ranges::const_sentinel_t;

// Validate view_interface::cbegin
STATIC_ASSERT(CanMemberCBegin<F>);
if (forward_range<V>) { // intentionally not if constexpr
// Ditto "let's make some extra calls because memoization"
const same_as<const_iterator_t<F>> auto ci = r.cbegin();
if (!is_empty) {
assert(*ci == *begin(expected));
}
assert(*r.cbegin() == *begin(expected));
assert(*r.cbegin() == *begin(expected));

if constexpr (copy_constructible<V>) {
auto r2 = r;
const same_as<const_iterator_t<F>> auto ci2 = r2.cbegin();
assert(*r2.cbegin() == *ci2);
assert(*r2.cbegin() == *ci2);
if (!is_empty) {
assert(*ci2 == *ci);
}
}

STATIC_ASSERT(!CanMemberCBegin<const F>);
}

// Validate view_interface::cend
STATIC_ASSERT(CanMemberCEnd<F>);
if (!is_empty) {
if constexpr (common_range<V>) {
same_as<const_iterator_t<F>> auto ci = r.cend();
if constexpr (bidirectional_range<V>) {
assert(*prev(ci) == *prev(end(expected)));
}
} else {
[[maybe_unused]] same_as<const_sentinel_t<F>> auto cs = r.cend();
}

if constexpr (bidirectional_range<V> && common_range<V> && copy_constructible<V>) {
auto r2 = r;
assert(*prev(r2.cend()) == *prev(end(expected)));
}

STATIC_ASSERT(!CanMemberCEnd<const F>);
}
#endif // _HAS_CXX23

// Validate view_interface::data
STATIC_ASSERT(!CanData<F>);
STATIC_ASSERT(!CanData<const F>);
Expand Down
71 changes: 71 additions & 0 deletions tests/std/tests/P0896R4_views_join/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,77 @@ constexpr bool test_one(Outer&& rng, Expected&& expected) {
}
}

#if _HAS_CXX23
using ranges::const_iterator_t, ranges::const_sentinel_t;

// Validate view_interface::cbegin
static_assert(CanMemberCBegin<R>);
static_assert(CanMemberCBegin<const R>
== (forward_range<const V> && is_reference_v<range_reference_t<const V>>
&& input_range<range_reference_t<const V>>) );
if (forward_range<R>) { // intentionally not if constexpr
const same_as<const_iterator_t<R>> auto ci = r.cbegin();
if (!is_empty) {
assert(*ci == *begin(expected));
}

if constexpr (copyable<V>) {
auto r2 = r;
const same_as<const_iterator_t<R>> auto ci2 = r2.cbegin();
if (!is_empty) {
assert(*ci2 == *ci);
}
}

static_assert(CanMemberCBegin<const R> == CanCBegin<const R&>);
if constexpr (CanMemberCBegin<const R>) {
const same_as<const_iterator_t<const R>> auto ci2 = as_const(r).cbegin();
if (!is_empty) {
assert(*ci2 == *ci);
}

if constexpr (copyable<V>) {
const auto r2 = r;
const same_as<const_iterator_t<const R>> auto ci3 = r2.cbegin();
if (!is_empty) {
assert(*ci3 == *ci);
}
}
}
}

// Validate view_interface::cend
static_assert(CanMemberCEnd<R>);
static_assert(CanMemberCEnd<const R>
== (forward_range<const V> && is_reference_v<range_reference_t<const V>>
&& input_range<range_reference_t<const V>>) );
const same_as<const_sentinel_t<R>> auto cs = r.end();
if (!is_empty) {
if constexpr (bidirectional_range<R> && common_range<R>) {
assert(*prev(cs) == *prev(end(expected)));

if constexpr (copyable<V>) {
auto r2 = r;
assert(*prev(r2.cend()) == *prev(end(expected)));
}
}

static_assert(CanMemberCEnd<const R> == CanCEnd<const R&>);
if constexpr (CanMemberCEnd<const R>) {
const same_as<const_sentinel_t<const R>> auto cs2 = as_const(r).cend();
if constexpr (bidirectional_range<R> && common_range<R>) {
assert(*prev(cs2) == *prev(end(expected)));

if constexpr (copyable<V>) {
const auto r2 = r;
const same_as<const_sentinel_t<const R>> auto cs3 = r2.cend();
assert(*prev(cs3) == *prev(end(expected)));
}
}
}
}
#endif // _HAS_CXX23

// Validate view_interface::data
static_assert(!CanData<R>);
static_assert(!CanData<const R>);
Expand Down
58 changes: 58 additions & 0 deletions tests/std/tests/P0896R4_views_reverse/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,64 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
}

#if _HAS_CXX23
// Validate view_interface::cbegin
static_assert(CanMemberCBegin<R>);
{
// Ditto "let's make some extra calls because reverse_view sometimes caches begin"
const same_as<const_iterator<reverse_iterator<iterator_t<V>>>> auto ci = r.cbegin();
if (!is_empty) {
assert(*ci == *begin(expected));
}

if constexpr (copyable<V>) {
auto r2 = r;
const same_as<const_iterator<reverse_iterator<iterator_t<V>>>> auto ci2 = r2.cbegin();
assert(r2.cbegin() == ci2);
assert(r2.cbegin() == ci2);
if (!is_empty) {
assert(*ci2 == *ci);
}
}

static_assert(CanMemberCBegin<const R> == common_range<Rng>);
if constexpr (CanMemberCBegin<const R>) {
const same_as<const_iterator<reverse_iterator<iterator_t<const V>>>> auto ci3 = as_const(r).cbegin();
assert(as_const(r).cbegin() == ci3);
assert(as_const(r).cbegin() == ci3);
if (!is_empty) {
assert(*ci3 == *ci);
}

if constexpr (copyable<V>) {
const auto r2 = r;
const same_as<const_iterator<reverse_iterator<iterator_t<const V>>>> auto ci4 = r2.cbegin();
assert(r2.cbegin() == ci4);
assert(r2.cbegin() == ci4);
if (!is_empty) {
assert(*ci4 == *ci);
}
}
}
}

// Validate view_interface::cend
static_assert(CanMemberCEnd<R>);
if (!is_empty) {
assert(*prev(r.cend()) == *prev(end(expected)));

if constexpr (copyable<V>) {
auto r2 = r;
assert(*prev(r2.cend()) == *prev(end(expected)));
}

static_assert(CanMemberCEnd<const R> == common_range<Rng>);
if constexpr (CanMemberCEnd<const R>) {
assert(*prev(as_const(r).cend()) == *prev(end(expected)));
}
}
#endif // _HAS_CXX23

// Validate view_interface::data
static_assert(!CanData<R>);
static_assert(!CanData<const R>);
Expand Down
48 changes: 48 additions & 0 deletions tests/std/tests/P0896R4_views_transform/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,54 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
}

#if _HAS_CXX23
using ranges::const_iterator_t, ranges::const_sentinel_t;

// Validate view_interface::cbegin
STATIC_ASSERT(CanMemberCBegin<R>);
STATIC_ASSERT(CanMemberCBegin<const R&> == (range<const V> && const_invocable));
if (forward_range<V>) { // intentionally not if constexpr
const same_as<const_iterator_t<R>> auto ci = r.cbegin();
if (!is_empty) {
assert(*ci == *begin(expected));
}

if constexpr (copy_constructible<V>) {
auto r2 = r;
const same_as<const_iterator_t<R>> auto ci2 = r2.cbegin();
if (!is_empty) {
assert(*ci2 == *ci);
}
}

if constexpr (CanMemberCBegin<const R&>) {
const same_as<const_iterator_t<const R>> auto ci3 = as_const(r).cbegin();
if (!is_empty) {
assert(*ci3 == *ci);
}
}
}

// Validate view_interface::cend
STATIC_ASSERT(CanMemberCEnd<R>);
STATIC_ASSERT(CanMemberCEnd<const R&> == (range<const V> && const_invocable));
if (!is_empty) {
same_as<const_sentinel_t<R>> auto cs = r.cend();
STATIC_ASSERT(is_same_v<const_sentinel_t<R>, const_iterator_t<R>> == common_range<V>);
if constexpr (bidirectional_range<R> && common_range<R>) {
assert(*prev(cs) == *prev(end(expected)));
}

if constexpr (CanMemberCEnd<const R&>) {
same_as<const_sentinel_t<const R>> auto cs2 = as_const(r).cend();
STATIC_ASSERT(is_same_v<const_sentinel_t<const R>, const_iterator_t<const R>> == common_range<const V>);
if constexpr (bidirectional_range<const R> && common_range<const R>) {
assert(*prev(cs2) == *prev(end(expected)));
}
}
}
#endif // _HAS_CXX23

// Validate view_interface::data
STATIC_ASSERT(!CanData<TV>);
STATIC_ASSERT(!CanData<const TV>);
Expand Down