]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // |
2 | // impl/use_awaitable.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
1e59de90 | 5 | // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
92f5a8d4 TL |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | // | |
10 | ||
11 | #ifndef BOOST_ASIO_IMPL_USE_AWAITABLE_HPP | |
12 | #define BOOST_ASIO_IMPL_USE_AWAITABLE_HPP | |
13 | ||
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) | |
15 | # pragma once | |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | |
17 | ||
18 | #include <boost/asio/detail/config.hpp> | |
19 | #include <boost/asio/async_result.hpp> | |
1e59de90 | 20 | #include <boost/asio/cancellation_signal.hpp> |
92f5a8d4 TL |
21 | |
22 | #include <boost/asio/detail/push_options.hpp> | |
23 | ||
24 | namespace boost { | |
25 | namespace asio { | |
26 | namespace detail { | |
27 | ||
28 | template <typename Executor, typename T> | |
29 | class awaitable_handler_base | |
30 | : public awaitable_thread<Executor> | |
31 | { | |
32 | public: | |
33 | typedef void result_type; | |
34 | typedef awaitable<T, Executor> awaitable_type; | |
35 | ||
36 | // Construct from the entry point of a new thread of execution. | |
1e59de90 TL |
37 | awaitable_handler_base(awaitable<awaitable_thread_entry_point, Executor> a, |
38 | const Executor& ex, cancellation_slot pcs, cancellation_state cs) | |
39 | : awaitable_thread<Executor>(std::move(a), ex, pcs, cs) | |
92f5a8d4 TL |
40 | { |
41 | } | |
42 | ||
43 | // Transfer ownership from another awaitable_thread. | |
44 | explicit awaitable_handler_base(awaitable_thread<Executor>* h) | |
45 | : awaitable_thread<Executor>(std::move(*h)) | |
46 | { | |
47 | } | |
48 | ||
49 | protected: | |
50 | awaitable_frame<T, Executor>* frame() noexcept | |
51 | { | |
1e59de90 TL |
52 | return static_cast<awaitable_frame<T, Executor>*>( |
53 | this->entry_point()->top_of_stack_); | |
92f5a8d4 TL |
54 | } |
55 | }; | |
56 | ||
57 | template <typename, typename...> | |
58 | class awaitable_handler; | |
59 | ||
60 | template <typename Executor> | |
20effc67 | 61 | class awaitable_handler<Executor> |
92f5a8d4 TL |
62 | : public awaitable_handler_base<Executor, void> |
63 | { | |
64 | public: | |
65 | using awaitable_handler_base<Executor, void>::awaitable_handler_base; | |
66 | ||
67 | void operator()() | |
68 | { | |
69 | this->frame()->attach_thread(this); | |
70 | this->frame()->return_void(); | |
1e59de90 | 71 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
72 | this->frame()->pop_frame(); |
73 | this->pump(); | |
74 | } | |
75 | }; | |
76 | ||
77 | template <typename Executor> | |
78 | class awaitable_handler<Executor, boost::system::error_code> | |
79 | : public awaitable_handler_base<Executor, void> | |
80 | { | |
81 | public: | |
82 | using awaitable_handler_base<Executor, void>::awaitable_handler_base; | |
83 | ||
84 | void operator()(const boost::system::error_code& ec) | |
85 | { | |
86 | this->frame()->attach_thread(this); | |
87 | if (ec) | |
88 | this->frame()->set_error(ec); | |
89 | else | |
90 | this->frame()->return_void(); | |
1e59de90 | 91 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
92 | this->frame()->pop_frame(); |
93 | this->pump(); | |
94 | } | |
95 | }; | |
96 | ||
97 | template <typename Executor> | |
98 | class awaitable_handler<Executor, std::exception_ptr> | |
99 | : public awaitable_handler_base<Executor, void> | |
100 | { | |
101 | public: | |
102 | using awaitable_handler_base<Executor, void>::awaitable_handler_base; | |
103 | ||
104 | void operator()(std::exception_ptr ex) | |
105 | { | |
106 | this->frame()->attach_thread(this); | |
107 | if (ex) | |
108 | this->frame()->set_except(ex); | |
109 | else | |
110 | this->frame()->return_void(); | |
1e59de90 | 111 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
112 | this->frame()->pop_frame(); |
113 | this->pump(); | |
114 | } | |
115 | }; | |
116 | ||
117 | template <typename Executor, typename T> | |
118 | class awaitable_handler<Executor, T> | |
119 | : public awaitable_handler_base<Executor, T> | |
120 | { | |
121 | public: | |
122 | using awaitable_handler_base<Executor, T>::awaitable_handler_base; | |
123 | ||
124 | template <typename Arg> | |
125 | void operator()(Arg&& arg) | |
126 | { | |
127 | this->frame()->attach_thread(this); | |
128 | this->frame()->return_value(std::forward<Arg>(arg)); | |
1e59de90 | 129 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
130 | this->frame()->pop_frame(); |
131 | this->pump(); | |
132 | } | |
133 | }; | |
134 | ||
135 | template <typename Executor, typename T> | |
136 | class awaitable_handler<Executor, boost::system::error_code, T> | |
137 | : public awaitable_handler_base<Executor, T> | |
138 | { | |
139 | public: | |
140 | using awaitable_handler_base<Executor, T>::awaitable_handler_base; | |
141 | ||
142 | template <typename Arg> | |
143 | void operator()(const boost::system::error_code& ec, Arg&& arg) | |
144 | { | |
145 | this->frame()->attach_thread(this); | |
146 | if (ec) | |
147 | this->frame()->set_error(ec); | |
148 | else | |
149 | this->frame()->return_value(std::forward<Arg>(arg)); | |
1e59de90 | 150 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
151 | this->frame()->pop_frame(); |
152 | this->pump(); | |
153 | } | |
154 | }; | |
155 | ||
156 | template <typename Executor, typename T> | |
157 | class awaitable_handler<Executor, std::exception_ptr, T> | |
158 | : public awaitable_handler_base<Executor, T> | |
159 | { | |
160 | public: | |
161 | using awaitable_handler_base<Executor, T>::awaitable_handler_base; | |
162 | ||
163 | template <typename Arg> | |
164 | void operator()(std::exception_ptr ex, Arg&& arg) | |
165 | { | |
166 | this->frame()->attach_thread(this); | |
167 | if (ex) | |
168 | this->frame()->set_except(ex); | |
169 | else | |
170 | this->frame()->return_value(std::forward<Arg>(arg)); | |
1e59de90 | 171 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
172 | this->frame()->pop_frame(); |
173 | this->pump(); | |
174 | } | |
175 | }; | |
176 | ||
177 | template <typename Executor, typename... Ts> | |
178 | class awaitable_handler | |
179 | : public awaitable_handler_base<Executor, std::tuple<Ts...>> | |
180 | { | |
181 | public: | |
182 | using awaitable_handler_base<Executor, | |
183 | std::tuple<Ts...>>::awaitable_handler_base; | |
184 | ||
185 | template <typename... Args> | |
186 | void operator()(Args&&... args) | |
187 | { | |
188 | this->frame()->attach_thread(this); | |
189 | this->frame()->return_values(std::forward<Args>(args)...); | |
1e59de90 | 190 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
191 | this->frame()->pop_frame(); |
192 | this->pump(); | |
193 | } | |
194 | }; | |
195 | ||
196 | template <typename Executor, typename... Ts> | |
197 | class awaitable_handler<Executor, boost::system::error_code, Ts...> | |
198 | : public awaitable_handler_base<Executor, std::tuple<Ts...>> | |
199 | { | |
200 | public: | |
201 | using awaitable_handler_base<Executor, | |
202 | std::tuple<Ts...>>::awaitable_handler_base; | |
203 | ||
204 | template <typename... Args> | |
205 | void operator()(const boost::system::error_code& ec, Args&&... args) | |
206 | { | |
207 | this->frame()->attach_thread(this); | |
208 | if (ec) | |
209 | this->frame()->set_error(ec); | |
210 | else | |
211 | this->frame()->return_values(std::forward<Args>(args)...); | |
1e59de90 | 212 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
213 | this->frame()->pop_frame(); |
214 | this->pump(); | |
215 | } | |
216 | }; | |
217 | ||
218 | template <typename Executor, typename... Ts> | |
219 | class awaitable_handler<Executor, std::exception_ptr, Ts...> | |
220 | : public awaitable_handler_base<Executor, std::tuple<Ts...>> | |
221 | { | |
222 | public: | |
223 | using awaitable_handler_base<Executor, | |
224 | std::tuple<Ts...>>::awaitable_handler_base; | |
225 | ||
226 | template <typename... Args> | |
227 | void operator()(std::exception_ptr ex, Args&&... args) | |
228 | { | |
229 | this->frame()->attach_thread(this); | |
230 | if (ex) | |
231 | this->frame()->set_except(ex); | |
232 | else | |
233 | this->frame()->return_values(std::forward<Args>(args)...); | |
1e59de90 | 234 | this->frame()->clear_cancellation_slot(); |
92f5a8d4 TL |
235 | this->frame()->pop_frame(); |
236 | this->pump(); | |
237 | } | |
238 | }; | |
239 | ||
240 | } // namespace detail | |
241 | ||
242 | #if !defined(GENERATING_DOCUMENTATION) | |
243 | ||
20effc67 TL |
244 | #if defined(_MSC_VER) |
245 | template <typename T> | |
246 | T dummy_return() | |
247 | { | |
248 | return std::move(*static_cast<T*>(nullptr)); | |
249 | } | |
250 | ||
251 | template <> | |
1e59de90 | 252 | inline void dummy_return() |
20effc67 TL |
253 | { |
254 | } | |
255 | #endif // defined(_MSC_VER) | |
256 | ||
92f5a8d4 TL |
257 | template <typename Executor, typename R, typename... Args> |
258 | class async_result<use_awaitable_t<Executor>, R(Args...)> | |
259 | { | |
260 | public: | |
261 | typedef typename detail::awaitable_handler< | |
262 | Executor, typename decay<Args>::type...> handler_type; | |
263 | typedef typename handler_type::awaitable_type return_type; | |
264 | ||
92f5a8d4 | 265 | template <typename Initiation, typename... InitArgs> |
1e59de90 TL |
266 | #if defined(__APPLE_CC__) && (__clang_major__ == 13) |
267 | __attribute__((noinline)) | |
268 | #endif // defined(__APPLE_CC__) && (__clang_major__ == 13) | |
269 | static handler_type* do_init( | |
270 | detail::awaitable_frame_base<Executor>* frame, Initiation& initiation, | |
271 | use_awaitable_t<Executor> u, InitArgs&... args) | |
92f5a8d4 | 272 | { |
20effc67 | 273 | (void)u; |
1e59de90 TL |
274 | BOOST_ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_)); |
275 | handler_type handler(frame->detach_thread()); | |
276 | std::move(initiation)(std::move(handler), std::move(args)...); | |
277 | return nullptr; | |
278 | } | |
20effc67 | 279 | |
1e59de90 TL |
280 | template <typename Initiation, typename... InitArgs> |
281 | static return_type initiate(Initiation initiation, | |
282 | use_awaitable_t<Executor> u, InitArgs... args) | |
283 | { | |
284 | co_await [&] (auto* frame) | |
92f5a8d4 | 285 | { |
1e59de90 | 286 | return do_init(frame, initiation, u, args...); |
92f5a8d4 TL |
287 | }; |
288 | ||
289 | for (;;) {} // Never reached. | |
290 | #if defined(_MSC_VER) | |
291 | co_return dummy_return<typename return_type::value_type>(); | |
292 | #endif // defined(_MSC_VER) | |
293 | } | |
294 | }; | |
295 | ||
296 | #endif // !defined(GENERATING_DOCUMENTATION) | |
297 | ||
298 | } // namespace asio | |
299 | } // namespace boost | |
300 | ||
301 | #include <boost/asio/detail/pop_options.hpp> | |
302 | ||
303 | #endif // BOOST_ASIO_IMPL_USE_AWAITABLE_HPP |