use_future.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. //
  2. // impl/use_future.hpp
  3. // ~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 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. #ifndef BOOST_ASIO_IMPL_USE_FUTURE_HPP
  11. #define BOOST_ASIO_IMPL_USE_FUTURE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <tuple>
  17. #include <boost/asio/async_result.hpp>
  18. #include <boost/asio/detail/memory.hpp>
  19. #include <boost/asio/detail/type_traits.hpp>
  20. #include <boost/asio/dispatch.hpp>
  21. #include <boost/asio/disposition.hpp>
  22. #include <boost/asio/execution.hpp>
  23. #include <boost/asio/packaged_task.hpp>
  24. #include <boost/system/system_error.hpp>
  25. #include <boost/asio/system_executor.hpp>
  26. #include <boost/asio/detail/push_options.hpp>
  27. namespace boost {
  28. namespace asio {
  29. namespace detail {
  30. template <typename T, typename F, typename... Args>
  31. inline void promise_invoke_and_set(std::promise<T>& p,
  32. F& f, Args&&... args)
  33. {
  34. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  35. try
  36. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  37. {
  38. p.set_value(f(static_cast<Args&&>(args)...));
  39. }
  40. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  41. catch (...)
  42. {
  43. p.set_exception(std::current_exception());
  44. }
  45. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  46. }
  47. template <typename F, typename... Args>
  48. inline void promise_invoke_and_set(std::promise<void>& p,
  49. F& f, Args&&... args)
  50. {
  51. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  52. try
  53. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  54. {
  55. f(static_cast<Args&&>(args)...);
  56. p.set_value();
  57. }
  58. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  59. catch (...)
  60. {
  61. p.set_exception(std::current_exception());
  62. }
  63. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  64. }
  65. // A function object adapter to invoke a nullary function object and capture
  66. // any exception thrown into a promise.
  67. template <typename T, typename F>
  68. class promise_invoker
  69. {
  70. public:
  71. promise_invoker(const shared_ptr<std::promise<T>>& p,
  72. F&& f)
  73. : p_(p), f_(static_cast<F&&>(f))
  74. {
  75. }
  76. void operator()()
  77. {
  78. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  79. try
  80. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  81. {
  82. f_();
  83. }
  84. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  85. catch (...)
  86. {
  87. p_->set_exception(std::current_exception());
  88. }
  89. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  90. }
  91. private:
  92. shared_ptr<std::promise<T>> p_;
  93. decay_t<F> f_;
  94. };
  95. // An executor that adapts the system_executor to capture any exception thrown
  96. // by a submitted function object and save it into a promise.
  97. template <typename T, typename Blocking = execution::blocking_t::possibly_t>
  98. class promise_executor
  99. {
  100. public:
  101. explicit promise_executor(const shared_ptr<std::promise<T>>& p)
  102. : p_(p)
  103. {
  104. }
  105. execution_context& query(execution::context_t) const noexcept
  106. {
  107. return boost::asio::query(system_executor(), execution::context);
  108. }
  109. static constexpr Blocking query(execution::blocking_t)
  110. {
  111. return Blocking();
  112. }
  113. promise_executor<T, execution::blocking_t::possibly_t>
  114. require(execution::blocking_t::possibly_t) const
  115. {
  116. return promise_executor<T, execution::blocking_t::possibly_t>(p_);
  117. }
  118. promise_executor<T, execution::blocking_t::never_t>
  119. require(execution::blocking_t::never_t) const
  120. {
  121. return promise_executor<T, execution::blocking_t::never_t>(p_);
  122. }
  123. template <typename F>
  124. void execute(F&& f) const
  125. {
  126. boost::asio::require(system_executor(), Blocking()).execute(
  127. promise_invoker<T, F>(p_, static_cast<F&&>(f)));
  128. }
  129. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  130. execution_context& context() const noexcept
  131. {
  132. return system_executor().context();
  133. }
  134. void on_work_started() const noexcept {}
  135. void on_work_finished() const noexcept {}
  136. template <typename F, typename A>
  137. void dispatch(F&& f, const A&) const
  138. {
  139. promise_invoker<T, F>(p_, static_cast<F&&>(f))();
  140. }
  141. template <typename F, typename A>
  142. void post(F&& f, const A& a) const
  143. {
  144. system_executor().post(
  145. promise_invoker<T, F>(p_, static_cast<F&&>(f)), a);
  146. }
  147. template <typename F, typename A>
  148. void defer(F&& f, const A& a) const
  149. {
  150. system_executor().defer(
  151. promise_invoker<T, F>(p_, static_cast<F&&>(f)), a);
  152. }
  153. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  154. friend bool operator==(const promise_executor& a,
  155. const promise_executor& b) noexcept
  156. {
  157. return a.p_ == b.p_;
  158. }
  159. friend bool operator!=(const promise_executor& a,
  160. const promise_executor& b) noexcept
  161. {
  162. return a.p_ != b.p_;
  163. }
  164. private:
  165. shared_ptr<std::promise<T>> p_;
  166. };
  167. // The base class for all completion handlers that create promises.
  168. template <typename T>
  169. class promise_creator
  170. {
  171. public:
  172. typedef promise_executor<T> executor_type;
  173. executor_type get_executor() const noexcept
  174. {
  175. return executor_type(p_);
  176. }
  177. typedef std::future<T> future_type;
  178. future_type get_future()
  179. {
  180. return p_->get_future();
  181. }
  182. protected:
  183. template <typename Allocator>
  184. void create_promise(const Allocator& a)
  185. {
  186. BOOST_ASIO_REBIND_ALLOC(Allocator, char) b(a);
  187. p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b);
  188. }
  189. shared_ptr<std::promise<T>> p_;
  190. };
  191. // For completion signature void().
  192. class promise_handler_0
  193. : public promise_creator<void>
  194. {
  195. public:
  196. void operator()()
  197. {
  198. this->p_->set_value();
  199. }
  200. };
  201. // For completion signature void(disposition auto).
  202. template <typename Disposition>
  203. class promise_handler_d_0
  204. : public promise_creator<void>
  205. {
  206. public:
  207. void operator()(Disposition d)
  208. {
  209. if (d != no_error)
  210. {
  211. this->p_->set_exception(
  212. (to_exception_ptr)(static_cast<Disposition&&>(d)));
  213. }
  214. else
  215. {
  216. this->p_->set_value();
  217. }
  218. }
  219. };
  220. // For completion signature void(T).
  221. template <typename T>
  222. class promise_handler_1
  223. : public promise_creator<T>
  224. {
  225. public:
  226. template <typename Arg>
  227. void operator()(Arg&& arg)
  228. {
  229. this->p_->set_value(static_cast<Arg&&>(arg));
  230. }
  231. };
  232. // For completion signature void(disposition auto, T).
  233. template <typename Disposition, typename T>
  234. class promise_handler_d_1
  235. : public promise_creator<T>
  236. {
  237. public:
  238. template <typename Arg>
  239. void operator()(Disposition d, Arg&& arg)
  240. {
  241. if (d != no_error)
  242. {
  243. this->p_->set_exception(
  244. (to_exception_ptr)(static_cast<Disposition&&>(d)));
  245. }
  246. else
  247. this->p_->set_value(static_cast<Arg&&>(arg));
  248. }
  249. };
  250. // For completion signature void(T1, ..., Tn);
  251. template <typename T>
  252. class promise_handler_n
  253. : public promise_creator<T>
  254. {
  255. public:
  256. template <typename... Args>
  257. void operator()(Args&&... args)
  258. {
  259. this->p_->set_value(
  260. std::forward_as_tuple(
  261. static_cast<Args&&>(args)...));
  262. }
  263. };
  264. // For completion signature void(error_code, T1, ..., Tn);
  265. template <typename Disposition, typename T>
  266. class promise_handler_d_n
  267. : public promise_creator<T>
  268. {
  269. public:
  270. template <typename... Args>
  271. void operator()(Disposition d, Args&&... args)
  272. {
  273. if (d != no_error)
  274. {
  275. this->p_->set_exception(
  276. (to_exception_ptr)(static_cast<Disposition&&>(d)));
  277. }
  278. else
  279. {
  280. this->p_->set_value(
  281. std::forward_as_tuple(
  282. static_cast<Args&&>(args)...));
  283. }
  284. }
  285. };
  286. // Helper template to choose the appropriate concrete promise handler
  287. // implementation based on the supplied completion signature.
  288. template <typename, typename = void> class promise_handler_selector;
  289. template <>
  290. class promise_handler_selector<void()>
  291. : public promise_handler_0 {};
  292. template <typename Arg>
  293. class promise_handler_selector<void(Arg),
  294. enable_if_t<is_disposition<Arg>::value>>
  295. : public promise_handler_d_0<Arg> {};
  296. template <typename Arg>
  297. class promise_handler_selector<void(Arg),
  298. enable_if_t<!is_disposition<Arg>::value>>
  299. : public promise_handler_1<Arg> {};
  300. template <typename Arg0, typename Arg1>
  301. class promise_handler_selector<void(Arg0, Arg1),
  302. enable_if_t<is_disposition<Arg0>::value>>
  303. : public promise_handler_d_1<Arg0, Arg1> {};
  304. template <typename Arg0, typename... ArgN>
  305. class promise_handler_selector<void(Arg0, ArgN...),
  306. enable_if_t<!is_disposition<Arg0>::value>>
  307. : public promise_handler_n<std::tuple<Arg0, ArgN...>> {};
  308. template <typename Arg0, typename... ArgN>
  309. class promise_handler_selector<void(Arg0, ArgN...),
  310. enable_if_t<is_disposition<Arg0>::value>>
  311. : public promise_handler_d_n<Arg0, std::tuple<ArgN...>> {};
  312. // Completion handlers produced from the use_future completion token, when not
  313. // using use_future::operator().
  314. template <typename Signature, typename Allocator>
  315. class promise_handler
  316. : public promise_handler_selector<Signature>
  317. {
  318. public:
  319. typedef Allocator allocator_type;
  320. typedef void result_type;
  321. promise_handler(use_future_t<Allocator> u)
  322. : allocator_(u.get_allocator())
  323. {
  324. this->create_promise(allocator_);
  325. }
  326. allocator_type get_allocator() const noexcept
  327. {
  328. return allocator_;
  329. }
  330. private:
  331. Allocator allocator_;
  332. };
  333. template <typename Function>
  334. struct promise_function_wrapper
  335. {
  336. explicit promise_function_wrapper(Function& f)
  337. : function_(static_cast<Function&&>(f))
  338. {
  339. }
  340. explicit promise_function_wrapper(const Function& f)
  341. : function_(f)
  342. {
  343. }
  344. void operator()()
  345. {
  346. function_();
  347. }
  348. Function function_;
  349. };
  350. // Helper base class for async_result specialisation.
  351. template <typename Signature, typename Allocator>
  352. class promise_async_result
  353. {
  354. public:
  355. typedef promise_handler<Signature, Allocator> completion_handler_type;
  356. typedef typename completion_handler_type::future_type return_type;
  357. explicit promise_async_result(completion_handler_type& h)
  358. : future_(h.get_future())
  359. {
  360. }
  361. return_type get()
  362. {
  363. return static_cast<return_type&&>(future_);
  364. }
  365. private:
  366. return_type future_;
  367. };
  368. // Return value from use_future::operator().
  369. template <typename Function, typename Allocator>
  370. class packaged_token
  371. {
  372. public:
  373. packaged_token(Function f, const Allocator& a)
  374. : function_(static_cast<Function&&>(f)),
  375. allocator_(a)
  376. {
  377. }
  378. //private:
  379. Function function_;
  380. Allocator allocator_;
  381. };
  382. // Completion handlers produced from the use_future completion token, when
  383. // using use_future::operator().
  384. template <typename Function, typename Allocator, typename Result>
  385. class packaged_handler
  386. : public promise_creator<Result>
  387. {
  388. public:
  389. typedef Allocator allocator_type;
  390. typedef void result_type;
  391. packaged_handler(packaged_token<Function, Allocator> t)
  392. : function_(static_cast<Function&&>(t.function_)),
  393. allocator_(t.allocator_)
  394. {
  395. this->create_promise(allocator_);
  396. }
  397. allocator_type get_allocator() const noexcept
  398. {
  399. return allocator_;
  400. }
  401. template <typename... Args>
  402. void operator()(Args&&... args)
  403. {
  404. (promise_invoke_and_set)(*this->p_,
  405. function_, static_cast<Args&&>(args)...);
  406. }
  407. private:
  408. Function function_;
  409. Allocator allocator_;
  410. };
  411. // Helper base class for async_result specialisation.
  412. template <typename Function, typename Allocator, typename Result>
  413. class packaged_async_result
  414. {
  415. public:
  416. typedef packaged_handler<Function, Allocator, Result> completion_handler_type;
  417. typedef typename completion_handler_type::future_type return_type;
  418. explicit packaged_async_result(completion_handler_type& h)
  419. : future_(h.get_future())
  420. {
  421. }
  422. return_type get()
  423. {
  424. return static_cast<return_type&&>(future_);
  425. }
  426. private:
  427. return_type future_;
  428. };
  429. } // namespace detail
  430. template <typename Allocator> template <typename Function>
  431. inline detail::packaged_token<decay_t<Function>, Allocator>
  432. use_future_t<Allocator>::operator()(Function&& f) const
  433. {
  434. return detail::packaged_token<decay_t<Function>, Allocator>(
  435. static_cast<Function&&>(f), allocator_);
  436. }
  437. #if !defined(GENERATING_DOCUMENTATION)
  438. template <typename Allocator, typename Result, typename... Args>
  439. class async_result<use_future_t<Allocator>, Result(Args...)>
  440. : public detail::promise_async_result<
  441. void(decay_t<Args>...), Allocator>
  442. {
  443. public:
  444. explicit async_result(
  445. typename detail::promise_async_result<void(decay_t<Args>...),
  446. Allocator>::completion_handler_type& h)
  447. : detail::promise_async_result<
  448. void(decay_t<Args>...), Allocator>(h)
  449. {
  450. }
  451. };
  452. template <typename Function, typename Allocator,
  453. typename Result, typename... Args>
  454. class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)>
  455. : public detail::packaged_async_result<Function, Allocator,
  456. result_of_t<Function(Args...)>>
  457. {
  458. public:
  459. explicit async_result(
  460. typename detail::packaged_async_result<Function, Allocator,
  461. result_of_t<Function(Args...)>>::completion_handler_type& h)
  462. : detail::packaged_async_result<Function, Allocator,
  463. result_of_t<Function(Args...)>>(h)
  464. {
  465. }
  466. };
  467. namespace traits {
  468. #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  469. template <typename T, typename Blocking>
  470. struct equality_comparable<
  471. boost::asio::detail::promise_executor<T, Blocking>>
  472. {
  473. static constexpr bool is_valid = true;
  474. static constexpr bool is_noexcept = true;
  475. };
  476. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  477. #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  478. template <typename T, typename Blocking, typename Function>
  479. struct execute_member<
  480. boost::asio::detail::promise_executor<T, Blocking>, Function>
  481. {
  482. static constexpr bool is_valid = true;
  483. static constexpr bool is_noexcept = false;
  484. typedef void result_type;
  485. };
  486. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  487. #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
  488. template <typename T, typename Blocking, typename Property>
  489. struct query_static_constexpr_member<
  490. boost::asio::detail::promise_executor<T, Blocking>,
  491. Property,
  492. typename boost::asio::enable_if<
  493. boost::asio::is_convertible<
  494. Property,
  495. boost::asio::execution::blocking_t
  496. >::value
  497. >::type
  498. >
  499. {
  500. static constexpr bool is_valid = true;
  501. static constexpr bool is_noexcept = true;
  502. typedef Blocking result_type;
  503. static constexpr result_type value() noexcept
  504. {
  505. return Blocking();
  506. }
  507. };
  508. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
  509. #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  510. template <typename T, typename Blocking>
  511. struct query_member<
  512. boost::asio::detail::promise_executor<T, Blocking>,
  513. execution::context_t
  514. >
  515. {
  516. static constexpr bool is_valid = true;
  517. static constexpr bool is_noexcept = true;
  518. typedef boost::asio::system_context& result_type;
  519. };
  520. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  521. #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  522. template <typename T, typename Blocking>
  523. struct require_member<
  524. boost::asio::detail::promise_executor<T, Blocking>,
  525. execution::blocking_t::possibly_t
  526. >
  527. {
  528. static constexpr bool is_valid = true;
  529. static constexpr bool is_noexcept = true;
  530. typedef boost::asio::detail::promise_executor<T,
  531. execution::blocking_t::possibly_t> result_type;
  532. };
  533. template <typename T, typename Blocking>
  534. struct require_member<
  535. boost::asio::detail::promise_executor<T, Blocking>,
  536. execution::blocking_t::never_t
  537. >
  538. {
  539. static constexpr bool is_valid = true;
  540. static constexpr bool is_noexcept = true;
  541. typedef boost::asio::detail::promise_executor<T,
  542. execution::blocking_t::never_t> result_type;
  543. };
  544. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  545. } // namespace traits
  546. #endif // !defined(GENERATING_DOCUMENTATION)
  547. } // namespace asio
  548. } // namespace boost
  549. #include <boost/asio/detail/pop_options.hpp>
  550. #endif // BOOST_ASIO_IMPL_USE_FUTURE_HPP