Add tests for bind_back_handler

This commit is contained in:
Vinnie Falco
2019-01-09 09:52:19 -08:00
parent 5292df6e72
commit b4c63028e2
4 changed files with 315 additions and 607 deletions

View File

@ -6,6 +6,7 @@ Version 202
* Refactor async_op_base * Refactor async_op_base
* Use async_op_base * Use async_op_base
* async_op_base is a public interface * async_op_base is a public interface
* Add tests for bind_back_handler
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -121,7 +121,7 @@ class bind_wrapper
} }
public: public:
using result_type = void; using result_type = void; // asio needs this
bind_wrapper(bind_wrapper&&) = default; bind_wrapper(bind_wrapper&&) = default;
bind_wrapper(bind_wrapper const&) = default; bind_wrapper(bind_wrapper const&) = default;
@ -222,268 +222,11 @@ class bind_front_wrapper;
// //
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// 0-arg specialization template<class Handler, class... Args>
template<class Handler> class bind_front_wrapper
class bind_front_wrapper<Handler>
{ {
Handler h_; Handler h_;
detail::tuple<Args...> args_;
template<class T, class Executor>
friend struct net::associated_executor;
public:
using result_type = void;
bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default;
template<class Handler_>
explicit
bind_front_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_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_));
}
};
//------------------------------------------------------------------------------
// 1-arg specialization
template<class Handler, class Arg>
class bind_front_wrapper<Handler, Arg>
{
Handler h_;
Arg arg_;
template<class T, class Executor>
friend struct net::associated_executor;
public:
using result_type = void;
bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default;
template<
class Handler_,
class Arg_>
bind_front_wrapper(
Handler_&& handler,
Arg_&& arg)
: h_(std::forward<Handler_>(handler))
, arg_(std::forward<Arg_>(arg))
{
}
template<class... Ts>
void operator()(Ts&&... ts)
{
h_( std::move(arg_),
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_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_));
}
};
//------------------------------------------------------------------------------
// 2-arg specialization
template<class Handler, class Arg1, class Arg2>
class bind_front_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_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default;
template<
class Handler_,
class Arg1_,
class Arg2_>
bind_front_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::move(arg1_),
std::move(arg2_),
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_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_));
}
};
//------------------------------------------------------------------------------
// 3+ arg specialization
template<
class Handler,
class Arg1, class Arg2, class Arg3,
class... Args>
class bind_front_wrapper<
Handler, Arg1, Arg2, Arg3, Args...>
{
Handler h_;
detail::tuple<
Arg1, Arg2, Arg3, Args...> args_;
template<class T, class Executor> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@ -499,27 +242,17 @@ class bind_front_wrapper<
} }
public: public:
using result_type = void; using result_type = void; // asio needs this
bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default; bind_front_wrapper(bind_front_wrapper const&) = default;
template< template<class Handler_, class... Args_>
class Handler_,
class Arg1_, class Arg2_, class Arg3_,
class... Args_>
bind_front_wrapper( bind_front_wrapper(
Handler_&& handler, Handler_&& handler,
Arg1_&& arg1,
Arg2_&& arg2,
Arg3_&& arg3,
Args_&&... args) Args_&&... args)
: h_(std::forward<Handler_>(handler)) : h_(std::forward<Handler_>(handler))
, args_( , args_(std::forward<Args_>(args)...)
std::forward<Arg1_>(arg1),
std::forward<Arg2_>(arg2),
std::forward<Arg3_>(arg3),
std::forward<Args_>(args)...)
{ {
} }
@ -527,8 +260,7 @@ public:
void operator()(Ts&&... ts) void operator()(Ts&&... ts)
{ {
invoke( invoke(
mp11::index_sequence_for< mp11::index_sequence_for<Args...>{},
Arg1, Arg2, Arg3, Args...>{},
std::forward<Ts>(ts)...); std::forward<Ts>(ts)...);
} }
@ -596,7 +328,7 @@ class bind_front_wrapper<
std::size_t n_; std::size_t n_;
public: public:
using result_type = void; using result_type = void; // asio needs this
bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default; bind_front_wrapper(bind_front_wrapper const&) = default;
@ -670,268 +402,11 @@ public:
// //
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// 0-arg specialization template<class Handler, class... Args>
template<class Handler> class bind_back_wrapper
class bind_back_wrapper<Handler>
{ {
Handler h_; Handler h_;
detail::tuple<Args...> args_;
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_));
}
};
//------------------------------------------------------------------------------
// 1-arg specialization
template<class Handler, class Arg>
class bind_back_wrapper<Handler, Arg>
{
Handler h_;
Arg arg_;
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 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> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@ -947,27 +422,15 @@ class bind_back_wrapper<
} }
public: public:
using result_type = void; using result_type = void; // asio needs this
bind_back_wrapper(bind_back_wrapper&&) = default; bind_back_wrapper(bind_back_wrapper&&) = default;
bind_back_wrapper(bind_back_wrapper const&) = default; bind_back_wrapper(bind_back_wrapper const&) = default;
template< template<class Handler_, class... Args_>
class Handler_, bind_back_wrapper(Handler_&& handler, Args_&&... args)
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)) : h_(std::forward<Handler_>(handler))
, args_( , args_(std::forward<Args_>(args)...)
std::forward<Arg1_>(arg1),
std::forward<Arg2_>(arg2),
std::forward<Arg3_>(arg3),
std::forward<Args_>(args)...)
{ {
} }
@ -975,8 +438,7 @@ public:
void operator()(Ts&&... ts) void operator()(Ts&&... ts)
{ {
invoke( invoke(
mp11::index_sequence_for< mp11::index_sequence_for<Args...>{},
Arg1, Arg2, Arg3, Args...>{},
std::forward<Ts>(ts)...); std::forward<Ts>(ts)...);
} }
@ -1044,7 +506,7 @@ class bind_back_wrapper<
std::size_t n_; std::size_t n_;
public: public:
using result_type = void; using result_type = void; // asio needs this
bind_back_wrapper(bind_back_wrapper&&) = default; bind_back_wrapper(bind_back_wrapper&&) = default;
bind_back_wrapper(bind_back_wrapper const&) = default; bind_back_wrapper(bind_back_wrapper const&) = default;

View File

@ -10,6 +10,8 @@
// Test that header file is self-contained. // Test that header file is self-contained.
#include <boost/beast/core/bind_handler.hpp> #include <boost/beast/core/bind_handler.hpp>
#include "test_handler.hpp"
#include <boost/beast/core/detail/type_traits.hpp> #include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/_experimental/test/stream.hpp> #include <boost/beast/_experimental/test/stream.hpp>
@ -28,8 +30,6 @@
namespace boost { namespace boost {
namespace beast { namespace beast {
//------------------------------------------------------------------------------
class bind_handler_test : public unit_test::suite class bind_handler_test : public unit_test::suite
{ {
public: public:
@ -42,54 +42,6 @@ public:
} }
}; };
template <class AsyncReadStream, class ReadHandler>
void
signal_aborted (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_handler (std::forward <ReadHandler> (handler),
net::error::operation_aborted, 0));
}
template <class AsyncReadStream, class ReadHandler>
void
signal_eof (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_front_handler (std::forward<ReadHandler> (handler),
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
testJavadocs()
{
BEAST_EXPECT((
&bind_handler_test::signal_aborted<
test::stream, handler<error_code, std::size_t>>));
BEAST_EXPECT((
&bind_handler_test::signal_eof<
test::stream, handler<error_code, std::size_t>>));
BEAST_EXPECT((
&bind_handler_test::signal_unreachable<
test::stream, handler<error_code, std::size_t>>));
}
//--------------------------------------------------------------------------
struct copyable struct copyable
{ {
template<class... Args> template<class... Args>
@ -307,6 +259,12 @@ public:
{ {
std::bind(bind_front_handler(test_cb{*this})); std::bind(bind_front_handler(test_cb{*this}));
} }
void
failStdBindBack()
{
std::bind(bind_back_handler(test_cb{*this}));
}
#endif #endif
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@ -440,6 +398,13 @@ public:
bind_handler(test_cb{*this}, 42)); bind_handler(test_cb{*this}, 42));
ioc.run(); ioc.run();
} }
// legacy hooks
legacy_handler::test(*this,
[](legacy_handler h)
{
return bind_handler(h);
});
} }
void void
@ -513,14 +478,165 @@ public:
test_executor(*this, ioc), test_cb{*this}), test_executor(*this, ioc), test_cb{*this}),
ec, n)); ec, n));
} }
// legacy hooks
legacy_handler::test(*this,
[](legacy_handler h)
{
return bind_front_handler(h);
});
legacy_handler::test(*this,
[](legacy_handler h)
{
return bind_front_handler(
h, error_code{}, std::size_t{});
});
} }
void
testBindBackHandler()
{
using m1 = move_arg<1>;
using m2 = move_arg<2>;
// 0-ary
bind_back_handler(test_cb{*this})();
// 1-ary
bind_back_handler(test_cb{*this}, 42)();
bind_back_handler(test_cb{*this})(42);
// 2-ary
bind_back_handler(test_cb{*this}, 42, "s")();
bind_back_handler(test_cb{*this}, "s")(42);
bind_back_handler(test_cb{*this})(42, "s");
// 3-ary
bind_back_handler(test_cb{*this}, 42, "s", m1{})();
bind_back_handler(test_cb{*this}, m1{})(42, "s");
bind_back_handler(test_cb{*this}, "s", m1{})(42);
bind_back_handler(test_cb{*this})(42, "s", m1{});
// 4-ary
bind_back_handler(test_cb{*this}, 42, "s", m1{}, m2{})();
bind_back_handler(test_cb{*this}, "s", m1{}, m2{})(42);
bind_back_handler(test_cb{*this}, m1{}, m2{})(42, "s");
bind_back_handler(test_cb{*this}, "s", m1{}, m2{})(42);
bind_back_handler(test_cb{*this})(42, "s", m1{}, m2{});
error_code ec;
std::size_t n = 256;
// void(error_code, size_t)
bind_back_handler(test_cb{*this}, ec, n)();
// void(error_code, size_t)(string_view)
bind_back_handler(test_cb{*this}, "s")(ec, n);
// perfect forwarding
{
std::shared_ptr<int> const sp =
std::make_shared<int>(42);
bind_back_handler(test_cb{*this}, sp)();
BEAST_EXPECT(sp.get() != nullptr);
}
// associated executor
{
net::io_context ioc;
testHooks(ioc, bind_back_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{*this})
));
testHooks(ioc, bind_back_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{*this}),
42));
testHooks(ioc, bind_back_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{*this}),
42, "s"));
testHooks(ioc, bind_back_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{*this}),
42, "s", m1{}));
testHooks(ioc, bind_back_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{*this}),
42, "s", m1{}, m2{}));
testHooks(ioc, bind_back_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{*this}),
ec, n));
}
// legacy hooks
legacy_handler::test(*this,
[](legacy_handler h)
{
return bind_back_handler(h);
});
legacy_handler::test(*this,
[](legacy_handler h)
{
return bind_back_handler(
h, error_code{}, std::size_t{});
});
}
//--------------------------------------------------------------------------
template <class AsyncReadStream, class ReadHandler>
void
signal_aborted (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_handler (std::forward <ReadHandler> (handler),
net::error::operation_aborted, 0));
}
template <class AsyncReadStream, class ReadHandler>
void
signal_eof (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_front_handler (std::forward<ReadHandler> (handler),
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
testJavadocs()
{
BEAST_EXPECT((
&bind_handler_test::signal_aborted<
test::stream, handler<error_code, std::size_t>>));
BEAST_EXPECT((
&bind_handler_test::signal_eof<
test::stream, handler<error_code, std::size_t>>));
BEAST_EXPECT((
&bind_handler_test::signal_unreachable<
test::stream, handler<error_code, std::size_t>>));
}
//--------------------------------------------------------------------------
void void
run() override run() override
{ {
testJavadocs();
testBindHandler(); testBindHandler();
testBindFrontHandler(); testBindFrontHandler();
testBindBackHandler();
testJavadocs();
} }
}; };

View File

@ -0,0 +1,129 @@
//
// Copyright (c) 2016-2017 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_TEST_HANDLER_HPP
#define BOOST_BEAST_TEST_HANDLER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/_experimental/unit_test/suite.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>
namespace boost {
namespace beast {
// Used to test the legacy handler hooks
struct legacy_handler
{
bool& hook_invoked;
struct executor
{
void* context() { return nullptr; }
void on_work_started() {}
void on_work_finished() {}
template<class F> void dispatch(F&&) {}
template<class F> void post(F&&) {}
template<class F> void defer(F&&) {}
};
executor
get_executor() const noexcept
{
return {};
};
// Signature of `f` is H<legacy_handler> where H is the wrapper to test
template<class F>
static
void
test(unit_test::suite& suite, F const& f)
{
{
bool hook_invoked = false;
bool lambda_invoked = false;
auto h = f(legacy_handler{hook_invoked});
using net::asio_handler_invoke;
asio_handler_invoke(
[&lambda_invoked]
{
lambda_invoked =true;
}, &h);
suite.BEAST_EXPECT(hook_invoked);
suite.BEAST_EXPECT(lambda_invoked);
}
{
bool hook_invoked = false;
auto h = f(legacy_handler{hook_invoked});
using net::asio_handler_allocate;
asio_handler_allocate(0, &h);
suite.BEAST_EXPECT(hook_invoked);
}
{
bool hook_invoked = false;
auto h = f(legacy_handler{hook_invoked});
using net::asio_handler_deallocate;
asio_handler_deallocate(nullptr, 0, &h);
suite.BEAST_EXPECT(hook_invoked);
}
{
bool hook_invoked = false;
auto h = f(legacy_handler{hook_invoked});
using net::asio_handler_is_continuation;
asio_handler_is_continuation(&h);
suite.BEAST_EXPECT(hook_invoked);
}
}
};
template<class Function>
void
asio_handler_invoke(
Function&& f,
legacy_handler* p)
{
p->hook_invoked = true;
f();
}
inline
void*
asio_handler_allocate(
std::size_t,
legacy_handler* p)
{
p->hook_invoked = true;
return nullptr;
}
inline
void
asio_handler_deallocate(
void*, std::size_t,
legacy_handler* p)
{
p->hook_invoked = true;
}
inline
bool
asio_handler_is_continuation(
legacy_handler* p)
{
p->hook_invoked = true;
return false;
}
} // beast
} // boost
#endif