/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @copyright Copyright (C) 2009-2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_shared_ptr_h_HEADER_GUARD_ #define _TelepathyQt_shared_ptr_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class RefCounted; template class SharedPtr; template class WeakPtr; class TP_QT_EXPORT RefCounted { Q_DISABLE_COPY(RefCounted) class SharedCount { Q_DISABLE_COPY(SharedCount) public: SharedCount(RefCounted *d) : d(d), strongref(0), weakref(0) { } private: template friend class SharedPtr; template friend class WeakPtr; friend class RefCounted; RefCounted *d; mutable QAtomicInt strongref; mutable QAtomicInt weakref; }; public: inline RefCounted() : sc(new SharedCount(this)) { sc->weakref.ref(); } inline virtual ~RefCounted() { sc->d = 0; if (!sc->weakref.deref()) { delete sc; } } private: template friend class SharedPtr; template friend class WeakPtr; // TODO: Remove when Conn.I.ContactList, etc becomes mandatory. This is required to circumvent // a reference cycle when using contact list channels, due to the fact that Channels hold // strong references to their parent Connection, but not needed when using // Conn.I.ContactList and friends. friend class ContactManager; inline void ref() const { sc->strongref.ref(); } inline bool deref() const { return sc->strongref.deref(); } SharedCount *sc; }; template class SharedPtr { typedef bool (SharedPtr::*UnspecifiedBoolType)() const; public: inline SharedPtr() : d(0) { } explicit inline SharedPtr(T *d) : d(d) { if (d) { d->ref(); } } template inline SharedPtr(const SharedPtr &o) : d(o.data()) { if (d) { d->ref(); } } inline SharedPtr(const SharedPtr &o) : d(o.d) { if (d) { d->ref(); } } explicit inline SharedPtr(const WeakPtr &o) { RefCounted::SharedCount *sc = o.sc; if (sc) { // increase the strongref, but never up from zero // or less (negative is used on untracked objects) register int tmp = sc->strongref.fetchAndAddOrdered(0); while (tmp > 0) { // try to increment from "tmp" to "tmp + 1" if (sc->strongref.testAndSetRelaxed(tmp, tmp + 1)) { // succeeded break; } // failed, try again tmp = sc->strongref.fetchAndAddOrdered(0); } if (tmp > 0) { d = dynamic_cast(sc->d); Q_ASSERT(d != NULL); } else { d = 0; } } else { d = 0; } } inline ~SharedPtr() { if (d && !d->deref()) { T *saved = d; d = 0; delete saved; } } inline void reset() { SharedPtr().swap(*this); } inline T *data() const { return d; } inline const T *constData() const { return d; } inline T *operator->() { return d; } inline T *operator->() const { return d; } inline bool isNull() const { return !d; } inline bool operator!() const { return isNull(); } operator UnspecifiedBoolType() const { return !isNull() ? &SharedPtr::operator! : 0; } inline bool operator==(const SharedPtr &o) const { return d == o.d; } inline bool operator!=(const SharedPtr &o) const { return d != o.d; } inline bool operator==(const T *ptr) const { return d == ptr; } inline bool operator!=(const T *ptr) const { return d != ptr; } inline SharedPtr &operator=(const SharedPtr &o) { SharedPtr(o).swap(*this); return *this; } inline void swap(SharedPtr &o) { T *tmp = d; d = o.d; o.d = tmp; } template static inline SharedPtr staticCast(const SharedPtr &src) { return SharedPtr(static_cast(src.data())); } template static inline SharedPtr dynamicCast(const SharedPtr &src) { return SharedPtr(dynamic_cast(src.data())); } template static inline SharedPtr constCast(const SharedPtr &src) { return SharedPtr(const_cast(src.data())); } template static inline SharedPtr qObjectCast(const SharedPtr &src) { return SharedPtr(qobject_cast(src.data())); } private: friend class WeakPtr; T *d; }; template inline uint qHash(const SharedPtr &ptr) { return QT_PREPEND_NAMESPACE(qHash(ptr.data())); } template inline uint qHash(const WeakPtr &ptr); template class WeakPtr { typedef bool (WeakPtr::*UnspecifiedBoolType)() const; public: inline WeakPtr() : sc(0) { } explicit inline WeakPtr(T *d) { if (d) { sc = d->sc; sc->weakref.ref(); } else { sc = 0; } } inline WeakPtr(const WeakPtr &o) : sc(o.sc) { if (sc) { sc->weakref.ref(); } } inline WeakPtr(const SharedPtr &o) { if (o.d) { sc = o.d->sc; sc->weakref.ref(); } else { sc = 0; } } inline ~WeakPtr() { if (sc && !sc->weakref.deref()) { delete sc; } } inline bool isNull() const { return !sc || sc->strongref.fetchAndAddOrdered(0) <= 0; } inline bool operator!() const { return isNull(); } operator UnspecifiedBoolType() const { return !isNull() ? &WeakPtr::operator! : 0; } inline WeakPtr &operator=(const WeakPtr &o) { WeakPtr(o).swap(*this); return *this; } inline WeakPtr &operator=(const SharedPtr &o) { WeakPtr(o).swap(*this); return *this; } inline void swap(WeakPtr &o) { RefCounted::SharedCount *tmp = sc; sc = o.sc; o.sc = tmp; } SharedPtr toStrongRef() const { return SharedPtr(*this); } private: friend class SharedPtr; friend uint qHash(const WeakPtr &ptr); RefCounted::SharedCount *sc; }; template inline uint qHash(const WeakPtr &ptr) { T *actualPtr = ptr.sc ? ptr.sc.d : 0; return QT_PREPEND_NAMESPACE(qHash(actualPtr)); } } // Tp #endif