/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef Q_QDOC #ifndef QSHAREDPOINTER_H #error Do not include qsharedpointer_impl.h directly #endif #if 0 // These macros are duplicated here to make syncqt not complain a about // this header, as we have a "qt_sync_stop_processing" below, which in turn // is here because this file contains a template mess and duplicates the // classes found in qsharedpointer.h QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_END_NAMESPACE QT_END_HEADER #pragma qt_sync_stop_processing #endif #include #include #include // for qobject_cast QT_BEGIN_HEADER QT_BEGIN_NAMESPACE // Macro QSHAREDPOINTER_VERIFY_AUTO_CAST // generates a compiler error if the following construct isn't valid: // T *ptr1; // X *ptr2 = ptr1; // #ifdef QT_NO_DEBUG # define QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X) qt_noop() #else template inline void qt_sharedpointer_cast_check(T *) { } # define QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X) \ qt_sharedpointer_cast_check(static_cast(0)) #endif // // forward declarations // template class QWeakPointer; template class QSharedPointer; template QSharedPointer qSharedPointerCast(const QSharedPointer &ptr); template QSharedPointer qSharedPointerDynamicCast(const QSharedPointer &ptr); template QSharedPointer qSharedPointerConstCast(const QSharedPointer &ptr); #ifndef QT_NO_QOBJECT template QSharedPointer qSharedPointerObjectCast(const QSharedPointer &ptr); #endif namespace QtSharedPointer { template class InternalRefCount; template class ExternalRefCount; template QSharedPointer copyAndSetPointer(X * ptr, const QSharedPointer &src); // used in debug mode to verify the reuse of pointers Q_CORE_EXPORT void internalSafetyCheckAdd2(const void *, const volatile void *); Q_CORE_EXPORT void internalSafetyCheckRemove2(const void *); template inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)()) { (t->*memberDeleter)(); } template inline void executeDeleter(T *t, Deleter d) { d(t); } template inline void normalDeleter(T *t) { delete t; } // this uses partial template specialization template struct RemovePointer; template struct RemovePointer { typedef T Type; }; template struct RemovePointer > { typedef T Type; }; template struct RemovePointer > { typedef T Type; }; // This class provides the basic functionality of a pointer wrapper. // Its existence is mostly legacy, since originally QSharedPointer // could also be used for internally-refcounted objects. template class Basic { typedef T *Basic:: *RestrictedBool; public: typedef T Type; typedef T element_type; typedef T value_type; typedef value_type *pointer; typedef const value_type *const_pointer; typedef value_type &reference; typedef const value_type &const_reference; typedef qptrdiff difference_type; inline T *data() const { return value; } inline bool isNull() const { return !data(); } inline operator RestrictedBool() const { return isNull() ? 0 : &Basic::value; } inline bool operator !() const { return isNull(); } inline T &operator*() const { return *data(); } inline T *operator->() const { return data(); } protected: inline Basic(T *ptr = 0) : value(ptr) { } inline Basic(Qt::Initialization) { } // ~Basic(); inline void internalConstruct(T *ptr) { value = ptr; } #if defined(Q_NO_TEMPLATE_FRIENDS) public: #else template friend class QT_PREPEND_NAMESPACE(QWeakPointer); #endif Type *value; }; // This class is the d-pointer of QSharedPointer and QWeakPointer. // // It is a reference-counted reference counter. "strongref" is the inner // reference counter, and it tracks the lifetime of the pointer itself. // "weakref" is the outer reference counter and it tracks the lifetime of // the ExternalRefCountData object. struct ExternalRefCountData { QBasicAtomicInt weakref; QBasicAtomicInt strongref; inline ExternalRefCountData() { strongref.store(1); weakref.store(1); } inline ExternalRefCountData(Qt::Initialization) { } virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref.load()); Q_ASSERT(strongref.load() <= 0); } // overridden by derived classes // returns false to indicate caller should delete the pointer // returns true in case it has already done so virtual inline bool destroy() { return false; } #ifndef QT_NO_QOBJECT Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *); Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable); Q_CORE_EXPORT void checkQObjectShared(const QObject *); #endif inline void checkQObjectShared(...) { } inline void setQObjectShared(...) { } }; // sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit) // This class extends ExternalRefCountData with a pointer // to a function, which is called by the destroy() function. struct ExternalRefCountWithDestroyFn: public ExternalRefCountData { typedef void (*DestroyerFn)(ExternalRefCountData *); DestroyerFn destroyer; inline ExternalRefCountWithDestroyFn(DestroyerFn d) : destroyer(d) { } inline bool destroy() { destroyer(this); return true; } inline void operator delete(void *ptr) { ::operator delete(ptr); } inline void operator delete(void *, void *) { } }; // sizeof(ExternalRefCountWithDestroyFn) = 16 (32-bit) / 24 (64-bit) // This class extends ExternalRefCountWithDestroyFn and implements // the static function that deletes the object. The pointer and the // custom deleter are kept in the "extra" member. template struct ExternalRefCountWithCustomDeleter: public ExternalRefCountWithDestroyFn { typedef ExternalRefCountWithCustomDeleter Self; typedef ExternalRefCountWithDestroyFn BaseClass; struct CustomDeleter { Deleter deleter; T *ptr; inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {} }; CustomDeleter extra; // sizeof(CustomDeleter) = sizeof(Deleter) + sizeof(void*) // for Deleter = function pointer: 8 (32-bit) / 16 (64-bit) // for Deleter = PMF: 12 (32-bit) / 24 (64-bit) (GCC) static inline void deleter(ExternalRefCountData *self) { Self *realself = static_cast(self); executeDeleter(realself->extra.ptr, realself->extra.deleter); // delete the deleter too realself->extra.~CustomDeleter(); } static void safetyCheckDeleter(ExternalRefCountData *self) { internalSafetyCheckRemove2(self); deleter(self); } static inline Self *create(T *ptr, Deleter userDeleter) { # ifdef QT_SHAREDPOINTER_TRACK_POINTERS DestroyerFn destroy = &safetyCheckDeleter; # else DestroyerFn destroy = &deleter; # endif Self *d = static_cast(::operator new(sizeof(Self))); // initialize the two sub-objects new (&d->extra) CustomDeleter(ptr, userDeleter); new (d) BaseClass(destroy); // can't throw return d; } private: // prevent construction and the emission of virtual symbols ExternalRefCountWithCustomDeleter(); ~ExternalRefCountWithCustomDeleter(); }; // This class extends ExternalRefCountWithDestroyFn and adds a "T" // member. That way, when the create() function is called, we allocate // memory for both QSharedPointer's d-pointer and the actual object being // tracked. template struct ExternalRefCountWithContiguousData: public ExternalRefCountWithDestroyFn { typedef ExternalRefCountWithDestroyFn Parent; T data; static void deleter(ExternalRefCountData *self) { ExternalRefCountWithContiguousData *that = static_cast(self); that->data.~T(); } static void safetyCheckDeleter(ExternalRefCountData *self) { internalSafetyCheckRemove2(self); deleter(self); } static inline ExternalRefCountData *create(T **ptr) { # ifdef QT_SHAREDPOINTER_TRACK_POINTERS DestroyerFn destroy = &safetyCheckDeleter; # else DestroyerFn destroy = &deleter; # endif ExternalRefCountWithContiguousData *d = static_cast(::operator new(sizeof(ExternalRefCountWithContiguousData))); // initialize the d-pointer sub-object // leave d->data uninitialized new (d) Parent(destroy); // can't throw *ptr = &d->data; return d; } private: // prevent construction and the emission of virtual symbols ExternalRefCountWithContiguousData(); ~ExternalRefCountWithContiguousData(); }; // This is the main body of QSharedPointer. It implements the // external reference counting functionality. template class ExternalRefCount: public Basic { protected: typedef ExternalRefCountData Data; inline void deref() { deref(d, this->value); } static inline void deref(Data *d, T *value) { if (!d) return; if (!d->strongref.deref()) { if (!d->destroy()) delete value; } if (!d->weakref.deref()) delete d; } inline void internalConstruct(T *ptr) { #ifdef QT_SHAREDPOINTER_TRACK_POINTERS internalConstruct(ptr, normalDeleter); #else if (ptr) d = new Data; else d = 0; internalFinishConstruction(ptr); #endif } template inline void internalConstruct(T *ptr, Deleter deleter) { if (ptr) d = ExternalRefCountWithCustomDeleter::create(ptr, deleter); else d = 0; internalFinishConstruction(ptr); } inline void internalCreate() { T *ptr; d = ExternalRefCountWithContiguousData::create(&ptr); Basic::internalConstruct(ptr); } inline void internalFinishConstruction(T *ptr) { Basic::internalConstruct(ptr); if (ptr) d->setQObjectShared(ptr, true); #ifdef QT_SHAREDPOINTER_TRACK_POINTERS if (ptr) internalSafetyCheckAdd2(d, ptr); #endif } inline ExternalRefCount() : d(0) { } inline ExternalRefCount(Qt::Initialization i) : Basic(i) { } inline ExternalRefCount(T *ptr) : Basic(Qt::Uninitialized) // throws { internalConstruct(ptr); } template inline ExternalRefCount(T *ptr, Deleter deleter) : Basic(Qt::Uninitialized) // throws { internalConstruct(ptr, deleter); } inline ExternalRefCount(const ExternalRefCount &other) : Basic(other), d(other.d) { if (d) ref(); } template inline ExternalRefCount(const ExternalRefCount &other) : Basic(other.value), d(other.d) { if (d) ref(); } inline ~ExternalRefCount() { deref(); } template inline void internalCopy(const ExternalRefCount &other) { Data *o = other.d; T *actual = other.value; if (o) other.ref(); qSwap(d, o); qSwap(this->value, actual); deref(o, actual); } inline void internalSwap(ExternalRefCount &other) { qSwap(d, other.d); qSwap(this->value, other.value); } #if defined(Q_NO_TEMPLATE_FRIENDS) public: #else template friend class ExternalRefCount; template friend class QT_PREPEND_NAMESPACE(QWeakPointer); template friend QSharedPointer copyAndSetPointer(X * ptr, const QSharedPointer &src); #endif inline void ref() const { d->weakref.ref(); d->strongref.ref(); } inline void internalSet(Data *o, T *actual) { if (o) { // increase the strongref, but never up from zero // or less (-1 is used by QWeakPointer on untracked QObject) register int tmp = o->strongref.load(); while (tmp > 0) { // try to increment from "tmp" to "tmp + 1" if (o->strongref.testAndSetRelaxed(tmp, tmp + 1)) break; // succeeded tmp = o->strongref.load(); // failed, try again } if (tmp > 0) { o->weakref.ref(); } else { o->checkQObjectShared(actual); o = 0; } } qSwap(d, o); qSwap(this->value, actual); if (!d || d->strongref.load() == 0) this->value = 0; // dereference saved data deref(o, actual); } Data *d; private: template ExternalRefCount(const InternalRefCount &); }; } // namespace QtSharedPointer template class QSharedPointer: public QtSharedPointer::ExternalRefCount { typedef typename QtSharedPointer::ExternalRefCount BaseClass; public: inline QSharedPointer() { } // inline ~QSharedPointer() { } inline explicit QSharedPointer(T *ptr) : BaseClass(ptr) // throws { } template inline QSharedPointer(T *ptr, Deleter d) : BaseClass(ptr, d) // throws { } inline QSharedPointer(const QSharedPointer &other) : BaseClass(other) { } inline QSharedPointer &operator=(const QSharedPointer &other) { BaseClass::internalCopy(other); return *this; } #ifdef Q_COMPILER_RVALUE_REFS inline QSharedPointer &operator=(QSharedPointer &&other) { QSharedPointer::internalSwap(other); return *this; } #endif template inline QSharedPointer(const QSharedPointer &other) : BaseClass(other) { } template inline QSharedPointer &operator=(const QSharedPointer &other) { QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid BaseClass::internalCopy(other); return *this; } template inline QSharedPointer(const QWeakPointer &other) : BaseClass(Qt::Uninitialized) { this->d = 0; *this = other; } template inline QSharedPointer &operator=(const QWeakPointer &other) { BaseClass::internalSet(other.d, other.value); return *this; } inline void swap(QSharedPointer &other) { QSharedPointer::internalSwap(other); } template QSharedPointer staticCast() const { return qSharedPointerCast(*this); } template QSharedPointer dynamicCast() const { return qSharedPointerDynamicCast(*this); } template QSharedPointer constCast() const { return qSharedPointerConstCast(*this); } #ifndef QT_NO_QOBJECT template QSharedPointer objectCast() const { return qSharedPointerObjectCast(*this); } #endif inline void clear() { *this = QSharedPointer(); } QWeakPointer toWeakRef() const; protected: inline explicit QSharedPointer(Qt::Initialization i) : BaseClass(i) {} public: static inline QSharedPointer create() { QSharedPointer result(Qt::Uninitialized); result.internalCreate(); // now initialize the data new (result.data()) T(); result.internalFinishConstruction(result.data()); return result; } }; template class QWeakPointer { typedef T *QWeakPointer:: *RestrictedBool; typedef QtSharedPointer::ExternalRefCountData Data; public: typedef T element_type; typedef T value_type; typedef value_type *pointer; typedef const value_type *const_pointer; typedef value_type &reference; typedef const value_type &const_reference; typedef qptrdiff difference_type; inline bool isNull() const { return d == 0 || d->strongref.load() == 0 || value == 0; } inline operator RestrictedBool() const { return isNull() ? 0 : &QWeakPointer::value; } inline bool operator !() const { return isNull(); } inline T *data() const { return d == 0 || d->strongref.load() == 0 ? 0 : value; } inline QWeakPointer() : d(0), value(0) { } inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; } #ifndef QT_NO_QOBJECT // special constructor that is enabled only if X derives from QObject template inline QWeakPointer(X *ptr) : d(ptr ? d->getAndRef(ptr) : 0), value(ptr) { } #endif template inline QWeakPointer &operator=(X *ptr) { return *this = QWeakPointer(ptr); } inline QWeakPointer(const QWeakPointer &o) : d(o.d), value(o.value) { if (d) d->weakref.ref(); } inline QWeakPointer &operator=(const QWeakPointer &o) { internalSet(o.d, o.value); return *this; } inline QWeakPointer(const QSharedPointer &o) : d(o.d), value(o.data()) { if (d) d->weakref.ref();} inline QWeakPointer &operator=(const QSharedPointer &o) { internalSet(o.d, o.value); return *this; } template inline QWeakPointer(const QWeakPointer &o) : d(0), value(0) { *this = o; } template inline QWeakPointer &operator=(const QWeakPointer &o) { // conversion between X and T could require access to the virtual table // so force the operation to go through QSharedPointer *this = o.toStrongRef(); return *this; } template inline bool operator==(const QWeakPointer &o) const { return d == o.d && value == static_cast(o.value); } template inline bool operator!=(const QWeakPointer &o) const { return !(*this == o); } template inline QWeakPointer(const QSharedPointer &o) : d(0), value(0) { *this = o; } template inline QWeakPointer &operator=(const QSharedPointer &o) { QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid internalSet(o.d, o.data()); return *this; } template inline bool operator==(const QSharedPointer &o) const { return d == o.d; } template inline bool operator!=(const QSharedPointer &o) const { return !(*this == o); } inline void clear() { *this = QWeakPointer(); } inline QSharedPointer toStrongRef() const { return QSharedPointer(*this); } #if defined(QWEAKPOINTER_ENABLE_ARROW) inline T *operator->() const { return data(); } #endif private: #if defined(Q_NO_TEMPLATE_FRIENDS) public: #else template friend class QSharedPointer; #endif inline void internalSet(Data *o, T *actual) { if (d == o) return; if (o) o->weakref.ref(); if (d && !d->weakref.deref()) delete d; d = o; value = actual; } Data *d; T *value; }; // // operator== and operator!= // template bool operator==(const QSharedPointer &ptr1, const QSharedPointer &ptr2) { return ptr1.data() == ptr2.data(); } template bool operator!=(const QSharedPointer &ptr1, const QSharedPointer &ptr2) { return ptr1.data() != ptr2.data(); } template bool operator==(const QSharedPointer &ptr1, const X *ptr2) { return ptr1.data() == ptr2; } template bool operator==(const T *ptr1, const QSharedPointer &ptr2) { return ptr1 == ptr2.data(); } template bool operator!=(const QSharedPointer &ptr1, const X *ptr2) { return !(ptr1 == ptr2); } template bool operator!=(const T *ptr1, const QSharedPointer &ptr2) { return !(ptr2 == ptr1); } template bool operator==(const QSharedPointer &ptr1, const QWeakPointer &ptr2) { return ptr2 == ptr1; } template bool operator!=(const QSharedPointer &ptr1, const QWeakPointer &ptr2) { return ptr2 != ptr1; } // // operator- // template Q_INLINE_TEMPLATE typename QSharedPointer::difference_type operator-(const QSharedPointer &ptr1, const QSharedPointer &ptr2) { return ptr1.data() - ptr2.data(); } template Q_INLINE_TEMPLATE typename QSharedPointer::difference_type operator-(const QSharedPointer &ptr1, X *ptr2) { return ptr1.data() - ptr2; } template Q_INLINE_TEMPLATE typename QSharedPointer::difference_type operator-(T *ptr1, const QSharedPointer &ptr2) { return ptr1 - ptr2.data(); } // // operator< // template Q_INLINE_TEMPLATE bool operator<(const QSharedPointer &ptr1, const QSharedPointer &ptr2) { return ptr1.data() < ptr2.data(); } template Q_INLINE_TEMPLATE bool operator<(const QSharedPointer &ptr1, X *ptr2) { return ptr1.data() < ptr2; } template Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer &ptr2) { return ptr1 < ptr2.data(); } // // qHash // template inline uint qHash(const T *key); // defined in qhash.h template Q_INLINE_TEMPLATE uint qHash(const QSharedPointer &ptr) { return QT_PREPEND_NAMESPACE(qHash)(ptr.data()); } template Q_INLINE_TEMPLATE QWeakPointer QSharedPointer::toWeakRef() const { return QWeakPointer(*this); } template inline void qSwap(QSharedPointer &p1, QSharedPointer &p2) { p1.swap(p2); } #ifndef QT_NO_STL QT_END_NAMESPACE namespace std { template inline void swap(QT_PREPEND_NAMESPACE(QSharedPointer) &p1, QT_PREPEND_NAMESPACE(QSharedPointer) &p2) { p1.swap(p2); } } QT_BEGIN_NAMESPACE #endif namespace QtSharedPointer { // helper functions: template Q_INLINE_TEMPLATE QSharedPointer copyAndSetPointer(X *ptr, const QSharedPointer &src) { QSharedPointer result; result.internalSet(src.d, ptr); return result; } } // cast operators template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerCast(const QSharedPointer &src) { register X *ptr = static_cast(src.data()); // if you get an error in this line, the cast is invalid return QtSharedPointer::copyAndSetPointer(ptr, src); } template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerCast(const QWeakPointer &src) { return qSharedPointerCast(src.toStrongRef()); } template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerDynamicCast(const QSharedPointer &src) { register X *ptr = dynamic_cast(src.data()); // if you get an error in this line, the cast is invalid return QtSharedPointer::copyAndSetPointer(ptr, src); } template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerDynamicCast(const QWeakPointer &src) { return qSharedPointerDynamicCast(src.toStrongRef()); } template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerConstCast(const QSharedPointer &src) { register X *ptr = const_cast(src.data()); // if you get an error in this line, the cast is invalid return QtSharedPointer::copyAndSetPointer(ptr, src); } template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerConstCast(const QWeakPointer &src) { return qSharedPointerConstCast(src.toStrongRef()); } template Q_INLINE_TEMPLATE QWeakPointer qWeakPointerCast(const QSharedPointer &src) { return qSharedPointerCast(src).toWeakRef(); } #ifndef QT_NO_QOBJECT template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerObjectCast(const QSharedPointer &src) { register X *ptr = qobject_cast(src.data()); return QtSharedPointer::copyAndSetPointer(ptr, src); } template Q_INLINE_TEMPLATE QSharedPointer qSharedPointerObjectCast(const QWeakPointer &src) { return qSharedPointerObjectCast(src.toStrongRef()); } template inline QSharedPointer::Type> qobject_cast(const QSharedPointer &src) { return qSharedPointerObjectCast::Type, T>(src); } template inline QSharedPointer::Type> qobject_cast(const QWeakPointer &src) { return qSharedPointerObjectCast::Type, T>(src); } #endif template Q_DECLARE_TYPEINFO_BODY(QWeakPointer, Q_MOVABLE_TYPE); template Q_DECLARE_TYPEINFO_BODY(QSharedPointer, Q_MOVABLE_TYPE); QT_END_NAMESPACE QT_END_HEADER #endif