diff --git a/include/boost/cobalt/detail/generator.hpp b/include/boost/cobalt/detail/generator.hpp index 2c2760cb..4f793ec9 100644 --- a/include/boost/cobalt/detail/generator.hpp +++ b/include/boost/cobalt/detail/generator.hpp @@ -104,7 +104,7 @@ struct generator_receiver : generator_receiver_base { if (!lhs.done && !lhs.exception) { - reference = this; + *reference = this; lhs.exception = moved_from_exception(); } lhs.done = true; @@ -112,18 +112,47 @@ struct generator_receiver : generator_receiver_base ~generator_receiver() { - if (!done && reference == this) - reference = nullptr; + if (!done && *reference == this) + *reference = nullptr; } generator_receiver(generator_receiver * &reference, asio::cancellation_signal & cancel_signal) - : reference(reference), cancel_signal(cancel_signal) + : reference(&reference), cancel_signal(&cancel_signal) { reference = this; } - generator_receiver * &reference; - asio::cancellation_signal & cancel_signal; + + generator_receiver& operator=(generator_receiver && lhs) noexcept + { + if (*reference == this) + { + *reference = nullptr; + } + + generator_receiver_base::operator=(std::move(lhs)); + exception = std::move(lhs.exception); + done = lhs.done; + result = std::move(lhs.result); + result_buffer = std::move(lhs.result_buffer); + awaited_from = std::move(lhs.awaited_from); + yield_from = std::move(lhs.yield_from); + lazy = lhs.lazy; + reference = lhs.reference; + cancel_signal = lhs.cancel_signal; + + if (!lhs.done && !lhs.exception) + { + *reference = this; + lhs.exception = moved_from_exception(); + } + lhs.done = true; + + return *this; + } + + generator_receiver **reference; + asio::cancellation_signal * cancel_signal; using yield_awaitable = generator_yield_awaitable; @@ -185,7 +214,7 @@ struct generator_receiver : generator_receiver_base if constexpr (requires (Promise p) {p.get_cancellation_slot();}) if ((cl = h.promise().get_cancellation_slot()).is_connected()) - cl.emplace(self->cancel_signal); + cl.emplace(*self->cancel_signal); self->awaited_from.reset(h.address()); diff --git a/include/boost/cobalt/detail/promise.hpp b/include/boost/cobalt/detail/promise.hpp index e9dc78ed..68b2035c 100644 --- a/include/boost/cobalt/detail/promise.hpp +++ b/include/boost/cobalt/detail/promise.hpp @@ -120,22 +120,45 @@ struct promise_receiver : promise_value_holder { if (!done && !exception) { - reference = this; + *reference = this; lhs.exception = moved_from_exception(); } lhs.done = true; + } + + promise_receiver& operator=(promise_receiver && lhs) noexcept + { + if (*reference == this) + { + *reference = nullptr; + } + + promise_value_holder::operator=(std::move(lhs)); + exception = std::move(lhs.exception); + done = std::move(lhs.done); + awaited_from = std::move(lhs.awaited_from); + reference = std::move(lhs.reference); + cancel_signal = std::move(lhs.cancel_signal); + if (!done && !exception) + { + *reference = this; + lhs.exception = moved_from_exception(); + } + + return *this; } + ~promise_receiver() { - if (!done && reference == this) - reference = nullptr; + if (!done && *reference == this) + *reference = nullptr; } promise_receiver(promise_receiver * &reference, asio::cancellation_signal & cancel_signal) - : reference(reference), cancel_signal(cancel_signal) + : reference(&reference), cancel_signal(&cancel_signal) { reference = this; } @@ -176,7 +199,7 @@ struct promise_receiver : promise_value_holder if constexpr (requires (Promise p) {p.get_cancellation_slot();}) if ((cl = h.promise().get_cancellation_slot()).is_connected()) - cl.emplace(self->cancel_signal); + cl.emplace(*self->cancel_signal); self->awaited_from.reset(h.address()); return true; @@ -232,8 +255,8 @@ struct promise_receiver : promise_value_holder } }; - promise_receiver * &reference; - asio::cancellation_signal & cancel_signal; + promise_receiver **reference; + asio::cancellation_signal * cancel_signal; awaitable get_awaitable() {return awaitable{this};} diff --git a/include/boost/cobalt/generator.hpp b/include/boost/cobalt/generator.hpp index 2ef76d99..06ab1ebf 100644 --- a/include/boost/cobalt/generator.hpp +++ b/include/boost/cobalt/generator.hpp @@ -24,7 +24,7 @@ struct [[nodiscard]] generator // Movable generator(generator &&lhs) noexcept = default; - generator& operator=(generator &&) noexcept = default; + generator& operator=(generator &&) noexcept; // True until it co_returns & is co_awaited after <1> explicit operator bool() const; @@ -89,8 +89,8 @@ inline generator::operator bool() const template inline void generator::cancel(asio::cancellation_type ct) { - if (!receiver_.done && receiver_.reference == &receiver_) - receiver_.cancel_signal.emit(ct); + if (!receiver_.done && *receiver_.reference == &receiver_) + receiver_.cancel_signal->emit(ct); } template @@ -107,6 +107,14 @@ inline Yield generator::get() template inline generator::~generator() { cancel(); } +template +inline +generator& generator::operator=(generator && lhs) noexcept +{ + cancel(); + receiver_ = std::move(lhs.receiver_); + return *this; +} } diff --git a/include/boost/cobalt/promise.hpp b/include/boost/cobalt/promise.hpp index 0094f2dd..9107c174 100644 --- a/include/boost/cobalt/promise.hpp +++ b/include/boost/cobalt/promise.hpp @@ -87,10 +87,11 @@ template inline promise& promise::operator=(promise && lhs) noexcept { - if (attached_) + if (attached_) cancel(); receiver_ = std::move(lhs.receiver_); attached_ = std::exchange(lhs.attached_, false); + return *this; } template @@ -106,8 +107,8 @@ template inline void promise::cancel(asio::cancellation_type ct) { - if (!receiver_.done && receiver_.reference == &receiver_) - receiver_.cancel_signal.emit(ct); + if (!receiver_.done && *receiver_.reference == &receiver_) + receiver_.cancel_signal->emit(ct); } template diff --git a/test/generator.cpp b/test/generator.cpp index a11d99cd..2bafefc9 100644 --- a/test/generator.cpp +++ b/test/generator.cpp @@ -47,6 +47,11 @@ CO_TEST_CASE(generator_int) BOOST_CHECK(i == 11); + g = gen(); + BOOST_CHECK(g); + while (g) + co_await g; + co_return ; } diff --git a/test/promise.cpp b/test/promise.cpp index ff550e11..c1fe8746 100644 --- a/test/promise.cpp +++ b/test/promise.cpp @@ -146,7 +146,7 @@ struct promise_move_only { promise_move_only() = default; promise_move_only(promise_move_only &&) = default; - promise_move_only & operator=(promise_move_only &&) = delete; + promise_move_only & operator=(promise_move_only &&) = default; }; cobalt::promise pro_move_only_test() @@ -156,7 +156,10 @@ cobalt::promise pro_move_only_test() CO_TEST_CASE(move_only) { - co_await pro_move_only_test(); + auto p = pro_move_only_test(); + co_await p; + p = pro_move_only_test(); + co_await p; } BOOST_AUTO_TEST_SUITE_END(); \ No newline at end of file