1 //
2 // impl/use_future.hpp
3 // ~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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_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>
19 #include <tuple>
20 #include <boost/asio/async_result.hpp>
21 #include <boost/asio/detail/memory.hpp>
22 #include <boost/asio/dispatch.hpp>
23 #include <boost/system/error_code.hpp>
24 #include <boost/asio/execution.hpp>
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>
promise_invoke_and_set(std::promise<T> & p,F & f,BOOST_ASIO_MOVE_ARG (Args)...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>
promise_invoke_and_set(std::promise<void> & p,F & f,BOOST_ASIO_MOVE_ARG (Args)...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:
promise_invoker(const shared_ptr<std::promise<T>> & p,BOOST_ASIO_MOVE_ARG (F)f)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
operator ()()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.
206 template <typename T, typename Blocking = execution::blocking_t::possibly_t>
207 class promise_executor
208 {
209 public:
promise_executor(const shared_ptr<std::promise<T>> & p)210 explicit promise_executor(const shared_ptr<std::promise<T> >& p)
211 : p_(p)
212 {
213 }
214
query(execution::blocking_t)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>
require(execution::blocking_t::possibly_t) const221 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>
require(execution::blocking_t::never_t) const227 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>
execute(BOOST_ASIO_MOVE_ARG (F)f) const233 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)
context() const241 execution_context& context() const BOOST_ASIO_NOEXCEPT
242 {
243 return system_executor().context();
244 }
245
on_work_started() const246 void on_work_started() const BOOST_ASIO_NOEXCEPT {}
on_work_finished() const247 void on_work_finished() const BOOST_ASIO_NOEXCEPT {}
248
249 template <typename F, typename A>
dispatch(BOOST_ASIO_MOVE_ARG (F)f,const A &) const250 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>
post(BOOST_ASIO_MOVE_ARG (F)f,const A & a) const256 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>
defer(BOOST_ASIO_MOVE_ARG (F)f,const A & a) const263 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 }
268 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
269
operator ==(const promise_executor & a,const promise_executor & b)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
operator !=(const promise_executor & a,const promise_executor & b)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
get_executor() const293 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
294 {
295 return executor_type(p_);
296 }
297
298 typedef std::future<T> future_type;
299
get_future()300 future_type get_future()
301 {
302 return p_->get_future();
303 }
304
305 protected:
306 template <typename Allocator>
create_promise(const Allocator & a)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:
operator ()()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:
operator ()(const boost::system::error_code & ec)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:
operator ()(const std::exception_ptr & ex)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>
operator ()(BOOST_ASIO_MOVE_ARG (Arg)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>
operator ()(const boost::system::error_code & ec,BOOST_ASIO_MOVE_ARG (Arg)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>
operator ()(const std::exception_ptr & ex,BOOST_ASIO_MOVE_ARG (Arg)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>
operator ()(BOOST_ASIO_MOVE_ARG (Args)...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>
operator ()(const boost::system::error_code & ec,BOOST_ASIO_MOVE_ARG (Args)...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>
operator ()(const std::exception_ptr & ex,BOOST_ASIO_MOVE_ARG (Args)...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 /**/
610 BOOST_ASIO_VARIADIC_GENERATE_5(BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF)
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
promise_handler(use_future_t<Allocator> u)625 promise_handler(use_future_t<Allocator> u)
626 : allocator_(u.get_allocator())
627 {
628 this->create_promise(allocator_);
629 }
630
get_allocator() const631 allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
632 {
633 return allocator_;
634 }
635
636 private:
637 Allocator allocator_;
638 };
639
640 template <typename Function>
641 struct promise_function_wrapper
642 {
promise_function_wrapperboost::asio::detail::promise_function_wrapper643 explicit promise_function_wrapper(Function& f)
644 : function_(BOOST_ASIO_MOVE_CAST(Function)(f))
645 {
646 }
647
promise_function_wrapperboost::asio::detail::promise_function_wrapper648 explicit promise_function_wrapper(const Function& f)
649 : function_(f)
650 {
651 }
652
operator ()boost::asio::detail::promise_function_wrapper653 void operator()()
654 {
655 function_();
656 }
657
658 Function function_;
659 };
660
661 #if !defined(BOOST_ASIO_NO_DEPRECATED)
662
663 template <typename Function, typename Signature, typename Allocator>
asio_handler_invoke(Function & f,promise_handler<Signature,Allocator> * h)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());
669 boost::asio::dispatch(ex, promise_function_wrapper<Function>(f));
670 }
671
672 template <typename Function, typename Signature, typename Allocator>
asio_handler_invoke(const Function & f,promise_handler<Signature,Allocator> * h)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());
678 boost::asio::dispatch(ex, promise_function_wrapper<Function>(f));
679 }
680
681 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
682
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
promise_async_result(completion_handler_type & h)691 explicit promise_async_result(completion_handler_type& h)
692 : future_(h.get_future())
693 {
694 }
695
get()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:
packaged_token(Function f,const Allocator & a)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
packaged_handler(packaged_token<Function,Allocator> t)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
get_allocator() const738 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>
operator ()(BOOST_ASIO_MOVE_ARG (Args)...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
operator ()()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
777 #if !defined(BOOST_ASIO_NO_DEPRECATED)
778
779 template <typename Function,
780 typename Function1, typename Allocator, typename Result>
asio_handler_invoke(Function & f,packaged_handler<Function1,Allocator,Result> * h)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());
786 boost::asio::dispatch(ex, promise_function_wrapper<Function>(f));
787 }
788
789 template <typename Function,
790 typename Function1, typename Allocator, typename Result>
asio_handler_invoke(const Function & f,packaged_handler<Function1,Allocator,Result> * h)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());
796 boost::asio::dispatch(ex, promise_function_wrapper<Function>(f));
797 }
798
799 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
800
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
packaged_async_result(completion_handler_type & h)809 explicit packaged_async_result(completion_handler_type& h)
810 : future_(h.get_future())
811 {
812 }
813
get()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>
operator ()(BOOST_ASIO_MOVE_ARG (Function)f) const827 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:
async_result(typename detail::promise_async_result<void (typename decay<Args>::type...),Allocator>::completion_handler_type & h)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:
async_result(typename detail::packaged_async_result<Function,Allocator,typename result_of<Function (Args...)>::type>::completion_handler_type & h)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:
async_result(typename detail::promise_async_result<void (),Allocator>::completion_handler_type & h)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:
async_result(typename detail::packaged_async_result<Function,Allocator,typename result_of<Function ()>::type>::completion_handler_type & h)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
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
valueboost::asio::traits::query_static_constexpr_member985 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
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
1031