include/boost/capy/ex/run.hpp

99.8% Lines (501/502) 99.3% List of functions (138/139)
run.hpp
f(x) Functions (139)
Function Calls Lines Blocks
boost::capy::detail::dispatch_trampoline::promise_type::get_return_object() :79 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::promise_type::initial_suspend() :85 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::promise_type::final_suspend() :87 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::promise_type::final_suspend()::awaiter::await_ready() const :92 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::promise_type::final_suspend()::awaiter::await_suspend(std::__n4861::coroutine_handle<void>) :94 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::promise_type::final_suspend()::awaiter::await_resume() const :101 0 50.0% 0.0% boost::capy::detail::dispatch_trampoline::promise_type::return_void() :106 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::dispatch_trampoline() :112 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::~dispatch_trampoline() :114 39x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::dispatch_trampoline(boost::capy::detail::dispatch_trampoline&&) :122 13x 100.0% 100.0% boost::capy::detail::dispatch_trampoline::operator=(boost::capy::detail::dispatch_trampoline&&) :125 13x 100.0% 88.0% boost::capy::detail::dispatch_trampoline::dispatch_trampoline(std::__n4861::coroutine_handle<boost::capy::detail::dispatch_trampoline::promise_type>) :136 13x 100.0% 100.0% boost::capy::detail::make_dispatch_trampoline() :140 13x 100.0% 44.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, true, void>::run_awaitable_ex(boost::capy::test_executor, boost::capy::task<bool>) :176 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::run_awaitable_ex(boost::capy::strand<boost::capy::thread_pool::executor_type>, boost::capy::task<void>) :176 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<int>, boost::capy::test_executor, true, void>::run_awaitable_ex(boost::capy::test_executor, boost::capy::test::custom_task<int>) :176 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<void>, boost::capy::test_executor, true, void>::run_awaitable_ex(boost::capy::test_executor, boost::capy::test::custom_task<void>) :176 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, false, void>::run_awaitable_ex(boost::capy::test_executor, boost::capy::task<bool>, std::stop_token) :184 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, void>::run_awaitable_ex(boost::capy::test_executor, boost::capy::task<int>, std::stop_token) :184 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::test_executor, false, void>::run_awaitable_ex(boost::capy::test_executor, boost::capy::task<void>, std::stop_token) :184 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::run_awaitable_ex<boost::capy::test_allocator<std::byte> >(boost::capy::test_executor, boost::capy::test_allocator<std::byte>, boost::capy::task<int>) :195 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, std::pmr::memory_resource*>::run_awaitable_ex<std::pmr::memory_resource*>(boost::capy::test_executor, std::pmr::memory_resource*, boost::capy::task<int>) :195 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::run_awaitable_ex<boost::capy::test_allocator<std::byte> >(boost::capy::test_executor, boost::capy::test_allocator<std::byte>, boost::capy::task<int>, std::stop_token) :205 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, std::pmr::memory_resource*>::run_awaitable_ex<std::pmr::memory_resource*>(boost::capy::test_executor, std::pmr::memory_resource*, boost::capy::task<int>, std::stop_token) :205 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, false, void>::await_ready() const :213 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, true, void>::await_ready() const :213 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, std::pmr::memory_resource*>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, void>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, std::pmr::memory_resource*>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::test_executor, false, void>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<int>, boost::capy::test_executor, true, void>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<void>, boost::capy::test_executor, true, void>::await_ready() const :213 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, false, void>::await_resume() :218 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, true, void>::await_resume() :218 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, std::pmr::memory_resource*>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, void>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, std::pmr::memory_resource*>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::test_executor, false, void>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<int>, boost::capy::test_executor, true, void>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<void>, boost::capy::test_executor, true, void>::await_resume() :218 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, false, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 2x 100.0% 94.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, true, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 2x 100.0% 94.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 95.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, std::pmr::memory_resource*>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 95.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 94.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 95.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, std::pmr::memory_resource*>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 95.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 95.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::test_executor, false, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 94.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<int>, boost::capy::test_executor, true, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 94.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<void>, boost::capy::test_executor, true, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :223 1x 100.0% 94.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, false, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, false, void>&&) :254 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, true, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<bool>, boost::capy::test_executor, true, void>&&) :254 2x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, std::pmr::memory_resource*>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, std::pmr::memory_resource*>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, false, void>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, std::pmr::memory_resource*>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<int>, boost::capy::test_executor, true, std::pmr::memory_resource*>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::test_executor, false, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::task<void>, boost::capy::test_executor, false, void>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<int>, boost::capy::test_executor, true, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<int>, boost::capy::test_executor, true, void>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<void>, boost::capy::test_executor, true, void>::run_awaitable_ex(boost::capy::detail::run_awaitable_ex<boost::capy::test::custom_task<void>, boost::capy::test_executor, true, void>&&) :254 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, void>::run_awaitable(boost::capy::task<int>, std::stop_token) :285 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, boost::capy::test_allocator<std::byte> >::run_awaitable<boost::capy::test_allocator<std::byte> >(boost::capy::test_allocator<std::byte>, boost::capy::task<int>) :295 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, std::pmr::memory_resource*>::run_awaitable<std::pmr::memory_resource*>(std::pmr::memory_resource*, boost::capy::task<int>) :295 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<void>, true, std::pmr::memory_resource*>::run_awaitable<std::pmr::memory_resource*>(std::pmr::memory_resource*, boost::capy::task<void>) :295 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, boost::capy::test_allocator<std::byte> >::run_awaitable<boost::capy::test_allocator<std::byte> >(boost::capy::test_allocator<std::byte>, boost::capy::task<int>, std::stop_token) :304 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, std::pmr::memory_resource*>::run_awaitable<std::pmr::memory_resource*>(std::pmr::memory_resource*, boost::capy::task<int>, std::stop_token) :304 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, boost::capy::test_allocator<std::byte> >::await_ready() const :311 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, std::pmr::memory_resource*>::await_ready() const :311 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, void>::await_ready() const :311 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, boost::capy::test_allocator<std::byte> >::await_ready() const :311 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, std::pmr::memory_resource*>::await_ready() const :311 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<void>, true, std::pmr::memory_resource*>::await_ready() const :311 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, boost::capy::test_allocator<std::byte> >::await_resume() :316 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, std::pmr::memory_resource*>::await_resume() :316 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, void>::await_resume() :316 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, boost::capy::test_allocator<std::byte> >::await_resume() :316 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, std::pmr::memory_resource*>::await_resume() :316 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<void>, true, std::pmr::memory_resource*>::await_resume() :316 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, boost::capy::test_allocator<std::byte> >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :321 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, std::pmr::memory_resource*>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :321 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, void>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :321 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, boost::capy::test_allocator<std::byte> >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :321 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, std::pmr::memory_resource*>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :321 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<void>, true, std::pmr::memory_resource*>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :321 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, boost::capy::test_allocator<std::byte> >::run_awaitable(boost::capy::detail::run_awaitable<boost::capy::task<int>, false, boost::capy::test_allocator<std::byte> >&&) :347 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, std::pmr::memory_resource*>::run_awaitable(boost::capy::detail::run_awaitable<boost::capy::task<int>, false, std::pmr::memory_resource*>&&) :347 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, false, void>::run_awaitable(boost::capy::detail::run_awaitable<boost::capy::task<int>, false, void>&&) :347 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, boost::capy::test_allocator<std::byte> >::run_awaitable(boost::capy::detail::run_awaitable<boost::capy::task<int>, true, boost::capy::test_allocator<std::byte> >&&) :347 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<int>, true, std::pmr::memory_resource*>::run_awaitable(boost::capy::detail::run_awaitable<boost::capy::task<int>, true, std::pmr::memory_resource*>&&) :347 1x 100.0% 100.0% boost::capy::detail::run_awaitable<boost::capy::task<void>, true, std::pmr::memory_resource*>::run_awaitable(boost::capy::detail::run_awaitable<boost::capy::task<void>, true, std::pmr::memory_resource*>&&) :347 1x 100.0% 100.0% boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::run_wrapper_ex(boost::capy::test_executor, boost::capy::test_allocator<std::byte>) :366 1x 100.0% 100.0% boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::run_wrapper_ex(boost::capy::test_executor, std::stop_token, boost::capy::test_allocator<std::byte>) :375 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, boost::capy::test_allocator<std::byte> >::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :392 1x 100.0% 71.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, boost::capy::test_allocator<std::byte> >::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :392 1x 100.0% 82.0% boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, std::pmr::memory_resource*>::run_wrapper_ex(boost::capy::test_executor, std::pmr::memory_resource*) :412 1x 100.0% 100.0% boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, std::pmr::memory_resource*>::run_wrapper_ex(boost::capy::test_executor, std::stop_token, std::pmr::memory_resource*) :420 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, std::pmr::memory_resource*>::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :436 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, std::pmr::memory_resource*>::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :436 1x 100.0% 100.0% boost::capy::detail::run_wrapper_ex<boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::run_wrapper_ex(boost::capy::strand<boost::capy::thread_pool::executor_type>) :455 1x 100.0% 100.0% boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, void>::run_wrapper_ex(boost::capy::test_executor) :455 4x 100.0% 100.0% boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, void>::run_wrapper_ex(boost::capy::test_executor, std::stop_token) :461 4x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::strand<boost::capy::thread_pool::executor_type>, true, void>::operator()<boost::capy::task<void> >(boost::capy::task<void>) && :475 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, void>::operator()<boost::capy::task<bool> >(boost::capy::task<bool>) && :475 2x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, void>::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :475 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, false, void>::operator()<boost::capy::task<void> >(boost::capy::task<void>) && :475 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, void>::operator()<boost::capy::task<bool> >(boost::capy::task<bool>) && :475 2x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, void>::operator()<boost::capy::test::custom_task<int> >(boost::capy::test::custom_task<int>) && :475 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper_ex<boost::capy::test_executor, true, void>::operator()<boost::capy::test::custom_task<void> >(boost::capy::test::custom_task<void>) && :475 1x 100.0% 100.0% boost::capy::detail::run_wrapper<true, boost::capy::test_allocator<std::byte> >::run_wrapper(boost::capy::test_allocator<std::byte>) :499 1x 100.0% 100.0% boost::capy::detail::run_wrapper<false, boost::capy::test_allocator<std::byte> >::run_wrapper(std::stop_token, boost::capy::test_allocator<std::byte>) :507 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper<false, boost::capy::test_allocator<std::byte> >::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :523 1x 100.0% 69.0% auto boost::capy::detail::run_wrapper<true, boost::capy::test_allocator<std::byte> >::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :523 1x 100.0% 80.0% boost::capy::detail::run_wrapper<true, std::pmr::memory_resource*>::run_wrapper(std::pmr::memory_resource*) :542 2x 100.0% 100.0% boost::capy::detail::run_wrapper<false, std::pmr::memory_resource*>::run_wrapper(std::stop_token, std::pmr::memory_resource*) :549 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper<false, std::pmr::memory_resource*>::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :564 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper<true, std::pmr::memory_resource*>::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :564 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper<true, std::pmr::memory_resource*>::operator()<boost::capy::task<void> >(boost::capy::task<void>) && :564 1x 100.0% 100.0% boost::capy::detail::run_wrapper<false, void>::run_wrapper(std::stop_token) :582 1x 100.0% 100.0% auto boost::capy::detail::run_wrapper<false, void>::operator()<boost::capy::task<int> >(boost::capy::task<int>) && :594 1x 100.0% 100.0% auto boost::capy::run<boost::capy::strand<boost::capy::thread_pool::executor_type> >(boost::capy::strand<boost::capy::thread_pool::executor_type>) :623 1x 100.0% 100.0% auto boost::capy::run<boost::capy::test_executor>(boost::capy::test_executor) :623 4x 100.0% 100.0% auto boost::capy::run<boost::capy::test_executor>(boost::capy::test_executor, std::stop_token) :637 4x 100.0% 100.0% auto boost::capy::run<boost::capy::test_executor>(boost::capy::test_executor, std::pmr::memory_resource*) :652 1x 100.0% 100.0% auto boost::capy::run<boost::capy::test_executor, boost::capy::test_allocator<std::byte> >(boost::capy::test_executor, boost::capy::test_allocator<std::byte>) :667 1x 100.0% 100.0% auto boost::capy::run<boost::capy::test_executor>(boost::capy::test_executor, std::stop_token, std::pmr::memory_resource*) :683 1x 100.0% 100.0% auto boost::capy::run<boost::capy::test_executor, boost::capy::test_allocator<std::byte> >(boost::capy::test_executor, std::stop_token, boost::capy::test_allocator<std::byte>) :699 1x 100.0% 82.0% boost::capy::run(std::stop_token) :721 1x 100.0% 100.0% boost::capy::run(std::pmr::memory_resource*) :736 2x 100.0% 100.0% auto boost::capy::run<boost::capy::test_allocator<std::byte> >(boost::capy::test_allocator<std::byte>) :752 1x 100.0% 100.0% boost::capy::run(std::stop_token, std::pmr::memory_resource*) :767 1x 100.0% 100.0% auto boost::capy::run<boost::capy::test_allocator<std::byte> >(std::stop_token, boost::capy::test_allocator<std::byte>) :784 1x 100.0% 80.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/capy
8 //
9
10 #ifndef BOOST_CAPY_RUN_HPP
11 #define BOOST_CAPY_RUN_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/detail/await_suspend_helper.hpp>
15 #include <boost/capy/detail/run.hpp>
16 #include <boost/capy/concept/executor.hpp>
17 #include <boost/capy/concept/io_runnable.hpp>
18 #include <boost/capy/ex/executor_ref.hpp>
19 #include <coroutine>
20 #include <boost/capy/ex/frame_allocator.hpp>
21 #include <boost/capy/ex/io_env.hpp>
22
23 #include <memory_resource>
24 #include <stop_token>
25 #include <type_traits>
26 #include <utility>
27 #include <variant>
28
29 /*
30 Allocator Lifetime Strategy
31 ===========================
32
33 When using run() with a custom allocator:
34
35 co_await run(ex, alloc)(my_task());
36
37 The evaluation order is:
38 1. run(ex, alloc) creates a temporary wrapper
39 2. my_task() allocates its coroutine frame using TLS
40 3. operator() returns an awaitable
41 4. Wrapper temporary is DESTROYED
42 5. co_await suspends caller, resumes task
43 6. Task body executes (wrapper is already dead!)
44
45 Problem: The wrapper's frame_memory_resource dies before the task
46 body runs. When initial_suspend::await_resume() restores TLS from
47 the saved pointer, it would point to dead memory.
48
49 Solution: Store a COPY of the allocator in the awaitable (not just
50 the wrapper). The co_await mechanism extends the awaitable's lifetime
51 until the await completes. In await_suspend, we overwrite the promise's
52 saved frame_allocator pointer to point to the awaitable's resource.
53
54 This works because standard allocator copies are equivalent - memory
55 allocated with one copy can be deallocated with another copy. The
56 task's own frame uses the footer-stored pointer (safe), while nested
57 task creation uses TLS pointing to the awaitable's resource (also safe).
58 */
59
60 namespace boost::capy::detail {
61
62 /** Minimal coroutine that dispatches through the caller's executor.
63
64 Sits between the inner task and the parent when executors
65 diverge. The inner task's `final_suspend` resumes this
66 trampoline via symmetric transfer. The trampoline's own
67 `final_suspend` dispatches the parent through the caller's
68 executor to restore the correct execution context.
69
70 The trampoline never touches the task's result.
71 */
72 struct dispatch_trampoline
73 {
74 struct promise_type
75 {
76 executor_ref caller_ex_;
77 continuation parent_;
78
79 13x dispatch_trampoline get_return_object() noexcept
80 {
81 return dispatch_trampoline{
82 13x std::coroutine_handle<promise_type>::from_promise(*this)};
83 }
84
85 13x std::suspend_always initial_suspend() noexcept { return {}; }
86
87 13x auto final_suspend() noexcept
88 {
89 struct awaiter
90 {
91 promise_type* p_;
92 13x bool await_ready() const noexcept { return false; }
93
94 13x auto await_suspend(
95 std::coroutine_handle<>) noexcept
96 {
97 13x return detail::symmetric_transfer(
98 26x p_->caller_ex_.dispatch(p_->parent_));
99 }
100
101 void await_resume() const noexcept {}
102 };
103 13x return awaiter{this};
104 }
105
106 13x void return_void() noexcept {}
107 void unhandled_exception() noexcept {}
108 };
109
110 std::coroutine_handle<promise_type> h_{nullptr};
111
112 13x dispatch_trampoline() noexcept = default;
113
114 39x ~dispatch_trampoline()
115 {
116 39x if(h_) h_.destroy();
117 39x }
118
119 dispatch_trampoline(dispatch_trampoline const&) = delete;
120 dispatch_trampoline& operator=(dispatch_trampoline const&) = delete;
121
122 13x dispatch_trampoline(dispatch_trampoline&& o) noexcept
123 13x : h_(std::exchange(o.h_, nullptr)) {}
124
125 13x dispatch_trampoline& operator=(dispatch_trampoline&& o) noexcept
126 {
127 13x if(this != &o)
128 {
129 13x if(h_) h_.destroy();
130 13x h_ = std::exchange(o.h_, nullptr);
131 }
132 13x return *this;
133 }
134
135 private:
136 13x explicit dispatch_trampoline(std::coroutine_handle<promise_type> h) noexcept
137 13x : h_(h) {}
138 };
139
140 13x inline dispatch_trampoline make_dispatch_trampoline()
141 {
142 co_return;
143 26x }
144
145 /** Awaitable that binds an IoRunnable to a specific executor.
146
147 Stores the executor and inner task by value. When co_awaited, the
148 co_await expression's lifetime extension keeps both alive for the
149 duration of the operation.
150
151 A dispatch trampoline handles the executor switch on completion:
152 the inner task's `final_suspend` resumes the trampoline, which
153 dispatches back through the caller's executor.
154
155 The `io_env` is owned by this awaitable and is guaranteed to
156 outlive the inner task and all awaitables in its chain. Awaitables
157 may store `io_env const*` without concern for dangling references.
158
159 @tparam Task The IoRunnable type
160 @tparam Ex The executor type
161 @tparam InheritStopToken If true, inherit caller's stop token
162 @tparam Alloc The allocator type (void for no allocator)
163 */
164 template<IoRunnable Task, Executor Ex, bool InheritStopToken, class Alloc = void>
165 struct [[nodiscard]] run_awaitable_ex
166 {
167 Ex ex_;
168 frame_memory_resource<Alloc> resource_;
169 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
170 io_env env_;
171 dispatch_trampoline tr_;
172 continuation task_cont_;
173 Task inner_; // Last: destroyed first, while env_ is still valid
174
175 // void allocator, inherit stop token
176 5x run_awaitable_ex(Ex ex, Task inner)
177 requires (InheritStopToken && std::is_void_v<Alloc>)
178 5x : ex_(std::move(ex))
179 5x , inner_(std::move(inner))
180 {
181 5x }
182
183 // void allocator, explicit stop token
184 4x run_awaitable_ex(Ex ex, Task inner, std::stop_token st)
185 requires (!InheritStopToken && std::is_void_v<Alloc>)
186 4x : ex_(std::move(ex))
187 4x , st_(std::move(st))
188 4x , inner_(std::move(inner))
189 {
190 4x }
191
192 // with allocator, inherit stop token (use template to avoid void parameter)
193 template<class A>
194 requires (InheritStopToken && !std::is_void_v<Alloc> && std::same_as<A, Alloc>)
195 2x run_awaitable_ex(Ex ex, A alloc, Task inner)
196 2x : ex_(std::move(ex))
197 2x , resource_(std::move(alloc))
198 2x , inner_(std::move(inner))
199 {
200 2x }
201
202 // with allocator, explicit stop token (use template to avoid void parameter)
203 template<class A>
204 requires (!InheritStopToken && !std::is_void_v<Alloc> && std::same_as<A, Alloc>)
205 2x run_awaitable_ex(Ex ex, A alloc, Task inner, std::stop_token st)
206 2x : ex_(std::move(ex))
207 2x , resource_(std::move(alloc))
208 2x , st_(std::move(st))
209 2x , inner_(std::move(inner))
210 {
211 2x }
212
213 13x bool await_ready() const noexcept
214 {
215 13x return inner_.await_ready();
216 }
217
218 13x decltype(auto) await_resume()
219 {
220 13x return inner_.await_resume();
221 }
222
223 13x std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, io_env const* caller_env)
224 {
225 13x tr_ = make_dispatch_trampoline();
226 13x tr_.h_.promise().caller_ex_ = caller_env->executor;
227 13x tr_.h_.promise().parent_.h = cont;
228
229 13x auto h = inner_.handle();
230 13x auto& p = h.promise();
231 13x p.set_continuation(tr_.h_);
232
233 13x env_.executor = ex_;
234 if constexpr (InheritStopToken)
235 7x env_.stop_token = caller_env->stop_token;
236 else
237 6x env_.stop_token = st_;
238
239 if constexpr (!std::is_void_v<Alloc>)
240 4x env_.frame_allocator = resource_.get();
241 else
242 9x env_.frame_allocator = caller_env->frame_allocator;
243
244 13x p.set_environment(&env_);
245 13x task_cont_.h = h;
246 26x return ex_.dispatch(task_cont_);
247 }
248
249 // Non-copyable
250 run_awaitable_ex(run_awaitable_ex const&) = delete;
251 run_awaitable_ex& operator=(run_awaitable_ex const&) = delete;
252
253 // Movable (no noexcept - Task may throw)
254 13x run_awaitable_ex(run_awaitable_ex&&) = default;
255 run_awaitable_ex& operator=(run_awaitable_ex&&) = default;
256 };
257
258 /** Awaitable that runs a task with optional stop_token override.
259
260 Does NOT store an executor - the task inherits the caller's executor
261 directly. Executors always match, so no dispatch trampoline is needed.
262 The inner task's `final_suspend` resumes the parent directly via
263 unconditional symmetric transfer.
264
265 @tparam Task The IoRunnable type
266 @tparam InheritStopToken If true, inherit caller's stop token
267 @tparam Alloc The allocator type (void for no allocator)
268 */
269 template<IoRunnable Task, bool InheritStopToken, class Alloc = void>
270 struct [[nodiscard]] run_awaitable
271 {
272 frame_memory_resource<Alloc> resource_;
273 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
274 io_env env_;
275 Task inner_; // Last: destroyed first, while env_ is still valid
276
277 // void allocator, inherit stop token
278 explicit run_awaitable(Task inner)
279 requires (InheritStopToken && std::is_void_v<Alloc>)
280 : inner_(std::move(inner))
281 {
282 }
283
284 // void allocator, explicit stop token
285 1x run_awaitable(Task inner, std::stop_token st)
286 requires (!InheritStopToken && std::is_void_v<Alloc>)
287 1x : st_(std::move(st))
288 1x , inner_(std::move(inner))
289 {
290 1x }
291
292 // with allocator, inherit stop token (use template to avoid void parameter)
293 template<class A>
294 requires (InheritStopToken && !std::is_void_v<Alloc> && std::same_as<A, Alloc>)
295 3x run_awaitable(A alloc, Task inner)
296 3x : resource_(std::move(alloc))
297 3x , inner_(std::move(inner))
298 {
299 3x }
300
301 // with allocator, explicit stop token (use template to avoid void parameter)
302 template<class A>
303 requires (!InheritStopToken && !std::is_void_v<Alloc> && std::same_as<A, Alloc>)
304 2x run_awaitable(A alloc, Task inner, std::stop_token st)
305 2x : resource_(std::move(alloc))
306 2x , st_(std::move(st))
307 2x , inner_(std::move(inner))
308 {
309 2x }
310
311 6x bool await_ready() const noexcept
312 {
313 6x return inner_.await_ready();
314 }
315
316 6x decltype(auto) await_resume()
317 {
318 6x return inner_.await_resume();
319 }
320
321 6x std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, io_env const* caller_env)
322 {
323 6x auto h = inner_.handle();
324 6x auto& p = h.promise();
325 6x p.set_continuation(cont);
326
327 6x env_.executor = caller_env->executor;
328 if constexpr (InheritStopToken)
329 3x env_.stop_token = caller_env->stop_token;
330 else
331 3x env_.stop_token = st_;
332
333 if constexpr (!std::is_void_v<Alloc>)
334 5x env_.frame_allocator = resource_.get();
335 else
336 1x env_.frame_allocator = caller_env->frame_allocator;
337
338 6x p.set_environment(&env_);
339 6x return h;
340 }
341
342 // Non-copyable
343 run_awaitable(run_awaitable const&) = delete;
344 run_awaitable& operator=(run_awaitable const&) = delete;
345
346 // Movable (no noexcept - Task may throw)
347 6x run_awaitable(run_awaitable&&) = default;
348 run_awaitable& operator=(run_awaitable&&) = default;
349 };
350
351 /** Wrapper returned by run(ex, ...) that accepts a task for execution.
352
353 @tparam Ex The executor type.
354 @tparam InheritStopToken If true, inherit caller's stop token.
355 @tparam Alloc The allocator type (void for no allocator).
356 */
357 template<Executor Ex, bool InheritStopToken, class Alloc>
358 class [[nodiscard]] run_wrapper_ex
359 {
360 Ex ex_;
361 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
362 frame_memory_resource<Alloc> resource_;
363 Alloc alloc_; // Copy to pass to awaitable
364
365 public:
366 1x run_wrapper_ex(Ex ex, Alloc alloc)
367 requires InheritStopToken
368 1x : ex_(std::move(ex))
369 1x , resource_(alloc)
370 1x , alloc_(std::move(alloc))
371 {
372 1x set_current_frame_allocator(&resource_);
373 1x }
374
375 1x run_wrapper_ex(Ex ex, std::stop_token st, Alloc alloc)
376 requires (!InheritStopToken)
377 1x : ex_(std::move(ex))
378 1x , st_(std::move(st))
379 1x , resource_(alloc)
380 1x , alloc_(std::move(alloc))
381 {
382 1x set_current_frame_allocator(&resource_);
383 1x }
384
385 // Non-copyable, non-movable (must be used immediately)
386 run_wrapper_ex(run_wrapper_ex const&) = delete;
387 run_wrapper_ex(run_wrapper_ex&&) = delete;
388 run_wrapper_ex& operator=(run_wrapper_ex const&) = delete;
389 run_wrapper_ex& operator=(run_wrapper_ex&&) = delete;
390
391 template<IoRunnable Task>
392 2x [[nodiscard]] auto operator()(Task t) &&
393 {
394 if constexpr (InheritStopToken)
395 return run_awaitable_ex<Task, Ex, true, Alloc>{
396 1x std::move(ex_), std::move(alloc_), std::move(t)};
397 else
398 return run_awaitable_ex<Task, Ex, false, Alloc>{
399 1x std::move(ex_), std::move(alloc_), std::move(t), std::move(st_)};
400 }
401 };
402
403 /// Specialization for memory_resource* - stores pointer directly.
404 template<Executor Ex, bool InheritStopToken>
405 class [[nodiscard]] run_wrapper_ex<Ex, InheritStopToken, std::pmr::memory_resource*>
406 {
407 Ex ex_;
408 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
409 std::pmr::memory_resource* mr_;
410
411 public:
412 1x run_wrapper_ex(Ex ex, std::pmr::memory_resource* mr)
413 requires InheritStopToken
414 1x : ex_(std::move(ex))
415 1x , mr_(mr)
416 {
417 1x set_current_frame_allocator(mr_);
418 1x }
419
420 1x run_wrapper_ex(Ex ex, std::stop_token st, std::pmr::memory_resource* mr)
421 requires (!InheritStopToken)
422 1x : ex_(std::move(ex))
423 1x , st_(std::move(st))
424 1x , mr_(mr)
425 {
426 1x set_current_frame_allocator(mr_);
427 1x }
428
429 // Non-copyable, non-movable (must be used immediately)
430 run_wrapper_ex(run_wrapper_ex const&) = delete;
431 run_wrapper_ex(run_wrapper_ex&&) = delete;
432 run_wrapper_ex& operator=(run_wrapper_ex const&) = delete;
433 run_wrapper_ex& operator=(run_wrapper_ex&&) = delete;
434
435 template<IoRunnable Task>
436 2x [[nodiscard]] auto operator()(Task t) &&
437 {
438 if constexpr (InheritStopToken)
439 return run_awaitable_ex<Task, Ex, true, std::pmr::memory_resource*>{
440 1x std::move(ex_), mr_, std::move(t)};
441 else
442 return run_awaitable_ex<Task, Ex, false, std::pmr::memory_resource*>{
443 1x std::move(ex_), mr_, std::move(t), std::move(st_)};
444 }
445 };
446
447 /// Specialization for no allocator (void).
448 template<Executor Ex, bool InheritStopToken>
449 class [[nodiscard]] run_wrapper_ex<Ex, InheritStopToken, void>
450 {
451 Ex ex_;
452 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
453
454 public:
455 5x explicit run_wrapper_ex(Ex ex)
456 requires InheritStopToken
457 5x : ex_(std::move(ex))
458 {
459 5x }
460
461 4x run_wrapper_ex(Ex ex, std::stop_token st)
462 requires (!InheritStopToken)
463 4x : ex_(std::move(ex))
464 4x , st_(std::move(st))
465 {
466 4x }
467
468 // Non-copyable, non-movable (must be used immediately)
469 run_wrapper_ex(run_wrapper_ex const&) = delete;
470 run_wrapper_ex(run_wrapper_ex&&) = delete;
471 run_wrapper_ex& operator=(run_wrapper_ex const&) = delete;
472 run_wrapper_ex& operator=(run_wrapper_ex&&) = delete;
473
474 template<IoRunnable Task>
475 9x [[nodiscard]] auto operator()(Task t) &&
476 {
477 if constexpr (InheritStopToken)
478 return run_awaitable_ex<Task, Ex, true>{
479 5x std::move(ex_), std::move(t)};
480 else
481 return run_awaitable_ex<Task, Ex, false>{
482 4x std::move(ex_), std::move(t), std::move(st_)};
483 }
484 };
485
486 /** Wrapper returned by run(st) or run(alloc) that accepts a task.
487
488 @tparam InheritStopToken If true, inherit caller's stop token.
489 @tparam Alloc The allocator type (void for no allocator).
490 */
491 template<bool InheritStopToken, class Alloc>
492 class [[nodiscard]] run_wrapper
493 {
494 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
495 frame_memory_resource<Alloc> resource_;
496 Alloc alloc_; // Copy to pass to awaitable
497
498 public:
499 1x explicit run_wrapper(Alloc alloc)
500 requires InheritStopToken
501 1x : resource_(alloc)
502 1x , alloc_(std::move(alloc))
503 {
504 1x set_current_frame_allocator(&resource_);
505 1x }
506
507 1x run_wrapper(std::stop_token st, Alloc alloc)
508 requires (!InheritStopToken)
509 1x : st_(std::move(st))
510 1x , resource_(alloc)
511 1x , alloc_(std::move(alloc))
512 {
513 1x set_current_frame_allocator(&resource_);
514 1x }
515
516 // Non-copyable, non-movable (must be used immediately)
517 run_wrapper(run_wrapper const&) = delete;
518 run_wrapper(run_wrapper&&) = delete;
519 run_wrapper& operator=(run_wrapper const&) = delete;
520 run_wrapper& operator=(run_wrapper&&) = delete;
521
522 template<IoRunnable Task>
523 2x [[nodiscard]] auto operator()(Task t) &&
524 {
525 if constexpr (InheritStopToken)
526 return run_awaitable<Task, true, Alloc>{
527 1x std::move(alloc_), std::move(t)};
528 else
529 return run_awaitable<Task, false, Alloc>{
530 1x std::move(alloc_), std::move(t), std::move(st_)};
531 }
532 };
533
534 /// Specialization for memory_resource* - stores pointer directly.
535 template<bool InheritStopToken>
536 class [[nodiscard]] run_wrapper<InheritStopToken, std::pmr::memory_resource*>
537 {
538 std::conditional_t<InheritStopToken, std::monostate, std::stop_token> st_;
539 std::pmr::memory_resource* mr_;
540
541 public:
542 2x explicit run_wrapper(std::pmr::memory_resource* mr)
543 requires InheritStopToken
544 2x : mr_(mr)
545 {
546 2x set_current_frame_allocator(mr_);
547 2x }
548
549 1x run_wrapper(std::stop_token st, std::pmr::memory_resource* mr)
550 requires (!InheritStopToken)
551 1x : st_(std::move(st))
552 1x , mr_(mr)
553 {
554 1x set_current_frame_allocator(mr_);
555 1x }
556
557 // Non-copyable, non-movable (must be used immediately)
558 run_wrapper(run_wrapper const&) = delete;
559 run_wrapper(run_wrapper&&) = delete;
560 run_wrapper& operator=(run_wrapper const&) = delete;
561 run_wrapper& operator=(run_wrapper&&) = delete;
562
563 template<IoRunnable Task>
564 3x [[nodiscard]] auto operator()(Task t) &&
565 {
566 if constexpr (InheritStopToken)
567 return run_awaitable<Task, true, std::pmr::memory_resource*>{
568 2x mr_, std::move(t)};
569 else
570 return run_awaitable<Task, false, std::pmr::memory_resource*>{
571 1x mr_, std::move(t), std::move(st_)};
572 }
573 };
574
575 /// Specialization for stop_token only (no allocator).
576 template<>
577 class [[nodiscard]] run_wrapper<false, void>
578 {
579 std::stop_token st_;
580
581 public:
582 1x explicit run_wrapper(std::stop_token st)
583 1x : st_(std::move(st))
584 {
585 1x }
586
587 // Non-copyable, non-movable (must be used immediately)
588 run_wrapper(run_wrapper const&) = delete;
589 run_wrapper(run_wrapper&&) = delete;
590 run_wrapper& operator=(run_wrapper const&) = delete;
591 run_wrapper& operator=(run_wrapper&&) = delete;
592
593 template<IoRunnable Task>
594 1x [[nodiscard]] auto operator()(Task t) &&
595 {
596 1x return run_awaitable<Task, false, void>{std::move(t), std::move(st_)};
597 }
598 };
599
600 } // namespace boost::capy::detail
601
602 namespace boost::capy {
603
604 /** Bind a task to execute on a specific executor.
605
606 Returns a wrapper that accepts a task and produces an awaitable.
607 When co_awaited, the task runs on the specified executor.
608
609 @par Example
610 @code
611 co_await run(other_executor)(my_task());
612 @endcode
613
614 @param ex The executor on which the task should run.
615
616 @return A wrapper that accepts a task for execution.
617
618 @see task
619 @see executor
620 */
621 template<Executor Ex>
622 [[nodiscard]] auto
623 5x run(Ex ex)
624 {
625 5x return detail::run_wrapper_ex<Ex, true, void>{std::move(ex)};
626 }
627
628 /** Bind a task to an executor with a stop token.
629
630 @param ex The executor on which the task should run.
631 @param st The stop token for cooperative cancellation.
632
633 @return A wrapper that accepts a task for execution.
634 */
635 template<Executor Ex>
636 [[nodiscard]] auto
637 4x run(Ex ex, std::stop_token st)
638 {
639 return detail::run_wrapper_ex<Ex, false, void>{
640 4x std::move(ex), std::move(st)};
641 }
642
643 /** Bind a task to an executor with a memory resource.
644
645 @param ex The executor on which the task should run.
646 @param mr The memory resource for frame allocation.
647
648 @return A wrapper that accepts a task for execution.
649 */
650 template<Executor Ex>
651 [[nodiscard]] auto
652 1x run(Ex ex, std::pmr::memory_resource* mr)
653 {
654 return detail::run_wrapper_ex<Ex, true, std::pmr::memory_resource*>{
655 1x std::move(ex), mr};
656 }
657
658 /** Bind a task to an executor with a standard allocator.
659
660 @param ex The executor on which the task should run.
661 @param alloc The allocator for frame allocation.
662
663 @return A wrapper that accepts a task for execution.
664 */
665 template<Executor Ex, detail::Allocator Alloc>
666 [[nodiscard]] auto
667 1x run(Ex ex, Alloc alloc)
668 {
669 return detail::run_wrapper_ex<Ex, true, Alloc>{
670 1x std::move(ex), std::move(alloc)};
671 }
672
673 /** Bind a task to an executor with stop token and memory resource.
674
675 @param ex The executor on which the task should run.
676 @param st The stop token for cooperative cancellation.
677 @param mr The memory resource for frame allocation.
678
679 @return A wrapper that accepts a task for execution.
680 */
681 template<Executor Ex>
682 [[nodiscard]] auto
683 1x run(Ex ex, std::stop_token st, std::pmr::memory_resource* mr)
684 {
685 return detail::run_wrapper_ex<Ex, false, std::pmr::memory_resource*>{
686 1x std::move(ex), std::move(st), mr};
687 }
688
689 /** Bind a task to an executor with stop token and standard allocator.
690
691 @param ex The executor on which the task should run.
692 @param st The stop token for cooperative cancellation.
693 @param alloc The allocator for frame allocation.
694
695 @return A wrapper that accepts a task for execution.
696 */
697 template<Executor Ex, detail::Allocator Alloc>
698 [[nodiscard]] auto
699 1x run(Ex ex, std::stop_token st, Alloc alloc)
700 {
701 return detail::run_wrapper_ex<Ex, false, Alloc>{
702 1x std::move(ex), std::move(st), std::move(alloc)};
703 }
704
705 /** Run a task with a custom stop token.
706
707 The task inherits the caller's executor. Only the stop token
708 is overridden.
709
710 @par Example
711 @code
712 std::stop_source source;
713 co_await run(source.get_token())(cancellable_task());
714 @endcode
715
716 @param st The stop token for cooperative cancellation.
717
718 @return A wrapper that accepts a task for execution.
719 */
720 [[nodiscard]] inline auto
721 1x run(std::stop_token st)
722 {
723 1x return detail::run_wrapper<false, void>{std::move(st)};
724 }
725
726 /** Run a task with a custom memory resource.
727
728 The task inherits the caller's executor. The memory resource
729 is used for nested frame allocations.
730
731 @param mr The memory resource for frame allocation.
732
733 @return A wrapper that accepts a task for execution.
734 */
735 [[nodiscard]] inline auto
736 2x run(std::pmr::memory_resource* mr)
737 {
738 2x return detail::run_wrapper<true, std::pmr::memory_resource*>{mr};
739 }
740
741 /** Run a task with a custom standard allocator.
742
743 The task inherits the caller's executor. The allocator is used
744 for nested frame allocations.
745
746 @param alloc The allocator for frame allocation.
747
748 @return A wrapper that accepts a task for execution.
749 */
750 template<detail::Allocator Alloc>
751 [[nodiscard]] auto
752 1x run(Alloc alloc)
753 {
754 1x return detail::run_wrapper<true, Alloc>{std::move(alloc)};
755 }
756
757 /** Run a task with stop token and memory resource.
758
759 The task inherits the caller's executor.
760
761 @param st The stop token for cooperative cancellation.
762 @param mr The memory resource for frame allocation.
763
764 @return A wrapper that accepts a task for execution.
765 */
766 [[nodiscard]] inline auto
767 1x run(std::stop_token st, std::pmr::memory_resource* mr)
768 {
769 return detail::run_wrapper<false, std::pmr::memory_resource*>{
770 1x std::move(st), mr};
771 }
772
773 /** Run a task with stop token and standard allocator.
774
775 The task inherits the caller's executor.
776
777 @param st The stop token for cooperative cancellation.
778 @param alloc The allocator for frame allocation.
779
780 @return A wrapper that accepts a task for execution.
781 */
782 template<detail::Allocator Alloc>
783 [[nodiscard]] auto
784 1x run(std::stop_token st, Alloc alloc)
785 {
786 return detail::run_wrapper<false, Alloc>{
787 1x std::move(st), std::move(alloc)};
788 }
789
790 } // namespace boost::capy
791
792 #endif
793