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