2222#include < type_traits>
2323#include < utility>
2424#include < variant>
25+ #include < tuple>
26+ #include < atomic>
2527
2628namespace beman ::execution::detail {
2729template <class Sndr , class Promise >
@@ -31,58 +33,78 @@ class sender_awaitable {
3133 ::beman::execution::detail::single_sender_value_type<Sndr, ::beman::execution::env_of_t <Promise>>;
3234 using result_type = ::std::conditional_t <::std::is_void_v<value_type>, unit, value_type>;
3335 using variant_type = ::std::variant<::std::monostate, result_type, ::std::exception_ptr>;
36+ using data_type = ::std::tuple<variant_type, ::std::atomic<bool >, ::std::coroutine_handle<Promise>>;
37+
3438 struct awaitable_receiver {
3539 using receiver_concept = ::beman::execution::receiver_t ;
3640
41+ void resume () {
42+ if (::std::get<1 >(*result_ptr_).exchange (true , std::memory_order_acq_rel)) {
43+ ::std::get<2 >(*result_ptr_).resume ();
44+ }
45+ }
46+
3747 template <class ... Args>
3848 requires ::std::constructible_from<result_type, Args...>
3949 void set_value (Args&&... args) && noexcept {
4050 try {
41- result_ptr_-> template emplace <1 >(::std::forward<Args>(args)...);
51+ ::std::get< 0 >(*result_ptr_). template emplace <1 >(::std::forward<Args>(args)...);
4252 } catch (...) {
43- result_ptr_-> template emplace <2 >(::std::current_exception ());
53+ ::std::get< 0 >(*result_ptr_). template emplace <2 >(::std::current_exception ());
4454 }
45- continuation_. resume ();
55+ this -> resume ();
4656 }
47-
4857 template <class Error >
4958 void set_error (Error&& error) && noexcept {
50- result_ptr_->template emplace <2 >(::beman::execution::detail::as_except_ptr (::std::forward<Error>(error)));
51- continuation_.resume ();
59+ ::std::get<0 >(*result_ptr_)
60+ .template emplace <2 >(::beman::execution::detail::as_except_ptr (::std::forward<Error>(error)));
61+ this ->resume ();
5262 }
5363
5464 void set_stopped () && noexcept {
55- static_cast <::std::coroutine_handle<>>(continuation_.promise ().unhandled_stopped ()).resume ();
65+ if (::std::get<1 >(*result_ptr_).exchange (true , ::std::memory_order_acq_rel)) {
66+ static_cast <::std::coroutine_handle<>>(::std::get<2 >(*result_ptr_).promise ().unhandled_stopped ())
67+ .resume ();
68+ }
5669 }
5770
5871 auto get_env () const noexcept {
59- return ::beman::execution::detail::fwd_env{::beman::execution::get_env (continuation_.promise ())};
72+ return ::beman::execution::detail::fwd_env{
73+ ::beman::execution::get_env (::std::get<2 >(*result_ptr_).promise())};
6074 }
6175
62- variant_type* result_ptr_;
63- ::std::coroutine_handle<Promise> continuation_;
76+ data_type* result_ptr_;
6477 };
6578 using op_state_type = ::beman::execution::connect_result_t <Sndr, awaitable_receiver>;
6679
67- variant_type result{};
80+ data_type result{};
6881 op_state_type state;
6982
7083 public:
7184 sender_awaitable (Sndr&& sndr, Promise& p)
72- : state {::beman::execution::connect (
73- ::std::forward<Sndr>(sndr),
74- awaitable_receiver{::std::addressof (result), ::std::coroutine_handle<Promise>:: from_promise (p )})} {}
85+ : result {::std::monostate{}, false , ::std::coroutine_handle<Promise>:: from_promise (p)},
86+ state{:: beman::execution::connect ( ::std::forward<Sndr>(sndr),
87+ sender_awaitable:: awaitable_receiver{::std::addressof (result)})} {}
7588
7689 static constexpr bool await_ready () noexcept { return false ; }
77- void await_suspend (::std::coroutine_handle<Promise>) noexcept { ::beman::execution::start (state); }
90+ bool await_suspend (::std::coroutine_handle<Promise>) noexcept {
91+ ::beman::execution::start (state);
92+ if (::std::get<1 >(this ->result ).exchange (true , std::memory_order_acq_rel)) {
93+ if (::std::holds_alternative<::std::monostate>(::std::get<0 >(this ->result ))) {
94+ return bool (::std::get<2 >(this ->result ).promise ().unhandled_stopped ());
95+ }
96+ return false ;
97+ }
98+ return true ;
99+ }
78100 value_type await_resume () {
79- if (::std::holds_alternative<::std::exception_ptr>(result)) {
80- ::std::rethrow_exception (::std::get<::std::exception_ptr>(result));
101+ if (::std::holds_alternative<::std::exception_ptr>(::std::get< 0 >( result) )) {
102+ ::std::rethrow_exception (::std::get<::std::exception_ptr>(::std::get< 0 >( result) ));
81103 }
82104 if constexpr (::std::is_void_v<value_type>) {
83105 return ;
84106 } else {
85- return ::std::get<value_type>(std::move (result));
107+ return ::std::get<value_type>(std::move (::std::get< 0 >( result) ));
86108 }
87109 }
88110};
0 commit comments