Skip to content

Commit

Permalink
fix promise & generator operator=
Browse files Browse the repository at this point in the history
  • Loading branch information
klemens-morgenstern committed Apr 21, 2024
1 parent 0b813af commit c0f0768
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 22 deletions.
43 changes: 36 additions & 7 deletions include/boost/cobalt/detail/generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,55 @@ struct generator_receiver : generator_receiver_base<Yield, Push>
{
if (!lhs.done && !lhs.exception)
{
reference = this;
*reference = this;
lhs.exception = moved_from_exception();
}
lhs.done = true;
}

~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<Yield, Push>::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<Yield, Push>;

Expand Down Expand Up @@ -185,7 +214,7 @@ struct generator_receiver : generator_receiver_base<Yield, Push>

if constexpr (requires (Promise p) {p.get_cancellation_slot();})
if ((cl = h.promise().get_cancellation_slot()).is_connected())
cl.emplace<forward_cancellation>(self->cancel_signal);
cl.emplace<forward_cancellation>(*self->cancel_signal);

self->awaited_from.reset(h.address());

Expand Down
37 changes: 30 additions & 7 deletions include/boost/cobalt/detail/promise.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,45 @@ struct promise_receiver : promise_value_holder<T>
{
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<T>::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;
}
Expand Down Expand Up @@ -176,7 +199,7 @@ struct promise_receiver : promise_value_holder<T>

if constexpr (requires (Promise p) {p.get_cancellation_slot();})
if ((cl = h.promise().get_cancellation_slot()).is_connected())
cl.emplace<forward_cancellation>(self->cancel_signal);
cl.emplace<forward_cancellation>(*self->cancel_signal);

self->awaited_from.reset(h.address());
return true;
Expand Down Expand Up @@ -232,8 +255,8 @@ struct promise_receiver : promise_value_holder<T>
}
};

promise_receiver * &reference;
asio::cancellation_signal & cancel_signal;
promise_receiver **reference;
asio::cancellation_signal * cancel_signal;

awaitable get_awaitable() {return awaitable{this};}

Expand Down
14 changes: 11 additions & 3 deletions include/boost/cobalt/generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -89,8 +89,8 @@ inline generator<Yield, Push>::operator bool() const
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);
if (!receiver_.done && *receiver_.reference == &receiver_)
receiver_.cancel_signal->emit(ct);
}

template<typename Yield, typename Push >
Expand All @@ -107,6 +107,14 @@ inline Yield generator<Yield, Push>::get()
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;
}

}

Expand Down
7 changes: 4 additions & 3 deletions include/boost/cobalt/promise.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,11 @@ template<typename T>
inline
promise<T>& promise<T>::operator=(promise && lhs) noexcept
{
if (attached_)
if (attached_)
cancel();
receiver_ = std::move(lhs.receiver_);
attached_ = std::exchange(lhs.attached_, false);
return *this;
}

template<typename T>
Expand All @@ -106,8 +107,8 @@ template<typename T>
inline
void promise<T>::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<typename T>
Expand Down
5 changes: 5 additions & 0 deletions test/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;
}

Expand Down
7 changes: 5 additions & 2 deletions test/promise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<promise_move_only> pro_move_only_test()
Expand All @@ -156,7 +156,10 @@ cobalt::promise<promise_move_only> 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();

0 comments on commit c0f0768

Please sign in to comment.