From aa442e9450c8a288b8aaa2dda79ccb69d8774429 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 15 Oct 2020 01:26:14 +0200 Subject: [PATCH] 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 --- src/corelib/tools/qshareddata.cpp | 39 +++++++++++++++++++++++++++- src/corelib/tools/qshareddata.h | 9 ++++++- src/corelib/tools/qshareddata_impl.h | 11 ++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qshareddata.cpp b/src/corelib/tools/qshareddata.cpp index 42360a4caef..6db2a9adb9b 100644 --- a/src/corelib/tools/qshareddata.cpp +++ b/src/corelib/tools/qshareddata.cpp @@ -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 const T* QSharedDataPointer::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 const T* QSharedDataPointer::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 QSharedDataPointer::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 QSharedDataPointer::QSharedDataPointer(const QSharedDataPointer& 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 QExplicitlySharedDataPointer::operator bool () const diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 669d9d14c40..bda117739c9 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -64,6 +64,8 @@ public: ~QSharedData() = default; }; +struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; }; + template 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(); } diff --git a/src/corelib/tools/qshareddata_impl.h b/src/corelib/tools/qshareddata_impl.h index 0a218b0b4b9..cf1c534cdf2 100644 --- a/src/corelib/tools/qshareddata_impl.h +++ b/src/corelib/tools/qshareddata_impl.h @@ -46,6 +46,7 @@ #define QSHAREDDATA_IMPL_H #include +#include 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;