GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 79.6% 785 / 0 / 986
Functions: 83.6% 310 / 0 / 371
Branches: 55.6% 85 / 0 / 153

libs/capy/include/boost/capy/task.hpp
Line Branch Exec Source
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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/corosio
8 //
9
10 #ifndef BOOST_CAPY_TASK_HPP
11 #define BOOST_CAPY_TASK_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/concept/executor.hpp>
15 #include <boost/capy/io_awaitable.hpp>
16 #include <boost/capy/ex/executor_ref.hpp>
17 #include <boost/capy/ex/frame_allocator.hpp>
18
19 #include <exception>
20 #include <optional>
21 #include <type_traits>
22 #include <utility>
23 #include <variant>
24
25 namespace boost {
26 namespace capy {
27
28 namespace detail {
29
30 // Helper base for result storage and return_void/return_value
31 template<typename T>
32 struct task_return_base
33 {
34 std::optional<T> result_;
35
36 283 void return_value(T value)
37 {
38 283 result_ = std::move(value);
39 283 }
40
41 87 T&& result() noexcept
42 {
43 87 return std::move(*result_);
44 }
45 };
46
47 template<>
48 struct task_return_base<void>
49 {
50 65 void return_void()
51 {
52 65 }
53 };
54
55 } // namespace detail
56
57 /** A coroutine task type implementing the affine awaitable protocol.
58
59 This task type represents an asynchronous operation that can be awaited.
60 It implements the affine awaitable protocol where `await_suspend` receives
61 the caller's executor, enabling proper completion dispatch across executor
62 boundaries.
63
64 @tparam T The return type of the task. Defaults to void.
65
66 Key features:
67 @li Lazy execution - the coroutine does not start until awaited
68 @li Symmetric transfer - uses coroutine handle returns for efficient
69 resumption
70 @li Executor inheritance - inherits caller's executor unless explicitly
71 bound
72
73 The task uses `[[clang::coro_await_elidable]]` (when available) to enable
74 heap allocation elision optimization (HALO) for nested coroutine calls.
75
76 @see executor_ref
77 */
78 template<typename T = void>
79 struct [[nodiscard]] BOOST_CAPY_CORO_AWAIT_ELIDABLE
80 task
81 {
82 struct promise_type
83 : frame_allocating_base
84 , io_awaitable_support<promise_type>
85 , detail::task_return_base<T>
86 {
87 std::exception_ptr ep_;
88 detail::frame_allocator_base* alloc_ = nullptr;
89
90 161 std::exception_ptr exception() const noexcept
91 {
92 161 return ep_;
93 }
94
95 392 task get_return_object()
96 {
97 392 return task{std::coroutine_handle<promise_type>::from_promise(*this)};
98 }
99
100 392 auto initial_suspend() noexcept
101 {
102 struct awaiter
103 {
104 promise_type* p_;
105
106 bool await_ready() const noexcept
107 {
108 return false;
109 }
110
111 void await_suspend(coro) const noexcept
112 {
113 // Capture TLS allocator while it's still valid
114 p_->alloc_ = get_frame_allocator();
115 }
116
117 void await_resume() const noexcept
118 {
119 // Restore TLS when body starts executing
120 if(p_->alloc_)
121 set_frame_allocator(*p_->alloc_);
122 }
123 };
124 392 return awaiter{this};
125 }
126
127 391 auto final_suspend() noexcept
128 {
129 struct awaiter
130 {
131 promise_type* p_;
132
133 bool await_ready() const noexcept
134 {
135 return false;
136 }
137
138 coro await_suspend(coro) const noexcept
139 {
140 return p_->complete();
141 }
142
143 void await_resume() const noexcept
144 {
145 }
146 };
147 391 return awaiter{this};
148 }
149
150 // return_void() or return_value() inherited from task_return_base
151
152 43 void unhandled_exception()
153 {
154 43 ep_ = std::current_exception();
155 43 }
156
157 template<class Awaitable>
158 struct transform_awaiter
159 {
160 std::decay_t<Awaitable> a_;
161 promise_type* p_;
162
163 199 bool await_ready()
164 {
165 199 return a_.await_ready();
166 }
167
168 199 auto await_resume()
169 {
170 // Restore TLS before body resumes
171
31/76
boost::capy::task<bool>::promise_type::transform_awaiter<boost::capy::task<std::stop_token> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<boost::capy::io_result<unsigned long> >::promise_type::transform_awaiter<boost::capy::(anonymous namespace)::mock_error_stream::read_some<boost::capy::consuming_buffers<boost::capy::mutable_buffer> >(boost::capy::consuming_buffers<boost::capy::mutable_buffer> const&)::awaitable>::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<boost::capy::io_result<unsigned long> >::promise_type::transform_awaiter<boost::capy::(anonymous namespace)::mock_error_stream::write_some<boost::capy::consuming_buffers<boost::capy::const_buffer> >(boost::capy::consuming_buffers<boost::capy::const_buffer> const&)::awaitable>::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<boost::capy::io_result<unsigned long> >::promise_type::transform_awaiter<boost::capy::(anonymous namespace)::mock_read_awaitable>::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
boost::capy::task<boost::capy::io_result<unsigned long> >::promise_type::transform_awaiter<boost::capy::(anonymous namespace)::mock_write_awaitable>::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::detail::run_on_awaitable<boost::capy::test::custom_task<int>, boost::capy::test_executor> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::task<int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::task<std::pair<unsigned long, int> > >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::task<std::pair<unsigned long, std::variant<int> > > >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::task<std::tuple<int, int> > >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::task<void> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
boost::capy::task<std::pair<unsigned long, int> >::promise_type::transform_awaiter<boost::capy::detail::when_any_homogeneous_launcher<int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int, int, int, int, int, int, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int, int, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<std::pair<unsigned long, std::variant<std::monostate, int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<void, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<std::pair<unsigned long, std::variant<std::monostate> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<void, void, void> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<std::tuple<int, int, int, int, int, int, int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, int, int, int, int, int, int, int> >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<std::tuple<int, int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, int, int> >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<std::tuple<int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
boost::capy::task<std::tuple<int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, void, int> >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<std::tuple<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, void> >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<std::tuple<int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, void> >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<std::tuple<int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<unsigned long>::promise_type::transform_awaiter<boost::capy::detail::when_any_homogeneous_launcher<void> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::async_event::wait_awaiter>::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::detail::run_on_awaitable<boost::capy::test::custom_task<void>, boost::capy::test_executor> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<void, void, void> >::await_resume():
✗ Branch 0 not taken.
✗ Branch 1 not taken.
boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::task<boost::capy::io_result<unsigned long> > >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::task<int> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::task<void> >::await_resume():
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
199 if(p_->alloc_)
172 set_frame_allocator(*p_->alloc_);
173 199 return a_.await_resume();
174 }
175
176 template<class Promise>
177 162 auto await_suspend(std::coroutine_handle<Promise> h)
178 {
179
18/25
auto boost::capy::task<bool>::promise_type::transform_awaiter<boost::capy::task<std::stop_token> >::await_suspend<boost::capy::task<bool>::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<bool>::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::task<int> >::await_suspend<boost::capy::task<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<int>::promise_type>):
✓ Branch 5 taken 4 times.
auto boost::capy::task<int>::promise_type::transform_awaiter<boost::capy::yield_awaitable>::await_suspend<boost::capy::task<int>::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<int>::promise_type>):
✓ Branch 5 taken 24 times.
auto boost::capy::task<std::pair<unsigned long, int> >::promise_type::transform_awaiter<boost::capy::detail::when_any_homogeneous_launcher<int> >::await_suspend<boost::capy::task<std::pair<unsigned long, int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, int> >::promise_type>):
✓ Branch 5 taken 13 times.
auto boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::promise_type>):
✓ Branch 5 taken 2 times.
auto boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> > >::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int, int, int, int, int, int, int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int, int, int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int, int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>):
✓ Branch 5 taken 9 times.
auto boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int, int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>):
✓ Branch 5 taken 17 times.
auto boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<int> > >::promise_type>):
✓ Branch 5 taken 2 times.
auto boost::capy::task<std::pair<unsigned long, std::variant<std::monostate, int> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<void, int> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<std::monostate, int> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<std::monostate, int> > >::promise_type>):
✓ Branch 5 taken 2 times.
auto boost::capy::task<std::pair<unsigned long, std::variant<std::monostate> > >::promise_type::transform_awaiter<boost::capy::detail::when_any_launcher<void, void, void> >::await_suspend<boost::capy::task<std::pair<unsigned long, std::variant<std::monostate> > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::pair<unsigned long, std::variant<std::monostate> > >::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<std::tuple<int, int, int, int, int, int, int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, int, int, int, int, int, int, int> >::await_suspend<boost::capy::task<std::tuple<int, int, int, int, int, int, int, int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int, int, int, int, int, int, int, int> >::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<std::tuple<int, int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, int, int> >::await_suspend<boost::capy::task<std::tuple<int, int, int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int, int, int> >::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<std::tuple<int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, int> >::await_suspend<boost::capy::task<std::tuple<int, int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int, int> >::promise_type>):
✓ Branch 5 taken 4 times.
auto boost::capy::task<std::tuple<int, int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, void, int> >::await_suspend<boost::capy::task<std::tuple<int, int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int, int> >::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<std::tuple<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, void> >::await_suspend<boost::capy::task<std::tuple<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<std::tuple<int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int, void> >::await_suspend<boost::capy::task<std::tuple<int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int> >::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<std::tuple<int> >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<int> >::await_suspend<boost::capy::task<std::tuple<int> >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<int> >::promise_type>):
✓ Branch 5 taken 1 time.
auto boost::capy::task<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::await_suspend<boost::capy::task<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<unsigned long>::promise_type::transform_awaiter<boost::capy::detail::when_any_homogeneous_launcher<void> >::await_suspend<boost::capy::task<unsigned long>::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<unsigned long>::promise_type>):
✓ Branch 5 taken 2 times.
auto boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::detail::when_all_launcher<void, void, void> >::await_suspend<boost::capy::task<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<void>::promise_type>):
✗ Branch 5 not taken.
auto boost::capy::task<void>::promise_type::transform_awaiter<boost::capy::task<boost::capy::io_result<unsigned long> > >::await_suspend<boost::capy::task<void>::promise_type>(std::__n4861::coroutine_handle<boost::capy::task<void>::promise_type>):
✓ Branch 5 taken 16 times.
162 return a_.await_suspend(h, p_->executor(), p_->stop_token());
180 }
181 };
182
183 template<class Awaitable>
184 199 auto transform_awaitable(Awaitable&& a)
185 {
186 using A = std::decay_t<Awaitable>;
187 if constexpr (IoAwaitable<A>)
188 {
189 // Zero-overhead path for I/O awaitables
190 return transform_awaiter<Awaitable>{
191 267 std::forward<Awaitable>(a), this};
192 }
193 else
194 {
195 static_assert(sizeof(A) == 0, "requires IoAwaitable");
196 }
197 68 }
198 };
199
200 std::coroutine_handle<promise_type> h_;
201
202 1277 ~task()
203 {
204
25/32
boost::capy::task<bool>::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
boost::capy::task<boost::capy::io_result<unsigned long> >::~task():
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
boost::capy::task<double>::~task():
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5 times.
boost::capy::task<int>::~task():
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 809 times.
boost::capy::task<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::~task():
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 27 times.
boost::capy::task<std::pair<unsigned long, int> >::~task():
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 14 times.
boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
boost::capy::task<std::pair<unsigned long, std::variant<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double> > >::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::~task():
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 33 times.
boost::capy::task<std::pair<unsigned long, std::variant<std::monostate, int> > >::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
boost::capy::task<std::pair<unsigned long, std::variant<std::monostate> > >::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
boost::capy::task<std::stop_token>::~task():
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
boost::capy::task<std::tuple<int, int> >::~task():
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
boost::capy::task<std::tuple<int> >::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
boost::capy::task<unsigned long>::~task():
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
boost::capy::task<void>::~task():
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 127 times.
1277 if(h_)
205 221 h_.destroy();
206 1277 }
207
208 221 bool await_ready() const noexcept
209 {
210 221 return false;
211 }
212
213 220 auto await_resume()
214 {
215
11/18
boost::capy::task<boost::capy::io_result<unsigned long> >::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
boost::capy::task<double>::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
boost::capy::task<int>::await_resume():
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 153 times.
boost::capy::task<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
boost::capy::task<std::pair<unsigned long, int> >::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
boost::capy::task<std::pair<unsigned long, std::variant<int> > >::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
boost::capy::task<std::stop_token>::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
boost::capy::task<std::tuple<int, int> >::await_resume():
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
boost::capy::task<void>::await_resume():
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 16 times.
220 if(h_.promise().ep_)
216 16 std::rethrow_exception(h_.promise().ep_);
217 if constexpr (! std::is_void_v<T>)
218 188 return std::move(*h_.promise().result_);
219 else
220 16 return;
221 }
222
223 // IoAwaitable: receive caller's executor and stop_token for completion dispatch
224 template<typename Ex>
225 220 coro await_suspend(coro cont, Ex const& caller_ex, std::stop_token token)
226 {
227 220 h_.promise().set_continuation(cont, caller_ex);
228 220 h_.promise().set_executor(caller_ex);
229 220 h_.promise().set_stop_token(token);
230 220 return h_;
231 }
232
233 /** Return the coroutine handle.
234
235 @return The coroutine handle.
236 */
237 174 std::coroutine_handle<promise_type> handle() const noexcept
238 {
239 174 return h_;
240 }
241
242 /** Release ownership of the coroutine handle.
243
244 After calling this, the task no longer owns the handle and will
245 not destroy it. The caller is responsible for the handle's lifetime.
246 */
247 171 void release() noexcept
248 {
249 171 h_ = nullptr;
250 171 }
251
252 // Non-copyable
253 task(task const&) = delete;
254 task& operator=(task const&) = delete;
255
256 // Movable
257 885 task(task&& other) noexcept
258 885 : h_(std::exchange(other.h_, nullptr))
259 {
260 885 }
261
262 task& operator=(task&& other) noexcept
263 {
264 if(this != &other)
265 {
266 if(h_)
267 h_.destroy();
268 h_ = std::exchange(other.h_, nullptr);
269 }
270 return *this;
271 }
272
273 private:
274 392 explicit task(std::coroutine_handle<promise_type> h)
275 392 : h_(h)
276 {
277 392 }
278 };
279
280 } // namespace capy
281 } // namespace boost
282
283 #endif
284