// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP #define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace beast { namespace detail { //------------------------------------------------------------------------------ // // bind_handler // //------------------------------------------------------------------------------ template class bind_wrapper { using args_type = detail::tuple; Handler h_; args_type args_; template friend struct net::associated_executor; template friend struct net::associated_allocator; template static typename std::enable_if< std::is_placeholder::type>::value == 0 && boost::is_placeholder::type>::value == 0, Arg&&>::type extract(Arg&& arg, Vals&& vals) { boost::ignore_unused(vals); return std::forward(arg); } template static typename std::enable_if< std::is_placeholder::type>::value != 0, tuple_element::type>::value - 1, Vals>>::type&& extract(Arg&&, Vals&& vals) { return detail::get::type>::value - 1>( std::forward(vals)); } template static typename std::enable_if< boost::is_placeholder::type>::value != 0, tuple_element::type>::value - 1, Vals>>::type&& extract(Arg&&, Vals&& vals) { return detail::get::type>::value - 1>( std::forward(vals)); } template static void invoke( Handler& h, ArgsTuple& args, tuple<>&&, mp11::index_sequence) { boost::ignore_unused(args); h(detail::get(std::move(args))...); } template< class ArgsTuple, class ValsTuple, std::size_t... S> static void invoke( Handler& h, ArgsTuple& args, ValsTuple&& vals, mp11::index_sequence) { boost::ignore_unused(args); boost::ignore_unused(vals); h(extract(detail::get(std::move(args)), std::forward(vals))...); } public: using result_type = void; // asio needs this bind_wrapper(bind_wrapper&&) = default; bind_wrapper(bind_wrapper const&) = default; template< class DeducedHandler, class... Args_> explicit bind_wrapper( DeducedHandler&& handler, Args_&&... args) : h_(std::forward(handler)) , args_(std::forward(args)...) { } template void operator()(Values&&... values) { invoke(h_, args_, tuple( std::forward(values)...), mp11::index_sequence_for()); } // template friend void asio_handler_invoke( Function&& f, bind_wrapper* op) { using net::asio_handler_invoke; asio_handler_invoke(f, std::addressof(op->h_)); } friend bool asio_handler_is_continuation( bind_wrapper* op) { using net::asio_handler_is_continuation; return asio_handler_is_continuation( std::addressof(op->h_)); } friend void* asio_handler_allocate( std::size_t size, bind_wrapper* op) { using net::asio_handler_allocate; return asio_handler_allocate( size, std::addressof(op->h_)); } friend void asio_handler_deallocate( void* p, std::size_t size, bind_wrapper* op) { using net::asio_handler_deallocate; asio_handler_deallocate( p, size, std::addressof(op->h_)); } }; template class bind_back_wrapper; template class bind_front_wrapper; //------------------------------------------------------------------------------ // // bind_front // //------------------------------------------------------------------------------ template class bind_front_wrapper { Handler h_; detail::tuple args_; template friend struct net::associated_executor; template friend struct net::associated_allocator; template void invoke( std::false_type, mp11::index_sequence, Ts&&... ts) { h_( detail::get(std::move(args_))..., std::forward(ts)...); } template void invoke( std::true_type, mp11::index_sequence, Ts&&... ts) { std::mem_fn(h_)( detail::get(std::move(args_))..., std::forward(ts)...); } public: using result_type = void; // asio needs this bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper const&) = default; template bind_front_wrapper( Handler_&& handler, Args_&&... args) : h_(std::forward(handler)) , args_(std::forward(args)...) { } template void operator()(Ts&&... ts) { invoke( std::is_member_function_pointer{}, mp11::index_sequence_for{}, std::forward(ts)...); } // template friend void asio_handler_invoke( Function&& f, bind_front_wrapper* op) { using net::asio_handler_invoke; asio_handler_invoke(f, std::addressof(op->h_)); } friend bool asio_handler_is_continuation( bind_front_wrapper* op) { using net::asio_handler_is_continuation; return asio_handler_is_continuation( std::addressof(op->h_)); } friend void* asio_handler_allocate( std::size_t size, bind_front_wrapper* op) { using net::asio_handler_allocate; return asio_handler_allocate( size, std::addressof(op->h_)); } friend void asio_handler_deallocate( void* p, std::size_t size, bind_front_wrapper* op) { using net::asio_handler_deallocate; asio_handler_deallocate( p, size, std::addressof(op->h_)); } }; } // detail } // beast } // boost //------------------------------------------------------------------------------ namespace boost { namespace asio { template struct associated_executor< beast::detail::bind_wrapper, Executor> { using type = typename associated_executor::type; static type get(beast::detail::bind_wrapper const& op, Executor const& ex = Executor{}) noexcept { return associated_executor< Handler, Executor>::get(op.h_, ex); } }; template struct associated_executor< beast::detail::bind_front_wrapper, Executor> { using type = typename associated_executor::type; static type get(beast::detail::bind_front_wrapper const& op, Executor const& ex = Executor{}) noexcept { return associated_executor< Handler, Executor>::get(op.h_, ex); } }; // template struct associated_allocator< beast::detail::bind_wrapper, Allocator> { using type = typename associated_allocator::type; static type get(beast::detail::bind_wrapper const& op, Allocator const& alloc = Allocator{}) noexcept { return associated_allocator< Handler, Allocator>::get(op.h_, alloc); } }; template struct associated_allocator< beast::detail::bind_front_wrapper, Allocator> { using type = typename associated_allocator::type; static type get(beast::detail::bind_front_wrapper const& op, Allocator const& alloc = Allocator{}) noexcept { return associated_allocator< Handler, Allocator>::get(op.h_, alloc); } }; } // asio } // boost //------------------------------------------------------------------------------ namespace std { // VFALCO Using std::bind on a completion handler will // cause undefined behavior later, because the executor // associated with the handler is not propagated to the // wrapper returned by std::bind; these overloads are // deleted to prevent mistakes. If this creates a problem // please contact me. template void bind(boost::beast::detail::bind_wrapper< Handler, Args...>, ...) = delete; template void bind(boost::beast::detail::bind_front_wrapper< Handler, Args...>, ...) = delete; } // std //------------------------------------------------------------------------------ #endif