Skip to content

Commit

Permalink
Implement LWG-4098 views::adjacent<0> should reject non-forward ran…
Browse files Browse the repository at this point in the history
…ges (#4815)

Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
frederick-vs-ja and StephanTLavavej committed Jul 11, 2024
1 parent de1eb6f commit 5236e38
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 11 deletions.
5 changes: 3 additions & 2 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -8370,7 +8370,7 @@ namespace ranges {

template <viewable_range _Rng>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&&) _CONST_CALL_OPERATOR noexcept
requires (_Nx == 0)
requires (_Nx == 0) && forward_range<_Rng>
{
return empty_view<tuple<>>{};
}
Expand Down Expand Up @@ -8706,7 +8706,8 @@ namespace ranges {
template <viewable_range _Rng, class _Fn>
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&&, _Fn&& _Func) _CONST_CALL_OPERATOR
noexcept(noexcept(views::zip_transform(_STD forward<_Fn>(_Func))))
requires (_Nx == 0) && requires { views::zip_transform(_STD forward<_Fn>(_Func)); }
requires (_Nx == 0)
&& forward_range<_Rng> && requires { views::zip_transform(_STD forward<_Fn>(_Func)); }
{
return views::zip_transform(_STD forward<_Fn>(_Func));
}
Expand Down
68 changes: 63 additions & 5 deletions tests/std/tests/P2321R2_views_adjacent/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static_assert(same_as<repeated_tuple<int, 5>, tuple<int, int, int, int, int>>);
// Check views::pairwise
static_assert(same_as<decltype(views::pairwise), decltype(views::adjacent<2>)>);

template <size_t N, ranges::input_range Rng, class Expected>
template <size_t N, ranges::forward_range Rng, class Expected>
constexpr bool test_one(Rng&& rng, Expected&& expected) {
using ranges::adjacent_view, ranges::forward_range, ranges::bidirectional_range, ranges::random_access_range,
ranges::sized_range, ranges::common_range, ranges::iterator_t, ranges::sentinel_t, ranges::const_iterator_t,
Expand All @@ -55,7 +55,6 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
using R = adjacent_view<V, N>;

static_assert(ranges::view<R>);
static_assert(ranges::input_range<R>);
static_assert(forward_range<R>);
static_assert(bidirectional_range<R> == bidirectional_range<Rng>);
static_assert(random_access_range<R> == random_access_range<Rng>);
Expand Down Expand Up @@ -732,7 +731,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
return true;
}

template <ranges::input_range Rng>
template <ranges::forward_range Rng>
constexpr void test_adjacent0(Rng&& rng) {
static_assert(!CanConstructAdjacentView<Rng, 0>);
using V = views::all_t<Rng>;
Expand Down Expand Up @@ -783,7 +782,7 @@ constexpr void test_adjacent0(Rng&& rng) {
}
}

template <size_t N, ranges::input_range Rng>
template <size_t N, ranges::forward_range Rng>
requires indirectly_swappable<ranges::iterator_t<Rng>>
constexpr void test_iter_swap(Rng& rng) {
// This test assumes that 'ranges::size(views::adjacent<N>(rng))' is at least 2
Expand Down Expand Up @@ -841,7 +840,7 @@ using test_range =

struct instantiator {
#ifdef TEST_EVERYTHING
template <ranges::input_range R>
template <ranges::forward_range R>
static constexpr void call() {
R r{some_ints};
test_one<1>(r, adjacent1_result);
Expand Down Expand Up @@ -899,6 +898,62 @@ constexpr void instantiation_test() {
#endif // TEST_EVERYTHING
}

// LWG-4098 views::adjacent<0> should reject non-forward ranges
template <size_t N, ranges::input_range Rng>
constexpr void test_input_only(Rng&&) {
if constexpr (!ranges::forward_range<Rng>) {
static_assert(!CanViewAdjacent<Rng&, N>);
static_assert(!CanViewAdjacent<Rng, N>);
static_assert(!CanConstructAdjacentView<Rng&, N>);
static_assert(!CanConstructAdjacentView<Rng, N>);
}

if constexpr (!ranges::forward_range<const Rng>) {
static_assert(!CanViewAdjacent<const Rng&, N>);
static_assert(!CanViewAdjacent<const Rng, N>);
static_assert(!CanConstructAdjacentView<const Rng&, N>);
static_assert(!CanConstructAdjacentView<const Rng, N>);
}
}

struct input_only_instantiator {
#ifdef TEST_EVERYTHING
template <ranges::input_range R>
static constexpr void call() {
R r{some_ints};
test_input_only<0>(r);
test_input_only<1>(r);
test_input_only<2>(r);
test_input_only<4>(r);
test_input_only<7>(r);
}
#else // ^^^ test all input range permutations / test only "interesting" permutations vvv
template <class Tag, test::Common IsCommon, test::Sized IsSized>
static constexpr void call() {
test_range<const int, Tag, IsCommon, IsSized> r{some_ints};
test_input_only<0>(r);
test_input_only<1>(r);
test_input_only<2>(r);
test_input_only<4>(r);
test_input_only<7>(r);
}
#endif // TEST_EVERYTHING
};

constexpr void instantiation_input_only_test() {
#ifdef TEST_EVERYTHING
test_in<input_only_instantiator, const int>();
#else // ^^^ test all input range permutations / test only "interesting" permutations vvv
using test::Common, test::Sized;

// The view is sensitive to category, commonality, and size, but oblivious to proxyness and differencing
input_only_instantiator::call<input_iterator_tag, Common::no, Sized::yes>();
input_only_instantiator::call<input_iterator_tag, Common::no, Sized::no>();
input_only_instantiator::call<input_iterator_tag, Common::yes, Sized::yes>();
input_only_instantiator::call<input_iterator_tag, Common::yes, Sized::no>();
#endif // TEST_EVERYTHING
}

template <class Category, test::Common IsCommon, bool is_random = derived_from<Category, random_access_iterator_tag>>
using move_only_view = test::range<Category, const int, test::Sized{is_random}, test::CanDifference{is_random},
IsCommon, test::CanCompare::yes, test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>},
Expand Down Expand Up @@ -939,4 +994,7 @@ int main() {

static_assert((instantiation_test(), true));
instantiation_test();

static_assert((instantiation_input_only_test(), true));
instantiation_input_only_test();
}
64 changes: 60 additions & 4 deletions tests/std/tests/P2321R2_views_adjacent_transform/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ using invoke_result_with_repeated_type = invoke_result_with_repeated_type_impl<F
static_assert(same_as<invoke_result_with_repeated_type<plus<int>, int, 2>, int>);
static_assert(same_as<invoke_result_with_repeated_type<equal_to<int>, int, 2>, bool>);

template <size_t N, ranges::input_range Rng, class Expected, class Fn>
template <size_t N, ranges::forward_range Rng, class Expected, class Fn>
constexpr bool test_one(Rng&& rng, Fn func, Expected&& expected_rng) {
using ranges::adjacent_transform_view, ranges::adjacent_view, ranges::forward_range, ranges::bidirectional_range,
ranges::random_access_range, ranges::sized_range, ranges::common_range, ranges::iterator_t,
Expand All @@ -86,7 +86,6 @@ constexpr bool test_one(Rng&& rng, Fn func, Expected&& expected_rng) {
using R = adjacent_transform_view<V, decay_t<Fn>, N>;

static_assert(ranges::view<R>);
static_assert(ranges::input_range<R>);
static_assert(forward_range<R>);
static_assert(bidirectional_range<R> == bidirectional_range<Rng>);
static_assert(random_access_range<R> == random_access_range<Rng>);
Expand Down Expand Up @@ -790,7 +789,7 @@ constexpr bool test_one(Rng&& rng, Fn func, Expected&& expected_rng) {
return true;
}

template <ranges::input_range Rng>
template <ranges::forward_range Rng>
constexpr void test_adjacent0(Rng&& rng) {
auto func = [] { return 602; };
using Fn = decltype(func);
Expand Down Expand Up @@ -884,7 +883,7 @@ using test_range =
test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}>;

struct instantiator {
template <ranges::input_range R>
template <ranges::forward_range R>
static constexpr void call() {
R r{some_ints};
test_one<1>(r, adjacent1_fn, adjacent1_result);
Expand Down Expand Up @@ -926,6 +925,60 @@ constexpr void instantiation_test() {
#endif // TEST_EVERYTHING
}

// LWG-4098 views::adjacent<0> should reject non-forward ranges
template <size_t N, ranges::input_range Rng, class Fn>
constexpr void test_input_only(Rng&&, Fn&&) {
if constexpr (!ranges::forward_range<Rng>) {
static_assert(!CanViewAdjacentTransform<Rng&, Fn, N>);
static_assert(!CanViewAdjacentTransform<Rng, Fn, N>);
}

if constexpr (!ranges::forward_range<const Rng>) {
static_assert(!CanViewAdjacentTransform<const Rng&, Fn, N>);
static_assert(!CanViewAdjacentTransform<const Rng, Fn, N>);
}
}

struct input_only_instantiator {
#ifdef TEST_EVERYTHING
template <ranges::input_range R>
static constexpr void call() {
R r{some_ints};
auto nullary_fn = [] { return 1729; };
test_input_only<0>(r, nullary_fn);
test_input_only<1>(r, adjacent1_fn);
test_input_only<2>(r, pairwise_fn);
test_input_only<4>(r, adjacent4_fn);
test_input_only<7>(r, adjacent7_fn);
}
#else // ^^^ test all input range permutations / test only "interesting" permutations vvv
template <class Tag, test::Common IsCommon, test::Sized IsSized>
static constexpr void call() {
test_range<Tag, IsCommon, IsSized> r{some_ints};
auto nullary_fn = [] { return 1729; };
test_input_only<0>(r, nullary_fn);
test_input_only<1>(r, adjacent1_fn);
test_input_only<2>(r, pairwise_fn);
test_input_only<4>(r, adjacent4_fn);
test_input_only<7>(r, adjacent7_fn);
}
#endif // TEST_EVERYTHING
};

constexpr void instantiation_input_only_test() {
#ifdef TEST_EVERYTHING
test_in<input_only_instantiator, const int>();
#else // ^^^ test all input range permutations / test only "interesting" permutations vvv
using test::Common, test::Sized;

// The view is sensitive to category, commonality, and size, but oblivious to proxyness and differencing
input_only_instantiator::call<input_iterator_tag, Common::no, Sized::yes>();
input_only_instantiator::call<input_iterator_tag, Common::no, Sized::no>();
input_only_instantiator::call<input_iterator_tag, Common::yes, Sized::yes>();
input_only_instantiator::call<input_iterator_tag, Common::yes, Sized::no>();
#endif // TEST_EVERYTHING
}

template <class Category, test::Common IsCommon, bool IsRandom = derived_from<Category, random_access_iterator_tag>>
using move_only_view = test::range<Category, const int, test::Sized{IsRandom}, test::CanDifference{IsRandom}, IsCommon,
test::CanCompare::yes, test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}, test::CanView::yes,
Expand Down Expand Up @@ -988,4 +1041,7 @@ int main() {

static_assert((instantiation_test(), true));
instantiation_test();

static_assert((instantiation_input_only_test(), true));
instantiation_input_only_test();
}

0 comments on commit 5236e38

Please sign in to comment.