diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ac1a815..c90249bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Version 201 * Decay bound arguments in handler wrapper parameters +* Add bind_back_handler -------------------------------------------------------------------------------- diff --git a/doc/qbk/03_core/5_composed.qbk b/doc/qbk/03_core/5_composed.qbk index 03f76e55..b24e4581 100644 --- a/doc/qbk/03_core/5_composed.qbk +++ b/doc/qbk/03_core/5_composed.qbk @@ -52,11 +52,13 @@ composed operations: be the same as those of the original handler. ]] [[ + [link beast.ref.boost__beast__bind_back_handler `bind_back_handler`] [link beast.ref.boost__beast__bind_front_handler `bind_front_handler`] ][ This function creates a new handler which, when invoked, calls - the original handler with the list of bound arguments, followed - by the list of invoked arguments. Placeholders are not supported. + the original handler with the list of bound arguments, along with + the list of invoked arguments at either the front or the back of + the argument list. Placeholders are not supported. The passed handler and arguments are forwarded into the returned handler, whose associated allocator and associated executor will diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 83e6105d..0d55e5b1 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -212,8 +212,9 @@ Functions - bind_handler + bind_back_handler bind_front_handler + bind_handler make_printable buffers_cat buffers_front diff --git a/include/boost/beast/core/bind_handler.hpp b/include/boost/beast/core/bind_handler.hpp index d9be4088..2d6620b9 100644 --- a/include/boost/beast/core/bind_handler.hpp +++ b/include/boost/beast/core/bind_handler.hpp @@ -131,6 +131,59 @@ bind_front_handler( std::forward(args)...); } +/** Bind parameters to a completion handler, creating a new handler. + + This function creates a new handler which, when invoked, calls + the original handler with the list of bound arguments. Any + parameters passed in the invocation will be forwarded in + the parameter list before the bound arguments. + + The passed handler and arguments are forwarded into the returned + handler, whose associated allocator and associated executor will + will be the same as those of the original handler. + + @par Example + + This function posts the invocation of the specified completion + handler with bound arguments: + + @code + template + void + signal_unreachable (AsyncReadStream& stream, ReadHandler&& handler) + { + net::post( + stream.get_executor(), + bind_back_handler (std::forward (handler), + net::error::network_unreachable, 0)); + } + @endcode + + @param handler The handler to wrap. + + @param args A list of arguments to bind to the handler. + The arguments are forwarded into the returned object. +*/ +template +#if BOOST_BEAST_DOXYGEN +__implementation_defined__ +#else +auto +#endif +bind_back_handler( + Handler&& handler, + Args&&... args) -> + detail::bind_back_wrapper< + typename std::decay::type, + typename std::decay::type...> +{ + return detail::bind_back_wrapper< + typename std::decay::type, + typename std::decay::type...>( + std::forward(handler), + std::forward(args)...); +} + } // beast } // boost diff --git a/include/boost/beast/core/detail/bind_handler.hpp b/include/boost/beast/core/detail/bind_handler.hpp index f30613b9..40e20da9 100644 --- a/include/boost/beast/core/detail/bind_handler.hpp +++ b/include/boost/beast/core/detail/bind_handler.hpp @@ -28,6 +28,12 @@ namespace boost { namespace beast { namespace detail { +//------------------------------------------------------------------------------ +// +// bind_handler +// +//------------------------------------------------------------------------------ + template class bind_wrapper { @@ -170,10 +176,10 @@ public: template friend void asio_handler_invoke( - Function&& f, bind_wrapper* w) + Function&& f, bind_wrapper* op) { using net::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(w->h_)); + asio_handler_invoke(f, std::addressof(op->h_)); } friend @@ -184,11 +190,36 @@ public: 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 +// //------------------------------------------------------------------------------ // 0-arg specialization @@ -233,10 +264,10 @@ public: template friend void asio_handler_invoke( - Function&& f, bind_front_wrapper* w) + Function&& f, bind_front_wrapper* op) { using net::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(w->h_)); + asio_handler_invoke(f, std::addressof(op->h_)); } friend @@ -247,6 +278,24 @@ public: 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_)); + } }; //------------------------------------------------------------------------------ @@ -299,10 +348,10 @@ public: template friend void asio_handler_invoke( - Function&& f, bind_front_wrapper* w) + Function&& f, bind_front_wrapper* op) { using net::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(w->h_)); + asio_handler_invoke(f, std::addressof(op->h_)); } friend @@ -313,6 +362,24 @@ public: 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_)); + } }; //------------------------------------------------------------------------------ @@ -370,10 +437,10 @@ public: template friend void asio_handler_invoke( - Function&& f, bind_front_wrapper* w) + Function&& f, bind_front_wrapper* op) { using net::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(w->h_)); + asio_handler_invoke(f, std::addressof(op->h_)); } friend @@ -385,6 +452,23 @@ public: 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_)); + } }; //------------------------------------------------------------------------------ @@ -462,10 +546,10 @@ public: template friend void asio_handler_invoke( - Function&& f, bind_front_wrapper* w) + Function&& f, bind_front_wrapper* op) { using net::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(w->h_)); + asio_handler_invoke(f, std::addressof(op->h_)); } friend @@ -476,6 +560,24 @@ public: 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_)); + } }; //------------------------------------------------------------------------------ @@ -528,10 +630,10 @@ public: template friend void asio_handler_invoke( - Function&& f, bind_front_wrapper* w) + Function&& f, bind_front_wrapper* op) { using net::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(w->h_)); + asio_handler_invoke(f, std::addressof(op->h_)); } friend @@ -542,30 +644,475 @@ public: 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_)); + } +}; + +//------------------------------------------------------------------------------ +// +// bind_back +// +//------------------------------------------------------------------------------ + +// 0-arg specialization +template +class bind_back_wrapper +{ + Handler h_; + + template + friend struct net::associated_executor; + +public: + using result_type = void; + + bind_back_wrapper(bind_back_wrapper&&) = default; + bind_back_wrapper(bind_back_wrapper const&) = default; + + template + explicit + bind_back_wrapper(Handler_&& handler) + : h_(std::forward(handler)) + { + } + + template + void operator()(Ts&&... ts) + { + h_(std::forward(ts)...); + } + + // + + using allocator_type = + net::associated_allocator_t; + + allocator_type + get_allocator() const noexcept + { + return net::get_associated_allocator(h_); + } + + template + friend + void asio_handler_invoke( + Function&& f, bind_back_wrapper* op) + { + using net::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_back_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_back_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_back_wrapper* op) + { + using net::asio_handler_deallocate; + asio_handler_deallocate( + p, size, 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. +// 1-arg specialization +template +class bind_back_wrapper +{ + Handler h_; + Arg arg_; -template -void* asio_handler_allocate(std::size_t, - bind_wrapper* op) = delete; + template + friend struct net::associated_executor; -template -void asio_handler_deallocate(void*, std::size_t, - bind_wrapper* op) = delete; +public: + using result_type = void; -template -void* asio_handler_allocate(std::size_t, - bind_front_wrapper* op) = delete; + bind_back_wrapper(bind_back_wrapper&&) = default; + bind_back_wrapper(bind_back_wrapper const&) = default; -template -void asio_handler_deallocate(void*, std::size_t, - bind_front_wrapper* op) = delete; + template< + class Handler_, + class Arg_> + bind_back_wrapper( + Handler_&& handler, + Arg_&& arg) + : h_(std::forward(handler)) + , arg_(std::forward(arg)) + { + } + + template + void operator()(Ts&&... ts) + { + h_( std::forward(ts)..., + std::move(arg_)); + } + + // + + using allocator_type = + net::associated_allocator_t; + + allocator_type + get_allocator() const noexcept + { + return net::get_associated_allocator(h_); + } + + template + friend + void asio_handler_invoke( + Function&& f, bind_back_wrapper* op) + { + using net::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_back_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_back_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_back_wrapper* op) + { + using net::asio_handler_deallocate; + asio_handler_deallocate( + p, size, std::addressof(op->h_)); + } +}; + +//------------------------------------------------------------------------------ + +// 2-arg specialization +template +class bind_back_wrapper +{ + Handler h_; + Arg1 arg1_; + Arg2 arg2_; + + template + friend struct net::associated_executor; + +public: + using result_type = void; + + bind_back_wrapper(bind_back_wrapper&&) = default; + bind_back_wrapper(bind_back_wrapper const&) = default; + + template< + class Handler_, + class Arg1_, + class Arg2_> + bind_back_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(ts)..., + std::move(arg1_), + std::move(arg2_)); + } + + // + + using allocator_type = + net::associated_allocator_t; + + allocator_type + get_allocator() const noexcept + { + return net::get_associated_allocator(h_); + } + + template + friend + void asio_handler_invoke( + Function&& f, bind_back_wrapper* op) + { + using net::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_back_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_back_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_back_wrapper* op) + { + using net::asio_handler_deallocate; + asio_handler_deallocate( + p, size, std::addressof(op->h_)); + } +}; + +//------------------------------------------------------------------------------ + +// 3+ arg specialization +template< + class Handler, + class Arg1, class Arg2, class Arg3, + class... Args> +class bind_back_wrapper< + Handler, Arg1, Arg2, Arg3, Args...> +{ + Handler h_; + detail::tuple< + Arg1, Arg2, Arg3, Args...> args_; + + template + friend struct net::associated_executor; + + template + void + invoke( + mp11::index_sequence, + Ts&&... ts) + { + h_( std::forward(ts)..., + detail::get(std::move(args_))...); + } + +public: + using result_type = void; + + bind_back_wrapper(bind_back_wrapper&&) = default; + bind_back_wrapper(bind_back_wrapper const&) = default; + + template< + class Handler_, + class Arg1_, class Arg2_, class Arg3_, + class... Args_> + bind_back_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)...) + { + } + + template + void operator()(Ts&&... ts) + { + invoke( + mp11::index_sequence_for< + Arg1, Arg2, Arg3, Args...>{}, + std::forward(ts)...); + } + + // + + using allocator_type = + net::associated_allocator_t; + + allocator_type + get_allocator() const noexcept + { + return net::get_associated_allocator(h_); + } + + template + friend + void asio_handler_invoke( + Function&& f, bind_back_wrapper* op) + { + using net::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_back_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_back_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_back_wrapper* op) + { + using net::asio_handler_deallocate; + asio_handler_deallocate( + p, size, std::addressof(op->h_)); + } +}; + +//------------------------------------------------------------------------------ + +// specialization for the most common case, +// to reduce instantiation time and memory. +template +class bind_back_wrapper< + Handler, error_code, std::size_t> +{ + template + friend struct net::associated_executor; + + Handler h_; + error_code ec_; + std::size_t n_; + +public: + using result_type = void; + + bind_back_wrapper(bind_back_wrapper&&) = default; + bind_back_wrapper(bind_back_wrapper const&) = default; + + template + bind_back_wrapper(DeducedHandler&& handler, + error_code ec, std::size_t n) + : h_(std::forward(handler)) + , ec_(ec) + , n_(n) + { + } + + template + void operator()(Ts&&... ts) + { + h_(std::forward(ts)..., ec_, n_); + } + + // + + using allocator_type = + net::associated_allocator_t; + + allocator_type + get_allocator() const noexcept + { + return net::get_associated_allocator(h_); + } + + template + friend + void asio_handler_invoke( + Function&& f, bind_back_wrapper* op) + { + using net::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_back_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_back_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_back_wrapper* op) + { + using net::asio_handler_deallocate; + asio_handler_deallocate( + p, size, std::addressof(op->h_)); + } +}; + +//------------------------------------------------------------------------------ } // detail } // beast @@ -585,11 +1132,11 @@ struct associated_executor< static type - get(beast::detail::bind_wrapper const& w, + get(beast::detail::bind_wrapper const& op, Executor const& ex = Executor()) noexcept { return associated_executor< - Handler, Executor>::get(w.h_, ex); + Handler, Executor>::get(op.h_, ex); } }; @@ -602,11 +1149,28 @@ struct associated_executor< static type - get(beast::detail::bind_front_wrapper const& w, + get(beast::detail::bind_front_wrapper const& op, Executor const& ex = Executor()) noexcept { return associated_executor< - Handler, Executor>::get(w.h_, ex); + Handler, Executor>::get(op.h_, ex); + } +}; + +template +struct associated_executor< + beast::detail::bind_back_wrapper, Executor> +{ + using type = typename + associated_executor::type; + + static + type + get(beast::detail::bind_back_wrapper const& op, + Executor const& ex = Executor()) noexcept + { + return associated_executor< + Handler, Executor>::get(op.h_, ex); } }; @@ -634,6 +1198,11 @@ void bind(boost::beast::detail::bind_front_wrapper< Handler, Args...>, ...) = delete; +template +void +bind(boost::beast::detail::bind_back_wrapper< + Handler, Args...>, ...) = delete; + } // std //------------------------------------------------------------------------------ diff --git a/test/beast/core/bind_handler.cpp b/test/beast/core/bind_handler.cpp index ee981a7a..8d5e65f8 100644 --- a/test/beast/core/bind_handler.cpp +++ b/test/beast/core/bind_handler.cpp @@ -62,6 +62,16 @@ public: net::error::eof, 0)); } + template + void + signal_unreachable (AsyncReadStream& stream, ReadHandler&& handler) + { + net::post( + stream.get_executor(), + bind_back_handler (std::forward (handler), + net::error::network_unreachable, 0)); + } + void testJavadocs() { @@ -72,6 +82,10 @@ public: BEAST_EXPECT(( &bind_handler_test::signal_eof< test::stream, handler>)); + + BEAST_EXPECT(( + &bind_handler_test::signal_unreachable< + test::stream, handler>)); } //--------------------------------------------------------------------------