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