summaryrefslogtreecommitdiff
path: root/boost/beast/core/handler_ptr.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core/handler_ptr.hpp')
-rw-r--r--boost/beast/core/handler_ptr.hpp152
1 files changed, 65 insertions, 87 deletions
diff --git a/boost/beast/core/handler_ptr.hpp b/boost/beast/core/handler_ptr.hpp
index f08a815c16..559c0c1559 100644
--- a/boost/beast/core/handler_ptr.hpp
+++ b/boost/beast/core/handler_ptr.hpp
@@ -10,10 +10,9 @@
#ifndef BOOST_BEAST_HANDLER_PTR_HPP
#define BOOST_BEAST_HANDLER_PTR_HPP
+#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
-#include <atomic>
-#include <cstdint>
#include <type_traits>
#include <utility>
@@ -22,69 +21,65 @@ namespace beast {
/** A smart pointer container with associated completion handler.
- This is a smart pointer that retains shared ownership of an
- object through a pointer. Memory is managed using the allocation
- and deallocation functions associated with a completion handler,
- which is also stored in the object. The managed object is
- destroyed and its memory deallocated when one of the following
- happens:
+ This is a smart pointer that retains unique ownership of an
+ object through a pointer. Memory is managed using the allocator
+ associated with a completion handler stored in the object. The
+ managed object is destroyed and its memory deallocated when one
+ of the following occurs:
@li The function @ref invoke is called.
@li The function @ref release_handler is called.
- @li The last remaining container owning the object is destroyed.
+ @li The container is destroyed.
- Objects of this type are used in the implementation of
- composed operations. Typically the composed operation's shared
- state is managed by the @ref handler_ptr and an allocator
- associated with the final handler is used to create the managed
- object.
+ Objects of this type are used in the implementation of composed
+ operations with states that are expensive or impossible to move.
+ This container manages that non-trivial state on behalf of the
+ composed operation.
- @note The reference count is stored using a 16 bit unsigned
- integer. Making more than 2^16 copies of one object results
- in undefined behavior.
+ @par Thread Safety
+ @e Distinct @e objects: Safe.@n
+ @e Shared @e objects: Unsafe.
- @tparam T The type of the owned object.
+ @tparam T The type of the owned object. Must be noexcept destructible.
@tparam Handler The type of the completion handler.
*/
template<class T, class Handler>
class handler_ptr
{
- struct P
- {
- T* t;
- std::atomic<std::uint16_t> n;
-
- // There's no way to put the handler anywhere else
- // without exposing ourselves to race conditions
- // and all sorts of ugliness.
- // See:
- // https://github.com/boostorg/beast/issues/215
- Handler handler;
+ using handler_storage_t = typename detail::aligned_union<1, Handler>::type;
- template<class DeducedHandler, class... Args>
- P(DeducedHandler&& handler, Args&&... args);
- };
+ T* t_ = nullptr;
+ handler_storage_t h_;
- P* p_;
+ void clear();
public:
- /// The type of element this object stores
+ static_assert(std::is_nothrow_destructible<T>::value,
+ "T must be nothrow destructible");
+
+ /// The type of element stored
using element_type = T;
- /// The type of handler this object stores
+ /// The type of handler stored
using handler_type = Handler;
- /// Copy assignment (disallowed).
+ /// Default constructor (deleted).
+ handler_ptr() = delete;
+
+ /// Copy assignment (deleted).
handler_ptr& operator=(handler_ptr const&) = delete;
- /** Destructs the owned object if no more @ref handler_ptr link to it.
+ /// Move assignment (deleted).
+ handler_ptr& operator=(handler_ptr &&) = delete;
+
+ /** Destructor
- If `*this` owns an object and it is the last @ref handler_ptr
- owning it, the object is destroyed and the memory deallocated
- using the associated deallocator.
+ If `*this` owns an object the object is destroyed and
+ the memory deallocated using the allocator associated
+ with the handler.
*/
~handler_ptr();
@@ -95,91 +90,76 @@ public:
*/
handler_ptr(handler_ptr&& other);
- /// Copy constructor
- handler_ptr(handler_ptr const& other);
+ /// Copy constructor (deleted).
+ handler_ptr(handler_ptr const& other) = delete;
- /** Construct a new @ref handler_ptr
+ /** Constructor
- This creates a new @ref handler_ptr with an owned object
- of type `T`. The allocator associated with the handler will
- be used to allocate memory for the owned object. The constructor
- for the owned object will be called thusly:
+ This creates a new container with an owned object of
+ type `T`. The allocator associated with the handler will
+ be used to allocate memory for the owned object. The
+ constructor for the owned object will be called with the
+ following equivalent signature:
@code
- T(handler, std::forward<Args>(args)...)
+ T::T(Handler const&, Args&&...)
@endcode
- @param handler The handler to associate with the owned
- object. The argument will be moved.
-
- @param args Optional arguments forwarded to
- the owned object's constructor.
- */
- template<class... Args>
- handler_ptr(Handler&& handler, Args&&... args);
-
- /** Construct a new @ref handler_ptr
-
- This creates a new @ref handler_ptr with an owned object
- of type `T`. The allocator associated with the handler will
- be used to allocate memory for the owned object. The constructor
- for the owned object will be called thusly:
-
- @code
- T(handler, std::forward<Args>(args)...)
- @endcode
+ @par Exception Safety
+ Strong guarantee.
@param handler The handler to associate with the owned
- object. The argument will be copied.
+ object. The argument will be moved if it is an xvalue.
@param args Optional arguments forwarded to
the owned object's constructor.
*/
- template<class... Args>
- handler_ptr(Handler const& handler, Args&&... args);
+ template<class DeducedHandler, class... Args>
+ explicit handler_ptr(DeducedHandler&& handler, Args&&... args);
- /// Returns a reference to the handler
- handler_type&
+ /// Returns a const reference to the handler
+ handler_type const&
handler() const
{
- return p_->handler;
+ return *reinterpret_cast<Handler const*>(&h_);
}
- /// Returns `true` if `*this` owns an object.
- explicit
- operator bool() const
+ /// Returns a reference to the handler
+ handler_type&
+ handler()
{
- return p_ && p_->t;
+ return *reinterpret_cast<Handler*>(&h_);
}
/** Returns a pointer to the owned object.
-
- If `*this` owns an object, a pointer to the
- object is returned, else `nullptr` is returned.
*/
T*
get() const
{
- return p_ ? p_->t : nullptr;
+ return t_;
}
/// Return a reference to the owned object.
T&
operator*() const
{
- return *p_->t;
+ return *t_;
}
/// Return a pointer to the owned object.
T*
operator->() const
{
- return p_->t;
+ return t_;
}
/** Release ownership of the handler
- If `*this` owns an object, it is first destroyed.
+ Requires: `*this` owns an object
+
+ Before this function returns, the owned object is
+ destroyed, satisfying the deallocation-before-invocation
+ Asio guarantee.
@return The released handler.
*/
@@ -191,9 +171,7 @@ public:
This function invokes the handler in the owned object
with a forwarded argument list. Before the invocation,
the owned object is destroyed, satisfying the
- deallocation-before-invocation Asio guarantee. All
- instances of @ref handler_ptr which refer to the
- same owned object will be reset, including this instance.
+ deallocation-before-invocation Asio guarantee.
@note Care must be taken when the arguments are themselves
stored in the owned object. Such arguments must first be