123 lines
3.1 KiB
C++
123 lines
3.1 KiB
C++
//
|
|
// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
|
|
//
|
|
// Distributed under 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)
|
|
//
|
|
|
|
#ifndef BOOST_COBALT_GENERATOR_HPP
|
|
#define BOOST_COBALT_GENERATOR_HPP
|
|
|
|
#include <boost/cobalt/detail/generator.hpp>
|
|
|
|
|
|
namespace boost::cobalt
|
|
{
|
|
|
|
// tag::outline[]
|
|
template<typename Yield, typename Push = void>
|
|
struct [[nodiscard]] generator
|
|
// end::outline[]
|
|
: detail::generator_base<Yield, Push>
|
|
// tag::outline[]
|
|
{
|
|
// Movable
|
|
|
|
generator(generator &&lhs) noexcept = default;
|
|
generator& operator=(generator &&) noexcept;
|
|
|
|
// True until it co_returns & is co_awaited after <1>
|
|
explicit operator bool() const;
|
|
|
|
// Cancel the generator. <3>
|
|
void cancel(asio::cancellation_type ct = asio::cancellation_type::all);
|
|
|
|
// Check if a value is available
|
|
bool ready() const;
|
|
|
|
// Get the returned value. If !ready() this function has undefined behaviour.
|
|
Yield get();
|
|
|
|
// Cancel & detach the generator.
|
|
~generator();
|
|
|
|
// end::outline[]
|
|
using promise_type = detail::generator_promise<Yield, Push>;
|
|
|
|
generator(const generator &) = delete;
|
|
generator& operator=(const generator &) = delete;
|
|
|
|
constexpr generator(noop<Yield> n) : receiver_(std::move(n)){}
|
|
|
|
private:
|
|
template<typename, typename>
|
|
friend struct detail::generator_base;
|
|
template<typename, typename>
|
|
friend struct detail::generator_promise;
|
|
|
|
generator(detail::generator_promise<Yield, Push> * generator) : receiver_(generator->receiver, generator->signal)
|
|
{
|
|
}
|
|
detail::generator_receiver<Yield, Push> receiver_;
|
|
|
|
/* tag::outline[]
|
|
// an awaitable that results in value of `Yield`.
|
|
using __generator_awaitable__ = __unspecified__;
|
|
|
|
// Present when `Push` != `void`
|
|
__generator_awaitable__ operator()( Push && push);
|
|
__generator_awaitable__ operator()(const Push & push);
|
|
|
|
// Present when `Push` == `void`, i.e. can `co_await` the generator directly.
|
|
__generator_awaitable__ operator co_await (); // <2>
|
|
end::outline[]
|
|
*/
|
|
|
|
|
|
// tag::outline[]
|
|
|
|
};
|
|
// end::outline[]
|
|
|
|
|
|
|
|
template<typename Yield, typename Push >
|
|
inline generator<Yield, Push>::operator bool() const
|
|
{
|
|
return !receiver_.done || receiver_.result || receiver_.exception;
|
|
}
|
|
|
|
template<typename Yield, typename Push >
|
|
inline void generator<Yield, Push>::cancel(asio::cancellation_type ct)
|
|
{
|
|
if (!receiver_.done && *receiver_.reference == &receiver_)
|
|
receiver_.cancel_signal->emit(ct);
|
|
}
|
|
|
|
template<typename Yield, typename Push >
|
|
inline bool generator<Yield, Push>::ready() const { return receiver_.result || receiver_.exception; }
|
|
|
|
template<typename Yield, typename Push >
|
|
inline Yield generator<Yield, Push>::get()
|
|
{
|
|
BOOST_ASSERT(ready());
|
|
receiver_.rethrow_if();
|
|
return receiver_.get_result();
|
|
}
|
|
|
|
template<typename Yield, typename Push >
|
|
inline generator<Yield, Push>::~generator() { cancel(); }
|
|
|
|
template<typename Yield, typename Push >
|
|
inline
|
|
generator<Yield, Push>& generator<Yield, Push>::operator=(generator && lhs) noexcept
|
|
{
|
|
cancel();
|
|
receiver_ = std::move(lhs.receiver_);
|
|
return *this;
|
|
}
|
|
|
|
}
|
|
|
|
#endif //BOOST_COBALT_GENERATOR_HPP
|