generator.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. //
  2. // Copyright (c) 2022 Klemens Morgenstern ([email protected])
  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. #ifndef BOOST_COBALT_GENERATOR_HPP
  8. #define BOOST_COBALT_GENERATOR_HPP
  9. #include <boost/cobalt/detail/generator.hpp>
  10. namespace boost::cobalt
  11. {
  12. // tag::outline[]
  13. template<typename Yield, typename Push = void>
  14. struct [[nodiscard]] generator
  15. // end::outline[]
  16. : detail::generator_base<Yield, Push>
  17. // tag::outline[]
  18. {
  19. // Movable
  20. generator(generator &&lhs) noexcept = default;
  21. generator& operator=(generator &&) noexcept = default;
  22. // True until it co_returns & is co_awaited after <1>
  23. explicit operator bool() const;
  24. // Cancel the generator. <3>
  25. void cancel(asio::cancellation_type ct = asio::cancellation_type::all);
  26. // Check if a value is available
  27. bool ready() const;
  28. // Get the returned value. If !ready() this function has undefined behaviour.
  29. Yield get();
  30. // Cancel & detach the generator.
  31. ~generator();
  32. // end::outline[]
  33. using promise_type = detail::generator_promise<Yield, Push>;
  34. generator(const generator &) = delete;
  35. generator& operator=(const generator &) = delete;
  36. private:
  37. template<typename, typename>
  38. friend struct detail::generator_base;
  39. template<typename, typename>
  40. friend struct detail::generator_promise;
  41. generator(detail::generator_promise<Yield, Push> * generator) : receiver_(generator->receiver, generator->signal)
  42. {
  43. }
  44. detail::generator_receiver<Yield, Push> receiver_;
  45. /* tag::outline[]
  46. // an awaitable that results in value of `Yield`.
  47. using __generator_awaitable__ = __unspecified__;
  48. // Present when `Push` != `void`
  49. __generator_awaitable__ operator()( Push && push);
  50. __generator_awaitable__ operator()(const Push & push);
  51. // Present when `Push` == `void`, i.e. can `co_await` the generator directly.
  52. __generator_awaitable__ operator co_await (); // <2>
  53. end::outline[]
  54. */
  55. // tag::outline[]
  56. };
  57. // end::outline[]
  58. template<typename Yield, typename Push >
  59. inline generator<Yield, Push>::operator bool() const
  60. {
  61. return !receiver_.done || receiver_.result || receiver_.exception;
  62. }
  63. template<typename Yield, typename Push >
  64. inline void generator<Yield, Push>::cancel(asio::cancellation_type ct)
  65. {
  66. if (!receiver_.done && receiver_.reference == &receiver_)
  67. receiver_.cancel_signal.emit(ct);
  68. }
  69. template<typename Yield, typename Push >
  70. inline bool generator<Yield, Push>::ready() const { return receiver_.result || receiver_.exception; }
  71. template<typename Yield, typename Push >
  72. inline Yield generator<Yield, Push>::get()
  73. {
  74. BOOST_ASSERT(ready());
  75. receiver_.rethrow_if();
  76. return receiver_.get_result();
  77. }
  78. template<typename Yield, typename Push >
  79. inline generator<Yield, Push>::~generator() { cancel(); }
  80. }
  81. #endif //BOOST_COBALT_GENERATOR_HPP