mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
handler_ptr gives the strong exception guarantee (API Change):
* The handler_ptr constructor now provides the strong exception guarantee. * The signature for managed objects constructed by `handler_ptr` receives a const reference to the handler. Actions required: * Change the constructor signature for state objects used with handler_ptr to receive a const reference to the handler.
This commit is contained in:
committed by
Vinnie Falco
parent
e08132106e
commit
285965d82e
10
CHANGELOG.md
10
CHANGELOG.md
@ -8,6 +8,16 @@ Version 149:
|
||||
* Don't copy completion handlers
|
||||
* handler_ptr is move-only
|
||||
|
||||
API Changes:
|
||||
|
||||
* handler_ptr gives the strong exception guarantee
|
||||
|
||||
Actions Required:
|
||||
|
||||
* Change the constructor signature for state objects
|
||||
used with handler_ptr to receive a const reference to
|
||||
the handler.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Version 148:
|
||||
|
@ -107,7 +107,7 @@ class echo_op
|
||||
// contained object constructor is a reference to the
|
||||
// managed final completion handler.
|
||||
//
|
||||
explicit state(Handler& handler, AsyncStream& stream_)
|
||||
explicit state(Handler const& handler, AsyncStream& stream_)
|
||||
: stream(stream_)
|
||||
, buffer((std::numeric_limits<std::size_t>::max)(),
|
||||
boost::asio::get_associated_allocator(handler))
|
||||
|
@ -49,8 +49,10 @@ namespace beast {
|
||||
template<class T, class Handler>
|
||||
class handler_ptr
|
||||
{
|
||||
using handler_storage_t = typename detail::aligned_union<1, Handler>::type;
|
||||
|
||||
T* t_ = nullptr;
|
||||
Handler h_;
|
||||
handler_storage_t h_;
|
||||
|
||||
void clear();
|
||||
|
||||
@ -100,9 +102,12 @@ public:
|
||||
following equivalent signature:
|
||||
|
||||
@code
|
||||
T::T(Handler&, Args&&...)
|
||||
T::T(Handler const&, Args&&...)
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Strong guarantee.
|
||||
|
||||
@param handler The handler to associate with the owned
|
||||
object. The argument will be moved if it is an xvalue.
|
||||
|
||||
@ -116,14 +121,14 @@ public:
|
||||
handler_type const&
|
||||
handler() const
|
||||
{
|
||||
return h_;
|
||||
return *reinterpret_cast<Handler const*>(&h_);
|
||||
}
|
||||
|
||||
/// Returns a reference to the handler
|
||||
handler_type&
|
||||
handler()
|
||||
{
|
||||
return h_;
|
||||
return *reinterpret_cast<Handler*>(&h_);
|
||||
}
|
||||
|
||||
/** Returns a pointer to the owned object.
|
||||
|
@ -24,8 +24,9 @@ clear()
|
||||
{
|
||||
typename beast::detail::allocator_traits<
|
||||
boost::asio::associated_allocator_t<
|
||||
Handler>>::template rebind_alloc<T> alloc{
|
||||
boost::asio::get_associated_allocator(h_)};
|
||||
Handler>>::template rebind_alloc<T> alloc(
|
||||
boost::asio::get_associated_allocator(
|
||||
handler()));
|
||||
beast::detail::allocator_traits<
|
||||
decltype(alloc)>::destroy(alloc, t_);
|
||||
beast::detail::allocator_traits<
|
||||
@ -38,43 +39,51 @@ handler_ptr<T, Handler>::
|
||||
~handler_ptr()
|
||||
{
|
||||
if(t_)
|
||||
{
|
||||
clear();
|
||||
handler().~Handler();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class Handler>
|
||||
handler_ptr<T, Handler>::
|
||||
handler_ptr(handler_ptr&& other)
|
||||
: t_(other.t_)
|
||||
, h_(std::move(other.h_))
|
||||
{
|
||||
other.t_ = nullptr;
|
||||
if(other.t_)
|
||||
{
|
||||
new(&h_) Handler(std::move(other.handler()));
|
||||
other.handler().~Handler();
|
||||
other.t_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class Handler>
|
||||
template<class DeducedHandler, class... Args>
|
||||
handler_ptr<T, Handler>::
|
||||
handler_ptr(DeducedHandler&& handler, Args&&... args)
|
||||
: t_([&]
|
||||
{
|
||||
BOOST_STATIC_ASSERT(! std::is_array<T>::value);
|
||||
typename beast::detail::allocator_traits<
|
||||
boost::asio::associated_allocator_t<
|
||||
Handler>>::template rebind_alloc<T> alloc{
|
||||
boost::asio::get_associated_allocator(handler)};
|
||||
using A = decltype(alloc);
|
||||
auto const d =
|
||||
[&alloc](T* p)
|
||||
{
|
||||
beast::detail::allocator_traits<A>::deallocate(alloc, p, 1);
|
||||
};
|
||||
std::unique_ptr<T, decltype(d)> p{
|
||||
beast::detail::allocator_traits<A>::allocate(alloc, 1), d};
|
||||
beast::detail::allocator_traits<A>::construct(
|
||||
alloc, p.get(), handler, std::forward<Args>(args)...);
|
||||
return p.release();
|
||||
}())
|
||||
, h_(std::forward<DeducedHandler>(handler))
|
||||
handler_ptr(DeducedHandler&& h, Args&&... args)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(! std::is_array<T>::value);
|
||||
typename beast::detail::allocator_traits<
|
||||
boost::asio::associated_allocator_t<
|
||||
Handler>>::template rebind_alloc<T> alloc{
|
||||
boost::asio::get_associated_allocator(h)};
|
||||
using A = decltype(alloc);
|
||||
bool destroy = false;
|
||||
auto deleter = [&alloc, &destroy](T* p)
|
||||
{
|
||||
if(destroy)
|
||||
beast::detail::allocator_traits<A>::destroy(alloc, p);
|
||||
beast::detail::allocator_traits<A>::deallocate(alloc, p, 1);
|
||||
};
|
||||
std::unique_ptr<T, decltype(deleter)> t{
|
||||
beast::detail::allocator_traits<A>::allocate(alloc, 1), deleter};
|
||||
beast::detail::allocator_traits<A>::construct(alloc, t.get(),
|
||||
static_cast<DeducedHandler const&>(h),
|
||||
std::forward<Args>(args)...);
|
||||
destroy = true;
|
||||
new(&h_) Handler(std::forward<DeducedHandler>(h));
|
||||
t_ = t.release();
|
||||
}
|
||||
|
||||
template<class T, class Handler>
|
||||
@ -85,7 +94,14 @@ release_handler() ->
|
||||
{
|
||||
BOOST_ASSERT(t_);
|
||||
clear();
|
||||
return std::move(h_);
|
||||
auto deleter = [](Handler* h)
|
||||
{
|
||||
h->~Handler();
|
||||
};
|
||||
std::unique_ptr<
|
||||
Handler, decltype(deleter)> destroyer{
|
||||
&handler(), deleter};
|
||||
return std::move(handler());
|
||||
}
|
||||
|
||||
template<class T, class Handler>
|
||||
@ -96,7 +112,14 @@ invoke(Args&&... args)
|
||||
{
|
||||
BOOST_ASSERT(t_);
|
||||
clear();
|
||||
h_(std::forward<Args>(args)...);
|
||||
auto deleter = [](Handler* h)
|
||||
{
|
||||
h->~Handler();
|
||||
};
|
||||
std::unique_ptr<
|
||||
Handler, decltype(deleter)> destroyer{
|
||||
&handler(), deleter};
|
||||
handler()(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
@ -316,7 +316,7 @@ class read_msg_op
|
||||
std::size_t bytes_transferred = 0;
|
||||
bool cont = false;
|
||||
|
||||
data(Handler&, Stream& s_,
|
||||
data(Handler const&, Stream& s_,
|
||||
DynamicBuffer& b_, message_type& m_)
|
||||
: s(s_)
|
||||
, b(b_)
|
||||
|
@ -306,7 +306,7 @@ class write_msg_op
|
||||
Stream& s;
|
||||
serializer<isRequest, Body, Fields> sr;
|
||||
|
||||
data(Handler&, Stream& s_, message<
|
||||
data(Handler const&, Stream& s_, message<
|
||||
isRequest, Body, Fields>& m_)
|
||||
: s(s_)
|
||||
, sr(m_)
|
||||
|
@ -45,7 +45,7 @@ class stream<NextLayer>::response_op
|
||||
response_type res;
|
||||
|
||||
template<class Body, class Allocator, class Decorator>
|
||||
data(Handler&, stream<NextLayer>& ws_, http::request<
|
||||
data(Handler const&, stream<NextLayer>& ws_, http::request<
|
||||
Body, http::basic_fields<Allocator>> const& req,
|
||||
Decorator const& decorator)
|
||||
: ws(ws_)
|
||||
@ -142,7 +142,7 @@ class stream<NextLayer>::accept_op
|
||||
stream<NextLayer>& ws;
|
||||
Decorator decorator;
|
||||
http::request_parser<http::empty_body> p;
|
||||
data(Handler&, stream<NextLayer>& ws_,
|
||||
data(Handler const&, stream<NextLayer>& ws_,
|
||||
Decorator const& decorator_)
|
||||
: ws(ws_)
|
||||
, decorator(decorator_)
|
||||
|
@ -48,7 +48,7 @@ class stream<NextLayer>::close_op
|
||||
bool cont = false;
|
||||
|
||||
state(
|
||||
Handler&,
|
||||
Handler const&,
|
||||
stream<NextLayer>& ws_,
|
||||
close_reason const& cr)
|
||||
: ws(ws_)
|
||||
|
@ -47,7 +47,7 @@ class stream<NextLayer>::handshake_op
|
||||
response_type res;
|
||||
|
||||
template<class Decorator>
|
||||
data(Handler&, stream<NextLayer>& ws_,
|
||||
data(Handler const&, stream<NextLayer>& ws_,
|
||||
response_type* res_p_,
|
||||
string_view host,
|
||||
string_view target,
|
||||
|
@ -44,7 +44,7 @@ class stream<NextLayer>::ping_op
|
||||
token tok;
|
||||
|
||||
state(
|
||||
Handler&,
|
||||
Handler const&,
|
||||
stream<NextLayer>& ws_,
|
||||
detail::opcode op,
|
||||
ping_data const& payload)
|
||||
|
@ -34,7 +34,8 @@ public:
|
||||
|
||||
struct T
|
||||
{
|
||||
T(handler&)
|
||||
explicit
|
||||
T(handler const&)
|
||||
{
|
||||
}
|
||||
|
||||
@ -45,7 +46,8 @@ public:
|
||||
|
||||
struct U
|
||||
{
|
||||
U(handler&)
|
||||
explicit
|
||||
U(handler const&)
|
||||
{
|
||||
throw std::exception{};
|
||||
}
|
||||
|
Reference in New Issue
Block a user