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