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