/**************************************************************************** ** ** 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 strongRefFromWeakHelper(const QWeakPointer &, X*); 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); } // // Depending on its template parameter, QSharedPointer derives from either // QtSharedPointer::InternalRefCount or from QtSharedPointer::ExternalRefCount. // Both of these classes derive from QtSharedPointer::Basic, which provides common // operations, // 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() : value(0) { } // ~Basic(); inline void verifyReconstruction(const T *ptr) { Q_ASSERT_X(!ptr || value != ptr, "QSharedPointer", "QSharedPointer violation: you cannot create two QSharedPointer objects " "from the same pointer"); // make use of the "ptr" variable in the no-op statement below // since this function is in a public header, we don't // want warnings on "unused variables" to show up everywhere ptr = 0; } inline void internalConstruct(T *ptr) { value = ptr; } #if defined(Q_NO_TEMPLATE_FRIENDS) public: #else template friend class QWeakPointer; #endif Type *value; }; struct ExternalRefCountData { QAtomicInt weakref; QAtomicInt strongref; inline ExternalRefCountData() : weakref(1), strongref(1) { } virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(!strongref); } virtual inline bool destroy() { return false; } }; template struct CustomDeleter { Deleter deleter; T *ptr; inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {} }; 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); } }; 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); } static inline Self *create(T *ptr, Deleter userDeleter) { DestroyerFn destroy = &deleter; 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 inline ExternalRefCountData *create(T **ptr) { DestroyerFn destroy = &deleter; 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 { typedef ExternalRefCountData Data; typedef void (*DeleterFunction)(T *); protected: 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) { Basic::internalConstruct(ptr); Q_ASSERT(!d); if (ptr) d = new Data; #ifdef QT_SHAREDPOINTER_TRACK_POINTERS if (ptr) internalSafetyCheckAdd2(d, ptr); #endif } template inline void internalConstruct(T *ptr, Deleter deleter) { Basic::internalConstruct(ptr); Q_ASSERT(!d); if (ptr) d = ExternalRefCountWithCustomDeleter::create(ptr, deleter); #ifdef QT_SHAREDPOINTER_TRACK_POINTERS if (ptr) internalSafetyCheckAdd2(d, ptr); #endif } inline void internalCreate() { T *ptr; d = ExternalRefCountWithContiguousData::create(&ptr); Basic::internalConstruct(ptr); #ifdef QT_SHAREDPOINTER_TRACK_POINTERS if (ptr) internalSafetyCheckAdd2(d, ptr); #endif } inline ExternalRefCount() : d(0) { } inline ~ExternalRefCount() { if (d && !deref()) delete d; } inline ExternalRefCount(const ExternalRefCount &other) : Basic(other), d(other.d) { if (d) ref(); } template inline void internalCopy(const ExternalRefCount &other) { internalSet(other.d, other.data()); } inline void internalDestroy() { #ifdef QT_SHAREDPOINTER_TRACK_POINTERS internalSafetyCheckRemove2(d); #endif if (!d->destroy()) delete this->value; } private: #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); template friend QSharedPointer QtSharedPointer::strongRefFromWeakHelper(const QWeakPointer &src, X *); #endif inline void internalSet(Data *o, T *actual) { if (d == o) return; if (o && !o->strongref) o = 0; if (o) { verifyReconstruction(actual); o->weakref.ref(); o->strongref.ref(); } if (d && !deref()) delete d; d = o; this->value = d && d->strongref ? actual : 0; } #if defined(QT_BUILD_INTERNAL) public: #endif 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) { 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; } inline QSharedPointer(const QWeakPointer &other) { *this = QtSharedPointer::strongRefFromWeakHelper(other, static_cast(0)); } inline QSharedPointer &operator=(const QWeakPointer &other) { *this = QtSharedPointer::strongRefFromWeakHelper(other, static_cast(0)); return *this; } template inline QSharedPointer(const QSharedPointer &other) { *this = 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) { *this = QtSharedPointer::strongRefFromWeakHelper(other, static_cast(0)); } template inline QSharedPointer &operator=(const QWeakPointer &other) { *this = strongRefFromWeakHelper(other, static_cast(0)); 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; public: static inline QSharedPointer create() { QSharedPointer result; result.internalCreate(); // now initialize the data new (result.data()) T(); 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 QWeakPointer() : d(0), value(0) { } inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; } 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 && value == static_cast(o.data()); } 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 QSharedPointer QtSharedPointer::strongRefFromWeakHelper(const QWeakPointer &src, X *); #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; } template Q_INLINE_TEMPLATE QSharedPointer strongRefFromWeakHelper (const QT_PREPEND_NAMESPACE(QWeakPointer) &src, X *) { QSharedPointer result; result.internalSet(src.d, src.value); 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()); } # ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION namespace QtSharedPointer { template struct RemovePointer; template struct RemovePointer { typedef T Type; }; template struct RemovePointer > { typedef T Type; }; template struct RemovePointer > { typedef T Type; }; } 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 #endif QT_END_NAMESPACE QT_END_HEADER #endif