File indexing completed on 2024-05-12 15:56:59

0001 /*
0002  *  SPDX-FileCopyrightText: 2005 Frerich Raabe <raabe@kde.org>
0003  *  SPDX-FileCopyrightText: 2006, 2010 Cyrille Berger <cberger@cberger.net>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #ifndef KIS_SHAREDPTR_H
0009 #define KIS_SHAREDPTR_H
0010 
0011 #include <QtGlobal>
0012 
0013 #include <kis_debug.h>
0014 
0015 #include "kis_memory_leak_tracker.h"
0016 
0017 template<class T>
0018 class KisWeakSharedPtr;
0019 
0020 /**
0021  * KisSharedPtr is a shared pointer similar to KSharedPtr and
0022  * boost::shared_ptr. The difference with KSharedPtr is that our
0023  * constructor is not explicit.
0024  *
0025  * A shared pointer is a wrapper around a real pointer. The shared
0026  * pointer keeps a reference count, and when the reference count drops
0027  * to 0 the contained pointer is deleted. You can use the shared
0028  * pointer just as you would use a real pointer.
0029  *
0030  * See also also item 28 and 29 of More Effective C++ and
0031  * https://bugs.kde.org/show_bug.cgi?id=52261 as well as
0032  * https://www.boost.org/libs/smart_ptr/shared_ptr.htm.
0033  *
0034  * Advantage of KisSharedPtr over boost pointer or QSharedPointer?
0035  *
0036  * The difference with boost share pointer is that in
0037  * boost::shared_ptr, the counter is kept inside the smart pointer,
0038  * meaning that you should never never remove the pointer from its
0039  * smart pointer object, because if you do that, and somewhere in the
0040  * code, the pointer is put back in a smart pointer, then you have two
0041  * counters, and when one reach zero, then the object gets deleted
0042  * while some other code thinks the pointer is still valid.
0043  *
0044  * Disadvantage of KisSharedPtr compared to boost pointer?
0045  *
0046  * KisSharedPtr requires the class to inherits KisShared.
0047  *
0048  * Difference with QSharedPointer
0049  *
0050  * QSharedPointer and KisSharedPtr are very similar, but
0051  * QSharedPointer has an explicit constructor which makes it more
0052  * painful to use in some constructions. And QSharedPointer
0053  * doesn't offer a weak pointer.
0054  */
0055 template<class T>
0056 class KisSharedPtr
0057 {
0058     friend class KisWeakSharedPtr<T>;
0059 public:
0060     /**
0061      * Creates a null pointer.
0062      */
0063     inline KisSharedPtr()
0064             : d(0) { }
0065 
0066     /**
0067      * Creates a new pointer.
0068      * @param p the pointer
0069      */
0070     inline KisSharedPtr(T* p)
0071             : d(p) {
0072         ref();
0073     }
0074 
0075     inline KisSharedPtr(const KisWeakSharedPtr<T>& o);
0076 
0077     // Free the pointer and set it to new value
0078     void attach(T* p);
0079 
0080     // Free the pointer
0081     void clear();
0082 
0083     /**
0084      * Copies a pointer.
0085      * @param o the pointer to copy
0086      */
0087     inline KisSharedPtr<T>(const KisSharedPtr<T>& o)
0088             : d(o.d) {
0089         ref();
0090     }
0091 
0092     /**
0093      * Dereferences the object that this pointer points to. If it was
0094      * the last reference, the object will be deleted.
0095      */
0096     inline ~KisSharedPtr() {
0097         deref();
0098     }
0099 
0100     inline KisSharedPtr<T>& operator= (const KisSharedPtr& o) {
0101         attach(o.d);
0102         return *this;
0103     }
0104     inline bool operator== (const T* p) const {
0105         return (d == p);
0106     }
0107     inline bool operator!= (const T* p) const {
0108         return (d != p);
0109     }
0110     inline bool operator== (const KisSharedPtr& o) const {
0111         return (d == o.d);
0112     }
0113     inline bool operator!= (const KisSharedPtr& o) const {
0114         return (d != o.d);
0115     }
0116 
0117     inline KisSharedPtr<T>& operator= (T* p) {
0118         attach(p);
0119         return *this;
0120     }
0121 
0122     inline operator const T*() const {
0123         return d;
0124     }
0125 
0126     template< class T2> inline operator KisSharedPtr<T2>() const {
0127         return KisSharedPtr<T2>(d);
0128     }
0129 
0130     /**
0131     * @return the contained pointer. If you delete the contained
0132     * pointer, you will make KisSharedPtr very unhappy. It is
0133     * perfectly safe to put the contained pointer in another
0134     * KisSharedPtr, though.
0135     */
0136     inline T* data() {
0137         return d;
0138     }
0139 
0140     /**
0141     * @return the pointer
0142     */
0143     inline const T* data() const {
0144         return d;
0145     }
0146 
0147     /**
0148     * @return a const pointer to the shared object.
0149     */
0150     inline const T* constData() const {
0151         return d;
0152     }
0153 
0154     inline const T& operator*() const {
0155         Q_ASSERT(d);
0156         return *d;
0157     }
0158     inline T& operator*() {
0159         Q_ASSERT(d);
0160         return *d;
0161     }
0162 
0163     inline const T* operator->() const {
0164         Q_ASSERT(d);
0165         return d;
0166     }
0167     inline T* operator->() {
0168         Q_ASSERT(d);
0169         return d;
0170     }
0171 
0172     /**
0173     * @return true if the pointer is null
0174     */
0175     inline bool isNull() const {
0176         return (d == 0);
0177     }
0178 
0179     inline static void ref(const KisSharedPtr<T>* sp, T* t)
0180     {
0181 #ifndef HAVE_MEMORY_LEAK_TRACKER
0182         Q_UNUSED(sp);
0183 #else
0184         KisMemoryLeakTracker::instance()->reference(t, sp);
0185 #endif
0186         if (t) {
0187             t->ref();
0188         }
0189     }
0190 
0191     inline static bool deref(const KisSharedPtr<T>* sp, T* t)
0192     {
0193 #ifndef HAVE_MEMORY_LEAK_TRACKER
0194         Q_UNUSED(sp);
0195 #else
0196         KisMemoryLeakTracker::instance()->dereference(t, sp);
0197 #endif
0198         if (t && !t->deref()) {
0199             delete t;
0200             return false;
0201         }
0202         return true;
0203     }
0204 
0205 private:    
0206     inline void ref() const
0207     {
0208         ref(this, d);
0209     }
0210 
0211     inline void deref() const
0212     {
0213         bool v = deref(this, d);
0214 #ifndef NDEBUG
0215         if (!v) {
0216             d = 0;
0217         }
0218 #else
0219     Q_UNUSED(v);
0220 #endif
0221     }
0222 
0223 private:
0224     mutable T* d;
0225 };
0226 
0227 /**
0228  * A weak shared ptr is an ordinary shared ptr, with two differences:
0229  * it doesn't delete the contained pointer if the refcount drops to
0230  * zero and it doesn't prevent the contained pointer from being
0231  * deleted if the last strong shared pointer goes out of scope.
0232  */
0233 template<class T>
0234 class KisWeakSharedPtr
0235 {
0236     friend class KisSharedPtr<T>;
0237 public:
0238     /**
0239      * Creates a null pointer.
0240      */
0241     inline KisWeakSharedPtr()
0242         : d(0), weakReference(0) { }
0243 
0244     /**
0245      * Creates a new pointer.
0246      * @param p the pointer
0247      */
0248     inline KisWeakSharedPtr(T* p) {
0249         load(p);
0250     }
0251 
0252     inline KisWeakSharedPtr<T>(const KisSharedPtr<T>& o) {
0253         load(o.d);
0254     }
0255 
0256     /**
0257      * Copies a pointer.
0258      * @param o the pointer to copy
0259      */
0260     inline KisWeakSharedPtr<T>(const KisWeakSharedPtr<T>& o) {
0261         if (o.isConsistent()) {
0262             load(o.d);
0263         }
0264         else {
0265             d = 0;
0266             weakReference = 0;
0267         }
0268     }
0269 
0270     inline ~KisWeakSharedPtr() {
0271         detach();
0272     }
0273 
0274     inline KisWeakSharedPtr<T>& operator= (const KisWeakSharedPtr& o) {
0275         attach(o);
0276         return *this;
0277     }
0278 
0279     inline bool operator== (const T* p) const {
0280         return (d == p);
0281     }
0282     inline bool operator!= (const T* p) const {
0283         return (d != p);
0284     }
0285     inline bool operator== (const KisWeakSharedPtr& o) const {
0286         return (d == o.d);
0287     }
0288     inline bool operator!= (const KisWeakSharedPtr& o) const {
0289         return (d != o.d);
0290     }
0291 
0292     inline KisWeakSharedPtr<T>& operator= (T* p) {
0293         attach(p);
0294         return *this;
0295     }
0296 
0297     template< class T2> inline operator KisWeakSharedPtr<T2>() const {
0298         return KisWeakSharedPtr<T2>(d);
0299     }
0300 
0301     /**
0302      * Note that if you use this function, the pointer might be destroyed
0303      * if KisSharedPtr pointing to this pointer are deleted, resulting in
0304      * a segmentation fault. Use with care.
0305      * @return a const pointer to the shared object.
0306      */
0307     inline T* data() {
0308         if (!isConsistent()) {
0309             warnKrita.noquote() << kisBacktrace();
0310             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0311         }
0312 
0313         return d;
0314     }
0315 
0316     /**
0317      * @see data()
0318      */
0319     inline const T* data() const {
0320         if (!isConsistent()) {
0321             warnKrita.noquote() << kisBacktrace();
0322             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0323         }
0324 
0325         return d;
0326     }
0327 
0328     /**
0329      * @see data()
0330      */
0331     inline const T* constData() const {
0332         if (!isConsistent()) {
0333             warnKrita.noquote() << kisBacktrace();
0334             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0335         }
0336 
0337         return d;
0338     }
0339 
0340     /**
0341      * @see data()
0342      */
0343     inline operator const T*() const {
0344         /**
0345          * This operator is used in boolean expressions where we check
0346          * for pointer consistency, so return 0 instead of asserting.
0347          */
0348 
0349         return isConsistent() ? d : 0;
0350     }
0351 
0352     inline const T& operator*() const {
0353         if (!isValid()) {
0354             warnKrita.noquote() << kisBacktrace();
0355             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0356         }
0357 
0358         return *d;
0359     }
0360 
0361     inline T& operator*() {
0362         if (!isValid()) {
0363             warnKrita.noquote() << kisBacktrace();
0364             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0365         }
0366 
0367         return *d;
0368     }
0369 
0370     inline const T* operator->() const {
0371         if (!isValid()) {
0372             warnKrita.noquote() << kisBacktrace();
0373             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0374         }
0375 
0376         return d;
0377     }
0378 
0379     inline T* operator->() {
0380         if (!isValid()) {
0381             warnKrita.noquote() << kisBacktrace();
0382             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0383         }
0384 
0385         return d;
0386     }
0387 
0388     /**
0389     * @return true if the pointer is null
0390     */
0391     inline bool isNull() const {
0392         return (d == 0);
0393     }
0394 
0395     /**
0396      * @return true if the weak pointer points to a valid pointer
0397      *         and false if the data has been deleted or is null
0398      */
0399     inline bool isValid() const {
0400         Q_ASSERT(!d || weakReference);
0401 
0402         return d && weakReference && isOdd((int)*weakReference);
0403     }
0404 
0405     /**
0406      * @brief toStrongRef returns a KisSharedPtr which may be dereferenced.
0407      *
0408      * Weak pointers should only be used to track ownership but never be used as pointers.
0409      * This has historically not been the case, but in new API this function should be used
0410      * instead of directly using a weak pointer as pointer.
0411      * @return a KisSharedPtr, which may be null
0412      */
0413     inline KisSharedPtr<T> toStrongRef() const {
0414         return KisSharedPtr<T>(*this);
0415     }
0416 
0417 private:
0418     static const qint32 WEAK_REF = 2;
0419     static inline bool isOdd(const qint32 &x) {
0420         return x & 0x01;
0421     }
0422 
0423     inline bool isConsistent() const {
0424         Q_ASSERT(!d || weakReference);
0425 
0426         return !d || (weakReference && isOdd((int)*weakReference));
0427     }
0428 
0429     void load(T* newValue) {
0430         d = newValue;
0431 
0432         if (d) {
0433             weakReference = d->sharedWeakReference();
0434             weakReference->fetchAndAddOrdered(WEAK_REF);
0435         }
0436         else {
0437             weakReference = 0;
0438         }
0439     }
0440 
0441     // see note in kis_shared.cc
0442     inline void attach(T* newValue) {
0443         detach();
0444         load(newValue);
0445     }
0446 
0447     inline void attach(const KisWeakSharedPtr& o) {
0448         detach();
0449         if (o.isConsistent()) {
0450             load(o.d);
0451         }
0452         else {
0453             d = 0;
0454             weakReference = 0;
0455         }
0456     }
0457 
0458     // see note in kis_shared.cc
0459     void detach() {
0460         d = 0;
0461 
0462         if (weakReference &&
0463             weakReference->fetchAndAddOrdered(-WEAK_REF) <= WEAK_REF) {
0464 
0465             // sanity check:
0466             Q_ASSERT((int)*weakReference == 0);
0467 
0468             delete weakReference;
0469             weakReference = 0;
0470         }
0471     }
0472 
0473     mutable T* d;
0474     QAtomicInt *weakReference;
0475 };
0476 
0477 
0478 template <class T>
0479 Q_INLINE_TEMPLATE  KisSharedPtr<T>::KisSharedPtr(const KisWeakSharedPtr<T>& o)
0480         : d(o.d)
0481 {
0482     if (o.isValid()) {
0483         ref();
0484 
0485         /**
0486          * Thread safety:
0487          * Is the object we have just referenced still valid?
0488          */
0489         Q_ASSERT(o.isConsistent());
0490     }
0491     else {
0492         d = 0;
0493     }
0494 }
0495 
0496 
0497 template <class T>
0498 Q_INLINE_TEMPLATE void KisSharedPtr<T>::attach(T* p)
0499 {
0500     if (d != p) {
0501         ref(this, p);
0502         T* old = d;
0503         d = p;
0504         deref(this, old);
0505     }
0506 }
0507 
0508 template <class T>
0509 Q_INLINE_TEMPLATE void KisSharedPtr<T>::clear()
0510 {
0511     attach((T*)0);
0512 }
0513 
0514 #endif