/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, 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.0, 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. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef Q_QDOC #ifndef QSHAREDPOINTER_H #error Do not include qsharedpointer_impl.h directly #endif #if 0 #pragma qt_sync_stop_processing #endif #include #include #include // for qobject_cast QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Core) // 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 // the only compilers that didn't support this were MSVC 6.0 and 2002 template struct RemovePointer; template struct RemovePointer { typedef T Type; }; template struct RemovePointer > { typedef T Type; }; template struct RemovePointer > { typedef T Type; }; template class Basic { typedef T *Basic:: *RestrictedBool; public: typedef T 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 QWeakPointer; #endif Type *value; }; struct ExternalRefCountData { QBasicAtomicInt weakref; QBasicAtomicInt strongref; inline ExternalRefCountData() { QBasicAtomicInt proto = Q_BASIC_ATOMIC_INITIALIZER(1); weakref = strongref = proto; } inline ExternalRefCountData(Qt::Initialization) { } virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(strongref <= 0); } 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); #endif inline void setQObjectShared(...) { } }; // sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit) template struct CustomDeleter { Deleter deleter; T *ptr; inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {} }; // 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) 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); } }; // sizeof(ExternalRefCountWithDestroyFn) = 16 (32-bit) / 24 (64-bit) template struct ExternalRefCountWithCustomDeleter: public ExternalRefCountWithDestroyFn { typedef ExternalRefCountWithCustomDeleter Self; typedef ExternalRefCountWithDestroyFn Parent; typedef CustomDeleter Next; Next extra; static inline void deleter(ExternalRefCountData *self) { Self *realself = static_cast(self); executeDeleter(realself->extra.ptr, realself->extra.deleter); // delete the deleter too realself->extra.~Next(); } 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) Next(ptr, userDeleter); new (d) Parent(destroy); // can't throw return d; } private: // prevent construction and the emission of virtual symbols ExternalRefCountWithCustomDeleter(); ~ExternalRefCountWithCustomDeleter(); }; 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(); }; template class ExternalRefCount: public Basic { protected: typedef ExternalRefCountData Data; inline void ref() const { d->weakref.ref(); d->strongref.ref(); } inline bool deref() { if (!d->strongref.deref()) { internalDestroy(); } return d->weakref.deref(); } 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(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() { if (d && !deref()) delete d; } template inline void internalCopy(const ExternalRefCount &other) { internalSet(other.d, other.data()); } inline void internalDestroy() { if (!d->destroy()) delete this->value; } #if defined(Q_NO_TEMPLATE_FRIENDS) public: #else template friend class ExternalRefCount; template friend class QWeakPointer; template friend QSharedPointer copyAndSetPointer(X * ptr, const QSharedPointer &src); #endif 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; while (tmp > 0) { // try to increment from "tmp" to "tmp + 1" if (o->strongref.testAndSetRelaxed(tmp, tmp + 1)) break; // succeeded tmp = o->strongref; // failed, try again } if (tmp > 0) o->weakref.ref(); else o = 0; } if (d && !deref()) delete d; d = o; this->value = d && d->strongref ? actual : 0; } 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(Qt::Uninitialized) { internalConstruct(ptr); } template inline QSharedPointer(T *ptr, Deleter d) { internalConstruct(ptr, d); } inline QSharedPointer(const QSharedPointer &other) : BaseClass(other) { } inline QSharedPointer &operator=(const QSharedPointer &other) { internalCopy(other); return *this; } 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 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) { internalSet(other.d, other.value); return *this; } 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 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: inline bool isNull() const { return d == 0 || d->strongref == 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 == 0 ? 0 : value; } inline QWeakPointer() : d(0), value(0) { } inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; } // special constructor that is enabled only if X derives from QObject template inline QWeakPointer(X *ptr) : d(ptr ? d->getAndRef(ptr) : 0), value(ptr) { } 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); } 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; }; 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; } template Q_INLINE_TEMPLATE QWeakPointer QSharedPointer::toWeakRef() const { return QWeakPointer(*this); } 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 QT_END_NAMESPACE QT_END_HEADER #endif