Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing: Check c(begin|end) members of C++20 ranges #3612

Merged
merged 13 commits into from
Apr 7, 2023
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
JMazurkiewicz marked this conversation as resolved.
Show resolved Hide resolved
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