connect.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. //
  2. // execution/connect.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. #ifndef BOOST_ASIO_EXECUTION_CONNECT_HPP
  11. #define BOOST_ASIO_EXECUTION_CONNECT_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/detail/type_traits.hpp>
  17. #include <boost/asio/execution/detail/as_invocable.hpp>
  18. #include <boost/asio/execution/detail/as_operation.hpp>
  19. #include <boost/asio/execution/detail/as_receiver.hpp>
  20. #include <boost/asio/execution/executor.hpp>
  21. #include <boost/asio/execution/operation_state.hpp>
  22. #include <boost/asio/execution/receiver.hpp>
  23. #include <boost/asio/execution/sender.hpp>
  24. #include <boost/asio/traits/connect_member.hpp>
  25. #include <boost/asio/traits/connect_free.hpp>
  26. #include <boost/asio/detail/push_options.hpp>
  27. #if defined(GENERATING_DOCUMENTATION)
  28. namespace boost {
  29. namespace asio {
  30. namespace execution {
  31. /// A customisation point that connects a sender to a receiver.
  32. /**
  33. * The name <tt>execution::connect</tt> denotes a customisation point object.
  34. * For some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type
  35. * such that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type
  36. * such that <tt>decltype((r))</tt> is <tt>R</tt>. The expression
  37. * <tt>execution::connect(s, r)</tt> is expression-equivalent to:
  38. *
  39. * @li <tt>s.connect(r)</tt>, if that expression is valid, if its type
  40. * satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies
  41. * <tt>sender</tt>.
  42. *
  43. * @li Otherwise, <tt>connect(s, r)</tt>, if that expression is valid, if its
  44. * type satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies
  45. * <tt>sender</tt>, with overload resolution performed in a context that
  46. * includes the declaration <tt>void connect();</tt> and that does not include
  47. * a declaration of <tt>execution::connect</tt>.
  48. *
  49. * @li Otherwise, <tt>as_operation{s, r}</tt>, if <tt>r</tt> is not an instance
  50. * of <tt>as_receiver<F, S></tt> for some type <tt>F</tt>, and if
  51. * <tt>receiver_of<R> && executor_of<remove_cvref_t<S>,
  52. * as_invocable<remove_cvref_t<R>, S>></tt> is <tt>true</tt>, where
  53. * <tt>as_operation</tt> is an implementation-defined class equivalent to
  54. * @code template <class S, class R>
  55. * struct as_operation
  56. * {
  57. * remove_cvref_t<S> e_;
  58. * remove_cvref_t<R> r_;
  59. * void start() noexcept try {
  60. * execution::execute(std::move(e_),
  61. * as_invocable<remove_cvref_t<R>, S>{r_});
  62. * } catch(...) {
  63. * execution::set_error(std::move(r_), current_exception());
  64. * }
  65. * }; @endcode
  66. * and <tt>as_invocable</tt> is a class template equivalent to the following:
  67. * @code template<class R>
  68. * struct as_invocable
  69. * {
  70. * R* r_;
  71. * explicit as_invocable(R& r) noexcept
  72. * : r_(std::addressof(r)) {}
  73. * as_invocable(as_invocable && other) noexcept
  74. * : r_(std::exchange(other.r_, nullptr)) {}
  75. * ~as_invocable() {
  76. * if(r_)
  77. * execution::set_done(std::move(*r_));
  78. * }
  79. * void operator()() & noexcept try {
  80. * execution::set_value(std::move(*r_));
  81. * r_ = nullptr;
  82. * } catch(...) {
  83. * execution::set_error(std::move(*r_), current_exception());
  84. * r_ = nullptr;
  85. * }
  86. * };
  87. * @endcode
  88. *
  89. * @li Otherwise, <tt>execution::connect(s, r)</tt> is ill-formed.
  90. */
  91. inline constexpr unspecified connect = unspecified;
  92. /// A type trait that determines whether a @c connect expression is
  93. /// well-formed.
  94. /**
  95. * Class template @c can_connect is a trait that is derived from
  96. * @c true_type if the expression <tt>execution::connect(std::declval<S>(),
  97. * std::declval<R>())</tt> is well formed; otherwise @c false_type.
  98. */
  99. template <typename S, typename R>
  100. struct can_connect :
  101. integral_constant<bool, automatically_determined>
  102. {
  103. };
  104. /// A type trait to determine the result of a @c connect expression.
  105. template <typename S, typename R>
  106. struct connect_result
  107. {
  108. /// The type of the connect expression.
  109. /**
  110. * The type of the expression <tt>execution::connect(std::declval<S>(),
  111. * std::declval<R>())</tt>.
  112. */
  113. typedef automatically_determined type;
  114. };
  115. /// A type alis to determine the result of a @c connect expression.
  116. template <typename S, typename R>
  117. using connect_result_t = typename connect_result<S, R>::type;
  118. } // namespace execution
  119. } // namespace asio
  120. } // namespace boost
  121. #else // defined(GENERATING_DOCUMENTATION)
  122. namespace asio_execution_connect_fn {
  123. using boost::asio::conditional;
  124. using boost::asio::declval;
  125. using boost::asio::enable_if;
  126. using boost::asio::execution::detail::as_invocable;
  127. using boost::asio::execution::detail::as_operation;
  128. using boost::asio::execution::detail::is_as_receiver;
  129. using boost::asio::execution::is_executor_of;
  130. using boost::asio::execution::is_operation_state;
  131. using boost::asio::execution::is_receiver;
  132. using boost::asio::execution::is_sender;
  133. using boost::asio::false_type;
  134. using boost::asio::remove_cvref;
  135. using boost::asio::traits::connect_free;
  136. using boost::asio::traits::connect_member;
  137. void connect();
  138. enum overload_type
  139. {
  140. call_member,
  141. call_free,
  142. adapter,
  143. ill_formed
  144. };
  145. template <typename S, typename R, typename = void,
  146. typename = void, typename = void, typename = void>
  147. struct call_traits
  148. {
  149. BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
  150. BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
  151. typedef void result_type;
  152. };
  153. template <typename S, typename R>
  154. struct call_traits<S, void(R),
  155. typename enable_if<
  156. connect_member<S, R>::is_valid
  157. >::type,
  158. typename enable_if<
  159. is_operation_state<typename connect_member<S, R>::result_type>::value
  160. >::type,
  161. typename enable_if<
  162. is_sender<typename remove_cvref<S>::type>::value
  163. >::type> :
  164. connect_member<S, R>
  165. {
  166. BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
  167. };
  168. template <typename S, typename R>
  169. struct call_traits<S, void(R),
  170. typename enable_if<
  171. !connect_member<S, R>::is_valid
  172. >::type,
  173. typename enable_if<
  174. connect_free<S, R>::is_valid
  175. >::type,
  176. typename enable_if<
  177. is_operation_state<typename connect_free<S, R>::result_type>::value
  178. >::type,
  179. typename enable_if<
  180. is_sender<typename remove_cvref<S>::type>::value
  181. >::type> :
  182. connect_free<S, R>
  183. {
  184. BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
  185. };
  186. template <typename S, typename R>
  187. struct call_traits<S, void(R),
  188. typename enable_if<
  189. !connect_member<S, R>::is_valid
  190. >::type,
  191. typename enable_if<
  192. !connect_free<S, R>::is_valid
  193. >::type,
  194. typename enable_if<
  195. is_receiver<R>::value
  196. >::type,
  197. typename enable_if<
  198. conditional<
  199. !is_as_receiver<
  200. typename remove_cvref<R>::type
  201. >::value,
  202. is_executor_of<
  203. typename remove_cvref<S>::type,
  204. as_invocable<typename remove_cvref<R>::type, S>
  205. >,
  206. false_type
  207. >::type::value
  208. >::type>
  209. {
  210. BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
  211. BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
  212. typedef as_operation<S, R> result_type;
  213. };
  214. struct impl
  215. {
  216. #if defined(BOOST_ASIO_HAS_MOVE)
  217. template <typename S, typename R>
  218. BOOST_ASIO_CONSTEXPR typename enable_if<
  219. call_traits<S, void(R)>::overload == call_member,
  220. typename call_traits<S, void(R)>::result_type
  221. >::type
  222. operator()(S&& s, R&& r) const
  223. BOOST_ASIO_NOEXCEPT_IF((
  224. call_traits<S, void(R)>::is_noexcept))
  225. {
  226. return BOOST_ASIO_MOVE_CAST(S)(s).connect(BOOST_ASIO_MOVE_CAST(R)(r));
  227. }
  228. template <typename S, typename R>
  229. BOOST_ASIO_CONSTEXPR typename enable_if<
  230. call_traits<S, void(R)>::overload == call_free,
  231. typename call_traits<S, void(R)>::result_type
  232. >::type
  233. operator()(S&& s, R&& r) const
  234. BOOST_ASIO_NOEXCEPT_IF((
  235. call_traits<S, void(R)>::is_noexcept))
  236. {
  237. return connect(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r));
  238. }
  239. template <typename S, typename R>
  240. BOOST_ASIO_CONSTEXPR typename enable_if<
  241. call_traits<S, void(R)>::overload == adapter,
  242. typename call_traits<S, void(R)>::result_type
  243. >::type
  244. operator()(S&& s, R&& r) const
  245. BOOST_ASIO_NOEXCEPT_IF((
  246. call_traits<S, void(R)>::is_noexcept))
  247. {
  248. return typename call_traits<S, void(R)>::result_type(
  249. BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r));
  250. }
  251. #else // defined(BOOST_ASIO_HAS_MOVE)
  252. template <typename S, typename R>
  253. BOOST_ASIO_CONSTEXPR typename enable_if<
  254. call_traits<S&, void(R&)>::overload == call_member,
  255. typename call_traits<S&, void(R&)>::result_type
  256. >::type
  257. operator()(S& s, R& r) const
  258. BOOST_ASIO_NOEXCEPT_IF((
  259. call_traits<S&, void(R&)>::is_noexcept))
  260. {
  261. return s.connect(r);
  262. }
  263. template <typename S, typename R>
  264. BOOST_ASIO_CONSTEXPR typename enable_if<
  265. call_traits<const S&, void(R&)>::overload == call_member,
  266. typename call_traits<const S&, void(R&)>::result_type
  267. >::type
  268. operator()(const S& s, R& r) const
  269. BOOST_ASIO_NOEXCEPT_IF((
  270. call_traits<const S&, void(R&)>::is_noexcept))
  271. {
  272. return s.connect(r);
  273. }
  274. template <typename S, typename R>
  275. BOOST_ASIO_CONSTEXPR typename enable_if<
  276. call_traits<S&, void(R&)>::overload == call_free,
  277. typename call_traits<S&, void(R&)>::result_type
  278. >::type
  279. operator()(S& s, R& r) const
  280. BOOST_ASIO_NOEXCEPT_IF((
  281. call_traits<S&, void(R&)>::is_noexcept))
  282. {
  283. return connect(s, r);
  284. }
  285. template <typename S, typename R>
  286. BOOST_ASIO_CONSTEXPR typename enable_if<
  287. call_traits<const S&, void(R&)>::overload == call_free,
  288. typename call_traits<const S&, void(R&)>::result_type
  289. >::type
  290. operator()(const S& s, R& r) const
  291. BOOST_ASIO_NOEXCEPT_IF((
  292. call_traits<const S&, void(R&)>::is_noexcept))
  293. {
  294. return connect(s, r);
  295. }
  296. template <typename S, typename R>
  297. BOOST_ASIO_CONSTEXPR typename enable_if<
  298. call_traits<S&, void(R&)>::overload == adapter,
  299. typename call_traits<S&, void(R&)>::result_type
  300. >::type
  301. operator()(S& s, R& r) const
  302. BOOST_ASIO_NOEXCEPT_IF((
  303. call_traits<S&, void(R&)>::is_noexcept))
  304. {
  305. return typename call_traits<S&, void(R&)>::result_type(s, r);
  306. }
  307. template <typename S, typename R>
  308. BOOST_ASIO_CONSTEXPR typename enable_if<
  309. call_traits<const S&, void(R&)>::overload == adapter,
  310. typename call_traits<const S&, void(R&)>::result_type
  311. >::type
  312. operator()(const S& s, R& r) const
  313. BOOST_ASIO_NOEXCEPT_IF((
  314. call_traits<const S&, void(R&)>::is_noexcept))
  315. {
  316. return typename call_traits<const S&, void(R&)>::result_type(s, r);
  317. }
  318. template <typename S, typename R>
  319. BOOST_ASIO_CONSTEXPR typename enable_if<
  320. call_traits<S&, void(const R&)>::overload == call_member,
  321. typename call_traits<S&, void(const R&)>::result_type
  322. >::type
  323. operator()(S& s, const R& r) const
  324. BOOST_ASIO_NOEXCEPT_IF((
  325. call_traits<S&, void(const R&)>::is_noexcept))
  326. {
  327. return s.connect(r);
  328. }
  329. template <typename S, typename R>
  330. BOOST_ASIO_CONSTEXPR typename enable_if<
  331. call_traits<const S&, void(const R&)>::overload == call_member,
  332. typename call_traits<const S&, void(const R&)>::result_type
  333. >::type
  334. operator()(const S& s, const R& r) const
  335. BOOST_ASIO_NOEXCEPT_IF((
  336. call_traits<const S&, void(const R&)>::is_noexcept))
  337. {
  338. return s.connect(r);
  339. }
  340. template <typename S, typename R>
  341. BOOST_ASIO_CONSTEXPR typename enable_if<
  342. call_traits<S&, void(const R&)>::overload == call_free,
  343. typename call_traits<S&, void(const R&)>::result_type
  344. >::type
  345. operator()(S& s, const R& r) const
  346. BOOST_ASIO_NOEXCEPT_IF((
  347. call_traits<S&, void(const R&)>::is_noexcept))
  348. {
  349. return connect(s, r);
  350. }
  351. template <typename S, typename R>
  352. BOOST_ASIO_CONSTEXPR typename enable_if<
  353. call_traits<const S&, void(const R&)>::overload == call_free,
  354. typename call_traits<const S&, void(const R&)>::result_type
  355. >::type
  356. operator()(const S& s, const R& r) const
  357. BOOST_ASIO_NOEXCEPT_IF((
  358. call_traits<const S&, void(const R&)>::is_noexcept))
  359. {
  360. return connect(s, r);
  361. }
  362. template <typename S, typename R>
  363. BOOST_ASIO_CONSTEXPR typename enable_if<
  364. call_traits<S&, void(const R&)>::overload == adapter,
  365. typename call_traits<S&, void(const R&)>::result_type
  366. >::type
  367. operator()(S& s, const R& r) const
  368. BOOST_ASIO_NOEXCEPT_IF((
  369. call_traits<S&, void(const R&)>::is_noexcept))
  370. {
  371. return typename call_traits<S&, void(const R&)>::result_type(s, r);
  372. }
  373. template <typename S, typename R>
  374. BOOST_ASIO_CONSTEXPR typename enable_if<
  375. call_traits<const S&, void(const R&)>::overload == adapter,
  376. typename call_traits<const S&, void(const R&)>::result_type
  377. >::type
  378. operator()(const S& s, const R& r) const
  379. BOOST_ASIO_NOEXCEPT_IF((
  380. call_traits<const S&, void(const R&)>::is_noexcept))
  381. {
  382. return typename call_traits<const S&, void(const R&)>::result_type(s, r);
  383. }
  384. #endif // defined(BOOST_ASIO_HAS_MOVE)
  385. };
  386. template <typename T = impl>
  387. struct static_instance
  388. {
  389. static const T instance;
  390. };
  391. template <typename T>
  392. const T static_instance<T>::instance = {};
  393. } // namespace asio_execution_connect_fn
  394. namespace boost {
  395. namespace asio {
  396. namespace execution {
  397. namespace {
  398. static BOOST_ASIO_CONSTEXPR const asio_execution_connect_fn::impl&
  399. connect = asio_execution_connect_fn::static_instance<>::instance;
  400. } // namespace
  401. template <typename S, typename R>
  402. struct can_connect :
  403. integral_constant<bool,
  404. asio_execution_connect_fn::call_traits<S, void(R)>::overload !=
  405. asio_execution_connect_fn::ill_formed>
  406. {
  407. };
  408. #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  409. template <typename S, typename R>
  410. constexpr bool can_connect_v = can_connect<S, R>::value;
  411. #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  412. template <typename S, typename R>
  413. struct is_nothrow_connect :
  414. integral_constant<bool,
  415. asio_execution_connect_fn::call_traits<S, void(R)>::is_noexcept>
  416. {
  417. };
  418. #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  419. template <typename S, typename R>
  420. constexpr bool is_nothrow_connect_v
  421. = is_nothrow_connect<S, R>::value;
  422. #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
  423. template <typename S, typename R>
  424. struct connect_result
  425. {
  426. typedef typename asio_execution_connect_fn::call_traits<
  427. S, void(R)>::result_type type;
  428. };
  429. #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
  430. template <typename S, typename R>
  431. using connect_result_t = typename connect_result<S, R>::type;
  432. #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
  433. } // namespace execution
  434. } // namespace asio
  435. } // namespace boost
  436. #endif // defined(GENERATING_DOCUMENTATION)
  437. #include <boost/asio/detail/pop_options.hpp>
  438. #endif // BOOST_ASIO_EXECUTION_CONNECT_HPP