diff options
Diffstat (limited to 'boost/beast/core/handler_ptr.hpp')
-rw-r--r-- | boost/beast/core/handler_ptr.hpp | 152 |
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 |