Implement LWG-4098 `views::adjacent<0>` should reject non-forward ranges (#4815)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
A. Jiang 2024-07-12 06:10:20 +08:00 коммит произвёл GitHub
Родитель de1eb6ff46
Коммит 5236e38152
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 126 добавлений и 11 удалений

Просмотреть файл

@ -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<>>{};
}
@ -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));
}

Просмотреть файл

@ -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,
@ -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>);
@ -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>;
@ -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
@ -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);
@ -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>},
@ -939,4 +994,7 @@ int main() {
static_assert((instantiation_test(), true));
instantiation_test();
static_assert((instantiation_input_only_test(), true));
instantiation_input_only_test();
}

Просмотреть файл

@ -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,
@ -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>);
@ -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);
@ -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);
@ -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,
@ -988,4 +1041,7 @@ int main() {
static_assert((instantiation_test(), true));
instantiation_test();
static_assert((instantiation_input_only_test(), true));
instantiation_input_only_test();
}