bulk_execute.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //
  2. // execution/bulk_execute.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_BULK_EXECUTE_HPP
  11. #define ASIO_EXECUTION_BULK_EXECUTE_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/bulk_guarantee.hpp"
  18. #include "asio/execution/detail/bulk_sender.hpp"
  19. #include "asio/execution/executor.hpp"
  20. #include "asio/execution/sender.hpp"
  21. #include "asio/traits/bulk_execute_member.hpp"
  22. #include "asio/traits/bulk_execute_free.hpp"
  23. #include "asio/detail/push_options.hpp"
  24. #if defined(GENERATING_DOCUMENTATION)
  25. namespace asio {
  26. namespace execution {
  27. /// A customisation point that creates a bulk sender.
  28. /**
  29. * The name <tt>execution::bulk_execute</tt> denotes a customisation point
  30. * object. If <tt>is_convertible_v<N, size_t></tt> is true, then the expression
  31. * <tt>execution::bulk_execute(S, F, N)</tt> for some subexpressions
  32. * <tt>S</tt>, <tt>F</tt>, and <tt>N</tt> is expression-equivalent to:
  33. *
  34. * @li <tt>S.bulk_execute(F, N)</tt>, if that expression is valid. If the
  35. * function selected does not execute <tt>N</tt> invocations of the function
  36. * object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward progress
  37. * guarantee <tt>asio::query(S, execution::bulk_guarantee)</tt>, and
  38. * the result of that function does not model <tt>sender<void></tt>, the
  39. * program is ill-formed with no diagnostic required.
  40. *
  41. * @li Otherwise, <tt>bulk_execute(S, F, N)</tt>, if that expression is valid,
  42. * with overload resolution performed in a context that includes the
  43. * declaration <tt>void bulk_execute();</tt> and that does not include a
  44. * declaration of <tt>execution::bulk_execute</tt>. If the function selected
  45. * by overload resolution does not execute <tt>N</tt> invocations of the
  46. * function object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward
  47. * progress guarantee <tt>asio::query(E,
  48. * execution::bulk_guarantee)</tt>, and the result of that function does not
  49. * model <tt>sender<void></tt>, the program is ill-formed with no diagnostic
  50. * required.
  51. *
  52. * @li Otherwise, if the types <tt>F</tt> and
  53. * <tt>executor_index_t<remove_cvref_t<S>></tt> model <tt>invocable</tt> and
  54. * if <tt>asio::query(S, execution::bulk_guarantee)</tt> equals
  55. * <tt>execution::bulk_guarantee.unsequenced</tt>, then
  56. *
  57. * - Evaluates <tt>DECAY_COPY(std::forward<decltype(F)>(F))</tt> on the
  58. * calling thread to create a function object <tt>cf</tt>. [Note:
  59. * Additional copies of <tt>cf</tt> may subsequently be created. --end
  60. * note.]
  61. *
  62. * - For each value of <tt>i</tt> in <tt>N</tt>, <tt>cf(i)</tt> (or copy of
  63. * <tt>cf</tt>)) will be invoked at most once by an execution agent that is
  64. * unique for each value of <tt>i</tt>.
  65. *
  66. * - May block pending completion of one or more invocations of <tt>cf</tt>.
  67. *
  68. * - Synchronizes with (C++Std [intro.multithread]) the invocations of
  69. * <tt>cf</tt>.
  70. *
  71. * @li Otherwise, <tt>execution::bulk_execute(S, F, N)</tt> is ill-formed.
  72. */
  73. inline constexpr unspecified bulk_execute = unspecified;
  74. /// A type trait that determines whether a @c bulk_execute expression is
  75. /// well-formed.
  76. /**
  77. * Class template @c can_bulk_execute is a trait that is derived from @c
  78. * true_type if the expression <tt>execution::bulk_execute(std::declval<S>(),
  79. * std::declval<F>(), std::declval<N>)</tt> is well formed; otherwise @c
  80. * false_type.
  81. */
  82. template <typename S, typename F, typename N>
  83. struct can_bulk_execute :
  84. integral_constant<bool, automatically_determined>
  85. {
  86. };
  87. } // namespace execution
  88. } // namespace asio
  89. #else // defined(GENERATING_DOCUMENTATION)
  90. namespace asio_execution_bulk_execute_fn {
  91. using asio::declval;
  92. using asio::enable_if;
  93. using asio::execution::bulk_guarantee_t;
  94. using asio::execution::detail::bulk_sender;
  95. using asio::execution::executor_index;
  96. using asio::execution::is_sender;
  97. using asio::is_convertible;
  98. using asio::is_same;
  99. using asio::remove_cvref;
  100. using asio::result_of;
  101. using asio::traits::bulk_execute_free;
  102. using asio::traits::bulk_execute_member;
  103. using asio::traits::static_require;
  104. void bulk_execute();
  105. enum overload_type
  106. {
  107. call_member,
  108. call_free,
  109. adapter,
  110. ill_formed
  111. };
  112. template <typename S, typename Args, typename = void, typename = void,
  113. typename = void, typename = void, typename = void, typename = void>
  114. struct call_traits
  115. {
  116. ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
  117. ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
  118. typedef void result_type;
  119. };
  120. template <typename S, typename F, typename N>
  121. struct call_traits<S, void(F, N),
  122. typename enable_if<
  123. is_convertible<N, std::size_t>::value
  124. >::type,
  125. typename enable_if<
  126. bulk_execute_member<S, F, N>::is_valid
  127. >::type,
  128. typename enable_if<
  129. is_sender<
  130. typename bulk_execute_member<S, F, N>::result_type
  131. >::value
  132. >::type> :
  133. bulk_execute_member<S, F, N>
  134. {
  135. ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
  136. };
  137. template <typename S, typename F, typename N>
  138. struct call_traits<S, void(F, N),
  139. typename enable_if<
  140. is_convertible<N, std::size_t>::value
  141. >::type,
  142. typename enable_if<
  143. !bulk_execute_member<S, F, N>::is_valid
  144. >::type,
  145. typename enable_if<
  146. bulk_execute_free<S, F, N>::is_valid
  147. >::type,
  148. typename enable_if<
  149. is_sender<
  150. typename bulk_execute_free<S, F, N>::result_type
  151. >::value
  152. >::type> :
  153. bulk_execute_free<S, F, N>
  154. {
  155. ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
  156. };
  157. template <typename S, typename F, typename N>
  158. struct call_traits<S, void(F, N),
  159. typename enable_if<
  160. is_convertible<N, std::size_t>::value
  161. >::type,
  162. typename enable_if<
  163. !bulk_execute_member<S, F, N>::is_valid
  164. >::type,
  165. typename enable_if<
  166. !bulk_execute_free<S, F, N>::is_valid
  167. >::type,
  168. typename enable_if<
  169. is_sender<S>::value
  170. >::type,
  171. typename enable_if<
  172. is_same<
  173. typename result_of<
  174. F(typename executor_index<typename remove_cvref<S>::type>::type)
  175. >::type,
  176. typename result_of<
  177. F(typename executor_index<typename remove_cvref<S>::type>::type)
  178. >::type
  179. >::value
  180. >::type,
  181. typename enable_if<
  182. static_require<S, bulk_guarantee_t::unsequenced_t>::is_valid
  183. >::type>
  184. {
  185. ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
  186. ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
  187. typedef bulk_sender<S, F, N> result_type;
  188. };
  189. struct impl
  190. {
  191. #if defined(ASIO_HAS_MOVE)
  192. template <typename S, typename F, typename N>
  193. ASIO_CONSTEXPR typename enable_if<
  194. call_traits<S, void(F, N)>::overload == call_member,
  195. typename call_traits<S, void(F, N)>::result_type
  196. >::type
  197. operator()(S&& s, F&& f, N&& n) const
  198. ASIO_NOEXCEPT_IF((
  199. call_traits<S, void(F, N)>::is_noexcept))
  200. {
  201. return ASIO_MOVE_CAST(S)(s).bulk_execute(
  202. ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
  203. }
  204. template <typename S, typename F, typename N>
  205. ASIO_CONSTEXPR typename enable_if<
  206. call_traits<S, void(F, N)>::overload == call_free,
  207. typename call_traits<S, void(F, N)>::result_type
  208. >::type
  209. operator()(S&& s, F&& f, N&& n) const
  210. ASIO_NOEXCEPT_IF((
  211. call_traits<S, void(F, N)>::is_noexcept))
  212. {
  213. return bulk_execute(ASIO_MOVE_CAST(S)(s),
  214. ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
  215. }
  216. template <typename S, typename F, typename N>
  217. ASIO_CONSTEXPR typename enable_if<
  218. call_traits<S, void(F, N)>::overload == adapter,
  219. typename call_traits<S, void(F, N)>::result_type
  220. >::type
  221. operator()(S&& s, F&& f, N&& n) const
  222. ASIO_NOEXCEPT_IF((
  223. call_traits<S, void(F, N)>::is_noexcept))
  224. {
  225. return typename call_traits<S, void(F, N)>::result_type(
  226. ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(F)(f),
  227. ASIO_MOVE_CAST(N)(n));
  228. }
  229. #else // defined(ASIO_HAS_MOVE)
  230. template <typename S, typename F, typename N>
  231. ASIO_CONSTEXPR typename enable_if<
  232. call_traits<S, void(const F&, const N&)>::overload == call_member,
  233. typename call_traits<S, void(const F&, const N&)>::result_type
  234. >::type
  235. operator()(S& s, const F& f, const N& n) const
  236. ASIO_NOEXCEPT_IF((
  237. call_traits<S, void(const F&, const N&)>::is_noexcept))
  238. {
  239. return s.bulk_execute(ASIO_MOVE_CAST(F)(f),
  240. ASIO_MOVE_CAST(N)(n));
  241. }
  242. template <typename S, typename F, typename N>
  243. ASIO_CONSTEXPR typename enable_if<
  244. call_traits<S, void(const F&, const N&)>::overload == call_member,
  245. typename call_traits<S, void(const F&, const N&)>::result_type
  246. >::type
  247. operator()(const S& s, const F& f, const N& n) const
  248. ASIO_NOEXCEPT_IF((
  249. call_traits<S, void(const F&, const N&)>::is_noexcept))
  250. {
  251. return s.bulk_execute(ASIO_MOVE_CAST(F)(f),
  252. ASIO_MOVE_CAST(N)(n));
  253. }
  254. template <typename S, typename F, typename N>
  255. ASIO_CONSTEXPR typename enable_if<
  256. call_traits<S, void(const F&, const N&)>::overload == call_free,
  257. typename call_traits<S, void(const F&, const N&)>::result_type
  258. >::type
  259. operator()(S& s, const F& f, const N& n) const
  260. ASIO_NOEXCEPT_IF((
  261. call_traits<S, void(const F&, const N&)>::is_noexcept))
  262. {
  263. return bulk_execute(s, ASIO_MOVE_CAST(F)(f),
  264. ASIO_MOVE_CAST(N)(n));
  265. }
  266. template <typename S, typename F, typename N>
  267. ASIO_CONSTEXPR typename enable_if<
  268. call_traits<S, void(const F&, const N&)>::overload == call_free,
  269. typename call_traits<S, void(const F&, const N&)>::result_type
  270. >::type
  271. operator()(const S& s, const F& f, const N& n) const
  272. ASIO_NOEXCEPT_IF((
  273. call_traits<S, void(const F&, const N&)>::is_noexcept))
  274. {
  275. return bulk_execute(s, ASIO_MOVE_CAST(F)(f),
  276. ASIO_MOVE_CAST(N)(n));
  277. }
  278. template <typename S, typename F, typename N>
  279. ASIO_CONSTEXPR typename enable_if<
  280. call_traits<S, void(const F&, const N&)>::overload == adapter,
  281. typename call_traits<S, void(const F&, const N&)>::result_type
  282. >::type
  283. operator()(S& s, const F& f, const N& n) const
  284. ASIO_NOEXCEPT_IF((
  285. call_traits<S, void(const F&, const N&)>::is_noexcept))
  286. {
  287. return typename call_traits<S, void(const F&, const N&)>::result_type(
  288. s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
  289. }
  290. template <typename S, typename F, typename N>
  291. ASIO_CONSTEXPR typename enable_if<
  292. call_traits<S, void(const F&, const N&)>::overload == adapter,
  293. typename call_traits<S, void(const F&, const N&)>::result_type
  294. >::type
  295. operator()(const S& s, const F& f, const N& n) const
  296. ASIO_NOEXCEPT_IF((
  297. call_traits<S, void(const F&, const N&)>::is_noexcept))
  298. {
  299. return typename call_traits<S, void(const F&, const N&)>::result_type(
  300. s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));
  301. }
  302. #endif // defined(ASIO_HAS_MOVE)
  303. };
  304. template <typename T = impl>
  305. struct static_instance
  306. {
  307. static const T instance;
  308. };
  309. template <typename T>
  310. const T static_instance<T>::instance = {};
  311. } // namespace asio_execution_bulk_execute_fn
  312. namespace asio {
  313. namespace execution {
  314. namespace {
  315. static ASIO_CONSTEXPR
  316. const asio_execution_bulk_execute_fn::impl& bulk_execute =
  317. asio_execution_bulk_execute_fn::static_instance<>::instance;
  318. } // namespace
  319. template <typename S, typename F, typename N>
  320. struct can_bulk_execute :
  321. integral_constant<bool,
  322. asio_execution_bulk_execute_fn::call_traits<
  323. S, void(F, N)>::overload !=
  324. asio_execution_bulk_execute_fn::ill_formed>
  325. {
  326. };
  327. #if defined(ASIO_HAS_VARIABLE_TEMPLATES)
  328. template <typename S, typename F, typename N>
  329. constexpr bool can_bulk_execute_v = can_bulk_execute<S, F, N>::value;
  330. #endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
  331. template <typename S, typename F, typename N>
  332. struct is_nothrow_bulk_execute :
  333. integral_constant<bool,
  334. asio_execution_bulk_execute_fn::call_traits<
  335. S, void(F, N)>::is_noexcept>
  336. {
  337. };
  338. #if defined(ASIO_HAS_VARIABLE_TEMPLATES)
  339. template <typename S, typename F, typename N>
  340. constexpr bool is_nothrow_bulk_execute_v
  341. = is_nothrow_bulk_execute<S, F, N>::value;
  342. #endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
  343. template <typename S, typename F, typename N>
  344. struct bulk_execute_result
  345. {
  346. typedef typename asio_execution_bulk_execute_fn::call_traits<
  347. S, void(F, N)>::result_type type;
  348. };
  349. } // namespace execution
  350. } // namespace asio
  351. #endif // defined(GENERATING_DOCUMENTATION)
  352. #include "asio/detail/pop_options.hpp"
  353. #endif // ASIO_EXECUTION_BULK_EXECUTE_HPP