From 2afe929bb73e95ad5245032993f360a8d7c50633 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Tue, 11 Dec 2018 13:35:14 -0800 Subject: [PATCH] Fix bind_handler, bind_front_handler: This tidies up small corner cases and bugs with the bind_handler and bind_front_handler wrappers: * Legacy allocation hooks are deleted * Fixes for bind_front_handler specializations * Decay bound arguments first, to reduce template instantiations * Proper moving and forwarding of bound arguments and call parameters --- CHANGELOG.md | 1 + include/boost/beast/core/bind_handler.hpp | 14 +- .../boost/beast/core/detail/bind_handler.hpp | 265 +++++++----------- 3 files changed, 110 insertions(+), 170 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee89a19e..2a9e01ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Version 198: * Add buffer_traits.hpp, buffers_type * Tidy up experimental files * Tidy up core files +* Fix bind_handler, bind_front_handler API Changes: diff --git a/include/boost/beast/core/bind_handler.hpp b/include/boost/beast/core/bind_handler.hpp index 40b55dac..de4331f8 100644 --- a/include/boost/beast/core/bind_handler.hpp +++ b/include/boost/beast/core/bind_handler.hpp @@ -108,12 +108,16 @@ __implementation_defined__ #else auto #endif -bind_front_handler(Handler&& handler, Args&&... args) -> - detail::bind_front_wrapper::type, Args...> +bind_front_handler( + Handler&& handler, + Args&&... args) -> + detail::bind_front_wrapper< + typename std::decay::type, + typename std::decay::type...> { - return detail::bind_front_wrapper::type, Args...>( + return detail::bind_front_wrapper< + typename std::decay::type, + typename std::decay::type...>( std::forward(handler), std::forward(args)...); } diff --git a/include/boost/beast/core/detail/bind_handler.hpp b/include/boost/beast/core/detail/bind_handler.hpp index 411f8550..f498318b 100644 --- a/include/boost/beast/core/detail/bind_handler.hpp +++ b/include/boost/beast/core/detail/bind_handler.hpp @@ -37,8 +37,6 @@ class bind_wrapper Handler h_; args_type args_; - // Can't friend partial specializations, - // so we just friend the whole thing. template friend struct net::associated_executor; @@ -178,24 +176,6 @@ public: asio_handler_invoke(f, std::addressof(w->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_)); - } - friend bool asio_handler_is_continuation( bind_wrapper* op) @@ -206,19 +186,17 @@ public: } }; -//------------------------------------------------------------------------------ - template class bind_front_wrapper; +//------------------------------------------------------------------------------ + // 0-arg specialization template class bind_front_wrapper { Handler h_; - // Can't friend partial specializations, - // so we just friend the whole thing. template friend struct net::associated_executor; @@ -228,10 +206,10 @@ public: bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper const&) = default; - template + template explicit - bind_front_wrapper(DeducedHandler&& handler) - : h_(std::forward(handler)) + bind_front_wrapper(Handler_&& handler) + : h_(std::forward(handler)) { } @@ -261,43 +239,25 @@ public: asio_handler_invoke(f, std::addressof(w->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_)); - } - 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_)); + std::addressof(op->h_)); } }; +//------------------------------------------------------------------------------ + // 1-arg specialization template class bind_front_wrapper { Handler h_; - typename std::decay::type arg_; + Arg arg_; - // Can't friend partial specializations, - // so we just friend the whole thing. template friend struct net::associated_executor; @@ -307,18 +267,21 @@ public: bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper const&) = default; - template + template< + class Handler_, + class Arg_> bind_front_wrapper( - DeducedHandler&& handler, Arg&& arg) - : h_(std::forward(handler)) - , arg_(std::forward(arg)) + Handler_&& handler, + Arg_&& arg) + : h_(std::forward(handler)) + , arg_(std::forward(arg)) { } template void operator()(Ts&&... ts) { - h_( std::forward(arg_), + h_( std::move(arg_), std::forward(ts)...); } @@ -342,44 +305,26 @@ public: asio_handler_invoke(f, std::addressof(w->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_)); - } - 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_)); + std::addressof(op->h_)); } }; +//------------------------------------------------------------------------------ + // 2-arg specialization template class bind_front_wrapper { Handler h_; - typename std::decay::type arg1_; - typename std::decay::type arg2_; + Arg1 arg1_; + Arg2 arg2_; - // Can't friend partial specializations, - // so we just friend the whole thing. template friend struct net::associated_executor; @@ -389,20 +334,25 @@ public: bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper const&) = default; - template - bind_front_wrapper(DeducedHandler&& handler, - Arg1&& arg1, Arg2&& arg2) - : h_(std::forward(handler)) - , arg1_(std::forward(arg1)) - , arg2_(std::forward(arg2)) + template< + class Handler_, + class Arg1_, + class Arg2_> + bind_front_wrapper( + Handler_&& handler, + Arg1_&& arg1, + Arg2_&& arg2) + : h_(std::forward(handler)) + , arg1_(std::forward(arg1)) + , arg2_(std::forward(arg2)) { } template void operator()(Ts&&... ts) { - h_( std::forward(arg1_), - std::forward(arg2_), + h_( std::move(arg1_), + std::move(arg2_), std::forward(ts)...); } @@ -426,50 +376,31 @@ public: asio_handler_invoke(f, std::addressof(w->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_)); - } - 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_)); + std::addressof(op->h_)); } + }; +//------------------------------------------------------------------------------ + // 3+ arg specialization -template -class bind_front_wrapper +template< + class Handler, + class Arg1, class Arg2, class Arg3, + class... Args> +class bind_front_wrapper< + Handler, Arg1, Arg2, Arg3, Args...> { - using args_type = tuple< - typename std::decay::type, - typename std::decay::type, - typename std::decay::type, - typename std::decay::type...>; - Handler h_; - args_type args_; + detail::tuple< + Arg1, Arg2, Arg3, Args...> args_; - // Can't friend partial specializations, - // so we just friend the whole thing. template friend struct net::associated_executor; @@ -489,16 +420,22 @@ public: bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper const&) = default; - template - bind_front_wrapper(DeducedHandler&& handler, - Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, - Args&&... args) - : h_(std::forward(handler)) + template< + class Handler_, + class Arg1_, class Arg2_, class Arg3_, + class... Args_> + bind_front_wrapper( + Handler_&& handler, + Arg1_&& arg1, + Arg2_&& arg2, + Arg3_&& arg3, + Args_&&... args) + : h_(std::forward(handler)) , args_( - std::forward(arg1), - std::forward(arg2), - std::forward(arg3), - std::forward(args)...) + std::forward(arg1), + std::forward(arg2), + std::forward(arg3), + std::forward(args)...) { } @@ -531,31 +468,13 @@ public: asio_handler_invoke(f, std::addressof(w->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_)); - } - 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_)); + std::addressof(op->h_)); } }; @@ -567,6 +486,9 @@ template class bind_front_wrapper< Handler, error_code, std::size_t> { + template + friend struct net::associated_executor; + Handler h_; error_code ec_; std::size_t n_; @@ -586,9 +508,10 @@ public: { } - void operator()() + template + void operator()(Ts&&... ts) { - h_(ec_, n_); + h_(ec_, n_, std::forward(ts)...); } // @@ -611,34 +534,39 @@ public: asio_handler_invoke(f, std::addressof(w->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_)); - } - 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_)); + std::addressof(op->h_)); } }; +//------------------------------------------------------------------------------ + +// VFALCO These are only called when using deprecated +// network interfaces in conjunction with extensions, +// and should not be needed. If this creates a problem +// please contact me. + +template +void* asio_handler_allocate(std::size_t, + bind_wrapper* op) = delete; + +template +void asio_handler_deallocate(void*, std::size_t, + bind_wrapper* op) = delete; + +template +void* asio_handler_allocate(std::size_t, + bind_front_wrapper* op) = delete; + +template +void asio_handler_deallocate(void*, std::size_t, + bind_front_wrapper* op) = delete; + } // detail } // beast } // boost @@ -689,6 +617,13 @@ struct associated_executor< 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<