| 1 | // |
| 2 | // Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) |
| 3 | // |
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | // |
| 7 | |
| 8 | #ifndef BOOST_COBALT_GENERATOR_HPP |
| 9 | #define BOOST_COBALT_GENERATOR_HPP |
| 10 | |
| 11 | #include <boost/cobalt/detail/generator.hpp> |
| 12 | |
| 13 | |
| 14 | namespace boost::cobalt |
| 15 | { |
| 16 | |
| 17 | // tag::outline[] |
| 18 | template<typename Yield, typename Push = void> |
| 19 | struct [[nodiscard]] generator |
| 20 | // end::outline[] |
| 21 | : detail::generator_base<Yield, Push> |
| 22 | // tag::outline[] |
| 23 | { |
| 24 | // Movable |
| 25 | |
| 26 | generator(generator &&lhs) noexcept = default; |
| 27 | generator& operator=(generator &&) noexcept = default; |
| 28 | |
| 29 | // True until it co_returns & is co_awaited after <1> |
| 30 | explicit operator bool() const; |
| 31 | |
| 32 | // Cancel the generator. <3> |
| 33 | void cancel(asio::cancellation_type ct = asio::cancellation_type::all); |
| 34 | |
| 35 | // Check if a value is available |
| 36 | bool ready() const; |
| 37 | |
| 38 | // Get the returned value. If !ready() this function has undefined behaviour. |
| 39 | Yield get(); |
| 40 | |
| 41 | // Cancel & detach the generator. |
| 42 | ~generator(); |
| 43 | |
| 44 | // end::outline[] |
| 45 | using promise_type = detail::generator_promise<Yield, Push>; |
| 46 | |
| 47 | generator(const generator &) = delete; |
| 48 | generator& operator=(const generator &) = delete; |
| 49 | |
| 50 | |
| 51 | private: |
| 52 | template<typename, typename> |
| 53 | friend struct detail::generator_base; |
| 54 | template<typename, typename> |
| 55 | friend struct detail::generator_promise; |
| 56 | |
| 57 | generator(detail::generator_promise<Yield, Push> * generator) : receiver_(generator->receiver, generator->signal) |
| 58 | { |
| 59 | } |
| 60 | detail::generator_receiver<Yield, Push> receiver_; |
| 61 | |
| 62 | /* tag::outline[] |
| 63 | // an awaitable that results in value of `Yield`. |
| 64 | using __generator_awaitable__ = __unspecified__; |
| 65 | |
| 66 | // Present when `Push` != `void` |
| 67 | __generator_awaitable__ operator()( Push && push); |
| 68 | __generator_awaitable__ operator()(const Push & push); |
| 69 | |
| 70 | // Present when `Push` == `void`, i.e. can `co_await` the generator directly. |
| 71 | __generator_awaitable__ operator co_await (); // <2> |
| 72 | end::outline[] |
| 73 | */ |
| 74 | |
| 75 | |
| 76 | // tag::outline[] |
| 77 | |
| 78 | }; |
| 79 | // end::outline[] |
| 80 | |
| 81 | |
| 82 | |
| 83 | template<typename Yield, typename Push > |
| 84 | inline generator<Yield, Push>::operator bool() const |
| 85 | { |
| 86 | return !receiver_.done || receiver_.result || receiver_.exception; |
| 87 | } |
| 88 | |
| 89 | template<typename Yield, typename Push > |
| 90 | inline void generator<Yield, Push>::cancel(asio::cancellation_type ct) |
| 91 | { |
| 92 | if (!receiver_.done && receiver_.reference == &receiver_) |
| 93 | receiver_.cancel_signal.emit(ct); |
| 94 | } |
| 95 | |
| 96 | template<typename Yield, typename Push > |
| 97 | inline bool generator<Yield, Push>::ready() const { return receiver_.result || receiver_.exception; } |
| 98 | |
| 99 | template<typename Yield, typename Push > |
| 100 | inline Yield generator<Yield, Push>::get() |
| 101 | { |
| 102 | BOOST_ASSERT(ready()); |
| 103 | receiver_.rethrow_if(); |
| 104 | return receiver_.get_result(); |
| 105 | } |
| 106 | |
| 107 | template<typename Yield, typename Push > |
| 108 | inline generator<Yield, Push>::~generator() { cancel(); } |
| 109 | |
| 110 | |
| 111 | } |
| 112 | |
| 113 | #endif //BOOST_COBALT_GENERATOR_HPP |
| 114 | |