bulk_execute.hpp 13 KB

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