connect.hpp 14 KB

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