mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 12:57: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
|
* Don't copy completion handlers
|
||||||
* handler_ptr is move-only
|
* 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:
|
Version 148:
|
||||||
|
@ -107,7 +107,7 @@ class echo_op
|
|||||||
// contained object constructor is a reference to the
|
// contained object constructor is a reference to the
|
||||||
// managed final completion handler.
|
// managed final completion handler.
|
||||||
//
|
//
|
||||||
explicit state(Handler& handler, AsyncStream& stream_)
|
explicit state(Handler const& handler, AsyncStream& stream_)
|
||||||
: stream(stream_)
|
: stream(stream_)
|
||||||
, buffer((std::numeric_limits<std::size_t>::max)(),
|
, buffer((std::numeric_limits<std::size_t>::max)(),
|
||||||
boost::asio::get_associated_allocator(handler))
|
boost::asio::get_associated_allocator(handler))
|
||||||
|
@ -49,8 +49,10 @@ namespace beast {
|
|||||||
template<class T, class Handler>
|
template<class T, class Handler>
|
||||||
class handler_ptr
|
class handler_ptr
|
||||||
{
|
{
|
||||||
|
using handler_storage_t = typename detail::aligned_union<1, Handler>::type;
|
||||||
|
|
||||||
T* t_ = nullptr;
|
T* t_ = nullptr;
|
||||||
Handler h_;
|
handler_storage_t h_;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
@ -100,9 +102,12 @@ public:
|
|||||||
following equivalent signature:
|
following equivalent signature:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
T::T(Handler&, Args&&...)
|
T::T(Handler const&, Args&&...)
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
@par Exception Safety
|
||||||
|
Strong guarantee.
|
||||||
|
|
||||||
@param handler The handler to associate with the owned
|
@param handler The handler to associate with the owned
|
||||||
object. The argument will be moved if it is an xvalue.
|
object. The argument will be moved if it is an xvalue.
|
||||||
|
|
||||||
@ -116,14 +121,14 @@ public:
|
|||||||
handler_type const&
|
handler_type const&
|
||||||
handler() const
|
handler() const
|
||||||
{
|
{
|
||||||
return h_;
|
return *reinterpret_cast<Handler const*>(&h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the handler
|
/// Returns a reference to the handler
|
||||||
handler_type&
|
handler_type&
|
||||||
handler()
|
handler()
|
||||||
{
|
{
|
||||||
return h_;
|
return *reinterpret_cast<Handler*>(&h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a pointer to the owned object.
|
/** Returns a pointer to the owned object.
|
||||||
|
@ -24,8 +24,9 @@ clear()
|
|||||||
{
|
{
|
||||||
typename beast::detail::allocator_traits<
|
typename beast::detail::allocator_traits<
|
||||||
boost::asio::associated_allocator_t<
|
boost::asio::associated_allocator_t<
|
||||||
Handler>>::template rebind_alloc<T> alloc{
|
Handler>>::template rebind_alloc<T> alloc(
|
||||||
boost::asio::get_associated_allocator(h_)};
|
boost::asio::get_associated_allocator(
|
||||||
|
handler()));
|
||||||
beast::detail::allocator_traits<
|
beast::detail::allocator_traits<
|
||||||
decltype(alloc)>::destroy(alloc, t_);
|
decltype(alloc)>::destroy(alloc, t_);
|
||||||
beast::detail::allocator_traits<
|
beast::detail::allocator_traits<
|
||||||
@ -38,43 +39,51 @@ handler_ptr<T, Handler>::
|
|||||||
~handler_ptr()
|
~handler_ptr()
|
||||||
{
|
{
|
||||||
if(t_)
|
if(t_)
|
||||||
|
{
|
||||||
clear();
|
clear();
|
||||||
|
handler().~Handler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class Handler>
|
template<class T, class Handler>
|
||||||
handler_ptr<T, Handler>::
|
handler_ptr<T, Handler>::
|
||||||
handler_ptr(handler_ptr&& other)
|
handler_ptr(handler_ptr&& other)
|
||||||
: t_(other.t_)
|
: 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 T, class Handler>
|
||||||
template<class DeducedHandler, class... Args>
|
template<class DeducedHandler, class... Args>
|
||||||
handler_ptr<T, Handler>::
|
handler_ptr<T, Handler>::
|
||||||
handler_ptr(DeducedHandler&& handler, Args&&... args)
|
handler_ptr(DeducedHandler&& h, 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))
|
|
||||||
{
|
{
|
||||||
|
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>
|
template<class T, class Handler>
|
||||||
@ -85,7 +94,14 @@ release_handler() ->
|
|||||||
{
|
{
|
||||||
BOOST_ASSERT(t_);
|
BOOST_ASSERT(t_);
|
||||||
clear();
|
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>
|
template<class T, class Handler>
|
||||||
@ -96,7 +112,14 @@ invoke(Args&&... args)
|
|||||||
{
|
{
|
||||||
BOOST_ASSERT(t_);
|
BOOST_ASSERT(t_);
|
||||||
clear();
|
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
|
} // beast
|
||||||
|
@ -316,7 +316,7 @@ class read_msg_op
|
|||||||
std::size_t bytes_transferred = 0;
|
std::size_t bytes_transferred = 0;
|
||||||
bool cont = false;
|
bool cont = false;
|
||||||
|
|
||||||
data(Handler&, Stream& s_,
|
data(Handler const&, Stream& s_,
|
||||||
DynamicBuffer& b_, message_type& m_)
|
DynamicBuffer& b_, message_type& m_)
|
||||||
: s(s_)
|
: s(s_)
|
||||||
, b(b_)
|
, b(b_)
|
||||||
|
@ -306,7 +306,7 @@ class write_msg_op
|
|||||||
Stream& s;
|
Stream& s;
|
||||||
serializer<isRequest, Body, Fields> sr;
|
serializer<isRequest, Body, Fields> sr;
|
||||||
|
|
||||||
data(Handler&, Stream& s_, message<
|
data(Handler const&, Stream& s_, message<
|
||||||
isRequest, Body, Fields>& m_)
|
isRequest, Body, Fields>& m_)
|
||||||
: s(s_)
|
: s(s_)
|
||||||
, sr(m_)
|
, sr(m_)
|
||||||
|
@ -45,7 +45,7 @@ class stream<NextLayer>::response_op
|
|||||||
response_type res;
|
response_type res;
|
||||||
|
|
||||||
template<class Body, class Allocator, class Decorator>
|
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,
|
Body, http::basic_fields<Allocator>> const& req,
|
||||||
Decorator const& decorator)
|
Decorator const& decorator)
|
||||||
: ws(ws_)
|
: ws(ws_)
|
||||||
@ -142,7 +142,7 @@ class stream<NextLayer>::accept_op
|
|||||||
stream<NextLayer>& ws;
|
stream<NextLayer>& ws;
|
||||||
Decorator decorator;
|
Decorator decorator;
|
||||||
http::request_parser<http::empty_body> p;
|
http::request_parser<http::empty_body> p;
|
||||||
data(Handler&, stream<NextLayer>& ws_,
|
data(Handler const&, stream<NextLayer>& ws_,
|
||||||
Decorator const& decorator_)
|
Decorator const& decorator_)
|
||||||
: ws(ws_)
|
: ws(ws_)
|
||||||
, decorator(decorator_)
|
, decorator(decorator_)
|
||||||
|
@ -48,7 +48,7 @@ class stream<NextLayer>::close_op
|
|||||||
bool cont = false;
|
bool cont = false;
|
||||||
|
|
||||||
state(
|
state(
|
||||||
Handler&,
|
Handler const&,
|
||||||
stream<NextLayer>& ws_,
|
stream<NextLayer>& ws_,
|
||||||
close_reason const& cr)
|
close_reason const& cr)
|
||||||
: ws(ws_)
|
: ws(ws_)
|
||||||
|
@ -47,7 +47,7 @@ class stream<NextLayer>::handshake_op
|
|||||||
response_type res;
|
response_type res;
|
||||||
|
|
||||||
template<class Decorator>
|
template<class Decorator>
|
||||||
data(Handler&, stream<NextLayer>& ws_,
|
data(Handler const&, stream<NextLayer>& ws_,
|
||||||
response_type* res_p_,
|
response_type* res_p_,
|
||||||
string_view host,
|
string_view host,
|
||||||
string_view target,
|
string_view target,
|
||||||
|
@ -44,7 +44,7 @@ class stream<NextLayer>::ping_op
|
|||||||
token tok;
|
token tok;
|
||||||
|
|
||||||
state(
|
state(
|
||||||
Handler&,
|
Handler const&,
|
||||||
stream<NextLayer>& ws_,
|
stream<NextLayer>& ws_,
|
||||||
detail::opcode op,
|
detail::opcode op,
|
||||||
ping_data const& payload)
|
ping_data const& payload)
|
||||||
|
@ -34,7 +34,8 @@ public:
|
|||||||
|
|
||||||
struct T
|
struct T
|
||||||
{
|
{
|
||||||
T(handler&)
|
explicit
|
||||||
|
T(handler const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,8 @@ public:
|
|||||||
|
|
||||||
struct U
|
struct U
|
||||||
{
|
{
|
||||||
U(handler&)
|
explicit
|
||||||
|
U(handler const&)
|
||||||
{
|
{
|
||||||
throw std::exception{};
|
throw std::exception{};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user