Add tests for async_op_base

This commit is contained in:
Vinnie Falco
2019-01-09 16:11:15 -08:00
parent b4c63028e2
commit 3599ccb09a
21 changed files with 454 additions and 306 deletions

View File

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

View File

@@ -61,8 +61,8 @@ public:
Handler_&& h)
: async_op_base<Handler,
detail::get_executor_type<flat_stream>>(
s.get_executor(),
std::forward<Handler_>(h))
std::forward<Handler_>(h),
s.get_executor())
, s_(s)
, b_(b)
, p_(nullptr, deleter{alloc_type{}})

View File

@@ -151,9 +151,9 @@ public:
Handler_&& h,
icy_stream& s,
MutableBufferSequence const& b)
: beast::stable_async_op_base<Handler,
: stable_async_op_base<Handler,
beast::detail::get_executor_type<icy_stream>>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, d_(beast::allocate_stable<data>(*this, s, b))
{
(*this)({}, 0);

View File

@@ -91,7 +91,7 @@ namespace beast {
AsyncReadStream& stream,
net::mutable_buffer buffer,
handler_type& handler)
: base_type(stream.get_executor(), std::move(handler))
: base_type(std::move(handler), stream.get_executor())
, stream_(stream)
, buffer_(buffer)
, total_bytes_transferred_(0)
@@ -197,6 +197,56 @@ class async_op_base
}
public:
/** Constructor
@param handler The final completion handler. The type of this
object must meet the requirements of <em>CompletionHandler</em>.
@param ex1 The executor associated with the implied I/O object
target of the operation. The implementation shall maintain an
executor work guard for the lifetime of the operation, or until
the final completion handler is invoked, whichever is shorter.
@param alloc The allocator to be associated with objects
derived from this class. If `Allocator` is default-constructible,
this parameter is optional and may be omitted.
*/
#if BOOST_BEAST_DOXYGEN
template<class Handler>
async_op_base(
Handler&& handler,
Executor1 const& ex1,
Allocator const& alloc = Allocator());
#else
template<
class Handler_,
class = typename std::enable_if<
! std::is_same<typename
std::decay<Handler_>::type,
async_op_base
>::value>::type
>
async_op_base(
Handler_&& handler,
Executor1 const& ex1)
: h_(std::forward<Handler_>(handler))
, wg_(ex1)
{
}
template<class Handler_>
async_op_base(
Handler_&& handler,
Executor1 const& ex1,
Allocator const& alloc)
: boost::empty_value<Allocator>(
boost::empty_init_t{}, alloc)
, h_(std::forward<Handler_>(handler))
, wg_(ex1)
{
}
#endif
/// Move Constructor
async_op_base(async_op_base&& other) = default;
@@ -264,56 +314,6 @@ public:
return std::move(h_);
}
protected:
/** Constructor
@param handler The final completion handler. The type of this
object must meet the requirements of <em>CompletionHandler</em>.
@param ex1 The executor associated with the implied I/O object
target of the operation. The implementation shall maintain an
executor work guard for the lifetime of the operation, or until
the final completion handler is invoked, whichever is shorter.
@param alloc The allocator to be associated with objects
derived from this class. If `Allocator` is default-constructible,
this parameter is optional and may be omitted.
*/
#if BOOST_BEAST_DOXYGEN
template<class Handler>
async_op_base(
Executor1 const& ex1,
Handler&& handler,
Allocator const& alloc = Allocator());
#else
template<
class Handler_,
class = typename std::enable_if<
! std::is_same<typename
std::decay<Handler_>::type,
async_op_base
>::value>::type
>
async_op_base(
Executor1 const& ex1,
Handler_&& handler)
: h_(std::forward<Handler_>(handler))
, wg_(ex1)
{
}
template<class Handler_>
async_op_base(
Executor1 const& ex1,
Handler_&& handler,
Allocator const& alloc)
: boost::empty_value<Allocator>(alloc)
, h_(std::forward<Handler_>(handler))
, wg_(ex1)
{
}
#endif
/** Invoke the final completion handler.
This invokes the final completion handler with the specified
@@ -334,7 +334,6 @@ protected:
}
#if ! BOOST_BEAST_DOXYGEN
public:
template<
class Handler_,
class Executor1_,
@@ -480,7 +479,7 @@ public:
enum { starting, waiting, writing } state_;
op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler)
: base_type(stream.get_executor(), std::move(handler))
: base_type(std::move(handler), stream.get_executor())
, stream_(stream)
, repeats_(repeats)
, state_(starting)
@@ -570,15 +569,6 @@ class stable_async_op_base
}
public:
/// Move Constructor
stable_async_op_base(stable_async_op_base&& other)
: async_op_base<Handler, Executor1, Allocator>(
std::move(other))
, list_(boost::exchange(other.list_, nullptr))
{
}
protected:
/** Constructor
@param handler The final completion handler. The type of this
@@ -609,26 +599,34 @@ protected:
>::value>::type
>
stable_async_op_base(
Executor1 const& ex1,
Handler_&& handler)
Handler_&& handler,
Executor1 const& ex1)
: async_op_base<
Handler, Executor1, Allocator>(
ex1, std::forward<Handler_>(handler))
std::forward<Handler_>(handler), ex1)
{
}
template<class Handler_>
stable_async_op_base(
Executor1 const& ex1,
Handler_&& handler,
Executor1 const& ex1,
Allocator const& alloc)
: async_op_base<
Handler, Executor1, Allocator>(
ex1, std::forward<Handler_>(handler))
std::forward<Handler_>(handler), ex1, alloc)
{
}
#endif
/// Move Constructor
stable_async_op_base(stable_async_op_base&& other)
: async_op_base<Handler, Executor1, Allocator>(
std::move(other))
, list_(boost::exchange(other.list_, nullptr))
{
}
/** Destructor
If the completion handler was not invoked, then any
@@ -676,6 +674,40 @@ void asio_handler_invoke(
}
#endif
namespace detail {
template<class State, class Allocator>
struct allocate_stable_state final
: stable_base
, boost::empty_value<Allocator>
{
State value;
template<class... Args>
explicit
allocate_stable_state(
Allocator const& alloc,
Args&&... args)
: boost::empty_value<Allocator>(
boost::empty_init_t{}, alloc)
, value{std::forward<Args>(args)...}
{
}
void destroy() override
{
using A = typename allocator_traits<
Allocator>::template rebind_alloc<
allocate_stable_state>;
A a(this->get());
detail::allocator_traits<A>::destroy(a, this);
detail::allocator_traits<A>::deallocate(a, this, 1);
}
};
} // detail
/** Allocate a temporary object to hold stable asynchronous operation state.
The object will be destroyed just before the completion
@@ -695,44 +727,19 @@ allocate_stable(
Handler, Executor1, Allocator>& base,
Args&&... args)
{
struct state;
using allocator_type = typename stable_async_op_base<
Handler, Executor1, Allocator>::allocator_type;
using A = typename detail::allocator_traits<
allocator_type>::template rebind_alloc<state>;
struct state final
: detail::stable_base
, boost::empty_value<allocator_type>
{
State value;
explicit
state(
allocator_type const& alloc,
detail::stable_base*& list,
Args&&... args)
: detail::stable_base(list)
, boost::empty_value<allocator_type>(
boost::empty_init_t{}, alloc)
, value{std::forward<Args>(args)...}
{
}
void destroy() override
{
A a(this->get());
detail::allocator_traits<A>::destroy(a, this);
detail::allocator_traits<A>::deallocate(a, this, 1);
}
};
allocator_type>::template rebind_alloc<
detail::allocate_stable_state<
State, allocator_type>>;
struct deleter
{
allocator_type alloc;
state* ptr;
detail::allocate_stable_state<
State, allocator_type>* ptr;
~deleter()
{
@@ -748,9 +755,9 @@ allocate_stable(
deleter d{base.get_allocator(), nullptr};
d.ptr = detail::allocator_traits<A>::allocate(a, 1);
detail::allocator_traits<A>::construct(a, d.ptr,
d.alloc,
base.list_,
std::forward<Args>(args)...);
d.alloc, std::forward<Args>(args)...);
d.ptr->next_ = base.list_;
base.list_ = d.ptr;
return boost::exchange(d.ptr, nullptr)->value;
}

View File

@@ -30,14 +30,13 @@ struct stable_base
}
}
stable_base* next_ = nullptr;
protected:
stable_base* next_;
virtual void destroy() = 0;
stable_base() = default;
virtual ~stable_base() = default;
explicit stable_base(stable_base*& list)
: next_(boost::exchange(list, this))
{
}
virtual void destroy() = 0;
};
} // detail

View File

@@ -18,9 +18,6 @@
#include <boost/asio/coroutine.hpp>
#include <boost/throw_exception.hpp>
// REMOVE
#define BOOST_BEAST_ENABLE_NON_BLOCKING
namespace boost {
namespace beast {
namespace detail {
@@ -56,9 +53,10 @@ public:
DynamicBuffer& b,
Condition cond,
Handler_&& h)
: async_op_base<
Handler, get_executor_type<Stream>>(
s.get_executor(), std::forward<Handler_>(h))
: async_op_base<Handler,
get_executor_type<Stream>>(
std::forward<Handler_>(h),
s.get_executor())
, s_(s)
, b_(b)
, cond_(cond)

View File

@@ -107,7 +107,7 @@ public:
Buffers const& b,
Handler_&& h)
: async_op_base<Handler, Executor>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, impl_(*s.impl_)
, pg_(impl_.read_pending)
, b_(b)
@@ -224,7 +224,7 @@ public:
Buffers const& b,
Handler_&& h)
: async_op_base<Handler, Executor>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, impl_(*s.impl_)
, pg_(impl_.write_pending)
, b_(b)
@@ -350,7 +350,7 @@ public:
Condition cond,
Handler_&& h)
: async_op_base<Handler, Executor>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, impl_(*s.impl_)
, pg0_(impl_.read_pending)
, pg1_(impl_.write_pending)
@@ -377,7 +377,7 @@ public:
Condition cond,
Handler_&& h)
: async_op_base<Handler, Executor>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, impl_(*s.impl_)
, pg0_(impl_.read_pending)
, pg1_(impl_.write_pending)

View File

@@ -44,7 +44,7 @@ public:
MutableBufferSequence const& b)
: async_op_base<
Handler, detail::get_executor_type<buffered_read_stream>>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, b_(b)
{

View File

@@ -350,11 +350,11 @@ public:
net::basic_stream_socket<Protocol>& s,
serializer<isRequest,
basic_file_body<file_win32>,Fields>& sr)
: beast::async_op_base<
: async_op_base<
Handler, typename net::basic_stream_socket<
Protocol>::executor_type>(
s.get_executor(),
std::forward<Handler_>(h))
std::forward<Handler_>(h),
s.get_executor())
, sock_(s)
, sr_(sr)
{

View File

@@ -184,9 +184,9 @@ public:
DynamicBuffer& b,
message_type& m,
Handler_&& h)
: beast::stable_async_op_base<
: stable_async_op_base<
Handler, beast::detail::get_executor_type<Stream>>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, d_(beast::allocate_stable<data>(
*this, s, m))
{

View File

@@ -72,9 +72,9 @@ public:
Handler_&& h,
Stream& s,
serializer<isRequest, Body, Fields>& sr)
: beast::async_op_base<
: async_op_base<
Handler, beast::detail::get_executor_type<Stream>>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, sr_(sr)
{
@@ -168,9 +168,9 @@ public:
Handler_&& h,
Stream& s,
serializer<isRequest, Body, Fields>& sr)
: beast::async_op_base<
: async_op_base<
Handler, beast::detail::get_executor_type<Stream>>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, sr_(sr)
{
@@ -229,9 +229,9 @@ public:
Stream& s,
Handler_&& h,
Args&&... args)
: beast::stable_async_op_base<
: stable_async_op_base<
Handler, beast::detail::get_executor_type<Stream>>(
s.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, sr_(beast::allocate_stable<
serializer<isRequest, Body, Fields>>(

View File

@@ -68,9 +68,9 @@ public:
Handler_&& h,
stream<NextLayer, deflateSupported>& ws,
Args&&... args)
: beast::stable_async_op_base<
: stable_async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, d_(beast::allocate_stable<data>(
*this, ws, std::forward<Args>(args)...))
{
@@ -136,9 +136,9 @@ public:
Handler_&& h,
stream<NextLayer, deflateSupported>& ws,
Args&&... args)
: beast::stable_async_op_base<
: stable_async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, d_(beast::allocate_stable<data>(
*this, ws, std::forward<Args>(args)...))
{

View File

@@ -67,9 +67,9 @@ public:
Handler_&& h,
stream<NextLayer, deflateSupported>& ws,
close_reason const& cr)
: beast::stable_async_op_base<
: stable_async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, d_(beast::allocate_stable<state>(
*this, ws, cr))
{

View File

@@ -71,9 +71,9 @@ public:
handshake_op(
Handler_&& h,
stream& ws, Args&&... args)
: beast::stable_async_op_base<Handler,
: stable_async_op_base<Handler,
beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, d_(beast::allocate_stable<data>(
*this, ws, std::forward<Args>(args)...))
{

View File

@@ -66,9 +66,9 @@ public:
stream<NextLayer, deflateSupported>& ws,
detail::opcode op,
ping_data const& payload)
: beast::stable_async_op_base<
: stable_async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, d_(beast::allocate_stable<state>(
*this, ws, op, payload))
{

View File

@@ -98,9 +98,9 @@ public:
Handler_&& h,
stream<NextLayer, deflateSupported>& ws,
MutableBufferSequence const& bs)
: beast::async_op_base<
: async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, ws_(ws)
, bs_(bs)
, cb_(bs)
@@ -690,9 +690,9 @@ public:
DynamicBuffer& b,
std::size_t limit,
bool some)
: beast::async_op_base<
: async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
std::forward<Handler_>(h), ws.get_executor())
, ws_(ws)
, b_(b)
, limit_(limit ? limit : (

View File

@@ -43,10 +43,10 @@ public:
Handler_&& h,
socket_type& s,
role_type role)
: beast::async_op_base<
Handler, beast::detail::get_executor_type<
net::ip::tcp::socket>>(s.get_executor(),
std::forward<Handler_>(h))
: async_op_base<Handler,
beast::detail::get_executor_type<
net::ip::tcp::socket>>(
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, role_(role)
{

View File

@@ -161,9 +161,9 @@ public:
stream<NextLayer, deflateSupported>& ws,
bool fin,
Buffers const& bs)
: beast::async_op_base<
Handler, beast::detail::get_executor_type<stream>>(
ws.get_executor(), std::forward<Handler_>(h))
: beast::async_op_base<Handler,
beast::detail::get_executor_type<stream>>(
std::forward<Handler_>(h), ws.get_executor())
, ws_(ws)
, cb_(bs)
, fin_(fin)

View File

@@ -16,6 +16,9 @@ add_executable (tests-beast-core
${EXTRAS_FILES}
${TEST_MAIN}
Jamfile
buffer_test.hpp
file_test.hpp
test_handler.hpp
_detail_base64.cpp
_detail_buffer.cpp
_detail_clamp.cpp
@@ -25,8 +28,6 @@ add_executable (tests-beast-core
_detail_variant.cpp
_detail_varint.cpp
async_op_base.cpp
buffer_test.hpp
file_test.hpp
basic_stream_socket.cpp
bind_handler.cpp
buffer_traits.cpp

View File

@@ -10,6 +10,8 @@
// Test that header file is self-contained.
#include <boost/beast/core/async_op_base.hpp>
#include "test_handler.hpp"
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/_experimental/test/stream.hpp>
#include <boost/beast/core/error.hpp>
@@ -19,6 +21,7 @@
#include <boost/asio/system_executor.hpp>
#include <boost/asio/write.hpp>
#include <boost/core/ignore_unused.hpp>
#include <stdexcept>
//------------------------------------------------------------------------------
@@ -104,61 +107,6 @@ struct handler<intrusive_ex, no_alloc>
{
};
struct legacy_handler
{
bool invoked = false;
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 {};
};
};
template<class Function>
void
asio_handler_invoke(
Function&& f,
legacy_handler* p)
{
p->invoked = true;
f();
}
void*
asio_handler_allocate(
std::size_t,
legacy_handler* p)
{
p->invoked = true;
return nullptr;
}
void
asio_handler_deallocate(
void*, std::size_t,
legacy_handler* p)
{
p->invoked = true;
}
bool
asio_handler_is_continuation(
legacy_handler* p)
{
p->invoked = true;
return false;
}
} // (anon)
} // beast
@@ -207,35 +155,6 @@ struct associated_executor<
}
};
template<class Allocator>
struct associated_allocator<
boost::beast::legacy_handler, Allocator>
{
using type = std::allocator<int>;
static type get(
boost::beast::legacy_handler const& h,
Allocator const& a = Allocator()) noexcept
{
return type{};
}
};
template<class Executor>
struct associated_executor<
boost::beast::legacy_handler, Executor>
{
using type = typename
boost::beast::legacy_handler::executor;
static type get(
boost::beast::legacy_handler const&,
Executor const& = Executor()) noexcept
{
return type{};
}
};
} // asio
} // boost
@@ -436,75 +355,195 @@ public:
net::system_executor // ignored
>>::value);
struct test_op : async_op_base<
legacy_handler, ex1_type>
struct final_handler
{
test_op()
: async_op_base<
legacy_handler,
ex1_type>(
ex1_type{}, legacy_handler{})
{
bool& invoked;
}
bool invoked() const noexcept
void
operator()()
{
return this->handler().invoked;
invoked = true;
}
};
void
testLegacyHooks()
testBase()
{
// asio_handler_invoke
// get_allocator
{
simple_allocator alloc;
simple_allocator alloc2;
async_op_base<
move_only_handler,
simple_executor,
simple_allocator> op(
move_only_handler{}, {}, alloc);
BEAST_EXPECT(op.get_allocator() == alloc);
BEAST_EXPECT(op.get_allocator() != alloc2);
}
// get_executor
{
simple_executor ex;
simple_executor ex2;
async_op_base<
move_only_handler,
simple_executor> op(
move_only_handler{}, ex);
BEAST_EXPECT(op.get_executor() == ex);
BEAST_EXPECT(op.get_executor() != ex2);
}
// move construction
{
async_op_base<
move_only_handler,
simple_executor> op(
move_only_handler{}, {});
auto op2 = std::move(op);
}
// observers
{
bool b = false;
async_op_base<
legacy_handler,
simple_executor> op(
legacy_handler{b}, {});
BEAST_EXPECT(! op.handler().hook_invoked);
b = true;
BEAST_EXPECT(op.handler().hook_invoked);
b = false;
BEAST_EXPECT(! op.release_handler().hook_invoked);
}
// invocation
{
test_op h;
BEAST_EXPECT(! h.invoked());
bool invoked = false;
using net::asio_handler_invoke;
asio_handler_invoke(
[&invoked]
{
invoked =true;
}, &h);
async_op_base<
final_handler,
simple_executor> op(
final_handler{invoked}, {});
op.invoke();
BEAST_EXPECT(invoked);
BEAST_EXPECT(h.invoked());
}
// asio_handler_allocate
{
test_op h;
BEAST_EXPECT(! h.invoked());
using net::asio_handler_allocate;
asio_handler_allocate(0, &h);
BEAST_EXPECT(h.invoked());
}
// asio_handler_deallocate
{
test_op h;
BEAST_EXPECT(! h.invoked());
using net::asio_handler_deallocate;
asio_handler_deallocate(nullptr, 0, &h);
BEAST_EXPECT(h.invoked());
}
// asio_handler_deallocate
{
test_op h;
BEAST_EXPECT(! h.invoked());
using net::asio_handler_is_continuation;
asio_handler_is_continuation(&h);
BEAST_EXPECT(h.invoked());
}
// legacy hooks
legacy_handler::test(*this,
[](legacy_handler h)
{
return async_op_base<
legacy_handler,
simple_executor>(
std::move(h), {});
});
}
void
testSpecialMembers()
testStableBase()
{
test_op h1;
test_op h2(std::move(h1));
// get_allocator
{
simple_allocator alloc;
simple_allocator alloc2;
stable_async_op_base<
move_only_handler,
simple_executor,
simple_allocator> op(
move_only_handler{}, {}, alloc);
BEAST_EXPECT(op.get_allocator() == alloc);
BEAST_EXPECT(op.get_allocator() != alloc2);
}
// get_executor
{
simple_executor ex;
simple_executor ex2;
stable_async_op_base<
move_only_handler,
simple_executor> op(
move_only_handler{}, ex);
BEAST_EXPECT(op.get_executor() == ex);
BEAST_EXPECT(op.get_executor() != ex2);
}
// move construction
{
stable_async_op_base<
move_only_handler,
simple_executor> op(
move_only_handler{}, {});
auto op2 = std::move(op);
}
// invocation
{
bool invoked = false;
stable_async_op_base<
final_handler,
simple_executor> op(
final_handler{invoked}, {});
op.invoke();
BEAST_EXPECT(invoked);
}
// legacy hooks
legacy_handler::test(*this,
[](legacy_handler h)
{
return stable_async_op_base<
legacy_handler,
simple_executor>(
std::move(h), {});
});
// allocate_stable
{
bool destroyed = false;
{
struct data
{
bool& destroyed;
~data()
{
destroyed = true;
}
};
stable_async_op_base<
move_only_handler,
simple_executor> op(
move_only_handler{}, {});
BEAST_EXPECT(! destroyed);
auto& d = allocate_stable<data>(op, destroyed);
BEAST_EXPECT(! d.destroyed);
}
BEAST_EXPECT(destroyed);
}
{
struct throwing_data
{
throwing_data()
{
BOOST_THROW_EXCEPTION(
std::exception{});
}
};
stable_async_op_base<
move_only_handler,
simple_executor> op(
move_only_handler{}, {});
try
{
allocate_stable<throwing_data>(op);
fail();
}
catch(std::exception const&)
{
pass();
}
}
}
//--------------------------------------------------------------------------
@@ -527,7 +566,7 @@ public:
AsyncReadStream& stream,
net::mutable_buffer buffer,
handler_type& handler)
: base_type(stream.get_executor(), std::move(handler))
: base_type(std::move(handler), stream.get_executor())
, stream_(stream)
, buffer_(buffer)
, total_bytes_transferred_(0)
@@ -599,7 +638,7 @@ public:
temporary_data& data_;
op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler)
: base_type(stream.get_executor(), std::move(handler))
: base_type(std::move(handler), stream.get_executor())
, state_(starting)
, stream_(stream)
, repeats_(repeats)
@@ -672,8 +711,8 @@ public:
void
run() override
{
testLegacyHooks();
testSpecialMembers();
testBase();
testStableBase();
testJavadocs();
}
};

View File

@@ -21,22 +21,90 @@
namespace boost {
namespace beast {
class simple_allocator
{
std::size_t id_;
public:
simple_allocator()
: id_([]
{
static std::size_t n = 0;
return ++n;
}())
{
}
friend
bool operator==(
simple_allocator const& lhs,
simple_allocator const& rhs) noexcept
{
return lhs.id_ == rhs.id_;
}
friend
bool operator!=(
simple_allocator const& lhs,
simple_allocator const& rhs) noexcept
{
return lhs.id_ != rhs.id_;
}
};
class simple_executor
{
std::size_t id_;
public:
simple_executor()
: id_([]
{
static std::size_t n = 0;
return ++n;
}())
{
}
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&&) {}
friend
bool operator==(
simple_executor const& lhs,
simple_executor const& rhs) noexcept
{
return lhs.id_ == rhs.id_;
}
friend
bool operator!=(
simple_executor const& lhs,
simple_executor const& rhs) noexcept
{
return lhs.id_ != rhs.id_;
}
};
// A move-only handler
struct move_only_handler
{
move_only_handler() = default;
move_only_handler(move_only_handler&&) = default;
move_only_handler(move_only_handler const&) = delete;
void operator()() const{};
};
// 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
simple_executor
get_executor() const noexcept
{
return {};
@@ -126,4 +194,39 @@ asio_handler_is_continuation(
} // beast
} // boost
namespace boost {
namespace asio {
template<class Allocator>
struct associated_allocator<
boost::beast::legacy_handler, Allocator>
{
using type = std::allocator<int>;
static type get(
boost::beast::legacy_handler const& h,
Allocator const& a = Allocator()) noexcept
{
return type{};
}
};
template<class Executor>
struct associated_executor<
boost::beast::legacy_handler, Executor>
{
using type = typename
boost::beast::simple_executor;
static type get(
boost::beast::legacy_handler const&,
Executor const& = Executor()) noexcept
{
return type{};
}
};
} // asio
} // boost
#endif