submit.hpp 13 KB

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