11module ;
2- #include < version>
3-
42#include " libfork/__impl/assume.hpp"
53#include " libfork/__impl/compiler.hpp"
64#include " libfork/__impl/exception.hpp"
@@ -251,7 +249,7 @@ struct awaitable : std::suspend_always {
251249 * @brief In a separate function to allow it to be placed in cold block.
252250 */
253251 template <typename T>
254- constexpr void cleanup_and_stash (this awaitable self, coro<promise_type<T, Context>> parent) noexcept {
252+ constexpr void stash_and_resume (this awaitable self, coro<promise_type<T, Context>> parent) noexcept {
255253 // Clean-up the child that will never be resumed.
256254 self.child ->handle ().destroy ();
257255 stash_current_exception (&parent.promise ().frame );
@@ -270,8 +268,7 @@ struct awaitable : std::suspend_always {
270268
271269 if (parent.promise ().frame .is_cancelled ()) [[unlikely]] {
272270 // Noop if canceled, must clean-up the child that will never be resumed.
273- self.child ->handle ().destroy ();
274- return parent;
271+ return self.child ->handle ().destroy (), parent;
275272 }
276273
277274 // Propagate parent->child relationships
@@ -288,8 +285,7 @@ struct awaitable : std::suspend_always {
288285 LF_TRY {
289286 not_null (thread_context<Context>)->push (frame_handle{key, &parent.promise ().frame });
290287 } LF_CATCH_ALL {
291- self.cleanup_and_stash (parent);
292- return parent;
288+ return self.stash_and_resume (parent), parent;
293289 }
294290 }
295291
@@ -423,7 +419,7 @@ struct join_awaitable {
423419
424420// =============== Frame mixin =============== //
425421
426- template <worker_context Context >
422+ template <worker_context Ctx >
427423struct mixin_frame {
428424
429425 // === For internal use === //
@@ -441,54 +437,60 @@ struct mixin_frame {
441437 // --- Allocation
442438
443439 static auto operator new(std::size_t sz) -> void * {
444- void *ptr = not_null (thread_context<Context >)->allocator ().push (sz);
440+ void *ptr = not_null (thread_context<Ctx >)->allocator ().push (sz);
445441 LF_ASSUME (is_aligned<k_new_align>(ptr));
446442 return std::assume_aligned<k_new_align>(ptr);
447443 }
448444
449445 static auto operator delete (void *p, std::size_t sz) noexcept -> void {
450- not_null (thread_context<Context >)->allocator ().pop (p, sz);
446+ not_null (thread_context<Ctx >)->allocator ().pop (p, sz);
451447 }
452448
453449 // --- Await transformations
454450
455451 template <category Cat, typename R, typename Fn, typename ... Args>
456- [[nodiscard]]
457- constexpr auto await_transform (this auto &self, pkg<Cat, Context, R, Fn, Args...> &&pkg) noexcept
458- -> awaitable<Cat, Context> {
452+ static constexpr auto await_transform_pkg (pkg<Cat, Ctx, R, Fn, Args...> &&pkg) -> awaitable<Cat, Ctx> {
459453
460- using U = async_result_t <Fn, Context , Args...>;
454+ using U = async_result_t <Fn, Ctx , Args...>;
461455
462- LF_TRY {
456+ // clang-format off
463457
464- // clang-format off
458+ promise_type<U, Ctx> *child_promise = access::promise<Ctx>(std::move (pkg.args ).apply (
459+ [&](auto &&...args ) LF_HOF (std::invoke (fwd_fn<Fn>(pkg.fn ), env<Ctx>{}, LF_FWD (args)...))
460+ ));
465461
466- auto *child_promise = access::promise<Context>(std::move (pkg.args ).apply (
467- [&](auto &&...args ) LF_HOF (std::invoke (fwd_fn<Fn>(pkg.fn ), env<Context>{}, LF_FWD (args)...))
468- ));
462+ // clang-format on
469463
470- // clang-format on
464+ LF_ASSUME (child_promise);
471465
472- LF_ASSUME (child_promise);
466+ // void can signal drop return.
467+ static_assert (std::same_as<R, U> || std::is_void_v<R>);
473468
474- if constexpr (!std::is_void_v<R>) {
475- child_promise->return_address = pkg.return_address ;
476- } else {
477- if constexpr (!std::is_void_v<U>) {
478- // Set child's return address to null to inhibit the return
479- // TODO: add test for this
480- child_promise->return_address = nullptr ;
481- }
482- }
469+ // TODO: tests for null path
483470
484- return {.child = &child_promise->frame };
471+ if constexpr (!std::is_void_v<R>) {
472+ child_promise->return_address = pkg.return_address ;
473+ } else if constexpr (!std::is_void_v<U>) {
474+ // Set child's return address to null to inhibit the return
475+ // TODO: add test for this
476+ child_promise->return_address = nullptr ;
477+ }
478+
479+ return {.child = &child_promise->frame };
480+ }
481+
482+ template <category Cat, typename R, typename Fn, typename ... Args>
483+ constexpr auto
484+ await_transform (this auto &self, pkg<Cat, Ctx, R, Fn, Args...> &&pkg) noexcept -> awaitable<Cat, Ctx> {
485+ LF_TRY {
486+ return self.await_transform_pkg (std::move (pkg));
485487 } LF_CATCH_ALL {
486488 stash_current_exception (&self.frame );
487- return {.child = nullptr };
488489 }
490+ return {.child = nullptr };
489491 }
490492
491- constexpr auto await_transform (this auto &self, join_type) noexcept -> join_awaitable<Context > {
493+ constexpr auto await_transform (this auto &self, join_type) noexcept -> join_awaitable<Ctx > {
492494 return {.frame = &self.frame };
493495 }
494496
@@ -525,7 +527,6 @@ struct promise_type : mixin_frame<Context> {
525527 requires std::assignable_from<T &, U &&>
526528 constexpr void return_value (U &&value) noexcept (std::is_nothrow_assignable_v<T &, U &&>) {
527529 if (return_address) {
528- // TODO: add the appropriate await_transforms
529530 *return_address = LF_FWD (value);
530531 }
531532 }
0 commit comments