generator.hpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. #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;
  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. constexpr generator(noop<Yield> n) : receiver_(std::move(n)){}
  37. private:
  38. template<typename, typename>
  39. friend struct detail::generator_base;
  40. template<typename, typename>
  41. friend struct detail::generator_promise;
  42. generator(detail::generator_promise<Yield, Push> * generator) : receiver_(generator->receiver, generator->signal)
  43. {
  44. }
  45. detail::generator_receiver<Yield, Push> receiver_;
  46. /* tag::outline[]
  47. // an awaitable that results in value of `Yield`.
  48. using __generator_awaitable__ = __unspecified__;
  49. // Present when `Push` != `void`
  50. __generator_awaitable__ operator()( Push && push);
  51. __generator_awaitable__ operator()(const Push & push);
  52. // Present when `Push` == `void`, i.e. can `co_await` the generator directly.
  53. __generator_awaitable__ operator co_await (); // <2>
  54. end::outline[]
  55. */
  56. // tag::outline[]
  57. };
  58. // end::outline[]
  59. template<typename Yield, typename Push >
  60. inline generator<Yield, Push>::operator bool() const
  61. {
  62. return !receiver_.done || receiver_.result || receiver_.exception;
  63. }
  64. template<typename Yield, typename Push >
  65. inline void generator<Yield, Push>::cancel(asio::cancellation_type ct)
  66. {
  67. if (!receiver_.done && *receiver_.reference == &receiver_)
  68. receiver_.cancel_signal->emit(ct);
  69. }
  70. template<typename Yield, typename Push >
  71. inline bool generator<Yield, Push>::ready() const { return receiver_.result || receiver_.exception; }
  72. template<typename Yield, typename Push >
  73. inline Yield generator<Yield, Push>::get()
  74. {
  75. BOOST_ASSERT(ready());
  76. receiver_.rethrow_if();
  77. return receiver_.get_result();
  78. }
  79. template<typename Yield, typename Push >
  80. inline generator<Yield, Push>::~generator() { cancel(); }
  81. template<typename Yield, typename Push >
  82. inline
  83. generator<Yield, Push>& generator<Yield, Push>::operator=(generator && lhs) noexcept
  84. {
  85. cancel();
  86. receiver_ = std::move(lhs.receiver_);
  87. return *this;
  88. }
  89. }
  90. #endif //BOOST_COBALT_GENERATOR_HPP