Add bind_back_handler

fix #1384
This commit is contained in:
Vinnie Falco
2018-12-20 13:38:43 -08:00
parent e7b8cc73a5
commit 92e598ade3
6 changed files with 675 additions and 35 deletions

View File

@@ -1,6 +1,7 @@
Version 201 Version 201
* Decay bound arguments in handler wrapper parameters * Decay bound arguments in handler wrapper parameters
* Add bind_back_handler
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -52,11 +52,13 @@ composed operations:
be the same as those of the original handler. 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`] [link beast.ref.boost__beast__bind_front_handler `bind_front_handler`]
][ ][
This function creates a new handler which, when invoked, calls This function creates a new handler which, when invoked, calls
the original handler with the list of bound arguments, followed the original handler with the list of bound arguments, along with
by the list of invoked arguments. Placeholders are not supported. 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 The passed handler and arguments are forwarded into the returned
handler, whose associated allocator and associated executor will handler, whose associated allocator and associated executor will

View File

@@ -212,8 +212,9 @@
<entry valign="top"> <entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead> <bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.boost__beast__bind_handler">bind_handler</link></member> <member><link linkend="beast.ref.boost__beast__bind_back_handler">bind_back_handler</link></member>
<member><link linkend="beast.ref.boost__beast__bind_front_handler">bind_front_handler</link></member> <member><link linkend="beast.ref.boost__beast__bind_front_handler">bind_front_handler</link></member>
<member><link linkend="beast.ref.boost__beast__bind_handler">bind_handler</link></member>
<member><link linkend="beast.ref.boost__beast__make_printable">make_printable</link></member> <member><link linkend="beast.ref.boost__beast__make_printable">make_printable</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_cat">buffers_cat</link></member> <member><link linkend="beast.ref.boost__beast__buffers_cat">buffers_cat</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_front">buffers_front</link></member> <member><link linkend="beast.ref.boost__beast__buffers_front">buffers_front</link></member>

View File

@@ -131,6 +131,59 @@ bind_front_handler(
std::forward<Args>(args)...); std::forward<Args>(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 <class AsyncReadStream, class ReadHandler>
void
signal_unreachable (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_back_handler (std::forward<ReadHandler> (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<class Handler, class... Args>
#if BOOST_BEAST_DOXYGEN
__implementation_defined__
#else
auto
#endif
bind_back_handler(
Handler&& handler,
Args&&... args) ->
detail::bind_back_wrapper<
typename std::decay<Handler>::type,
typename std::decay<Args>::type...>
{
return detail::bind_back_wrapper<
typename std::decay<Handler>::type,
typename std::decay<Args>::type...>(
std::forward<Handler>(handler),
std::forward<Args>(args)...);
}
} // beast } // beast
} // boost } // boost

View File

@@ -28,6 +28,12 @@ namespace boost {
namespace beast { namespace beast {
namespace detail { namespace detail {
//------------------------------------------------------------------------------
//
// bind_handler
//
//------------------------------------------------------------------------------
template<class Handler, class... Args> template<class Handler, class... Args>
class bind_wrapper class bind_wrapper
{ {
@@ -170,10 +176,10 @@ public:
template<class Function> template<class Function>
friend friend
void asio_handler_invoke( void asio_handler_invoke(
Function&& f, bind_wrapper* w) Function&& f, bind_wrapper* op)
{ {
using net::asio_handler_invoke; using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(op->h_));
} }
friend friend
@@ -184,11 +190,36 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); 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 Handler, class... Args>
class bind_back_wrapper;
template<class Handler, class... Args> template<class Handler, class... Args>
class bind_front_wrapper; class bind_front_wrapper;
//------------------------------------------------------------------------------
//
// bind_front
//
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// 0-arg specialization // 0-arg specialization
@@ -233,10 +264,10 @@ public:
template<class Function> template<class Function>
friend friend
void asio_handler_invoke( void asio_handler_invoke(
Function&& f, bind_front_wrapper* w) Function&& f, bind_front_wrapper* op)
{ {
using net::asio_handler_invoke; using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(op->h_));
} }
friend friend
@@ -247,6 +278,24 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); 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<class Function> template<class Function>
friend friend
void asio_handler_invoke( void asio_handler_invoke(
Function&& f, bind_front_wrapper* w) Function&& f, bind_front_wrapper* op)
{ {
using net::asio_handler_invoke; using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(op->h_));
} }
friend friend
@@ -313,6 +362,24 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); 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<class Function> template<class Function>
friend friend
void asio_handler_invoke( void asio_handler_invoke(
Function&& f, bind_front_wrapper* w) Function&& f, bind_front_wrapper* op)
{ {
using net::asio_handler_invoke; using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(op->h_));
} }
friend friend
@@ -385,6 +452,23 @@ public:
std::addressof(op->h_)); 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<class Function> template<class Function>
friend friend
void asio_handler_invoke( void asio_handler_invoke(
Function&& f, bind_front_wrapper* w) Function&& f, bind_front_wrapper* op)
{ {
using net::asio_handler_invoke; using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(op->h_));
} }
friend friend
@@ -476,6 +560,24 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); 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<class Function> template<class Function>
friend friend
void asio_handler_invoke( void asio_handler_invoke(
Function&& f, bind_front_wrapper* w) Function&& f, bind_front_wrapper* op)
{ {
using net::asio_handler_invoke; using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(op->h_));
} }
friend friend
@@ -542,30 +644,475 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); 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 Handler>
class bind_back_wrapper<Handler>
{
Handler h_;
template<class T, class Executor>
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_>
explicit
bind_back_wrapper(Handler_&& handler)
: h_(std::forward<Handler_>(handler))
{
}
template<class... Ts>
void operator()(Ts&&... ts)
{
h_(std::forward<Ts>(ts)...);
}
//
using allocator_type =
net::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return net::get_associated_allocator(h_);
}
template<class Function>
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 // 1-arg specialization
// network interfaces in conjunction with extensions, template<class Handler, class Arg>
// and should not be needed. If this creates a problem class bind_back_wrapper<Handler, Arg>
// please contact me. {
Handler h_;
Arg arg_;
template<class Handler, class... Args> template<class T, class Executor>
void* asio_handler_allocate(std::size_t, friend struct net::associated_executor;
bind_wrapper<Handler, Args...>* op) = delete;
template<class Handler, class... Args> public:
void asio_handler_deallocate(void*, std::size_t, using result_type = void;
bind_wrapper<Handler, Args...>* op) = delete;
template<class Handler, class... Args> bind_back_wrapper(bind_back_wrapper&&) = default;
void* asio_handler_allocate(std::size_t, bind_back_wrapper(bind_back_wrapper const&) = default;
bind_front_wrapper<Handler, Args...>* op) = delete;
template<class Handler, class... Args> template<
void asio_handler_deallocate(void*, std::size_t, class Handler_,
bind_front_wrapper<Handler, Args...>* op) = delete; class Arg_>
bind_back_wrapper(
Handler_&& handler,
Arg_&& arg)
: h_(std::forward<Handler_>(handler))
, arg_(std::forward<Arg_>(arg))
{
}
template<class... Ts>
void operator()(Ts&&... ts)
{
h_( std::forward<Ts>(ts)...,
std::move(arg_));
}
//
using allocator_type =
net::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return net::get_associated_allocator(h_);
}
template<class Function>
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 Handler, class Arg1, class Arg2>
class bind_back_wrapper<Handler, Arg1, Arg2>
{
Handler h_;
Arg1 arg1_;
Arg2 arg2_;
template<class T, class Executor>
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_>(handler))
, arg1_(std::forward<Arg1_>(arg1))
, arg2_(std::forward<Arg2_>(arg2))
{
}
template<class... Ts>
void operator()(Ts&&... ts)
{
h_( std::forward<Ts>(ts)...,
std::move(arg1_),
std::move(arg2_));
}
//
using allocator_type =
net::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return net::get_associated_allocator(h_);
}
template<class Function>
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<class T, class Executor>
friend struct net::associated_executor;
template<std::size_t... I, class... Ts>
void
invoke(
mp11::index_sequence<I...>,
Ts&&... ts)
{
h_( std::forward<Ts>(ts)...,
detail::get<I>(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_>(handler))
, args_(
std::forward<Arg1_>(arg1),
std::forward<Arg2_>(arg2),
std::forward<Arg3_>(arg3),
std::forward<Args_>(args)...)
{
}
template<class... Ts>
void operator()(Ts&&... ts)
{
invoke(
mp11::index_sequence_for<
Arg1, Arg2, Arg3, Args...>{},
std::forward<Ts>(ts)...);
}
//
using allocator_type =
net::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return net::get_associated_allocator(h_);
}
template<class Function>
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 Handler>
class bind_back_wrapper<
Handler, error_code, std::size_t>
{
template<class T, class Executor>
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<class DeducedHandler>
bind_back_wrapper(DeducedHandler&& handler,
error_code ec, std::size_t n)
: h_(std::forward<DeducedHandler>(handler))
, ec_(ec)
, n_(n)
{
}
template<class... Ts>
void operator()(Ts&&... ts)
{
h_(std::forward<Ts>(ts)..., ec_, n_);
}
//
using allocator_type =
net::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return net::get_associated_allocator(h_);
}
template<class Function>
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 } // detail
} // beast } // beast
@@ -585,11 +1132,11 @@ struct associated_executor<
static static
type type
get(beast::detail::bind_wrapper<Handler, Args...> const& w, get(beast::detail::bind_wrapper<Handler, Args...> const& op,
Executor const& ex = Executor()) noexcept Executor const& ex = Executor()) noexcept
{ {
return associated_executor< return associated_executor<
Handler, Executor>::get(w.h_, ex); Handler, Executor>::get(op.h_, ex);
} }
}; };
@@ -602,11 +1149,28 @@ struct associated_executor<
static static
type type
get(beast::detail::bind_front_wrapper<Handler, Args...> const& w, get(beast::detail::bind_front_wrapper<Handler, Args...> const& op,
Executor const& ex = Executor()) noexcept Executor const& ex = Executor()) noexcept
{ {
return associated_executor< return associated_executor<
Handler, Executor>::get(w.h_, ex); Handler, Executor>::get(op.h_, ex);
}
};
template<class Handler, class... Args, class Executor>
struct associated_executor<
beast::detail::bind_back_wrapper<Handler, Args...>, Executor>
{
using type = typename
associated_executor<Handler, Executor>::type;
static
type
get(beast::detail::bind_back_wrapper<Handler, Args...> 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< bind(boost::beast::detail::bind_front_wrapper<
Handler, Args...>, ...) = delete; Handler, Args...>, ...) = delete;
template<class Handler, class... Args>
void
bind(boost::beast::detail::bind_back_wrapper<
Handler, Args...>, ...) = delete;
} // std } // std
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -62,6 +62,16 @@ public:
net::error::eof, 0)); net::error::eof, 0));
} }
template <class AsyncReadStream, class ReadHandler>
void
signal_unreachable (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_back_handler (std::forward<ReadHandler> (handler),
net::error::network_unreachable, 0));
}
void void
testJavadocs() testJavadocs()
{ {
@@ -72,6 +82,10 @@ public:
BEAST_EXPECT(( BEAST_EXPECT((
&bind_handler_test::signal_eof< &bind_handler_test::signal_eof<
test::stream, handler<error_code, std::size_t>>)); test::stream, handler<error_code, std::size_t>>));
BEAST_EXPECT((
&bind_handler_test::signal_unreachable<
test::stream, handler<error_code, std::size_t>>));
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------