Skip to content

Commit 2d64a93

Browse files
committed
Defer construction of the awaitable state
Move `__awaitable1_` and `__awaiter_` into a helper type defer construction thereof to `start()`; this saves us from storing the `coroutine_handle` in the opstate.
1 parent a678007 commit 2d64a93

1 file changed

Lines changed: 58 additions & 26 deletions

File tree

include/stdexec/__detail/__connect_awaitable.hpp

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -210,33 +210,33 @@ namespace STDEXEC
210210
struct __opstate
211211
{
212212
constexpr explicit __opstate(_Awaitable&& __awaitable, _Receiver&& __rcvr)
213-
noexcept(__is_nothrow)
213+
noexcept(__nothrow_move_constructible<_Awaitable>)
214214
: __rcvr_(static_cast<_Receiver&&>(__rcvr))
215-
, __coro_(__co_impl(*this))
216-
, __awaitable1_(static_cast<_Awaitable&&>(__awaitable))
217-
, __awaitable2_(
218-
__get_awaitable(static_cast<_Awaitable&&>(__awaitable1_), __coro_.promise()))
219-
, __awaiter_(__get_awaiter(static_cast<__awaitable_t&&>(__awaitable2_)))
215+
, __source_awaitable_(static_cast<_Awaitable&&>(__awaitable))
220216
{}
221217

222218
void start() & noexcept
223219
{
220+
auto __coro = __co_impl(*this);
221+
224222
STDEXEC_TRY
225223
{
226-
if (!__awaiter_.await_ready())
224+
__awaiter_.emplace(__source_awaitable_, __coro);
225+
226+
if (!__awaiter_->await_ready())
227227
{
228-
using __suspend_result_t = decltype(__awaiter_.await_suspend(__coro_));
228+
using __suspend_result_t = decltype(__awaiter_->await_suspend(__coro));
229229

230230
// suspended
231231
if constexpr (std::is_void_v<__suspend_result_t>)
232232
{
233233
// void-returning await_suspend means "always suspend"
234-
__awaiter_.await_suspend(__coro_);
234+
__awaiter_->await_suspend(__coro);
235235
return;
236236
}
237237
else if constexpr (std::same_as<bool, __suspend_result_t>)
238238
{
239-
if (__awaiter_.await_suspend(__coro_))
239+
if (__awaiter_->await_suspend(__coro))
240240
{
241241
// returning true from a bool-returning await_suspend means suspend
242242
return;
@@ -249,7 +249,7 @@ namespace STDEXEC
249249
else
250250
{
251251
static_assert(__std::convertible_to<__suspend_result_t, __std::coroutine_handle<>>);
252-
auto __resume_target = __awaiter_.await_suspend(__coro_);
252+
auto __resume_target = __awaiter_->await_suspend(__coro);
253253
STDEXEC_TRY
254254
{
255255
__resume_target.resume();
@@ -270,8 +270,11 @@ namespace STDEXEC
270270
}
271271
STDEXEC_CATCH_ALL
272272
{
273-
if constexpr (!noexcept(__awaiter_.await_ready())
274-
|| !noexcept(__awaiter_.await_suspend(__coro_)))
273+
if constexpr (!__nothrow_constructible_from<__awaitable_state,
274+
_Awaitable&,
275+
__std::coroutine_handle<__promise_t>>
276+
|| !noexcept(__awaiter_->await_ready())
277+
|| !noexcept(__awaiter_->await_suspend(__coro)))
275278
{
276279
STDEXEC::set_error(static_cast<_Receiver&&>(__rcvr_), std::current_exception());
277280
}
@@ -286,10 +289,6 @@ namespace STDEXEC
286289
friend __promise_t;
287290
friend __final_awaiter;
288291

289-
static constexpr bool __is_nothrow = __nothrow_move_constructible<_Awaitable>
290-
&& __noexcept_of<__get_awaitable, _Awaitable, __promise_t&>
291-
&& __noexcept_of<__get_awaiter, __awaitable_t>;
292-
293292
static auto __co_impl(__opstate&) noexcept -> __std::coroutine_handle<__promise_t>
294293
{
295294
co_return;
@@ -299,19 +298,19 @@ namespace STDEXEC
299298
{
300299
STDEXEC_TRY
301300
{
302-
if constexpr (std::is_void_v<decltype(__awaiter_.await_resume())>)
301+
if constexpr (std::is_void_v<decltype(__awaiter_->await_resume())>)
303302
{
304-
__awaiter_.await_resume();
303+
__awaiter_->await_resume();
305304
STDEXEC::set_value(static_cast<_Receiver&&>(__rcvr_));
306305
}
307306
else
308307
{
309-
STDEXEC::set_value(static_cast<_Receiver&&>(__rcvr_), __awaiter_.await_resume());
308+
STDEXEC::set_value(static_cast<_Receiver&&>(__rcvr_), __awaiter_->await_resume());
310309
}
311310
}
312311
STDEXEC_CATCH_ALL
313312
{
314-
if constexpr (!noexcept(__awaiter_.await_resume()))
313+
if constexpr (!noexcept(__awaiter_->await_resume()))
315314
{
316315
STDEXEC::set_error(static_cast<_Receiver&&>(__rcvr_), std::current_exception());
317316
}
@@ -323,12 +322,45 @@ namespace STDEXEC
323322
STDEXEC::set_stopped(static_cast<_Receiver&&>(__rcvr_));
324323
}
325324

325+
struct __awaitable_state
326+
{
327+
explicit __awaitable_state(_Awaitable& __source,
328+
__std::coroutine_handle<__promise_t> __coro)
329+
noexcept(__is_nothrow)
330+
: __awaitable_(__get_awaitable(static_cast<_Awaitable&&>(__source), __coro.promise()))
331+
, __awaiter_(__get_awaiter(static_cast<__awaitable_t&&>(__awaitable_)))
332+
{}
333+
334+
constexpr auto await_ready() noexcept(noexcept(__awaiter_.await_ready())) -> bool
335+
{
336+
return __awaiter_.await_ready();
337+
}
338+
339+
template <class _P>
340+
constexpr auto await_suspend(__std::coroutine_handle<_P> __h)
341+
noexcept(noexcept(__awaiter_.await_suspend(__h)))
342+
{
343+
return __awaiter_.await_suspend(__h);
344+
}
345+
346+
constexpr decltype(auto) await_resume() noexcept(noexcept(__awaiter_.await_resume()))
347+
{
348+
return __awaiter_.await_resume();
349+
}
350+
351+
private:
352+
static constexpr bool __is_nothrow =
353+
__noexcept_of<__get_awaitable, _Awaitable, __promise_t&>
354+
&& __noexcept_of<__get_awaiter, __awaitable_t>;
355+
356+
__awaitable_t __awaitable_;
357+
__awaiter_t __awaiter_;
358+
};
359+
326360
alignas(__storage_align) std::byte __storage_[__storage_size];
327-
_Receiver __rcvr_;
328-
__std::coroutine_handle<__promise_t> __coro_;
329-
_Awaitable __awaitable1_;
330-
__awaitable_t __awaitable2_;
331-
__awaiter_t __awaiter_;
361+
_Receiver __rcvr_;
362+
_Awaitable __source_awaitable_;
363+
__optional<__awaitable_state> __awaiter_;
332364
};
333365
} // namespace __connect_await
334366

0 commit comments

Comments
 (0)