Files
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
init
2026-02-16 15:50:16 +03:00

293 lines
8.5 KiB
C++

// Range v3 library
//
// Copyright Casey Carter 2017
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//
#include <range/v3/detail/config.hpp>
#include <iostream>
#include <vector>
#include <range/v3/range/access.hpp>
#include <range/v3/range_for.hpp>
#include <range/v3/algorithm/copy.hpp>
#include <range/v3/algorithm/count.hpp>
#include <range/v3/algorithm/equal.hpp>
#include <range/v3/experimental/utility/generator.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/utility/swap.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/move.hpp>
#include <range/v3/view/take_exactly.hpp>
#include <range/v3/view/transform.hpp>
#include "../../simple_test.hpp"
#include "../../test_utils.hpp"
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wunused-const-variable"
#endif
#if RANGES_CXX_COROUTINES < RANGES_CXX_COROUTINES_TS1
#error This test uses coroutines.
#endif
template<bool Condition>
using maybe_sized_generator = meta::if_c<Condition,
meta::quote<ranges::experimental::sized_generator>,
meta::quote<ranges::experimental::generator>>;
template<typename T>
constexpr bool is_copy_constructible_or_ref() noexcept
{
return std::is_reference<T>::value ||(bool) ranges::copy_constructible<T>;
}
struct coro_fn
{
private:
template<typename V>
using generator_for = meta::invoke<
maybe_sized_generator<(bool) ranges::sized_range<V>>,
ranges::range_reference_t<V>,
ranges::range_value_t<V>>;
CPP_template(typename V)(
requires ranges::input_range<V> && ranges::view_<V> &&
(is_copy_constructible_or_ref<ranges::range_reference_t<V>>()))
static generator_for<V> impl(V v)
{
if(RANGES_CONSTEXPR_IF(ranges::sized_range<V>))
co_await static_cast<ranges::experimental::generator_size>((std::size_t)ranges::distance(v));
auto first = ranges::begin(v);
auto const last = ranges::end(v);
for (; first != last; ++first)
co_yield *first;
}
public:
CPP_template(typename Rng)(
requires (
!meta::is<ranges::uncvref_t<Rng>, ranges::experimental::generator>::value &&
!meta::is<ranges::uncvref_t<Rng>, ranges::experimental::sized_generator>::value &&
ranges::input_range<Rng> &&
is_copy_constructible_or_ref<ranges::range_reference_t<Rng>>()))
generator_for<ranges::views::all_t<Rng>> operator()(Rng &&rng) const
{
return impl(ranges::views::all(static_cast<Rng &&>(rng)));
}
template<typename R, typename V>
ranges::experimental::generator<R, V>
operator()(ranges::experimental::generator<R, V> g) const noexcept
{
return g;
}
template<typename R, typename V>
ranges::experimental::sized_generator<R, V>
operator()(ranges::experimental::sized_generator<R, V> g) const noexcept
{
return g;
}
};
inline namespace function_objects
{
RANGES_INLINE_VARIABLE(coro_fn, coro)
}
auto f(int const n)
{
return ::coro(ranges::views::iota(0, n));
}
ranges::experimental::sized_generator<int> g(int const n)
{
co_await static_cast<ranges::experimental::generator_size>((std::size_t) (n > 0 ? n : 0));
for (int i = 0; i < n; ++i)
co_yield i;
}
ranges::experimental::sized_generator<int &> h(int const n)
{
co_await static_cast<ranges::experimental::generator_size>((std::size_t) (n > 0 ? n : 0));
for (int i = 0; i < n; ++i)
co_yield i;
}
CPP_template(class T)(
requires ranges::weakly_incrementable<T>)
ranges::experimental::generator<T> iota_generator(T t)
{
for (;; ++t)
co_yield t;
}
CPP_template(class T, class S)(
requires (ranges::weakly_incrementable<T> &&
ranges::detail::weakly_equality_comparable_with_<T, S> &&
!ranges::sized_sentinel_for<S, T> && !(ranges::integral<T> && ranges::integral<S>)))
ranges::experimental::generator<T> iota_generator(T t, S const s)
{
for (; t != s; ++t)
co_yield t;
}
CPP_template(class T, class S)(
requires ranges::sized_sentinel_for<S, T> || (ranges::integral<T> && ranges::integral<S>))
ranges::experimental::sized_generator<T> iota_generator(T t, S const s)
{
co_await static_cast<ranges::experimental::generator_size>((std::size_t) (s - t));
for (; t != s; ++t)
co_yield t;
}
CPP_template(class V, class F)(
requires ranges::input_range<V> && ranges::view_<V> &&
ranges::indirect_unary_predicate<F, ranges::iterator_t<V>>)
ranges::experimental::generator<ranges::range_reference_t<V>, ranges::range_value_t<V>>
filter(V view, F f)
{
RANGES_FOR(auto &&i, view)
{
if (ranges::invoke(f, i))
co_yield i;
}
}
CPP_template(class V, class F)(
requires ranges::input_range<V> && ranges::view_<V> &&
ranges::indirectly_unary_invocable<F, ranges::iterator_t<V>>)
meta::invoke<
maybe_sized_generator<(bool) ranges::sized_range<V>>,
ranges::indirect_result_t<F &, ranges::iterator_t<V>>>
transform(V view, F f)
{
if(RANGES_CONSTEXPR_IF(ranges::sized_range<V>))
co_await static_cast<ranges::experimental::generator_size>((std::size_t) ranges::distance(view));
RANGES_FOR(auto &&i, view)
co_yield ranges::invoke(f, i);
}
struct MoveInt
{
int i_;
MoveInt(int i = 42) : i_{i}
{}
MoveInt(MoveInt &&that) noexcept
: i_{ranges::exchange(that.i_, 0)}
{}
MoveInt &operator=(MoveInt &&that) noexcept
{
i_ = ranges::exchange(that.i_, 0);
return *this;
}
friend bool operator==(MoveInt const &x, MoveInt const &y)
{
return x.i_ == y.i_;
}
friend bool operator!=(MoveInt const &x, MoveInt const &y)
{
return !(x == y);
}
friend std::ostream &operator<<(std::ostream &os, MoveInt const &mi)
{
return os << mi.i_;
}
};
int main()
{
using namespace ranges;
auto even = [](int i){ return i % 2 == 0; };
#ifndef RANGES_WORKAROUND_MSVC_835948
{
auto rng = ::iota_generator(0, 10);
CPP_assert(sized_range<decltype(rng)>);
CHECK(size(rng) == 10u);
::check_equal(rng, {0,1,2,3,4,5,6,7,8,9});
}
{
auto rng = ::coro(::coro(::coro(::iota_generator(0, 10))));
::has_type<decltype(::iota_generator(0, 10)) &>(rng);
CPP_assert(sized_range<decltype(rng)>);
CHECK(size(rng) == 10u);
::check_equal(rng, {0,1,2,3,4,5,6,7,8,9});
}
{
auto rng = ::coro(views::ints | views::filter(even) | views::take_exactly(10));
CPP_assert(sized_range<decltype(rng)>);
CHECK(size(rng) == 10u);
::check_equal(rng, {0,2,4,6,8,10,12,14,16,18});
}
{
auto const control = {1, 2, 3};
MoveInt a[] = {{1}, {2}, {3}};
MoveInt b[3];
CHECK(equal(a, control, std::equal_to<int>{}, &MoveInt::i_));
CHECK(count(b, 42, &MoveInt::i_) == 3);
auto rng = ::coro(views::move(a));
CPP_assert(sized_range<decltype(rng)>);
CHECK(size(rng) == 3u);
copy(rng, b);
CHECK(equal(b, control, std::equal_to<int>{}, &MoveInt::i_));
CHECK(count(a, 0, &MoveInt::i_) == 3);
}
{
int some_ints[] = {0,1,2};
auto rng = ::coro(some_ints);
CPP_assert(sized_range<decltype(rng)>);
CHECK(size(rng) == 3u);
auto i = begin(rng);
auto e = end(rng);
CHECK(i != e);
CHECK(&*i == &some_ints[0]);
++i;
CHECK(i != e);
CHECK(&*i == &some_ints[1]);
++i;
CHECK(i != e);
CHECK(&*i == &some_ints[2]);
++i;
CHECK(i == e);
}
{
std::vector<bool> vec(3, false);
auto rng = ::coro(vec);
CPP_assert(sized_range<decltype(rng)>);
CHECK(size(rng) == 3u);
::check_equal(rng, {false,false,false});
}
::check_equal(f(42), g(42));
::check_equal(f(42), h(42));
{
auto rng = h(20) | views::transform([](int &x) { return ++x; });
::check_equal(rng, {1,3,5,7,9,11,13,15,17,19});
}
{
auto rng = f(20) | views::filter(even);
::check_equal(rng, {0,2,4,6,8,10,12,14,16,18});
}
#endif // RANGES_WORKAROUND_MSVC_835948
{
auto square = [](int i) { return i * i; };
int const some_ints[] = {0,1,2,3,4,5,6,7};
auto rng = ::transform(::filter(debug_input_view<int const>{some_ints}, even), square);
::check_equal(rng, {0,4,16,36});
}
return ::test_result();
}