mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 13:27:33 +02:00
Add bind_front_handler:
This works similarly to bind_handler, and can help with reducing template instantiations and compiler memory usage (since it does not need to support placeholders). A specialization for the most common case `void(error_code, size_t)` is provided to minimize instantiation cost.
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
Version 191:
|
||||
|
||||
* Add bind_front_handler
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Version 190:
|
||||
|
||||
* Add missing includes to convenience headers
|
||||
|
@@ -51,6 +51,17 @@ composed operations:
|
||||
handler, whose associated allocator and associated executor will
|
||||
will be the same as those of the original 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 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.
|
||||
]]
|
||||
[[
|
||||
[link beast.ref.boost__beast__handler_ptr `handler_ptr`]
|
||||
][
|
||||
|
@@ -213,6 +213,7 @@
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<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_front_handler">bind_front_handler</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffers">buffers</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>
|
||||
|
@@ -56,7 +56,7 @@ template<class Handler, class... Args>
|
||||
#if BOOST_BEAST_DOXYGEN
|
||||
__implementation_defined__
|
||||
#else
|
||||
detail::bound_handler<
|
||||
detail::bind_wrapper<
|
||||
typename std::decay<Handler>::type, Args...>
|
||||
#endif
|
||||
bind_handler(Handler&& handler, Args&&... args)
|
||||
@@ -67,11 +67,57 @@ bind_handler(Handler&& handler, Args&&... args)
|
||||
Handler, void(Args...)>::value,
|
||||
"Handler requirements not met");
|
||||
#endif
|
||||
return detail::bound_handler<typename std::decay<
|
||||
return detail::bind_wrapper<typename std::decay<
|
||||
Handler>::type, Args...>(std::forward<
|
||||
Handler>(handler), 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 after 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.
|
||||
|
||||
Example:
|
||||
|
||||
@code
|
||||
template<class AsyncReadStream, class ReadHandler>
|
||||
void
|
||||
signal_aborted(AsyncReadStream& stream, ReadHandler&& handler)
|
||||
{
|
||||
boost::asio::post(
|
||||
stream.get_executor(),
|
||||
bind_front_handler(std::forward<ReadHandler>(handler),
|
||||
boost::asio::error::operation_aborted, 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_front_handler(Handler&& handler, Args&&... args) ->
|
||||
detail::bind_front_wrapper<typename
|
||||
std::decay<Handler>::type, Args...>
|
||||
{
|
||||
return detail::bind_front_wrapper<typename
|
||||
std::decay<Handler>::type, Args...>(
|
||||
std::forward<Handler>(handler),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
|
@@ -10,12 +10,14 @@
|
||||
#ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
|
||||
#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
|
||||
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/beast/core/detail/integer_sequence.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_executor.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 <utility>
|
||||
@@ -24,25 +26,20 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/* Nullary handler that calls Handler with bound arguments.
|
||||
|
||||
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...>;
|
||||
|
||||
Handler h_;
|
||||
args_type args_;
|
||||
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
template<class Arg, class Vals>
|
||||
static
|
||||
typename std::enable_if<
|
||||
@@ -95,13 +92,13 @@ class bound_handler
|
||||
static
|
||||
void
|
||||
invoke(
|
||||
Handler& h,
|
||||
Handler& w,
|
||||
ArgsTuple& args,
|
||||
std::tuple<>&&,
|
||||
index_sequence<S...>)
|
||||
{
|
||||
boost::ignore_unused(args);
|
||||
h(std::get<S>(std::move(args))...);
|
||||
w(std::get<S>(std::move(args))...);
|
||||
}
|
||||
|
||||
template<
|
||||
@@ -111,14 +108,14 @@ class bound_handler
|
||||
static
|
||||
void
|
||||
invoke(
|
||||
Handler& h,
|
||||
Handler& w,
|
||||
ArgsTuple& args,
|
||||
ValsTuple&& vals,
|
||||
index_sequence<S...>)
|
||||
{
|
||||
boost::ignore_unused(args);
|
||||
boost::ignore_unused(vals);
|
||||
h(extract(std::get<S>(std::move(args)),
|
||||
w(extract(std::get<S>(std::move(args)),
|
||||
std::forward<ValsTuple>(vals))...);
|
||||
}
|
||||
|
||||
@@ -128,12 +125,12 @@ public:
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
bound_handler(bound_handler&&) = default;
|
||||
bound_handler(bound_handler const&) = delete;
|
||||
bind_wrapper(bind_wrapper&&) = default;
|
||||
bind_wrapper(bind_wrapper const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
bound_handler(
|
||||
bind_wrapper(
|
||||
DeducedHandler&& handler, Args&&... args)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, args_(std::forward<Args>(args)...)
|
||||
@@ -148,18 +145,18 @@ public:
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bound_handler* h)
|
||||
asio_handler_is_continuation(bind_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(h->h_));
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, bound_handler* h)
|
||||
void asio_handler_invoke(Function&& f, bind_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(h->h_));
|
||||
asio_handler_invoke(f, std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class... Values>
|
||||
@@ -183,35 +180,386 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Handler, class... Args>
|
||||
class bind_front_wrapper;
|
||||
|
||||
// 0-arg specialization
|
||||
template<class Handler>
|
||||
class bind_front_wrapper<Handler>
|
||||
{
|
||||
Handler h_;
|
||||
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
bind_front_wrapper(bind_front_wrapper&&) = default;
|
||||
bind_front_wrapper(bind_front_wrapper const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
bind_front_wrapper(DeducedHandler&& handler)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
{
|
||||
}
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
void operator()(Ts&&... ts)
|
||||
{
|
||||
h_(std::forward<Ts>(ts)...);
|
||||
}
|
||||
};
|
||||
|
||||
// 1-arg specialization
|
||||
template<class Handler, class Arg>
|
||||
class bind_front_wrapper<Handler, Arg>
|
||||
{
|
||||
Handler h_;
|
||||
typename std::decay<Arg>::type arg_;
|
||||
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
bind_front_wrapper(bind_front_wrapper&&) = default;
|
||||
bind_front_wrapper(bind_front_wrapper const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
bind_front_wrapper(
|
||||
DeducedHandler&& handler, Arg&& arg)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, arg_(std::forward<Arg>(arg))
|
||||
{
|
||||
}
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
void operator()(Ts&&... ts)
|
||||
{
|
||||
h_( std::forward<Arg>(arg_),
|
||||
std::forward<Ts>(ts)...);
|
||||
}
|
||||
};
|
||||
|
||||
// 2-arg specialization
|
||||
template<class Handler, class Arg1, class Arg2>
|
||||
class bind_front_wrapper<Handler, Arg1, Arg2>
|
||||
{
|
||||
Handler h_;
|
||||
typename std::decay<Arg1>::type arg1_;
|
||||
typename std::decay<Arg2>::type arg2_;
|
||||
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
bind_front_wrapper(bind_front_wrapper&&) = default;
|
||||
bind_front_wrapper(bind_front_wrapper const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
bind_front_wrapper(DeducedHandler&& handler,
|
||||
Arg1&& arg1, Arg2&& arg2)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, arg1_(std::forward<Arg1>(arg1))
|
||||
, arg2_(std::forward<Arg2>(arg2))
|
||||
{
|
||||
}
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
void operator()(Ts&&... ts)
|
||||
{
|
||||
h_( std::forward<Arg1>(arg1_),
|
||||
std::forward<Arg2>(arg2_),
|
||||
std::forward<Ts>(ts)...);
|
||||
}
|
||||
};
|
||||
|
||||
// 3+ arg specialization
|
||||
template<class Handler,
|
||||
class Arg1, class Arg2, class Arg3, class... Args>
|
||||
class bind_front_wrapper<Handler, Arg1, Arg2, Arg3, Args...>
|
||||
{
|
||||
using args_type = std::tuple<
|
||||
typename std::decay<Arg1>::type,
|
||||
typename std::decay<Arg2>::type,
|
||||
typename std::decay<Arg3>::type,
|
||||
typename std::decay<Args>::type...>;
|
||||
|
||||
Handler h_;
|
||||
args_type args_;
|
||||
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
template<std::size_t... I, class... Ts>
|
||||
void
|
||||
invoke(
|
||||
boost::mp11::index_sequence<I...>,
|
||||
Ts&&... ts)
|
||||
{
|
||||
h_( std::get<I>(std::move(args_))...,
|
||||
std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
bind_front_wrapper(bind_front_wrapper&&) = default;
|
||||
bind_front_wrapper(bind_front_wrapper const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
bind_front_wrapper(DeducedHandler&& handler,
|
||||
Arg1&& arg1, Arg2&& arg2, Arg3&& arg3,
|
||||
Args&&... args)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, args_(
|
||||
std::forward<Arg1>(arg1),
|
||||
std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3),
|
||||
std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
void operator()(Ts&&... ts)
|
||||
{
|
||||
invoke(
|
||||
boost::mp11::index_sequence_for<
|
||||
Arg1, Arg2, Arg3, Args...>{},
|
||||
std::forward<Ts>(ts)...);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// specialization for the most common case,
|
||||
// to reduce instantiation time and memory.
|
||||
template<class Handler>
|
||||
class bind_front_wrapper<
|
||||
Handler, error_code, std::size_t>
|
||||
{
|
||||
Handler h_;
|
||||
error_code ec_;
|
||||
std::size_t n_;
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
bind_front_wrapper(bind_front_wrapper&&) = default;
|
||||
bind_front_wrapper(bind_front_wrapper const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
bind_front_wrapper(DeducedHandler&& handler,
|
||||
error_code ec, std::size_t n)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, ec_(ec)
|
||||
, n_(n)
|
||||
{
|
||||
}
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, bind_front_wrapper* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(w->h_));
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
h_(ec_, n_);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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,
|
||||
get(beast::detail::bind_wrapper<Handler, Args...> const& w,
|
||||
Executor const& ex = Executor()) noexcept
|
||||
{
|
||||
return associated_executor<
|
||||
Handler, Executor>::get(h.h_, ex);
|
||||
Handler, Executor>::get(w.h_, ex);
|
||||
}
|
||||
};
|
||||
|
||||
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& w,
|
||||
Executor const& ex = Executor()) noexcept
|
||||
{
|
||||
return associated_executor<
|
||||
Handler, Executor>::get(w.h_, ex);
|
||||
}
|
||||
};
|
||||
|
||||
} // asio
|
||||
|
||||
} // boost
|
||||
|
||||
namespace std {
|
||||
|
||||
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
|
||||
|
@@ -32,34 +32,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
// This function should fail to compile
|
||||
void
|
||||
failStdBind()
|
||||
{
|
||||
std::bind(bind_handler(handler<>{}));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
callback(int v)
|
||||
{
|
||||
BEAST_EXPECT(v == 42);
|
||||
}
|
||||
|
||||
void
|
||||
testPlaceholders()
|
||||
{
|
||||
namespace ph = std::placeholders;
|
||||
|
||||
bind_handler(handler<>{})();
|
||||
bind_handler(handler<int>{}, 1)();
|
||||
bind_handler(handler<int, std::string>{}, 1, "hello")();
|
||||
bind_handler(handler<int>{}, ph::_1)(1);
|
||||
bind_handler(handler<int, std::string>{}, ph::_1, ph::_2)(1, "hello");
|
||||
}
|
||||
|
||||
struct copyable_handler
|
||||
struct copyable
|
||||
{
|
||||
template<class... Args>
|
||||
void
|
||||
@@ -68,44 +41,154 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testAsioHandlerInvoke()
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
boost::asio::io_context ioc;
|
||||
boost::asio::io_service::strand s{ioc};
|
||||
test::stream ts{ioc};
|
||||
boost::asio::post(ioc.get_executor(),
|
||||
s.wrap(copyable_handler{}));
|
||||
}
|
||||
|
||||
struct move_only
|
||||
{
|
||||
move_only() = default;
|
||||
move_only(move_only&&) = default;
|
||||
move_only(move_only const&) = delete;
|
||||
void operator()() const{};
|
||||
};
|
||||
|
||||
void
|
||||
testMoveOnly()
|
||||
callback(int v)
|
||||
{
|
||||
bind_handler([](move_only){}, move_only{})();
|
||||
bind_handler([](move_only){}, std::placeholders::_1)(move_only{});
|
||||
bind_handler([](move_only, move_only){}, move_only{}, std::placeholders::_1)(move_only{});
|
||||
BEAST_EXPECT(v == 42);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// This function should fail to compile
|
||||
void
|
||||
failStdBind()
|
||||
{
|
||||
std::bind(bind_handler(handler<>{}));
|
||||
}
|
||||
void
|
||||
failStdBindFront()
|
||||
{
|
||||
std::bind(bind_front_handler(handler<>{}));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
testBindHandler()
|
||||
{
|
||||
// invocation
|
||||
{
|
||||
auto f = bind_handler(std::bind(
|
||||
&bind_handler_test::callback, this,
|
||||
std::placeholders::_1), 42);
|
||||
f();
|
||||
|
||||
}
|
||||
|
||||
// placeholders
|
||||
{
|
||||
namespace ph = std::placeholders;
|
||||
bind_handler(handler<>{})();
|
||||
bind_handler(handler<int>{}, 1)();
|
||||
bind_handler(handler<int, std::string>{}, 1, "hello")();
|
||||
bind_handler(handler<int>{}, ph::_1)(1);
|
||||
bind_handler(handler<int, std::string>{}, ph::_1, ph::_2)(1, "hello");
|
||||
}
|
||||
|
||||
// move-only
|
||||
{
|
||||
bind_handler([](move_only){}, move_only{})();
|
||||
bind_handler([](move_only){}, std::placeholders::_1)(move_only{});
|
||||
bind_handler([](move_only, move_only){}, move_only{}, std::placeholders::_1)(move_only{});
|
||||
}
|
||||
|
||||
// asio_handler_invoke
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
boost::asio::io_context ioc;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> s{
|
||||
ioc.get_executor()};
|
||||
test::stream ts{ioc};
|
||||
boost::asio::post(s,
|
||||
bind_handler(copyable{}, 42));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testBindFrontHandler()
|
||||
{
|
||||
// invocation
|
||||
{
|
||||
bind_front_handler(
|
||||
std::bind(
|
||||
&bind_handler_test::callback,
|
||||
this,
|
||||
42));
|
||||
|
||||
bind_front_handler(
|
||||
std::bind(
|
||||
&bind_handler_test::callback,
|
||||
this,
|
||||
std::placeholders::_1), 42);
|
||||
|
||||
bind_front_handler(
|
||||
std::bind(
|
||||
&bind_handler_test::callback,
|
||||
this,
|
||||
std::placeholders::_1))(42);
|
||||
|
||||
bind_front_handler(
|
||||
bind_front_handler(
|
||||
std::bind(
|
||||
&bind_handler_test::callback,
|
||||
this,
|
||||
std::placeholders::_1)),
|
||||
42);
|
||||
|
||||
bind_front_handler(
|
||||
bind_front_handler(
|
||||
std::bind(
|
||||
&bind_handler_test::callback,
|
||||
this,
|
||||
std::placeholders::_1)))(42);
|
||||
}
|
||||
|
||||
// move-only
|
||||
{
|
||||
bind_front_handler([]{});
|
||||
}
|
||||
|
||||
// specializations
|
||||
{
|
||||
bind_front_handler(copyable{});
|
||||
bind_front_handler(copyable{}, 1);
|
||||
bind_front_handler(copyable{}, 1, 2);
|
||||
bind_front_handler(copyable{}, 1, 2, 3);
|
||||
bind_front_handler(copyable{}, 1, 2, 3, 4);
|
||||
|
||||
bind_front_handler(copyable{},
|
||||
error_code{}, std::size_t(4));
|
||||
}
|
||||
|
||||
// asio_handler_invoke
|
||||
{
|
||||
// make sure things compile, also can set a
|
||||
// breakpoint in asio_handler_invoke to make sure
|
||||
// it is instantiated.
|
||||
boost::asio::io_context ioc;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> s{
|
||||
ioc.get_executor()};
|
||||
test::stream ts{ioc};
|
||||
boost::asio::post(s,
|
||||
bind_front_handler(copyable{}, 42));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
auto f = bind_handler(std::bind(
|
||||
&bind_handler_test::callback, this,
|
||||
std::placeholders::_1), 42);
|
||||
f();
|
||||
testPlaceholders();
|
||||
testAsioHandlerInvoke();
|
||||
testMoveOnly();
|
||||
testBindHandler();
|
||||
testBindFrontHandler();
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user