Q(E)SDP(V2): fill the API gap left by take()

take() returns a pointer to the shared data object *without*
decrementing the reference counter. The primary use case
is adopting the object from a Q(E)SDP into a different reference
counting mechanism. This is fine, but if we support the
"extraction" part, we shall also support the "adoption" part.
Also, the API for the shared data pointer classes should
match.

Add an adopting tag type and suitable constructors to the
shared data pointer classes, and add take() to the classes
lacking it.

Drive by, apply qExchange to take()'s implementation.

[ChangeLog][QtCore][QAdoptSharedDataTag] New class.
It is now possible to adopt pointers to shared data into
a QExplicitlySharedDataPointer or a QSharedDataPointer object
without incrementing the object's reference counter.

Change-Id: I62b8b005c1bfbe2add58566206fca27634bb7e70
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2020-10-15 01:26:14 +02:00
parent 7745b49b2d
commit aa442e9450
3 changed files with 57 additions and 2 deletions

View File

@ -64,6 +64,20 @@ QT_BEGIN_NAMESPACE
The parameter is ignored.
*/
/*!
\class QAdoptSharedDataTag
\inmodule QtCore
\threadsafe
\brief The QAdoptSharedDataTag is a helper tag class.
\since 6.0
QAdoptSharedDataTag objects are used in QSharedDataPointer
and QExplicitlySharedDataPointer to adopt a pointer to
shared data.
See QSharedDataPointer and QExplicitlySharedDataPointer for details.
*/
/*!
\class QSharedDataPointer
\inmodule QtCore
@ -302,6 +316,18 @@ QT_BEGIN_NAMESPACE
Same as data(). This function is provided for STL compatibility.
*/
/*! \fn template <class T> const T* QSharedDataPointer<T>::take()
\since 6.0
Returns a pointer to the shared object, and resets \e this to be \nullptr.
(That is, this function sets the \e{d pointer} of \e this to \nullptr.)
\note The reference count of the returned object will \b{not} be
decremented. This function can be used together with the
constructor that takes a QAdoptSharedDataTag tag object to transfer
the shared data object without intervening atomic operations.
*/
/*! \fn template <class T> const T* QSharedDataPointer<T>::constData() const
Returns a const pointer to the shared data object.
This function does \e not call detach().
@ -365,6 +391,15 @@ QT_BEGIN_NAMESPACE
\a data and increments \a{data}'s reference count.
*/
/*! \fn template <class T> QSharedDataPointer<T>::QSharedDataPointer(T* data, QAdoptSharedDataTag)
\since 6.0
Constructs a QSharedDataPointer with \e{d pointer} set to
\a data. \a data's reference counter is \b{not} incremented;
this can be used to adopt pointers obtained from take().
\sa take()
*/
/*! \fn template <class T> QSharedDataPointer<T>::QSharedDataPointer(const QSharedDataPointer<T>& o)
Sets the \e{d pointer} of \e this to the \e{d pointer} in
\a o and increments the reference count of the shared
@ -615,7 +650,9 @@ QT_BEGIN_NAMESPACE
(That is, this function sets the \e{d pointer} of \e this to \nullptr.)
\note The reference count of the returned object will \b{not} be
decremented.
decremented. This function can be used together with the
constructor that takes a QAdoptSharedDataTag tag object to transfer
the shared data object without intervening atomic operations.
*/
/*! \fn template <class T> QExplicitlySharedDataPointer<T>::operator bool () const

View File

@ -64,6 +64,8 @@ public:
~QSharedData() = default;
};
struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; };
template <typename T>
class QSharedDataPointer
{
@ -83,12 +85,15 @@ public:
const T *data() const noexcept { return d; }
const T *get() const noexcept { return d; }
const T *constData() const noexcept { return d; }
T *take() noexcept { return qExchange(d, nullptr); }
QSharedDataPointer() noexcept : d(nullptr) { }
~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
explicit QSharedDataPointer(T *data) noexcept : d(data)
{ if (d) d->ref.ref(); }
QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
{}
QSharedDataPointer(const QSharedDataPointer &o) noexcept : d(o.d)
{ if (d) d->ref.ref(); }
@ -166,7 +171,7 @@ public:
T *data() const noexcept { return d; }
T *get() const noexcept { return d; }
const T *constData() const noexcept { return d; }
T *take() noexcept { T *x = d; d = nullptr; return x; }
T *take() noexcept { return qExchange(d, nullptr); }
void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
@ -175,6 +180,8 @@ public:
explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data)
{ if (d) d->ref.ref(); }
QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
{}
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : d(o.d)
{ if (d) d->ref.ref(); }

View File

@ -46,6 +46,7 @@
#define QSHAREDDATA_IMPL_H
#include <QtCore/qglobal.h>
#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
@ -66,6 +67,11 @@ public:
d->ref.ref();
}
QExplicitlySharedDataPointerV2(T *t, QAdoptSharedDataTag) noexcept
: d(t)
{
}
QExplicitlySharedDataPointerV2(const QExplicitlySharedDataPointerV2 &other) noexcept
: d(other.d)
{
@ -120,6 +126,11 @@ public:
d->ref.ref();
}
constexpr T *take() noexcept
{
return qExchange(d, nullptr);
}
bool isShared() const noexcept
{
return d && d->ref.loadRelaxed() != 1;