diff options
Diffstat (limited to 'boost/beast/core/detail/bind_handler.hpp')
-rw-r--r-- | boost/beast/core/detail/bind_handler.hpp | 335 |
1 files changed, 264 insertions, 71 deletions
diff --git a/boost/beast/core/detail/bind_handler.hpp b/boost/beast/core/detail/bind_handler.hpp index 8bacc921f7..db481757f9 100644 --- a/boost/beast/core/detail/bind_handler.hpp +++ b/boost/beast/core/detail/bind_handler.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -10,39 +10,44 @@ #ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP #define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP -#include <boost/beast/core/detail/integer_sequence.hpp> +#include <boost/beast/core/error.hpp> +#include <boost/beast/core/detail/tuple.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> +#include <boost/asio/handler_alloc_hook.hpp> #include <boost/asio/handler_continuation_hook.hpp> #include <boost/asio/handler_invoke_hook.hpp> #include <boost/core/ignore_unused.hpp> +#include <boost/mp11/integer_sequence.hpp> #include <boost/is_placeholder.hpp> #include <functional> +#include <type_traits> #include <utility> namespace boost { namespace beast { namespace detail { -/* Nullary handler that calls Handler with bound arguments. +//------------------------------------------------------------------------------ +// +// bind_handler +// +//------------------------------------------------------------------------------ - The bound handler provides the same io_context execution - guarantees as the original handler. -*/ template<class Handler, class... Args> -class bound_handler +class bind_wrapper { - // Can't friend partial specializations, - // so we just friend the whole thing. - template<class T, class Executor> - friend struct boost::asio::associated_executor; - - using args_type = std::tuple< - typename std::decay<Args>::type...>; + using args_type = detail::tuple<Args...>; Handler h_; args_type args_; + template<class T, class Executor> + friend struct net::associated_executor; + + template<class T, class Allocator> + friend struct net::associated_allocator; + template<class Arg, class Vals> static typename std::enable_if< @@ -62,13 +67,12 @@ class bound_handler typename std::enable_if< std::is_placeholder<typename std::decay<Arg>::type>::value != 0, - typename std::tuple_element< - std::is_placeholder< - typename std::decay<Arg>::type>::value - 1, - Vals>>::type::type&& + tuple_element<std::is_placeholder< + typename std::decay<Arg>::type>::value - 1, + Vals>>::type&& extract(Arg&&, Vals&& vals) { - return std::get<std::is_placeholder< + return detail::get<std::is_placeholder< typename std::decay<Arg>::type>::value - 1>( std::forward<Vals>(vals)); } @@ -78,30 +82,27 @@ class bound_handler typename std::enable_if< boost::is_placeholder<typename std::decay<Arg>::type>::value != 0, - typename std::tuple_element< - boost::is_placeholder< - typename std::decay<Arg>::type>::value - 1, - Vals>>::type::type&& + tuple_element<boost::is_placeholder< + typename std::decay<Arg>::type>::value - 1, + Vals>>::type&& extract(Arg&&, Vals&& vals) { - return std::get<boost::is_placeholder< + return detail::get<boost::is_placeholder< typename std::decay<Arg>::type>::value - 1>( std::forward<Vals>(vals)); } - template< - class ArgsTuple, - std::size_t... S> + template<class ArgsTuple, std::size_t... S> static void invoke( Handler& h, ArgsTuple& args, - std::tuple<>&&, - index_sequence<S...>) + tuple<>&&, + mp11::index_sequence<S...>) { boost::ignore_unused(args); - h(std::get<S>(std::move(args))...); + h(detail::get<S>(std::move(args))...); } template< @@ -114,104 +115,296 @@ class bound_handler Handler& h, ArgsTuple& args, ValsTuple&& vals, - index_sequence<S...>) + mp11::index_sequence<S...>) { boost::ignore_unused(args); boost::ignore_unused(vals); - h(extract(std::get<S>(std::move(args)), + h(extract(detail::get<S>(std::move(args)), std::forward<ValsTuple>(vals))...); } public: - using result_type = void; + using result_type = void; // asio needs this - using allocator_type = - boost::asio::associated_allocator_t<Handler>; + bind_wrapper(bind_wrapper&&) = default; + bind_wrapper(bind_wrapper const&) = default; - bound_handler(bound_handler&&) = default; - bound_handler(bound_handler const&) = delete; - - template<class DeducedHandler> + template< + class DeducedHandler, + class... Args_> explicit - bound_handler( - DeducedHandler&& handler, Args&&... args) + bind_wrapper( + DeducedHandler&& handler, + Args_&&... args) : h_(std::forward<DeducedHandler>(handler)) - , args_(std::forward<Args>(args)...) + , args_(std::forward<Args_>(args)...) + { + } + + template<class... Values> + void + operator()(Values&&... values) { + invoke(h_, args_, + tuple<Values&&...>( + std::forward<Values>(values)...), + mp11::index_sequence_for<Args...>()); } - allocator_type - get_allocator() const noexcept + // + + template<class Function> + friend + void asio_handler_invoke( + Function&& f, bind_wrapper* op) { - return (boost::asio::get_associated_allocator)(h_); + using net::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); } friend - bool - asio_handler_is_continuation(bound_handler* h) + bool asio_handler_is_continuation( + bind_wrapper* op) { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation(std::addressof(h->h_)); + using net::asio_handler_is_continuation; + return asio_handler_is_continuation( + std::addressof(op->h_)); } - template<class Function> friend - void asio_handler_invoke(Function&& f, bound_handler* h) + void* asio_handler_allocate( + std::size_t size, bind_wrapper* op) { - using boost::asio::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(h->h_)); + using net::asio_handler_allocate; + return asio_handler_allocate( + size, std::addressof(op->h_)); } - template<class... Values> + 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 Handler, class... Args> +class bind_back_wrapper; + +template<class Handler, class... Args> +class bind_front_wrapper; + +//------------------------------------------------------------------------------ +// +// bind_front +// +//------------------------------------------------------------------------------ + +template<class Handler, class... Args> +class bind_front_wrapper +{ + Handler h_; + detail::tuple<Args...> args_; + + template<class T, class Executor> + friend struct net::associated_executor; + + template<class T, class Allocator> + friend struct net::associated_allocator; + + template<std::size_t... I, class... Ts> void - operator()(Values&&... values) + invoke( + std::false_type, + mp11::index_sequence<I...>, + Ts&&... ts) { - invoke(h_, args_, - std::forward_as_tuple( - std::forward<Values>(values)...), - index_sequence_for<Args...>()); + h_( detail::get<I>(std::move(args_))..., + std::forward<Ts>(ts)...); } - template<class... Values> + template<std::size_t... I, class... Ts> void - operator()(Values&&... values) const + invoke( + std::true_type, + mp11::index_sequence<I...>, + Ts&&... ts) { - invoke(h_, args_, - std::forward_as_tuple( - std::forward<Values>(values)...), - index_sequence_for<Args...>()); + std::mem_fn(h_)( + detail::get<I>(std::move(args_))..., + std::forward<Ts>(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<class Handler_, class... Args_> + bind_front_wrapper( + Handler_&& handler, + Args_&&... args) + : h_(std::forward<Handler_>(handler)) + , args_(std::forward<Args_>(args)...) + { + } + + template<class... Ts> + void operator()(Ts&&... ts) + { + invoke( + std::is_member_function_pointer<Handler>{}, + mp11::index_sequence_for<Args...>{}, + std::forward<Ts>(ts)...); + } + + // + + template<class Function> + 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<class Handler, class... Args, class Executor> struct associated_executor< - beast::detail::bound_handler<Handler, Args...>, Executor> + beast::detail::bind_wrapper<Handler, Args...>, Executor> { using type = typename associated_executor<Handler, Executor>::type; static type - get(beast::detail::bound_handler<Handler, Args...> const& h, - Executor const& ex = Executor()) noexcept + get(beast::detail::bind_wrapper<Handler, Args...> const& op, + Executor const& ex = Executor{}) noexcept { return associated_executor< - Handler, Executor>::get(h.h_, ex); + Handler, Executor>::get(op.h_, ex); } }; -} // asio +template<class Handler, class... Args, class Executor> +struct associated_executor< + beast::detail::bind_front_wrapper<Handler, Args...>, Executor> +{ + using type = typename + associated_executor<Handler, Executor>::type; + + static + type + get(beast::detail::bind_front_wrapper<Handler, Args...> const& op, + Executor const& ex = Executor{}) noexcept + { + return associated_executor< + Handler, Executor>::get(op.h_, ex); + } +}; + +// + +template<class Handler, class... Args, class Allocator> +struct associated_allocator< + beast::detail::bind_wrapper<Handler, Args...>, Allocator> +{ + using type = typename + associated_allocator<Handler, Allocator>::type; + + static + type + get(beast::detail::bind_wrapper<Handler, Args...> const& op, + Allocator const& alloc = Allocator{}) noexcept + { + return associated_allocator< + Handler, Allocator>::get(op.h_, alloc); + } +}; + +template<class Handler, class... Args, class Allocator> +struct associated_allocator< + beast::detail::bind_front_wrapper<Handler, Args...>, Allocator> +{ + using type = typename + associated_allocator<Handler, Allocator>::type; + + static + type + get(beast::detail::bind_front_wrapper<Handler, Args...> 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<class Handler, class... Args> void -bind(boost::beast::detail::bound_handler< +bind(boost::beast::detail::bind_wrapper< Handler, Args...>, ...) = delete; + +template<class Handler, class... Args> +void +bind(boost::beast::detail::bind_front_wrapper< + Handler, Args...>, ...) = delete; + } // std +//------------------------------------------------------------------------------ + #endif |