diff options
Diffstat (limited to 'src/corelib/tools/qsharedpointer_impl.h')
-rw-r--r-- | src/corelib/tools/qsharedpointer_impl.h | 216 |
1 files changed, 132 insertions, 84 deletions
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index eb8846249b..456be91d03 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -1,43 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2020 Intel Corporation. -** Copyright (C) 2019 Klarälvdalens Datakonsult AB. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2022 Intel Corporation. +// Copyright (C) 2019 Klarälvdalens Datakonsult AB. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef Q_QDOC @@ -62,13 +26,18 @@ QT_END_NAMESPACE #include <new> #include <QtCore/qatomic.h> -#include <QtCore/qobject.h> // for qobject_cast #include <QtCore/qhashfunctions.h> +#include <QtCore/qmetatype.h> // for IsPointerToTypeDerivedFromQObject +#include <QtCore/qxptype_traits.h> #include <memory> QT_BEGIN_NAMESPACE +class QObject; +template <class T> +T qobject_cast(const QObject *object); + // // forward declarations // @@ -147,11 +116,22 @@ namespace QtSharedPointer { #ifndef QT_NO_QOBJECT Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *); + QT6_ONLY( Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable); - Q_CORE_EXPORT void checkQObjectShared(const QObject *); + ) + QT6_ONLY(Q_CORE_EXPORT void checkQObjectShared(const QObject *);) #endif inline void checkQObjectShared(...) { } inline void setQObjectShared(...) { } + + // Normally, only subclasses of ExternalRefCountData are allocated + // One exception exists in getAndRef; that uses the global operator new + // to prevent a mismatch with the custom operator delete + inline void *operator new(std::size_t) = delete; + // placement new + inline void *operator new(std::size_t, void *ptr) noexcept { return ptr; } + inline void operator delete(void *ptr) { ::operator delete(ptr); } + inline void operator delete(void *, void *) { } }; // sizeof(ExternalRefCountData) = 12 (32-bit) / 16 (64-bit) @@ -299,23 +279,29 @@ public: T &operator*() const { return *data(); } T *operator->() const noexcept { return data(); } + Q_NODISCARD_CTOR constexpr QSharedPointer() noexcept : value(nullptr), d(nullptr) { } ~QSharedPointer() { deref(); } + Q_NODISCARD_CTOR constexpr QSharedPointer(std::nullptr_t) noexcept : value(nullptr), d(nullptr) { } template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept { internalConstruct(ptr, QtSharedPointer::NormalDeleter()); } template <class X, typename Deleter, IfCompatible<X> = true> + Q_NODISCARD_CTOR inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws { internalConstruct(ptr, deleter); } template <typename Deleter> + Q_NODISCARD_CTOR QSharedPointer(std::nullptr_t, Deleter deleter) : value(nullptr) { internalConstruct(static_cast<T *>(nullptr), deleter); } + Q_NODISCARD_CTOR QSharedPointer(const QSharedPointer &other) noexcept : value(other.value), d(other.d) { if (d) ref(); } QSharedPointer &operator=(const QSharedPointer &other) noexcept @@ -324,6 +310,7 @@ public: swap(copy); return *this; } + Q_NODISCARD_CTOR QSharedPointer(QSharedPointer &&other) noexcept : value(other.value), d(other.d) { @@ -333,6 +320,7 @@ public: QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedPointer) template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR QSharedPointer(QSharedPointer<X> &&other) noexcept : value(other.value), d(other.d) { @@ -349,6 +337,7 @@ public: } template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR QSharedPointer(const QSharedPointer<X> &other) noexcept : value(other.value), d(other.d) { if (d) ref(); } @@ -361,6 +350,7 @@ public: } template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR inline QSharedPointer(const QWeakPointer<X> &other) : value(nullptr), d(nullptr) { *this = other; } @@ -406,10 +396,10 @@ public: inline void clear() { QSharedPointer copy; swap(copy); } - QWeakPointer<T> toWeakRef() const; + [[nodiscard]] QWeakPointer<T> toWeakRef() const; template <typename... Args> - static QSharedPointer create(Args && ...arguments) + [[nodiscard]] static QSharedPointer create(Args && ...arguments) { typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private; # ifdef QT_SHAREDPOINTER_TRACK_POINTERS @@ -454,8 +444,27 @@ public: DECLARE_COMPARE_SET(const QSharedPointer &p1, p1.data(), std::nullptr_t, nullptr) DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QSharedPointer &p2, p2.data()) #undef DECLARE_TEMPLATE_COMPARE_SET +#undef DECLARE_COMPARE_SET + + template <typename X> + bool owner_before(const QSharedPointer<X> &other) const noexcept + { return std::less<>()(d, other.d); } + template <typename X> + bool owner_before(const QWeakPointer<X> &other) const noexcept + { return std::less<>()(d, other.d); } + + template <typename X> + bool owner_equal(const QSharedPointer<X> &other) const noexcept + { return d == other.d; } + template <typename X> + bool owner_equal(const QWeakPointer<X> &other) const noexcept + { return d == other.d; } + + size_t owner_hash() const noexcept + { return std::hash<Data *>()(d); } private: + Q_NODISCARD_CTOR explicit QSharedPointer(Qt::Initialization) {} void deref() noexcept @@ -492,23 +501,18 @@ private: #ifdef QT_SHAREDPOINTER_TRACK_POINTERS internalSafetyCheckAdd(d, ptr); #endif - d->setQObjectShared(ptr, true); enableSharedFromThis(ptr); } void internalSwap(QSharedPointer &other) noexcept { - qSwap(d, other.d); - qSwap(this->value, other.value); + qt_ptr_swap(d, other.d); + qt_ptr_swap(this->value, other.value); } -#if defined(Q_NO_TEMPLATE_FRIENDS) -public: -#else template <class X> friend class QSharedPointer; template <class X> friend class QWeakPointer; template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src); -#endif void ref() const noexcept { d->weakref.ref(); d->strongref.ref(); } inline void internalSet(Data *o, T *actual) @@ -524,16 +528,14 @@ public: tmp = o->strongref.loadRelaxed(); // failed, try again } - if (tmp > 0) { + if (tmp > 0) o->weakref.ref(); - } else { - o->checkQObjectShared(actual); + else o = nullptr; - } } - qSwap(d, o); - qSwap(this->value, actual); + qt_ptr_swap(d, o); + qt_ptr_swap(this->value, actual); if (!d || d->strongref.loadRelaxed() == 0) this->value = nullptr; @@ -552,6 +554,12 @@ class QWeakPointer template <typename X> using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type; + template <typename X> + using IfVirtualBase = typename std::enable_if<qxp::is_virtual_base_of_v<T, X>, bool>::type; + + template <typename X> + using IfNotVirtualBase = typename std::enable_if<!qxp::is_virtual_base_of_v<T, X>, bool>::type; + public: typedef T element_type; typedef T value_type; @@ -565,11 +573,14 @@ public: explicit operator bool() const noexcept { return !isNull(); } bool operator !() const noexcept { return isNull(); } - inline QWeakPointer() noexcept : d(nullptr), value(nullptr) { } + Q_NODISCARD_CTOR + constexpr QWeakPointer() noexcept : d(nullptr), value(nullptr) { } inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; } + Q_NODISCARD_CTOR QWeakPointer(const QWeakPointer &other) noexcept : d(other.d), value(other.value) { if (d) d->weakref.ref(); } + Q_NODISCARD_CTOR QWeakPointer(QWeakPointer &&other) noexcept : d(other.d), value(other.value) { @@ -577,6 +588,32 @@ public: other.value = nullptr; } QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QWeakPointer) + + template <class X, IfCompatible<X> = true, IfNotVirtualBase<X> = true> + Q_NODISCARD_CTOR + QWeakPointer(QWeakPointer<X> &&other) noexcept + : d(std::exchange(other.d, nullptr)), + value(std::exchange(other.value, nullptr)) + { + } + + template <class X, IfCompatible<X> = true, IfVirtualBase<X> = true> + Q_NODISCARD_CTOR + QWeakPointer(QWeakPointer<X> &&other) noexcept + : d(other.d), value(other.toStrongRef().get()) // must go through QSharedPointer, see below + { + other.d = nullptr; + other.value = nullptr; + } + + template <class X, IfCompatible<X> = true> + QWeakPointer &operator=(QWeakPointer<X> &&other) noexcept + { + QWeakPointer moved(std::move(other)); + swap(moved); + return *this; + } + QWeakPointer &operator=(const QWeakPointer &other) noexcept { QWeakPointer copy(other); @@ -586,10 +623,11 @@ public: void swap(QWeakPointer &other) noexcept { - qSwap(this->d, other.d); - qSwap(this->value, other.value); + qt_ptr_swap(this->d, other.d); + qt_ptr_swap(this->value, other.value); } + Q_NODISCARD_CTOR inline QWeakPointer(const QSharedPointer<T> &o) : d(o.d), value(o.data()) { if (d) d->weakref.ref();} inline QWeakPointer &operator=(const QSharedPointer<T> &o) @@ -599,6 +637,7 @@ public: } template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr) { *this = o; } @@ -612,6 +651,7 @@ public: } template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr) { *this = o; } @@ -624,13 +664,9 @@ public: inline void clear() { *this = QWeakPointer(); } - inline QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); } + [[nodiscard]] QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); } // std::weak_ptr compatibility: - inline QSharedPointer<T> lock() const { return toStrongRef(); } - -#if defined(QWEAKPOINTER_ENABLE_ARROW) - inline T *operator->() const { return data(); } -#endif + [[nodiscard]] QSharedPointer<T> lock() const { return toStrongRef(); } template <class X> bool operator==(const QWeakPointer<X> &o) const noexcept @@ -655,25 +691,45 @@ public: friend bool operator!=(const QSharedPointer<X> &p1, const QWeakPointer &p2) noexcept { return p2 != p1; } - DECLARE_COMPARE_SET(const QWeakPointer &p1, p1.d, std::nullptr_t, nullptr) - DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QWeakPointer &p2, p2.data()) -#undef DECLARE_COMPARE_SET + friend bool operator==(const QWeakPointer &p, std::nullptr_t) + { return p.isNull(); } + friend bool operator==(std::nullptr_t, const QWeakPointer &p) + { return p.isNull(); } + friend bool operator!=(const QWeakPointer &p, std::nullptr_t) + { return !p.isNull(); } + friend bool operator!=(std::nullptr_t, const QWeakPointer &p) + { return !p.isNull(); } + + template <typename X> + bool owner_before(const QWeakPointer<X> &other) const noexcept + { return std::less<>()(d, other.d); } + template <typename X> + bool owner_before(const QSharedPointer<X> &other) const noexcept + { return std::less<>()(d, other.d); } + + template <typename X> + bool owner_equal(const QWeakPointer<X> &other) const noexcept + { return d == other.d; } + template <typename X> + bool owner_equal(const QSharedPointer<X> &other) const noexcept + { return d == other.d; } + + size_t owner_hash() const noexcept + { return std::hash<Data *>()(d); } private: friend struct QtPrivate::EnableInternalData; -#if defined(Q_NO_TEMPLATE_FRIENDS) -public: -#else template <class X> friend class QSharedPointer; + template <class X> friend class QWeakPointer; template <class X> friend class QPointer; -#endif template <class X> inline QWeakPointer &assign(X *ptr) - { return *this = QWeakPointer<X>(ptr, true); } + { return *this = QWeakPointer<T>(ptr, true); } #ifndef QT_NO_QOBJECT template <class X, IfCompatible<X> = true> + Q_NODISCARD_CTOR inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr) { } #endif @@ -723,12 +779,8 @@ public: inline QSharedPointer<T> sharedFromThis() { return QSharedPointer<T>(weakPointer); } inline QSharedPointer<const T> sharedFromThis() const { return QSharedPointer<const T>(weakPointer); } -#ifndef Q_NO_TEMPLATE_FRIENDS private: template <class X> friend class QSharedPointer; -#else -public: -#endif template <class X> inline void initializeFromSharedPointer(const QSharedPointer<X> &ptr) const { @@ -785,7 +837,7 @@ Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer<X> &ptr2) template <class T> Q_INLINE_TEMPLATE size_t qHash(const QSharedPointer<T> &ptr, size_t seed = 0) { - return QT_PREPEND_NAMESPACE(qHash)(ptr.data(), seed); + return qHash(ptr.data(), seed); } @@ -916,15 +968,11 @@ std::shared_ptr<X> qobject_pointer_cast(std::shared_ptr<T> &&src) using element_type = typename std::shared_ptr<X>::element_type; auto castResult = qobject_cast<element_type *>(src.get()); if (castResult) { - auto result = std::shared_ptr<X>(std::move(src), castResult); -#if __cplusplus <= 201703L // C++2a's move aliasing constructor will leave src empty. // Before C++2a we don't really know if the compiler has support for it. // The move aliasing constructor is the resolution for LWG2996, // which does not impose a feature-testing macro. So: clear src. - src.reset(); -#endif - return result; + return std::shared_ptr<X>(std::exchange(src, nullptr), castResult); } return std::shared_ptr<X>(); } |