mirror of
https://github.com/boostorg/url.git
synced 2026-02-22 15:52:20 +00:00
recycled_ptr is nothrow copyable
This commit is contained in:
@@ -10,102 +10,14 @@
|
||||
#ifndef BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
|
||||
#define BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace urls {
|
||||
namespace grammar {
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
~recycled_ptr()
|
||||
{
|
||||
if(p_)
|
||||
bin_->release(p_);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled<T>& bin)
|
||||
: bin_(&bin)
|
||||
, p_(bin.try_acquire())
|
||||
{
|
||||
if(! p_)
|
||||
p_ = new U;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled<T>& bin,
|
||||
std::nullptr_t) noexcept
|
||||
: bin_(&bin)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr()
|
||||
: recycled_ptr(nullptr)
|
||||
{
|
||||
p_ = bin_->try_acquire();
|
||||
if(! p_)
|
||||
p_ = new U;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
std::nullptr_t) noexcept
|
||||
: recycled_ptr([]() -> B&
|
||||
{
|
||||
// VFALCO this needs the guaranteed
|
||||
// constexpr-init macro treatment
|
||||
static B r;
|
||||
return r;
|
||||
}(), nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled_ptr&& other) noexcept
|
||||
: bin_(other.bin_)
|
||||
, p_(other.p_)
|
||||
{
|
||||
other.p_ = nullptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T&
|
||||
recycled_ptr<T>::
|
||||
acquire()
|
||||
{
|
||||
if(! p_)
|
||||
{
|
||||
p_ = bin_->try_acquire();
|
||||
if(! p_)
|
||||
p_ = new U;
|
||||
}
|
||||
return p_->t;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
recycled_ptr<T>::
|
||||
release()
|
||||
{
|
||||
if(p_)
|
||||
{
|
||||
bin_->release(p_);
|
||||
p_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
recycled<T>::
|
||||
~recycled()
|
||||
@@ -119,6 +31,8 @@ recycled<T>::
|
||||
{
|
||||
++n;
|
||||
auto next = it->next;
|
||||
BOOST_ASSERT(
|
||||
it->refs == 0);
|
||||
delete it;
|
||||
it = next;
|
||||
}
|
||||
@@ -129,18 +43,28 @@ recycled<T>::
|
||||
template<class T>
|
||||
auto
|
||||
recycled<T>::
|
||||
try_acquire() ->
|
||||
acquire() ->
|
||||
U*
|
||||
{
|
||||
std::lock_guard<
|
||||
std::mutex> lock(m_);
|
||||
auto p = head_;
|
||||
if(p)
|
||||
U* p;
|
||||
{
|
||||
// recycle
|
||||
head_ = head_->next;
|
||||
detail::recycled_remove(sizeof(U));
|
||||
std::lock_guard<
|
||||
std::mutex> lock(m_);
|
||||
p = head_;
|
||||
if(p)
|
||||
{
|
||||
// reuse
|
||||
head_ = head_->next;
|
||||
detail::recycled_remove(
|
||||
sizeof(U));
|
||||
++p->refs;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new U;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(p->refs == 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -149,11 +73,139 @@ void
|
||||
recycled<T>::
|
||||
release(U* u) noexcept
|
||||
{
|
||||
if(--u->refs != 0)
|
||||
return;
|
||||
m_.lock();
|
||||
u->next = head_;
|
||||
head_ = u;
|
||||
m_.unlock();
|
||||
detail::recycled_add(sizeof(U));
|
||||
detail::recycled_add(
|
||||
sizeof(U));
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
~recycled_ptr()
|
||||
{
|
||||
if(p_)
|
||||
bin_->release(p_);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled<T>& bin)
|
||||
: bin_(&bin)
|
||||
, p_(bin.acquire())
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled<T>& bin,
|
||||
std::nullptr_t) noexcept
|
||||
: bin_(&bin)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr()
|
||||
: recycled_ptr(nullptr)
|
||||
{
|
||||
p_ = bin_->acquire();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
std::nullptr_t) noexcept
|
||||
: recycled_ptr([]() -> B&
|
||||
{
|
||||
// VFALCO need guaranteed constexpr-init
|
||||
static B r;
|
||||
return r;
|
||||
}(), nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled_ptr const& other) noexcept
|
||||
: bin_(other.bin_)
|
||||
, p_(other.p_)
|
||||
{
|
||||
if(p_)
|
||||
++p_->refs;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
recycled_ptr<T>::
|
||||
recycled_ptr(
|
||||
recycled_ptr&& other) noexcept
|
||||
: bin_(other.bin_)
|
||||
, p_(other.p_)
|
||||
{
|
||||
other.p_ = nullptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto
|
||||
recycled_ptr<T>::
|
||||
operator=(
|
||||
recycled_ptr&& other) noexcept ->
|
||||
recycled_ptr&
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
bin_ == other.bin_);
|
||||
if(p_)
|
||||
bin_->release(p_);
|
||||
p_ = other.p_;
|
||||
other.p_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto
|
||||
recycled_ptr<T>::
|
||||
operator=(
|
||||
recycled_ptr const& other) noexcept ->
|
||||
recycled_ptr&
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
bin_ == other.bin_);
|
||||
if(p_)
|
||||
bin_->release(p_);
|
||||
p_ = other.p_;
|
||||
if(p_)
|
||||
++p_->refs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T&
|
||||
recycled_ptr<T>::
|
||||
acquire()
|
||||
{
|
||||
if(! p_)
|
||||
p_ = bin_->acquire();
|
||||
return p_->t;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
recycled_ptr<T>::
|
||||
release() noexcept
|
||||
{
|
||||
if(p_)
|
||||
{
|
||||
bin_->release(p_);
|
||||
p_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // grammar
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/url/detail/config.hpp>
|
||||
#include <boost/url/grammar/detail/recycled.hpp>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <stddef.h> // ::max_align_t
|
||||
@@ -72,8 +73,8 @@ public:
|
||||
|
||||
All recycled instances of T are destroyed.
|
||||
Undefined behavior results if there are
|
||||
any @ref recycled_ptr which reference this
|
||||
bin.
|
||||
any @ref recycled_ptr which reference
|
||||
this recycle bin.
|
||||
*/
|
||||
~recycled();
|
||||
|
||||
@@ -89,11 +90,18 @@ private:
|
||||
{
|
||||
T t;
|
||||
U* next = nullptr;
|
||||
std::atomic<
|
||||
std::size_t> refs;
|
||||
|
||||
U()
|
||||
: refs{1}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct report;
|
||||
|
||||
U* try_acquire();
|
||||
U* acquire();
|
||||
void release(U* u) noexcept;
|
||||
|
||||
U* head_ = nullptr;
|
||||
@@ -102,12 +110,14 @@ private:
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
/** A pointer to an instance of T
|
||||
/** A pointer to shared instance of T
|
||||
|
||||
This is a smart pointer container
|
||||
which acquires an instance of `T` upon
|
||||
construction. The instance is guaranteed
|
||||
to be in a valid, but unknown state.
|
||||
This is a smart pointer container which can
|
||||
acquire shared ownership of an instance of
|
||||
`T` upon or after construction. The instance
|
||||
is guaranteed to be in a valid, but unknown
|
||||
state. Every recycled pointer references
|
||||
a valid recycle bin.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
@@ -119,8 +129,9 @@ private:
|
||||
ps->clear();
|
||||
@endcode
|
||||
|
||||
@tparam T the type of object to acquire,
|
||||
which must be <em>DefaultConstructible</em>.
|
||||
@tparam T the type of object to
|
||||
acquire, which must be
|
||||
<em>DefaultConstructible</em>.
|
||||
*/
|
||||
template<class T>
|
||||
class recycled_ptr
|
||||
@@ -141,20 +152,26 @@ class recycled_ptr
|
||||
public:
|
||||
/** Destructor
|
||||
|
||||
If a pointee exists, it is
|
||||
returned to the recycle bin.
|
||||
If this is not empty, shared ownership
|
||||
of the pointee is released. If this was
|
||||
the last reference, the object is
|
||||
returned to the original recycle bin.
|
||||
|
||||
@par Effects
|
||||
@code
|
||||
this->release();
|
||||
@endcode
|
||||
*/
|
||||
~recycled_ptr();
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, the pointer
|
||||
will acquire exclusive access to
|
||||
an instance of `T` which is either
|
||||
recycled from the specified bin,
|
||||
or newly allocated. The instance
|
||||
will be guaranteed to be in an
|
||||
unknown but valid state.
|
||||
Upon construction, this will acquire
|
||||
exclusive access to an object of type
|
||||
`T` which is either recycled from the
|
||||
specified bin, or newly allocated.
|
||||
The object will be in an unknown but
|
||||
valid state.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
@@ -166,7 +183,12 @@ public:
|
||||
ps->clear();
|
||||
@endcode
|
||||
|
||||
@param bin The bin to use for recycling.
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() == &bin && ! this->empty()
|
||||
@endcode
|
||||
|
||||
@param bin The recycle bin to use
|
||||
|
||||
@see
|
||||
@ref recycled.
|
||||
@@ -176,8 +198,8 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
The container will not hold
|
||||
any instance of `T`.
|
||||
After construction, this will be empty
|
||||
and refer to the specified recycle bin.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
@@ -190,7 +212,15 @@ public:
|
||||
ps->clear();
|
||||
@endcode
|
||||
|
||||
@param bin The bin to use for recycling.
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() == &bin && this->empty()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
|
||||
@param bin The recycle bin to use
|
||||
|
||||
@see
|
||||
@ref acquire,
|
||||
@@ -203,14 +233,12 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, the pointer
|
||||
will acquire exclusive access to
|
||||
an instance of `T` which is either
|
||||
recycled from an implementation-defined
|
||||
global instance of `recycled<T>`,
|
||||
or newly allocated. The instance
|
||||
will be guaranteed to be in an
|
||||
unknown but valid state.
|
||||
Upon construction, this will acquire
|
||||
exclusive access to an object of type
|
||||
`T` which is either recycled from a
|
||||
global recycle bin, or newly allocated.
|
||||
The object will be in an unknown but
|
||||
valid state.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
@@ -220,6 +248,11 @@ public:
|
||||
ps->clear();
|
||||
@endcode
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() != nullptr && ! this->empty()
|
||||
@endcode
|
||||
|
||||
@see
|
||||
@ref recycled.
|
||||
*/
|
||||
@@ -227,8 +260,8 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
The container will not hold
|
||||
any instance of `T`.
|
||||
After construction, this will be empty
|
||||
and refer to a global recycle bin.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
@@ -239,6 +272,14 @@ public:
|
||||
ps->clear();
|
||||
@endcode
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() != nullptr && this->empty()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
|
||||
@param bin The bin to use for recycling.
|
||||
|
||||
@see
|
||||
@@ -252,21 +293,104 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
After the move, the only valid operation
|
||||
on the moved-from object is destruction.
|
||||
If `other` references an object, the
|
||||
newly constructed pointer will acquire
|
||||
shared ownership. Otherwise this will
|
||||
be empty. The new pointer will reference
|
||||
the same recycle bin as `other`.
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() == &other->bin() && this->get() == other.get()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
|
||||
@param other The pointer to copy
|
||||
*/
|
||||
recycled_ptr(
|
||||
recycled_ptr&&) noexcept;
|
||||
recycled_ptr const& other) noexcept;
|
||||
|
||||
/** Assignment (deleted)
|
||||
/** Constructor
|
||||
|
||||
If `other` references an object,
|
||||
ownership is transferred including
|
||||
a reference to the recycle bin. After
|
||||
the move, the moved-from object will
|
||||
be empty.
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() == &other->bin() && ! this->empty() && other.empty()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
|
||||
@param other The pointer to move from
|
||||
*/
|
||||
recycled_ptr& operator=(
|
||||
recycled_ptr&&) = delete;
|
||||
recycled_ptr(
|
||||
recycled_ptr&& other) noexcept;
|
||||
|
||||
/** Return true if this does not own an object
|
||||
/** Assignment
|
||||
|
||||
This can only happen after this
|
||||
becomes moved-from.
|
||||
If `other` references an object,
|
||||
ownership is transferred including
|
||||
a reference to the recycle bin. After
|
||||
the move, the moved-from object will
|
||||
be empty.
|
||||
|
||||
@par Effects
|
||||
@code
|
||||
this->release()
|
||||
@endcode
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() == &other->bin()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
|
||||
@param other The pointer to move from
|
||||
*/
|
||||
recycled_ptr&
|
||||
operator=(
|
||||
recycled_ptr&& other) noexcept;
|
||||
|
||||
/** Assignment
|
||||
|
||||
If `other` references an object,
|
||||
this acquires shared ownership and
|
||||
references the same recycle bin as
|
||||
`other`. The previous object if any
|
||||
is released.
|
||||
|
||||
@par Effects
|
||||
@code
|
||||
this->release()
|
||||
@endcode
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
&this->bin() == &other->bin() && this->get() == other.get()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
|
||||
@param other The pointer to copy from
|
||||
*/
|
||||
recycled_ptr&
|
||||
operator=(
|
||||
recycled_ptr const&) noexcept;
|
||||
|
||||
/** Return true if this does not reference an object
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
*/
|
||||
bool
|
||||
empty() const noexcept
|
||||
@@ -274,34 +398,83 @@ public:
|
||||
return p_ == nullptr;
|
||||
}
|
||||
|
||||
/** Return the pointed-to object
|
||||
/** Return the referenced recycle bin
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
*/
|
||||
recycled<T>&
|
||||
bin() const noexcept
|
||||
{
|
||||
return *bin_;
|
||||
}
|
||||
|
||||
/** Return the referenced object
|
||||
|
||||
If this is empty, `nullptr` is returned.
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
*/
|
||||
T* get() const noexcept
|
||||
{
|
||||
return &p_->t;
|
||||
}
|
||||
|
||||
/** Return the pointed-to object
|
||||
/** Return the referenced object
|
||||
|
||||
If this is empty, `nullptr` is returned.
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
*/
|
||||
T* operator->() const noexcept
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
/** Return the pointed-to object
|
||||
/** Return the referenced object
|
||||
|
||||
@par Preconditions
|
||||
@code
|
||||
not this->empty()
|
||||
@endcode
|
||||
*/
|
||||
T& operator*() const noexcept
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
|
||||
/** Return the pointed-to object
|
||||
/** Return the referenced object
|
||||
|
||||
If this references an object, it is
|
||||
returned. Otherwise, exclusive ownership
|
||||
of a new object of type `T` is acquired
|
||||
and returned.
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
not this->empty()
|
||||
@endcode
|
||||
*/
|
||||
T& acquire();
|
||||
|
||||
/** Release the pointed-to object
|
||||
/** Release the referenced object
|
||||
|
||||
If this references an object, it is
|
||||
released to the referenced recycle bin.
|
||||
The pointer will continue to reference
|
||||
the same recycle bin.
|
||||
|
||||
@par Postconditions
|
||||
@code
|
||||
this->empty()
|
||||
@endcode
|
||||
|
||||
@par Exception Safety
|
||||
Throws nothing.
|
||||
*/
|
||||
void release();
|
||||
void release() noexcept;
|
||||
};
|
||||
|
||||
} // grammar
|
||||
|
||||
Reference in New Issue
Block a user