1 // 2 // execution/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_EXECUTE_HPP 12 #define BOOST_ASIO_EXECUTION_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/detail/as_invocable.hpp> 21 #include <boost/asio/execution/detail/as_receiver.hpp> 22 #include <boost/asio/traits/execute_member.hpp> 23 #include <boost/asio/traits/execute_free.hpp> 24 25 #include <boost/asio/detail/push_options.hpp> 26 27 #if defined(GENERATING_DOCUMENTATION) 28 29 namespace boost { 30 namespace asio { 31 namespace execution { 32 33 /// A customisation point that executes a function on an executor. 34 /** 35 * The name <tt>execution::execute</tt> denotes a customisation point object. 36 * 37 * For some subexpressions <tt>e</tt> and <tt>f</tt>, let <tt>E</tt> be a type 38 * such that <tt>decltype((e))</tt> is <tt>E</tt> and let <tt>F</tt> be a type 39 * such that <tt>decltype((f))</tt> is <tt>F</tt>. The expression 40 * <tt>execution::execute(e, f)</tt> is ill-formed if <tt>F</tt> does not model 41 * <tt>invocable</tt>, or if <tt>E</tt> does not model either <tt>executor</tt> 42 * or <tt>sender</tt>. Otherwise, it is expression-equivalent to: 43 * 44 * @li <tt>e.execute(f)</tt>, if that expression is valid. If the function 45 * selected does not execute the function object <tt>f</tt> on the executor 46 * <tt>e</tt>, the program is ill-formed with no diagnostic required. 47 * 48 * @li Otherwise, <tt>execute(e, f)</tt>, if that expression is valid, with 49 * overload resolution performed in a context that includes the declaration 50 * <tt>void execute();</tt> and that does not include a declaration of 51 * <tt>execution::execute</tt>. If the function selected by overload 52 * resolution does not execute the function object <tt>f</tt> on the executor 53 * <tt>e</tt>, the program is ill-formed with no diagnostic required. 54 */ 55 inline constexpr unspecified execute = unspecified; 56 57 /// A type trait that determines whether a @c execute expression is well-formed. 58 /** 59 * Class template @c can_execute is a trait that is derived from 60 * @c true_type if the expression <tt>execution::execute(std::declval<T>(), 61 * std::declval<F>())</tt> is well formed; otherwise @c false_type. 62 */ 63 template <typename T, typename F> 64 struct can_execute : 65 integral_constant<bool, automatically_determined> 66 { 67 }; 68 69 } // namespace execution 70 } // namespace asio 71 } // namespace boost 72 73 #else // defined(GENERATING_DOCUMENTATION) 74 75 namespace boost { 76 namespace asio { 77 namespace execution { 78 79 template <typename T, typename R> 80 struct is_sender_to; 81 82 namespace detail { 83 84 template <typename S, typename R> 85 void submit_helper(BOOST_ASIO_MOVE_ARG(S) s, BOOST_ASIO_MOVE_ARG(R) r); 86 87 } // namespace detail 88 } // namespace execution 89 } // namespace asio 90 } // namespace boost 91 namespace asio_execution_execute_fn { 92 93 using boost::asio::conditional; 94 using boost::asio::decay; 95 using boost::asio::declval; 96 using boost::asio::enable_if; 97 using boost::asio::execution::detail::as_receiver; 98 using boost::asio::execution::detail::is_as_invocable; 99 using boost::asio::execution::is_sender_to; 100 using boost::asio::false_type; 101 using boost::asio::result_of; 102 using boost::asio::traits::execute_free; 103 using boost::asio::traits::execute_member; 104 using boost::asio::true_type; 105 using boost::asio::void_type; 106 107 void execute(); 108 109 enum overload_type 110 { 111 call_member, 112 call_free, 113 adapter, 114 ill_formed 115 }; 116 117 template <typename Impl, typename T, typename F, typename = void, 118 typename = void, typename = void, typename = void, typename = void> 119 struct call_traits 120 { 121 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); 122 }; 123 124 template <typename Impl, typename T, typename F> 125 struct call_traits<Impl, T, void(F), 126 typename enable_if< 127 execute_member<typename Impl::template proxy<T>::type, F>::is_valid 128 >::type> : 129 execute_member<typename Impl::template proxy<T>::type, F> 130 { 131 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); 132 }; 133 134 template <typename Impl, typename T, typename F> 135 struct call_traits<Impl, T, void(F), 136 typename enable_if< 137 !execute_member<typename Impl::template proxy<T>, F>::is_valid 138 >::type, 139 typename enable_if< 140 execute_free<T, F>::is_valid 141 >::type> : 142 execute_free<T, F> 143 { 144 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); 145 }; 146 147 template <typename Impl, typename T, typename F> 148 struct call_traits<Impl, T, void(F), 149 typename enable_if< 150 !execute_member<typename Impl::template proxy<T>::type, F>::is_valid 151 >::type, 152 typename enable_if< 153 !execute_free<T, F>::is_valid 154 >::type, 155 typename void_type< 156 typename result_of<typename decay<F>::type&()>::type 157 >::type, 158 typename enable_if< 159 !is_as_invocable<typename decay<F>::type>::value 160 >::type, 161 typename enable_if< 162 is_sender_to<T, as_receiver<typename decay<F>::type, T> >::value 163 >::type> 164 { 165 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); 166 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); 167 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); 168 typedef void result_type; 169 }; 170 171 struct impl 172 { 173 template <typename T> 174 struct proxy 175 { 176 #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) 177 struct type 178 { 179 template <typename F> 180 auto execute(BOOST_ASIO_MOVE_ARG(F) f) 181 noexcept( 182 noexcept( 183 declval<typename conditional<true, T, F>::type>().execute( 184 BOOST_ASIO_MOVE_CAST(F)(f)) 185 ) 186 ) 187 -> decltype( 188 declval<typename conditional<true, T, F>::type>().execute( 189 BOOST_ASIO_MOVE_CAST(F)(f)) 190 ); 191 }; 192 #else // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) 193 typedef T type; 194 #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) 195 }; 196 197 template <typename T, typename F> 198 BOOST_ASIO_CONSTEXPR typename enable_if< 199 call_traits<impl, T, void(F)>::overload == call_member, 200 typename call_traits<impl, T, void(F)>::result_type 201 >::type operator ()asio_execution_execute_fn::impl202 operator()( 203 BOOST_ASIO_MOVE_ARG(T) t, 204 BOOST_ASIO_MOVE_ARG(F) f) const 205 BOOST_ASIO_NOEXCEPT_IF(( 206 call_traits<impl, T, void(F)>::is_noexcept)) 207 { 208 return BOOST_ASIO_MOVE_CAST(T)(t).execute(BOOST_ASIO_MOVE_CAST(F)(f)); 209 } 210 211 template <typename T, typename F> 212 BOOST_ASIO_CONSTEXPR typename enable_if< 213 call_traits<impl, T, void(F)>::overload == call_free, 214 typename call_traits<impl, T, void(F)>::result_type 215 >::type operator ()asio_execution_execute_fn::impl216 operator()( 217 BOOST_ASIO_MOVE_ARG(T) t, 218 BOOST_ASIO_MOVE_ARG(F) f) const 219 BOOST_ASIO_NOEXCEPT_IF(( 220 call_traits<impl, T, void(F)>::is_noexcept)) 221 { 222 return execute(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(F)(f)); 223 } 224 225 template <typename T, typename F> 226 BOOST_ASIO_CONSTEXPR typename enable_if< 227 call_traits<impl, T, void(F)>::overload == adapter, 228 typename call_traits<impl, T, void(F)>::result_type 229 >::type operator ()asio_execution_execute_fn::impl230 operator()( 231 BOOST_ASIO_MOVE_ARG(T) t, 232 BOOST_ASIO_MOVE_ARG(F) f) const 233 BOOST_ASIO_NOEXCEPT_IF(( 234 call_traits<impl, T, void(F)>::is_noexcept)) 235 { 236 return boost::asio::execution::detail::submit_helper( 237 BOOST_ASIO_MOVE_CAST(T)(t), 238 as_receiver<typename decay<F>::type, T>( 239 BOOST_ASIO_MOVE_CAST(F)(f), 0)); 240 } 241 }; 242 243 template <typename T = impl> 244 struct static_instance 245 { 246 static const T instance; 247 }; 248 249 template <typename T> 250 const T static_instance<T>::instance = {}; 251 252 } // namespace asio_execution_execute_fn 253 namespace boost { 254 namespace asio { 255 namespace execution { 256 namespace { 257 258 static BOOST_ASIO_CONSTEXPR const asio_execution_execute_fn::impl& 259 execute = asio_execution_execute_fn::static_instance<>::instance; 260 261 } // namespace 262 263 typedef asio_execution_execute_fn::impl execute_t; 264 265 template <typename T, typename F> 266 struct can_execute : 267 integral_constant<bool, 268 asio_execution_execute_fn::call_traits< 269 execute_t, T, void(F)>::overload != 270 asio_execution_execute_fn::ill_formed> 271 { 272 }; 273 274 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 275 276 template <typename T, typename F> 277 constexpr bool can_execute_v = can_execute<T, F>::value; 278 279 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) 280 281 } // namespace execution 282 } // namespace asio 283 } // namespace boost 284 285 #endif // defined(GENERATING_DOCUMENTATION) 286 287 #include <boost/asio/detail/pop_options.hpp> 288 289 #endif // BOOST_ASIO_EXECUTION_EXECUTE_HPP 290