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