]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // impl/use_future.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
f67539c2 | 5 | // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
b32b8144 FG |
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_FUTURE_HPP | |
12 | #define BOOST_ASIO_IMPL_USE_FUTURE_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> | |
b32b8144 FG |
19 | #include <tuple> |
20 | #include <boost/asio/async_result.hpp> | |
21 | #include <boost/asio/detail/memory.hpp> | |
20effc67 | 22 | #include <boost/asio/dispatch.hpp> |
b32b8144 | 23 | #include <boost/system/error_code.hpp> |
20effc67 | 24 | #include <boost/asio/execution.hpp> |
b32b8144 FG |
25 | #include <boost/asio/packaged_task.hpp> |
26 | #include <boost/system/system_error.hpp> | |
27 | #include <boost/asio/system_executor.hpp> | |
28 | ||
29 | #include <boost/asio/detail/push_options.hpp> | |
30 | ||
31 | namespace boost { | |
32 | namespace asio { | |
33 | namespace detail { | |
34 | ||
35 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
36 | ||
37 | template <typename T, typename F, typename... Args> | |
38 | inline void promise_invoke_and_set(std::promise<T>& p, | |
39 | F& f, BOOST_ASIO_MOVE_ARG(Args)... args) | |
40 | { | |
41 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
42 | try | |
43 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
44 | { | |
45 | p.set_value(f(BOOST_ASIO_MOVE_CAST(Args)(args)...)); | |
46 | } | |
47 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
48 | catch (...) | |
49 | { | |
50 | p.set_exception(std::current_exception()); | |
51 | } | |
52 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
53 | } | |
54 | ||
55 | template <typename F, typename... Args> | |
56 | inline void promise_invoke_and_set(std::promise<void>& p, | |
57 | F& f, BOOST_ASIO_MOVE_ARG(Args)... args) | |
58 | { | |
59 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
60 | try | |
61 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
62 | { | |
63 | f(BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
64 | p.set_value(); | |
65 | } | |
66 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
67 | catch (...) | |
68 | { | |
69 | p.set_exception(std::current_exception()); | |
70 | } | |
71 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
72 | } | |
73 | ||
74 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
75 | ||
76 | template <typename T, typename F> | |
77 | inline void promise_invoke_and_set(std::promise<T>& p, F& f) | |
78 | { | |
79 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
80 | try | |
81 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
82 | { | |
83 | p.set_value(f()); | |
84 | } | |
85 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
86 | catch (...) | |
87 | { | |
88 | p.set_exception(std::current_exception()); | |
89 | } | |
90 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
91 | } | |
92 | ||
93 | template <typename F, typename Args> | |
94 | inline void promise_invoke_and_set(std::promise<void>& p, F& f) | |
95 | { | |
96 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
97 | try | |
98 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
99 | { | |
100 | f(); | |
101 | p.set_value(); | |
102 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
103 | } | |
104 | catch (...) | |
105 | { | |
106 | p.set_exception(std::current_exception()); | |
107 | } | |
108 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
109 | } | |
110 | ||
111 | #if defined(BOOST_ASIO_NO_EXCEPTIONS) | |
112 | ||
113 | #define BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ | |
114 | template <typename T, typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
115 | inline void promise_invoke_and_set(std::promise<T>& p, \ | |
116 | F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
117 | { \ | |
118 | p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ | |
119 | } \ | |
120 | \ | |
121 | template <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
122 | inline void promise_invoke_and_set(std::promise<void>& p, \ | |
123 | F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
124 | { \ | |
125 | f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ | |
126 | p.set_value(); \ | |
127 | } \ | |
128 | /**/ | |
129 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF) | |
130 | #undef BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF | |
131 | ||
132 | #else // defined(BOOST_ASIO_NO_EXCEPTIONS) | |
133 | ||
134 | #define BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ | |
135 | template <typename T, typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
136 | inline void promise_invoke_and_set(std::promise<T>& p, \ | |
137 | F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
138 | { \ | |
139 | try \ | |
140 | { \ | |
141 | p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ | |
142 | } \ | |
143 | catch (...) \ | |
144 | { \ | |
145 | p.set_exception(std::current_exception()); \ | |
146 | } \ | |
147 | } \ | |
148 | \ | |
149 | template <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
150 | inline void promise_invoke_and_set(std::promise<void>& p, \ | |
151 | F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
152 | { \ | |
153 | try \ | |
154 | { \ | |
155 | f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ | |
156 | p.set_value(); \ | |
157 | } \ | |
158 | catch (...) \ | |
159 | { \ | |
160 | p.set_exception(std::current_exception()); \ | |
161 | } \ | |
162 | } \ | |
163 | /**/ | |
164 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF) | |
165 | #undef BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF | |
166 | ||
167 | #endif // defined(BOOST_ASIO_NO_EXCEPTIONS) | |
168 | ||
169 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
170 | ||
171 | // A function object adapter to invoke a nullary function object and capture | |
172 | // any exception thrown into a promise. | |
173 | template <typename T, typename F> | |
174 | class promise_invoker | |
175 | { | |
176 | public: | |
177 | promise_invoker(const shared_ptr<std::promise<T> >& p, | |
178 | BOOST_ASIO_MOVE_ARG(F) f) | |
179 | : p_(p), f_(BOOST_ASIO_MOVE_CAST(F)(f)) | |
180 | { | |
181 | } | |
182 | ||
183 | void operator()() | |
184 | { | |
185 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
186 | try | |
187 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
188 | { | |
189 | f_(); | |
190 | } | |
191 | #if !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
192 | catch (...) | |
193 | { | |
194 | p_->set_exception(std::current_exception()); | |
195 | } | |
196 | #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
197 | } | |
198 | ||
199 | private: | |
200 | shared_ptr<std::promise<T> > p_; | |
201 | typename decay<F>::type f_; | |
202 | }; | |
203 | ||
204 | // An executor that adapts the system_executor to capture any exeption thrown | |
205 | // by a submitted function object and save it into a promise. | |
20effc67 | 206 | template <typename T, typename Blocking = execution::blocking_t::possibly_t> |
b32b8144 FG |
207 | class promise_executor |
208 | { | |
209 | public: | |
210 | explicit promise_executor(const shared_ptr<std::promise<T> >& p) | |
211 | : p_(p) | |
212 | { | |
213 | } | |
214 | ||
20effc67 TL |
215 | static BOOST_ASIO_CONSTEXPR Blocking query(execution::blocking_t) |
216 | { | |
217 | return Blocking(); | |
218 | } | |
219 | ||
220 | promise_executor<T, execution::blocking_t::possibly_t> | |
221 | require(execution::blocking_t::possibly_t) const | |
222 | { | |
223 | return promise_executor<T, execution::blocking_t::possibly_t>(p_); | |
224 | } | |
225 | ||
226 | promise_executor<T, execution::blocking_t::never_t> | |
227 | require(execution::blocking_t::never_t) const | |
228 | { | |
229 | return promise_executor<T, execution::blocking_t::never_t>(p_); | |
230 | } | |
231 | ||
232 | template <typename F> | |
233 | void execute(BOOST_ASIO_MOVE_ARG(F) f) const | |
234 | { | |
235 | execution::execute( | |
236 | boost::asio::require(system_executor(), Blocking()), | |
237 | promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f))); | |
238 | } | |
239 | ||
240 | #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) | |
b32b8144 FG |
241 | execution_context& context() const BOOST_ASIO_NOEXCEPT |
242 | { | |
243 | return system_executor().context(); | |
244 | } | |
245 | ||
246 | void on_work_started() const BOOST_ASIO_NOEXCEPT {} | |
247 | void on_work_finished() const BOOST_ASIO_NOEXCEPT {} | |
248 | ||
249 | template <typename F, typename A> | |
250 | void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A&) const | |
251 | { | |
252 | promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f))(); | |
253 | } | |
254 | ||
255 | template <typename F, typename A> | |
256 | void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const | |
257 | { | |
258 | system_executor().post( | |
259 | promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); | |
260 | } | |
261 | ||
262 | template <typename F, typename A> | |
263 | void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const | |
264 | { | |
265 | system_executor().defer( | |
266 | promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); | |
267 | } | |
20effc67 | 268 | #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
b32b8144 FG |
269 | |
270 | friend bool operator==(const promise_executor& a, | |
271 | const promise_executor& b) BOOST_ASIO_NOEXCEPT | |
272 | { | |
273 | return a.p_ == b.p_; | |
274 | } | |
275 | ||
276 | friend bool operator!=(const promise_executor& a, | |
277 | const promise_executor& b) BOOST_ASIO_NOEXCEPT | |
278 | { | |
279 | return a.p_ != b.p_; | |
280 | } | |
281 | ||
282 | private: | |
283 | shared_ptr<std::promise<T> > p_; | |
284 | }; | |
285 | ||
286 | // The base class for all completion handlers that create promises. | |
287 | template <typename T> | |
288 | class promise_creator | |
289 | { | |
290 | public: | |
291 | typedef promise_executor<T> executor_type; | |
292 | ||
293 | executor_type get_executor() const BOOST_ASIO_NOEXCEPT | |
294 | { | |
295 | return executor_type(p_); | |
296 | } | |
297 | ||
298 | typedef std::future<T> future_type; | |
299 | ||
300 | future_type get_future() | |
301 | { | |
302 | return p_->get_future(); | |
303 | } | |
304 | ||
305 | protected: | |
306 | template <typename Allocator> | |
307 | void create_promise(const Allocator& a) | |
308 | { | |
309 | BOOST_ASIO_REBIND_ALLOC(Allocator, char) b(a); | |
310 | p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b); | |
311 | } | |
312 | ||
313 | shared_ptr<std::promise<T> > p_; | |
314 | }; | |
315 | ||
316 | // For completion signature void(). | |
317 | class promise_handler_0 | |
318 | : public promise_creator<void> | |
319 | { | |
320 | public: | |
321 | void operator()() | |
322 | { | |
323 | this->p_->set_value(); | |
324 | } | |
325 | }; | |
326 | ||
327 | // For completion signature void(error_code). | |
328 | class promise_handler_ec_0 | |
329 | : public promise_creator<void> | |
330 | { | |
331 | public: | |
332 | void operator()(const boost::system::error_code& ec) | |
333 | { | |
334 | if (ec) | |
335 | { | |
336 | this->p_->set_exception( | |
337 | std::make_exception_ptr( | |
338 | boost::system::system_error(ec))); | |
339 | } | |
340 | else | |
341 | { | |
342 | this->p_->set_value(); | |
343 | } | |
344 | } | |
345 | }; | |
346 | ||
347 | // For completion signature void(exception_ptr). | |
348 | class promise_handler_ex_0 | |
349 | : public promise_creator<void> | |
350 | { | |
351 | public: | |
352 | void operator()(const std::exception_ptr& ex) | |
353 | { | |
354 | if (ex) | |
355 | { | |
356 | this->p_->set_exception(ex); | |
357 | } | |
358 | else | |
359 | { | |
360 | this->p_->set_value(); | |
361 | } | |
362 | } | |
363 | }; | |
364 | ||
365 | // For completion signature void(T). | |
366 | template <typename T> | |
367 | class promise_handler_1 | |
368 | : public promise_creator<T> | |
369 | { | |
370 | public: | |
371 | template <typename Arg> | |
372 | void operator()(BOOST_ASIO_MOVE_ARG(Arg) arg) | |
373 | { | |
374 | this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); | |
375 | } | |
376 | }; | |
377 | ||
378 | // For completion signature void(error_code, T). | |
379 | template <typename T> | |
380 | class promise_handler_ec_1 | |
381 | : public promise_creator<T> | |
382 | { | |
383 | public: | |
384 | template <typename Arg> | |
385 | void operator()(const boost::system::error_code& ec, | |
386 | BOOST_ASIO_MOVE_ARG(Arg) arg) | |
387 | { | |
388 | if (ec) | |
389 | { | |
390 | this->p_->set_exception( | |
391 | std::make_exception_ptr( | |
392 | boost::system::system_error(ec))); | |
393 | } | |
394 | else | |
395 | this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); | |
396 | } | |
397 | }; | |
398 | ||
399 | // For completion signature void(exception_ptr, T). | |
400 | template <typename T> | |
401 | class promise_handler_ex_1 | |
402 | : public promise_creator<T> | |
403 | { | |
404 | public: | |
405 | template <typename Arg> | |
406 | void operator()(const std::exception_ptr& ex, | |
407 | BOOST_ASIO_MOVE_ARG(Arg) arg) | |
408 | { | |
409 | if (ex) | |
410 | this->p_->set_exception(ex); | |
411 | else | |
412 | this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); | |
413 | } | |
414 | }; | |
415 | ||
416 | // For completion signature void(T1, ..., Tn); | |
417 | template <typename T> | |
418 | class promise_handler_n | |
419 | : public promise_creator<T> | |
420 | { | |
421 | public: | |
422 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
423 | ||
424 | template <typename... Args> | |
425 | void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) | |
426 | { | |
427 | this->p_->set_value( | |
428 | std::forward_as_tuple( | |
429 | BOOST_ASIO_MOVE_CAST(Args)(args)...)); | |
430 | } | |
431 | ||
432 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
433 | ||
434 | #define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ | |
435 | template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
436 | void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
437 | {\ | |
438 | this->p_->set_value( \ | |
439 | std::forward_as_tuple( \ | |
440 | BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ | |
441 | } \ | |
442 | /**/ | |
443 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) | |
444 | #undef BOOST_ASIO_PRIVATE_CALL_OP_DEF | |
445 | ||
446 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
447 | }; | |
448 | ||
449 | // For completion signature void(error_code, T1, ..., Tn); | |
450 | template <typename T> | |
451 | class promise_handler_ec_n | |
452 | : public promise_creator<T> | |
453 | { | |
454 | public: | |
455 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
456 | ||
457 | template <typename... Args> | |
458 | void operator()(const boost::system::error_code& ec, | |
459 | BOOST_ASIO_MOVE_ARG(Args)... args) | |
460 | { | |
461 | if (ec) | |
462 | { | |
463 | this->p_->set_exception( | |
464 | std::make_exception_ptr( | |
465 | boost::system::system_error(ec))); | |
466 | } | |
467 | else | |
468 | { | |
469 | this->p_->set_value( | |
470 | std::forward_as_tuple( | |
471 | BOOST_ASIO_MOVE_CAST(Args)(args)...)); | |
472 | } | |
473 | } | |
474 | ||
475 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
476 | ||
477 | #define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ | |
478 | template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
479 | void operator()(const boost::system::error_code& ec, \ | |
480 | BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
481 | {\ | |
482 | if (ec) \ | |
483 | { \ | |
484 | this->p_->set_exception( \ | |
485 | std::make_exception_ptr( \ | |
486 | boost::system::system_error(ec))); \ | |
487 | } \ | |
488 | else \ | |
489 | { \ | |
490 | this->p_->set_value( \ | |
491 | std::forward_as_tuple( \ | |
492 | BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ | |
493 | } \ | |
494 | } \ | |
495 | /**/ | |
496 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) | |
497 | #undef BOOST_ASIO_PRIVATE_CALL_OP_DEF | |
498 | ||
499 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
500 | }; | |
501 | ||
502 | // For completion signature void(exception_ptr, T1, ..., Tn); | |
503 | template <typename T> | |
504 | class promise_handler_ex_n | |
505 | : public promise_creator<T> | |
506 | { | |
507 | public: | |
508 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
509 | ||
510 | template <typename... Args> | |
511 | void operator()(const std::exception_ptr& ex, | |
512 | BOOST_ASIO_MOVE_ARG(Args)... args) | |
513 | { | |
514 | if (ex) | |
515 | this->p_->set_exception(ex); | |
516 | else | |
517 | { | |
518 | this->p_->set_value( | |
519 | std::forward_as_tuple( | |
520 | BOOST_ASIO_MOVE_CAST(Args)(args)...)); | |
521 | } | |
522 | } | |
523 | ||
524 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
525 | ||
526 | #define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ | |
527 | template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
528 | void operator()(const std::exception_ptr& ex, \ | |
529 | BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
530 | {\ | |
531 | if (ex) \ | |
532 | this->p_->set_exception(ex); \ | |
533 | else \ | |
534 | { \ | |
535 | this->p_->set_value( \ | |
536 | std::forward_as_tuple( \ | |
537 | BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ | |
538 | } \ | |
539 | } \ | |
540 | /**/ | |
541 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) | |
542 | #undef BOOST_ASIO_PRIVATE_CALL_OP_DEF | |
543 | ||
544 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
545 | }; | |
546 | ||
547 | // Helper template to choose the appropriate concrete promise handler | |
548 | // implementation based on the supplied completion signature. | |
549 | template <typename> class promise_handler_selector; | |
550 | ||
551 | template <> | |
552 | class promise_handler_selector<void()> | |
553 | : public promise_handler_0 {}; | |
554 | ||
555 | template <> | |
556 | class promise_handler_selector<void(boost::system::error_code)> | |
557 | : public promise_handler_ec_0 {}; | |
558 | ||
559 | template <> | |
560 | class promise_handler_selector<void(std::exception_ptr)> | |
561 | : public promise_handler_ex_0 {}; | |
562 | ||
563 | template <typename Arg> | |
564 | class promise_handler_selector<void(Arg)> | |
565 | : public promise_handler_1<Arg> {}; | |
566 | ||
567 | template <typename Arg> | |
568 | class promise_handler_selector<void(boost::system::error_code, Arg)> | |
569 | : public promise_handler_ec_1<Arg> {}; | |
570 | ||
571 | template <typename Arg> | |
572 | class promise_handler_selector<void(std::exception_ptr, Arg)> | |
573 | : public promise_handler_ex_1<Arg> {}; | |
574 | ||
575 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
576 | ||
577 | template <typename... Arg> | |
578 | class promise_handler_selector<void(Arg...)> | |
579 | : public promise_handler_n<std::tuple<Arg...> > {}; | |
580 | ||
581 | template <typename... Arg> | |
582 | class promise_handler_selector<void(boost::system::error_code, Arg...)> | |
583 | : public promise_handler_ec_n<std::tuple<Arg...> > {}; | |
584 | ||
585 | template <typename... Arg> | |
586 | class promise_handler_selector<void(std::exception_ptr, Arg...)> | |
587 | : public promise_handler_ex_n<std::tuple<Arg...> > {}; | |
588 | ||
589 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
590 | ||
591 | #define BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \ | |
592 | template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
593 | class promise_handler_selector< \ | |
594 | void(Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ | |
595 | : public promise_handler_n< \ | |
596 | std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ | |
597 | \ | |
598 | template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
599 | class promise_handler_selector< \ | |
600 | void(boost::system::error_code, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ | |
601 | : public promise_handler_ec_n< \ | |
602 | std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ | |
603 | \ | |
604 | template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
605 | class promise_handler_selector< \ | |
606 | void(std::exception_ptr, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ | |
607 | : public promise_handler_ex_n< \ | |
608 | std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ | |
609 | /**/ | |
20effc67 | 610 | BOOST_ASIO_VARIADIC_GENERATE_5(BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF) |
b32b8144 FG |
611 | #undef BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF |
612 | ||
613 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
614 | ||
615 | // Completion handlers produced from the use_future completion token, when not | |
616 | // using use_future::operator(). | |
617 | template <typename Signature, typename Allocator> | |
618 | class promise_handler | |
619 | : public promise_handler_selector<Signature> | |
620 | { | |
621 | public: | |
622 | typedef Allocator allocator_type; | |
623 | typedef void result_type; | |
624 | ||
625 | promise_handler(use_future_t<Allocator> u) | |
626 | : allocator_(u.get_allocator()) | |
627 | { | |
628 | this->create_promise(allocator_); | |
629 | } | |
630 | ||
631 | allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT | |
632 | { | |
633 | return allocator_; | |
634 | } | |
635 | ||
636 | private: | |
637 | Allocator allocator_; | |
638 | }; | |
639 | ||
20effc67 TL |
640 | template <typename Function> |
641 | struct promise_function_wrapper | |
642 | { | |
643 | explicit promise_function_wrapper(Function& f) | |
644 | : function_(BOOST_ASIO_MOVE_CAST(Function)(f)) | |
645 | { | |
646 | } | |
647 | ||
648 | explicit promise_function_wrapper(const Function& f) | |
649 | : function_(f) | |
650 | { | |
651 | } | |
652 | ||
653 | void operator()() | |
654 | { | |
655 | function_(); | |
656 | } | |
657 | ||
658 | Function function_; | |
659 | }; | |
660 | ||
661 | #if !defined(BOOST_ASIO_NO_DEPRECATED) | |
662 | ||
b32b8144 FG |
663 | template <typename Function, typename Signature, typename Allocator> |
664 | inline void asio_handler_invoke(Function& f, | |
665 | promise_handler<Signature, Allocator>* h) | |
666 | { | |
667 | typename promise_handler<Signature, Allocator>::executor_type | |
668 | ex(h->get_executor()); | |
20effc67 | 669 | boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); |
b32b8144 FG |
670 | } |
671 | ||
672 | template <typename Function, typename Signature, typename Allocator> | |
673 | inline void asio_handler_invoke(const Function& f, | |
674 | promise_handler<Signature, Allocator>* h) | |
675 | { | |
676 | typename promise_handler<Signature, Allocator>::executor_type | |
677 | ex(h->get_executor()); | |
20effc67 | 678 | boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); |
b32b8144 FG |
679 | } |
680 | ||
20effc67 TL |
681 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
682 | ||
b32b8144 FG |
683 | // Helper base class for async_result specialisation. |
684 | template <typename Signature, typename Allocator> | |
685 | class promise_async_result | |
686 | { | |
687 | public: | |
688 | typedef promise_handler<Signature, Allocator> completion_handler_type; | |
689 | typedef typename completion_handler_type::future_type return_type; | |
690 | ||
691 | explicit promise_async_result(completion_handler_type& h) | |
692 | : future_(h.get_future()) | |
693 | { | |
694 | } | |
695 | ||
696 | return_type get() | |
697 | { | |
698 | return BOOST_ASIO_MOVE_CAST(return_type)(future_); | |
699 | } | |
700 | ||
701 | private: | |
702 | return_type future_; | |
703 | }; | |
704 | ||
705 | // Return value from use_future::operator(). | |
706 | template <typename Function, typename Allocator> | |
707 | class packaged_token | |
708 | { | |
709 | public: | |
710 | packaged_token(Function f, const Allocator& a) | |
711 | : function_(BOOST_ASIO_MOVE_CAST(Function)(f)), | |
712 | allocator_(a) | |
713 | { | |
714 | } | |
715 | ||
716 | //private: | |
717 | Function function_; | |
718 | Allocator allocator_; | |
719 | }; | |
720 | ||
721 | // Completion handlers produced from the use_future completion token, when | |
722 | // using use_future::operator(). | |
723 | template <typename Function, typename Allocator, typename Result> | |
724 | class packaged_handler | |
725 | : public promise_creator<Result> | |
726 | { | |
727 | public: | |
728 | typedef Allocator allocator_type; | |
729 | typedef void result_type; | |
730 | ||
731 | packaged_handler(packaged_token<Function, Allocator> t) | |
732 | : function_(BOOST_ASIO_MOVE_CAST(Function)(t.function_)), | |
733 | allocator_(t.allocator_) | |
734 | { | |
735 | this->create_promise(allocator_); | |
736 | } | |
737 | ||
738 | allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT | |
739 | { | |
740 | return allocator_; | |
741 | } | |
742 | ||
743 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
744 | ||
745 | template <typename... Args> | |
746 | void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) | |
747 | { | |
748 | (promise_invoke_and_set)(*this->p_, | |
749 | function_, BOOST_ASIO_MOVE_CAST(Args)(args)...); | |
750 | } | |
751 | ||
752 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
753 | ||
754 | void operator()() | |
755 | { | |
756 | (promise_invoke_and_set)(*this->p_, function_); | |
757 | } | |
758 | ||
759 | #define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ | |
760 | template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
761 | void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ | |
762 | {\ | |
763 | (promise_invoke_and_set)(*this->p_, \ | |
764 | function_, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ | |
765 | } \ | |
766 | /**/ | |
767 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) | |
768 | #undef BOOST_ASIO_PRIVATE_CALL_OP_DEF | |
769 | ||
770 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
771 | ||
772 | private: | |
773 | Function function_; | |
774 | Allocator allocator_; | |
775 | }; | |
776 | ||
20effc67 TL |
777 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
778 | ||
b32b8144 FG |
779 | template <typename Function, |
780 | typename Function1, typename Allocator, typename Result> | |
781 | inline void asio_handler_invoke(Function& f, | |
782 | packaged_handler<Function1, Allocator, Result>* h) | |
783 | { | |
784 | typename packaged_handler<Function1, Allocator, Result>::executor_type | |
785 | ex(h->get_executor()); | |
20effc67 | 786 | boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); |
b32b8144 FG |
787 | } |
788 | ||
789 | template <typename Function, | |
790 | typename Function1, typename Allocator, typename Result> | |
791 | inline void asio_handler_invoke(const Function& f, | |
792 | packaged_handler<Function1, Allocator, Result>* h) | |
793 | { | |
794 | typename packaged_handler<Function1, Allocator, Result>::executor_type | |
795 | ex(h->get_executor()); | |
20effc67 | 796 | boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); |
b32b8144 FG |
797 | } |
798 | ||
20effc67 TL |
799 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
800 | ||
b32b8144 FG |
801 | // Helper base class for async_result specialisation. |
802 | template <typename Function, typename Allocator, typename Result> | |
803 | class packaged_async_result | |
804 | { | |
805 | public: | |
806 | typedef packaged_handler<Function, Allocator, Result> completion_handler_type; | |
807 | typedef typename completion_handler_type::future_type return_type; | |
808 | ||
809 | explicit packaged_async_result(completion_handler_type& h) | |
810 | : future_(h.get_future()) | |
811 | { | |
812 | } | |
813 | ||
814 | return_type get() | |
815 | { | |
816 | return BOOST_ASIO_MOVE_CAST(return_type)(future_); | |
817 | } | |
818 | ||
819 | private: | |
820 | return_type future_; | |
821 | }; | |
822 | ||
823 | } // namespace detail | |
824 | ||
825 | template <typename Allocator> template <typename Function> | |
826 | inline detail::packaged_token<typename decay<Function>::type, Allocator> | |
827 | use_future_t<Allocator>::operator()(BOOST_ASIO_MOVE_ARG(Function) f) const | |
828 | { | |
829 | return detail::packaged_token<typename decay<Function>::type, Allocator>( | |
830 | BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); | |
831 | } | |
832 | ||
833 | #if !defined(GENERATING_DOCUMENTATION) | |
834 | ||
835 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
836 | ||
837 | template <typename Allocator, typename Result, typename... Args> | |
838 | class async_result<use_future_t<Allocator>, Result(Args...)> | |
839 | : public detail::promise_async_result< | |
840 | void(typename decay<Args>::type...), Allocator> | |
841 | { | |
842 | public: | |
843 | explicit async_result( | |
844 | typename detail::promise_async_result<void(typename decay<Args>::type...), | |
845 | Allocator>::completion_handler_type& h) | |
846 | : detail::promise_async_result< | |
847 | void(typename decay<Args>::type...), Allocator>(h) | |
848 | { | |
849 | } | |
850 | }; | |
851 | ||
852 | template <typename Function, typename Allocator, | |
853 | typename Result, typename... Args> | |
854 | class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)> | |
855 | : public detail::packaged_async_result<Function, Allocator, | |
856 | typename result_of<Function(Args...)>::type> | |
857 | { | |
858 | public: | |
859 | explicit async_result( | |
860 | typename detail::packaged_async_result<Function, Allocator, | |
861 | typename result_of<Function(Args...)>::type>::completion_handler_type& h) | |
862 | : detail::packaged_async_result<Function, Allocator, | |
863 | typename result_of<Function(Args...)>::type>(h) | |
864 | { | |
865 | } | |
866 | }; | |
867 | ||
868 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
869 | ||
870 | template <typename Allocator, typename Result> | |
871 | class async_result<use_future_t<Allocator>, Result()> | |
872 | : public detail::promise_async_result<void(), Allocator> | |
873 | { | |
874 | public: | |
875 | explicit async_result( | |
876 | typename detail::promise_async_result< | |
877 | void(), Allocator>::completion_handler_type& h) | |
878 | : detail::promise_async_result<void(), Allocator>(h) | |
879 | { | |
880 | } | |
881 | }; | |
882 | ||
883 | template <typename Function, typename Allocator, typename Result> | |
884 | class async_result<detail::packaged_token<Function, Allocator>, Result()> | |
885 | : public detail::packaged_async_result<Function, Allocator, | |
886 | typename result_of<Function()>::type> | |
887 | { | |
888 | public: | |
889 | explicit async_result( | |
890 | typename detail::packaged_async_result<Function, Allocator, | |
891 | typename result_of<Function()>::type>::completion_handler_type& h) | |
892 | : detail::packaged_async_result<Function, Allocator, | |
893 | typename result_of<Function()>::type>(h) | |
894 | { | |
895 | } | |
896 | }; | |
897 | ||
898 | #define BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ | |
899 | template <typename Allocator, \ | |
900 | typename Result, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
901 | class async_result<use_future_t<Allocator>, \ | |
902 | Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ | |
903 | : public detail::promise_async_result< \ | |
904 | void(BOOST_ASIO_VARIADIC_DECAY(n)), Allocator> \ | |
905 | { \ | |
906 | public: \ | |
907 | explicit async_result( \ | |
908 | typename detail::promise_async_result< \ | |
909 | void(BOOST_ASIO_VARIADIC_DECAY(n)), \ | |
910 | Allocator>::completion_handler_type& h) \ | |
911 | : detail::promise_async_result< \ | |
912 | void(BOOST_ASIO_VARIADIC_DECAY(n)), Allocator>(h) \ | |
913 | { \ | |
914 | } \ | |
915 | }; \ | |
916 | \ | |
917 | template <typename Function, typename Allocator, \ | |
918 | typename Result, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ | |
919 | class async_result<detail::packaged_token<Function, Allocator>, \ | |
920 | Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ | |
921 | : public detail::packaged_async_result<Function, Allocator, \ | |
922 | typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type> \ | |
923 | { \ | |
924 | public: \ | |
925 | explicit async_result( \ | |
926 | typename detail::packaged_async_result<Function, Allocator, \ | |
927 | typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type \ | |
928 | >::completion_handler_type& h) \ | |
929 | : detail::packaged_async_result<Function, Allocator, \ | |
930 | typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type>(h) \ | |
931 | { \ | |
932 | } \ | |
933 | }; \ | |
934 | /**/ | |
935 | BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF) | |
936 | #undef BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF | |
937 | ||
938 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
939 | ||
20effc67 TL |
940 | namespace traits { |
941 | ||
942 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) | |
943 | ||
944 | template <typename T, typename Blocking> | |
945 | struct equality_comparable< | |
946 | boost::asio::detail::promise_executor<T, Blocking> > | |
947 | { | |
948 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
949 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); | |
950 | }; | |
951 | ||
952 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) | |
953 | ||
954 | #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) | |
955 | ||
956 | template <typename T, typename Blocking, typename Function> | |
957 | struct execute_member< | |
958 | boost::asio::detail::promise_executor<T, Blocking>, Function> | |
959 | { | |
960 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
961 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); | |
962 | typedef void result_type; | |
963 | }; | |
964 | ||
965 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) | |
966 | ||
967 | #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT) | |
968 | ||
969 | template <typename T, typename Blocking, typename Property> | |
970 | struct query_static_constexpr_member< | |
971 | boost::asio::detail::promise_executor<T, Blocking>, | |
972 | Property, | |
973 | typename boost::asio::enable_if< | |
974 | boost::asio::is_convertible< | |
975 | Property, | |
976 | boost::asio::execution::blocking_t | |
977 | >::value | |
978 | >::type | |
979 | > | |
980 | { | |
981 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
982 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); | |
983 | typedef Blocking result_type; | |
984 | ||
985 | static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT | |
986 | { | |
987 | return Blocking(); | |
988 | } | |
989 | }; | |
990 | ||
991 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT) | |
992 | ||
993 | #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) | |
994 | ||
995 | template <typename T, typename Blocking> | |
996 | struct require_member< | |
997 | boost::asio::detail::promise_executor<T, Blocking>, | |
998 | execution::blocking_t::possibly_t | |
999 | > | |
1000 | { | |
1001 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
1002 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); | |
1003 | typedef boost::asio::detail::promise_executor<T, | |
1004 | execution::blocking_t::possibly_t> result_type; | |
1005 | }; | |
1006 | ||
1007 | template <typename T, typename Blocking> | |
1008 | struct require_member< | |
1009 | boost::asio::detail::promise_executor<T, Blocking>, | |
1010 | execution::blocking_t::never_t | |
1011 | > | |
1012 | { | |
1013 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); | |
1014 | BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); | |
1015 | typedef boost::asio::detail::promise_executor<T, | |
1016 | execution::blocking_t::never_t> result_type; | |
1017 | }; | |
1018 | ||
1019 | #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) | |
1020 | ||
1021 | } // namespace traits | |
1022 | ||
b32b8144 FG |
1023 | #endif // !defined(GENERATING_DOCUMENTATION) |
1024 | ||
1025 | } // namespace asio | |
1026 | } // namespace boost | |
1027 | ||
1028 | #include <boost/asio/detail/pop_options.hpp> | |
1029 | ||
1030 | #endif // BOOST_ASIO_IMPL_USE_FUTURE_HPP |