1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // Official repository: https://github.com/boostorg/beast 8 // 9 10 #ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP 11 #define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP 12 13 #include <boost/beast/core/error.hpp> 14 #include <boost/beast/core/detail/tuple.hpp> 15 #include <boost/asio/associated_allocator.hpp> 16 #include <boost/asio/associated_executor.hpp> 17 #include <boost/asio/handler_alloc_hook.hpp> 18 #include <boost/asio/handler_continuation_hook.hpp> 19 #include <boost/asio/handler_invoke_hook.hpp> 20 #include <boost/core/ignore_unused.hpp> 21 #include <boost/mp11/integer_sequence.hpp> 22 #include <boost/is_placeholder.hpp> 23 #include <functional> 24 #include <type_traits> 25 #include <utility> 26 27 namespace boost { 28 namespace beast { 29 namespace detail { 30 31 //------------------------------------------------------------------------------ 32 // 33 // bind_handler 34 // 35 //------------------------------------------------------------------------------ 36 37 template<class Handler, class... Args> 38 class bind_wrapper 39 { 40 using args_type = detail::tuple<Args...>; 41 42 Handler h_; 43 args_type args_; 44 45 template<class T, class Executor> 46 friend struct net::associated_executor; 47 48 template<class T, class Allocator> 49 friend struct net::associated_allocator; 50 51 template<class Arg, class Vals> 52 static 53 typename std::enable_if< 54 std::is_placeholder<typename 55 std::decay<Arg>::type>::value == 0 && 56 boost::is_placeholder<typename 57 std::decay<Arg>::type>::value == 0, 58 Arg&&>::type extract(Arg && arg,Vals && vals)59 extract(Arg&& arg, Vals&& vals) 60 { 61 boost::ignore_unused(vals); 62 return std::forward<Arg>(arg); 63 } 64 65 template<class Arg, class Vals> 66 static 67 typename std::enable_if< 68 std::is_placeholder<typename 69 std::decay<Arg>::type>::value != 0, 70 tuple_element<std::is_placeholder< 71 typename std::decay<Arg>::type>::value - 1, 72 Vals>>::type&& extract(Arg &&,Vals && vals)73 extract(Arg&&, Vals&& vals) 74 { 75 return detail::get<std::is_placeholder< 76 typename std::decay<Arg>::type>::value - 1>( 77 std::forward<Vals>(vals)); 78 } 79 80 template<class Arg, class Vals> 81 static 82 typename std::enable_if< 83 boost::is_placeholder<typename 84 std::decay<Arg>::type>::value != 0, 85 tuple_element<boost::is_placeholder< 86 typename std::decay<Arg>::type>::value - 1, 87 Vals>>::type&& extract(Arg &&,Vals && vals)88 extract(Arg&&, Vals&& vals) 89 { 90 return detail::get<boost::is_placeholder< 91 typename std::decay<Arg>::type>::value - 1>( 92 std::forward<Vals>(vals)); 93 } 94 95 template<class ArgsTuple, std::size_t... S> 96 static 97 void invoke(Handler & h,ArgsTuple & args,tuple<> &&,mp11::index_sequence<S...>)98 invoke( 99 Handler& h, 100 ArgsTuple& args, 101 tuple<>&&, 102 mp11::index_sequence<S...>) 103 { 104 boost::ignore_unused(args); 105 h(detail::get<S>(std::move(args))...); 106 } 107 108 template< 109 class ArgsTuple, 110 class ValsTuple, 111 std::size_t... S> 112 static 113 void invoke(Handler & h,ArgsTuple & args,ValsTuple && vals,mp11::index_sequence<S...>)114 invoke( 115 Handler& h, 116 ArgsTuple& args, 117 ValsTuple&& vals, 118 mp11::index_sequence<S...>) 119 { 120 boost::ignore_unused(args); 121 boost::ignore_unused(vals); 122 h(extract(detail::get<S>(std::move(args)), 123 std::forward<ValsTuple>(vals))...); 124 } 125 126 public: 127 using result_type = void; // asio needs this 128 129 bind_wrapper(bind_wrapper&&) = default; 130 bind_wrapper(bind_wrapper const&) = default; 131 132 template< 133 class DeducedHandler, 134 class... Args_> 135 explicit bind_wrapper(DeducedHandler && handler,Args_ &&...args)136 bind_wrapper( 137 DeducedHandler&& handler, 138 Args_&&... args) 139 : h_(std::forward<DeducedHandler>(handler)) 140 , args_(std::forward<Args_>(args)...) 141 { 142 } 143 144 template<class... Values> 145 void operator ()(Values &&...values)146 operator()(Values&&... values) 147 { 148 invoke(h_, args_, 149 tuple<Values&&...>( 150 std::forward<Values>(values)...), 151 mp11::index_sequence_for<Args...>()); 152 } 153 154 // 155 156 template<class Function> 157 friend 158 boost::asio::asio_handler_invoke_is_deprecated asio_handler_invoke(Function && f,bind_wrapper * op)159 asio_handler_invoke( 160 Function&& f, bind_wrapper* op) 161 { 162 using boost::asio::asio_handler_invoke; 163 return asio_handler_invoke(f, std::addressof(op->h_)); 164 } 165 166 friend asio_handler_is_continuation(bind_wrapper * op)167 bool asio_handler_is_continuation( 168 bind_wrapper* op) 169 { 170 using boost::asio::asio_handler_is_continuation; 171 return asio_handler_is_continuation( 172 std::addressof(op->h_)); 173 } 174 175 friend 176 boost::asio::asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size,bind_wrapper * op)177 asio_handler_allocate( 178 std::size_t size, bind_wrapper* op) 179 { 180 using boost::asio::asio_handler_allocate; 181 return asio_handler_allocate( 182 size, std::addressof(op->h_)); 183 } 184 185 friend 186 boost::asio::asio_handler_deallocate_is_deprecated asio_handler_deallocate(void * p,std::size_t size,bind_wrapper * op)187 asio_handler_deallocate( 188 void* p, std::size_t size, bind_wrapper* op) 189 { 190 using boost::asio::asio_handler_deallocate; 191 return asio_handler_deallocate( 192 p, size, std::addressof(op->h_)); 193 } 194 }; 195 196 template<class Handler, class... Args> 197 class bind_back_wrapper; 198 199 template<class Handler, class... Args> 200 class bind_front_wrapper; 201 202 //------------------------------------------------------------------------------ 203 // 204 // bind_front 205 // 206 //------------------------------------------------------------------------------ 207 208 template<class Handler, class... Args> 209 class bind_front_wrapper 210 { 211 Handler h_; 212 detail::tuple<Args...> args_; 213 214 template<class T, class Executor> 215 friend struct net::associated_executor; 216 217 template<class T, class Allocator> 218 friend struct net::associated_allocator; 219 220 template<std::size_t... I, class... Ts> 221 void invoke(std::false_type,mp11::index_sequence<I...>,Ts &&...ts)222 invoke( 223 std::false_type, 224 mp11::index_sequence<I...>, 225 Ts&&... ts) 226 { 227 h_( detail::get<I>(std::move(args_))..., 228 std::forward<Ts>(ts)...); 229 } 230 231 template<std::size_t... I, class... Ts> 232 void invoke(std::true_type,mp11::index_sequence<I...>,Ts &&...ts)233 invoke( 234 std::true_type, 235 mp11::index_sequence<I...>, 236 Ts&&... ts) 237 { 238 std::mem_fn(h_)( 239 detail::get<I>(std::move(args_))..., 240 std::forward<Ts>(ts)...); 241 } 242 243 public: 244 using result_type = void; // asio needs this 245 246 bind_front_wrapper(bind_front_wrapper&&) = default; 247 bind_front_wrapper(bind_front_wrapper const&) = default; 248 249 template<class Handler_, class... Args_> bind_front_wrapper(Handler_ && handler,Args_ &&...args)250 bind_front_wrapper( 251 Handler_&& handler, 252 Args_&&... args) 253 : h_(std::forward<Handler_>(handler)) 254 , args_(std::forward<Args_>(args)...) 255 { 256 } 257 258 template<class... Ts> operator ()(Ts &&...ts)259 void operator()(Ts&&... ts) 260 { 261 invoke( 262 std::is_member_function_pointer<Handler>{}, 263 mp11::index_sequence_for<Args...>{}, 264 std::forward<Ts>(ts)...); 265 } 266 267 // 268 269 template<class Function> 270 friend 271 boost::asio::asio_handler_invoke_is_deprecated asio_handler_invoke(Function && f,bind_front_wrapper * op)272 asio_handler_invoke( 273 Function&& f, bind_front_wrapper* op) 274 { 275 using boost::asio::asio_handler_invoke; 276 return asio_handler_invoke(f, std::addressof(op->h_)); 277 } 278 279 friend asio_handler_is_continuation(bind_front_wrapper * op)280 bool asio_handler_is_continuation( 281 bind_front_wrapper* op) 282 { 283 using boost::asio::asio_handler_is_continuation; 284 return asio_handler_is_continuation( 285 std::addressof(op->h_)); 286 } 287 288 friend 289 boost::asio::asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size,bind_front_wrapper * op)290 asio_handler_allocate( 291 std::size_t size, bind_front_wrapper* op) 292 { 293 using boost::asio::asio_handler_allocate; 294 return asio_handler_allocate( 295 size, std::addressof(op->h_)); 296 } 297 298 friend 299 boost::asio::asio_handler_deallocate_is_deprecated asio_handler_deallocate(void * p,std::size_t size,bind_front_wrapper * op)300 asio_handler_deallocate( 301 void* p, std::size_t size, bind_front_wrapper* op) 302 { 303 using boost::asio::asio_handler_deallocate; 304 return asio_handler_deallocate( 305 p, size, std::addressof(op->h_)); 306 } 307 }; 308 309 } // detail 310 } // beast 311 } // boost 312 313 //------------------------------------------------------------------------------ 314 315 namespace boost { 316 namespace asio { 317 318 template<class Handler, class... Args, class Executor> 319 struct associated_executor< 320 beast::detail::bind_wrapper<Handler, Args...>, Executor> 321 { 322 using type = typename 323 associated_executor<Handler, Executor>::type; 324 325 static 326 type getboost::asio::associated_executor327 get(beast::detail::bind_wrapper<Handler, Args...> const& op, 328 Executor const& ex = Executor{}) noexcept 329 { 330 return associated_executor< 331 Handler, Executor>::get(op.h_, ex); 332 } 333 }; 334 335 template<class Handler, class... Args, class Executor> 336 struct associated_executor< 337 beast::detail::bind_front_wrapper<Handler, Args...>, Executor> 338 { 339 using type = typename 340 associated_executor<Handler, Executor>::type; 341 342 static 343 type getboost::asio::associated_executor344 get(beast::detail::bind_front_wrapper<Handler, Args...> const& op, 345 Executor const& ex = Executor{}) noexcept 346 { 347 return associated_executor< 348 Handler, Executor>::get(op.h_, ex); 349 } 350 }; 351 352 // 353 354 template<class Handler, class... Args, class Allocator> 355 struct associated_allocator< 356 beast::detail::bind_wrapper<Handler, Args...>, Allocator> 357 { 358 using type = typename 359 associated_allocator<Handler, Allocator>::type; 360 361 static 362 type getboost::asio::associated_allocator363 get(beast::detail::bind_wrapper<Handler, Args...> const& op, 364 Allocator const& alloc = Allocator{}) noexcept 365 { 366 return associated_allocator< 367 Handler, Allocator>::get(op.h_, alloc); 368 } 369 }; 370 371 template<class Handler, class... Args, class Allocator> 372 struct associated_allocator< 373 beast::detail::bind_front_wrapper<Handler, Args...>, Allocator> 374 { 375 using type = typename 376 associated_allocator<Handler, Allocator>::type; 377 378 static 379 type getboost::asio::associated_allocator380 get(beast::detail::bind_front_wrapper<Handler, Args...> const& op, 381 Allocator const& alloc = Allocator{}) noexcept 382 { 383 return associated_allocator< 384 Handler, Allocator>::get(op.h_, alloc); 385 } 386 }; 387 388 } // asio 389 } // boost 390 391 //------------------------------------------------------------------------------ 392 393 namespace std { 394 395 // VFALCO Using std::bind on a completion handler will 396 // cause undefined behavior later, because the executor 397 // associated with the handler is not propagated to the 398 // wrapper returned by std::bind; these overloads are 399 // deleted to prevent mistakes. If this creates a problem 400 // please contact me. 401 402 template<class Handler, class... Args> 403 void 404 bind(boost::beast::detail::bind_wrapper< 405 Handler, Args...>, ...) = delete; 406 407 template<class Handler, class... Args> 408 void 409 bind(boost::beast::detail::bind_front_wrapper< 410 Handler, Args...>, ...) = delete; 411 412 } // std 413 414 //------------------------------------------------------------------------------ 415 416 #endif 417