composed.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //
  2. // composed.hpp
  3. // ~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 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_COMPOSED_HPP
  11. #define BOOST_ASIO_COMPOSED_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 <boost/asio/associated_executor.hpp>
  17. #include <boost/asio/async_result.hpp>
  18. #include <boost/asio/detail/base_from_cancellation_state.hpp>
  19. #include <boost/asio/detail/composed_work.hpp>
  20. #include <boost/asio/detail/handler_cont_helpers.hpp>
  21. #include <boost/asio/detail/type_traits.hpp>
  22. #include <boost/asio/detail/push_options.hpp>
  23. namespace boost {
  24. namespace asio {
  25. namespace detail {
  26. template <typename Impl, typename Work,
  27. typename Handler, typename... Signatures>
  28. class composed_op;
  29. template <typename Impl, typename Work, typename Handler>
  30. class composed_op<Impl, Work, Handler>
  31. : public base_from_cancellation_state<Handler>
  32. {
  33. public:
  34. template <typename I, typename W, typename H>
  35. composed_op(I&& impl,
  36. W&& work,
  37. H&& handler)
  38. : base_from_cancellation_state<Handler>(
  39. handler, enable_terminal_cancellation()),
  40. impl_(static_cast<I&&>(impl)),
  41. work_(static_cast<W&&>(work)),
  42. handler_(static_cast<H&&>(handler)),
  43. invocations_(0)
  44. {
  45. }
  46. composed_op(composed_op&& other)
  47. : base_from_cancellation_state<Handler>(
  48. static_cast<base_from_cancellation_state<Handler>&&>(other)),
  49. impl_(static_cast<Impl&&>(other.impl_)),
  50. work_(static_cast<Work&&>(other.work_)),
  51. handler_(static_cast<Handler&&>(other.handler_)),
  52. invocations_(other.invocations_)
  53. {
  54. }
  55. typedef typename composed_work_guard<
  56. typename Work::head_type>::executor_type io_executor_type;
  57. io_executor_type get_io_executor() const noexcept
  58. {
  59. return work_.head_.get_executor();
  60. }
  61. typedef associated_executor_t<Handler, io_executor_type> executor_type;
  62. executor_type get_executor() const noexcept
  63. {
  64. return (get_associated_executor)(handler_, work_.head_.get_executor());
  65. }
  66. typedef associated_allocator_t<Handler, std::allocator<void>> allocator_type;
  67. allocator_type get_allocator() const noexcept
  68. {
  69. return (get_associated_allocator)(handler_, std::allocator<void>());
  70. }
  71. template <typename... T>
  72. void operator()(T&&... t)
  73. {
  74. if (invocations_ < ~0u)
  75. ++invocations_;
  76. this->get_cancellation_state().slot().clear();
  77. impl_(*this, static_cast<T&&>(t)...);
  78. }
  79. template <typename... Args>
  80. auto complete(Args&&... args)
  81. -> decltype(declval<Handler>()(static_cast<Args&&>(args)...))
  82. {
  83. return static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
  84. }
  85. void reset_cancellation_state()
  86. {
  87. base_from_cancellation_state<Handler>::reset_cancellation_state(handler_);
  88. }
  89. template <typename Filter>
  90. void reset_cancellation_state(Filter&& filter)
  91. {
  92. base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
  93. static_cast<Filter&&>(filter));
  94. }
  95. template <typename InFilter, typename OutFilter>
  96. void reset_cancellation_state(InFilter&& in_filter,
  97. OutFilter&& out_filter)
  98. {
  99. base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
  100. static_cast<InFilter&&>(in_filter),
  101. static_cast<OutFilter&&>(out_filter));
  102. }
  103. cancellation_type_t cancelled() const noexcept
  104. {
  105. return base_from_cancellation_state<Handler>::cancelled();
  106. }
  107. //private:
  108. Impl impl_;
  109. Work work_;
  110. Handler handler_;
  111. unsigned invocations_;
  112. };
  113. template <typename Impl, typename Work, typename Handler,
  114. typename R, typename... Args>
  115. class composed_op<Impl, Work, Handler, R(Args...)>
  116. : public composed_op<Impl, Work, Handler>
  117. {
  118. public:
  119. using composed_op<Impl, Work, Handler>::composed_op;
  120. template <typename... T>
  121. void operator()(T&&... t)
  122. {
  123. if (this->invocations_ < ~0u)
  124. ++this->invocations_;
  125. this->get_cancellation_state().slot().clear();
  126. this->impl_(*this, static_cast<T&&>(t)...);
  127. }
  128. void complete(Args... args)
  129. {
  130. this->work_.reset();
  131. static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
  132. }
  133. };
  134. template <typename Impl, typename Work, typename Handler,
  135. typename R, typename... Args, typename... Signatures>
  136. class composed_op<Impl, Work, Handler, R(Args...), Signatures...>
  137. : public composed_op<Impl, Work, Handler, Signatures...>
  138. {
  139. public:
  140. using composed_op<Impl, Work, Handler, Signatures...>::composed_op;
  141. template <typename... T>
  142. void operator()(T&&... t)
  143. {
  144. if (this->invocations_ < ~0u)
  145. ++this->invocations_;
  146. this->get_cancellation_state().slot().clear();
  147. this->impl_(*this, static_cast<T&&>(t)...);
  148. }
  149. using composed_op<Impl, Work, Handler, Signatures...>::complete;
  150. void complete(Args... args)
  151. {
  152. this->work_.reset();
  153. static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
  154. }
  155. };
  156. template <typename Impl, typename Work, typename Handler, typename Signature>
  157. inline bool asio_handler_is_continuation(
  158. composed_op<Impl, Work, Handler, Signature>* this_handler)
  159. {
  160. return this_handler->invocations_ > 1 ? true
  161. : boost_asio_handler_cont_helpers::is_continuation(
  162. this_handler->handler_);
  163. }
  164. template <typename Implementation, typename Executors, typename... Signatures>
  165. class initiate_composed
  166. {
  167. public:
  168. typedef typename composed_io_executors<Executors>::head_type executor_type;
  169. template <typename I>
  170. initiate_composed(I&& impl, composed_io_executors<Executors>&& executors)
  171. : implementation_(std::forward<I>(impl)),
  172. executors_(std::move(executors))
  173. {
  174. }
  175. executor_type get_executor() const noexcept
  176. {
  177. return executors_.head_;
  178. }
  179. template <typename Handler, typename... Args>
  180. void operator()(Handler&& handler, Args&&... args) const &
  181. {
  182. composed_op<decay_t<Implementation>, composed_work<Executors>,
  183. decay_t<Handler>, Signatures...>(implementation_,
  184. composed_work<Executors>(executors_),
  185. static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
  186. }
  187. template <typename Handler, typename... Args>
  188. void operator()(Handler&& handler, Args&&... args) &&
  189. {
  190. composed_op<decay_t<Implementation>, composed_work<Executors>,
  191. decay_t<Handler>, Signatures...>(
  192. static_cast<Implementation&&>(implementation_),
  193. composed_work<Executors>(executors_),
  194. static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
  195. }
  196. private:
  197. Implementation implementation_;
  198. composed_io_executors<Executors> executors_;
  199. };
  200. template <typename Implementation, typename... Signatures>
  201. class initiate_composed<Implementation, void(), Signatures...>
  202. {
  203. public:
  204. template <typename I>
  205. initiate_composed(I&& impl, composed_io_executors<void()>&&)
  206. : implementation_(std::forward<I>(impl))
  207. {
  208. }
  209. template <typename Handler, typename... Args>
  210. void operator()(Handler&& handler, Args&&... args) const &
  211. {
  212. composed_op<decay_t<Implementation>, composed_work<void()>,
  213. decay_t<Handler>, Signatures...>(implementation_,
  214. composed_work<void()>(composed_io_executors<void()>()),
  215. static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
  216. }
  217. template <typename Handler, typename... Args>
  218. void operator()(Handler&& handler, Args&&... args) &&
  219. {
  220. composed_op<decay_t<Implementation>, composed_work<void()>,
  221. decay_t<Handler>, Signatures...>(
  222. static_cast<Implementation&&>(implementation_),
  223. composed_work<void()>(composed_io_executors<void()>()),
  224. static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
  225. }
  226. private:
  227. Implementation implementation_;
  228. };
  229. template <typename... Signatures, typename Implementation, typename Executors>
  230. inline initiate_composed<Implementation, Executors, Signatures...>
  231. make_initiate_composed(Implementation&& implementation,
  232. composed_io_executors<Executors>&& executors)
  233. {
  234. return initiate_composed<decay_t<Implementation>, Executors, Signatures...>(
  235. static_cast<Implementation&&>(implementation),
  236. static_cast<composed_io_executors<Executors>&&>(executors));
  237. }
  238. } // namespace detail
  239. #if !defined(GENERATING_DOCUMENTATION)
  240. template <template <typename, typename> class Associator,
  241. typename Impl, typename Work, typename Handler,
  242. typename Signature, typename DefaultCandidate>
  243. struct associator<Associator,
  244. detail::composed_op<Impl, Work, Handler, Signature>,
  245. DefaultCandidate>
  246. : Associator<Handler, DefaultCandidate>
  247. {
  248. static typename Associator<Handler, DefaultCandidate>::type get(
  249. const detail::composed_op<Impl, Work, Handler, Signature>& h) noexcept
  250. {
  251. return Associator<Handler, DefaultCandidate>::get(h.handler_);
  252. }
  253. static auto get(const detail::composed_op<Impl, Work, Handler, Signature>& h,
  254. const DefaultCandidate& c) noexcept
  255. -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
  256. {
  257. return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
  258. }
  259. };
  260. #endif // !defined(GENERATING_DOCUMENTATION)
  261. /// Creates an initiation function object that may be used to launch an
  262. /// asynchronous operation with a stateful implementation.
  263. /**
  264. * The @c composed function simplifies the implementation of composed
  265. * asynchronous operations automatically by wrapping a stateful function object
  266. * for use as an initiation function object.
  267. *
  268. * @param implementation A function object that contains the implementation of
  269. * the composed asynchronous operation. The first argument to the function
  270. * object is a non-const reference to the enclosing intermediate completion
  271. * handler. The remaining arguments are any arguments that originate from the
  272. * completion handlers of any asynchronous operations performed by the
  273. * implementation.
  274. *
  275. * @param io_objects_or_executors Zero or more I/O objects or I/O executors for
  276. * which outstanding work must be maintained.
  277. *
  278. * @par Per-Operation Cancellation
  279. * By default, terminal per-operation cancellation is enabled for composed
  280. * operations that are implemented using @c composed. To disable cancellation
  281. * for the composed operation, or to alter its supported cancellation types,
  282. * call the @c self object's @c reset_cancellation_state function.
  283. *
  284. * @par Example:
  285. *
  286. * @code struct async_echo_implementation
  287. * {
  288. * tcp::socket& socket_;
  289. * boost::asio::mutable_buffer buffer_;
  290. * enum { starting, reading, writing } state_;
  291. *
  292. * template <typename Self>
  293. * void operator()(Self& self,
  294. * boost::system::error_code error,
  295. * std::size_t n)
  296. * {
  297. * switch (state_)
  298. * {
  299. * case starting:
  300. * state_ = reading;
  301. * socket_.async_read_some(
  302. * buffer_, std::move(self));
  303. * break;
  304. * case reading:
  305. * if (error)
  306. * {
  307. * self.complete(error, 0);
  308. * }
  309. * else
  310. * {
  311. * state_ = writing;
  312. * boost::asio::async_write(socket_, buffer_,
  313. * boost::asio::transfer_exactly(n),
  314. * std::move(self));
  315. * }
  316. * break;
  317. * case writing:
  318. * self.complete(error, n);
  319. * break;
  320. * }
  321. * }
  322. * };
  323. *
  324. * template <typename CompletionToken>
  325. * auto async_echo(tcp::socket& socket,
  326. * boost::asio::mutable_buffer buffer,
  327. * CompletionToken&& token)
  328. * -> decltype(
  329. * boost::asio::async_initiate<CompletionToken,
  330. * void(boost::system::error_code, std::size_t)>(
  331. * boost::asio::composed(
  332. * async_echo_implementation{socket, buffer,
  333. * async_echo_implementation::starting}, socket),
  334. * token))
  335. * {
  336. * return boost::asio::async_initiate<CompletionToken,
  337. * void(boost::system::error_code, std::size_t)>(
  338. * boost::asio::composed(
  339. * async_echo_implementation{socket, buffer,
  340. * async_echo_implementation::starting}, socket),
  341. * token, boost::system::error_code{}, 0);
  342. * } @endcode
  343. */
  344. template <BOOST_ASIO_COMPLETION_SIGNATURE... Signatures,
  345. typename Implementation, typename... IoObjectsOrExecutors>
  346. inline auto composed(Implementation&& implementation,
  347. IoObjectsOrExecutors&&... io_objects_or_executors)
  348. -> decltype(
  349. detail::make_initiate_composed<Signatures...>(
  350. static_cast<Implementation&&>(implementation),
  351. detail::make_composed_io_executors(
  352. detail::get_composed_io_executor(
  353. static_cast<IoObjectsOrExecutors&&>(
  354. io_objects_or_executors))...)))
  355. {
  356. return detail::make_initiate_composed<Signatures...>(
  357. static_cast<Implementation&&>(implementation),
  358. detail::make_composed_io_executors(
  359. detail::get_composed_io_executor(
  360. static_cast<IoObjectsOrExecutors&&>(
  361. io_objects_or_executors))...));
  362. }
  363. } // namespace asio
  364. } // namespace boost
  365. #include <boost/asio/detail/pop_options.hpp>
  366. #endif // BOOST_ASIO_COMPOSE_HPP