File indexing completed on 2024-05-19 04:25:05

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 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     using element_type = T;
0061     using weak_type = KisWeakSharedPtr<T>;
0062 
0063     /**
0064      * Creates a null pointer.
0065      */
0066     inline KisSharedPtr()
0067             : d(0) { }
0068 
0069     /**
0070      * Creates a new pointer.
0071      * @param p the pointer
0072      */
0073     inline KisSharedPtr(T* p)
0074             : d(p) {
0075         ref();
0076     }
0077 
0078     inline KisSharedPtr(const KisWeakSharedPtr<T>& o);
0079 
0080     // Free the pointer and set it to new value
0081     void attach(T* p);
0082 
0083     // Free the pointer
0084     void clear();
0085 
0086     /**
0087      * Copies a pointer.
0088      * @param o the pointer to copy
0089      */
0090     inline KisSharedPtr<T>(const KisSharedPtr<T>& o)
0091             : d(o.d) {
0092         ref();
0093     }
0094 
0095     /**
0096      * Dereferences the object that this pointer points to. If it was
0097      * the last reference, the object will be deleted.
0098      */
0099     inline ~KisSharedPtr() {
0100         deref();
0101     }
0102 
0103     inline KisSharedPtr<T>& operator= (const KisSharedPtr& o) {
0104         attach(o.d);
0105         return *this;
0106     }
0107     inline bool operator== (const T* p) const {
0108         return (d == p);
0109     }
0110     inline bool operator!= (const T* p) const {
0111         return (d != p);
0112     }
0113     inline bool operator== (const KisSharedPtr& o) const {
0114         return (d == o.d);
0115     }
0116     inline bool operator!= (const KisSharedPtr& o) const {
0117         return (d != o.d);
0118     }
0119 
0120     inline KisSharedPtr<T>& operator= (T* p) {
0121         attach(p);
0122         return *this;
0123     }
0124 
0125     inline operator const T*() const {
0126         return d;
0127     }
0128 
0129     template< class T2> inline operator KisSharedPtr<T2>() const {
0130         return KisSharedPtr<T2>(d);
0131     }
0132 
0133     /**
0134     * @return the contained pointer. If you delete the contained
0135     * pointer, you will make KisSharedPtr very unhappy. It is
0136     * perfectly safe to put the contained pointer in another
0137     * KisSharedPtr, though.
0138     */
0139     inline T* data() {
0140         return d;
0141     }
0142 
0143     /**
0144     * @return the pointer
0145     */
0146     inline const T* data() const {
0147         return d;
0148     }
0149 
0150     /**
0151     * @return a const pointer to the shared object.
0152     */
0153     inline const T* constData() const {
0154         return d;
0155     }
0156 
0157     inline const T& operator*() const {
0158         Q_ASSERT(d);
0159         return *d;
0160     }
0161     inline T& operator*() {
0162         Q_ASSERT(d);
0163         return *d;
0164     }
0165 
0166     inline const T* operator->() const {
0167         Q_ASSERT(d);
0168         return d;
0169     }
0170     inline T* operator->() {
0171         Q_ASSERT(d);
0172         return d;
0173     }
0174 
0175     /**
0176     * @return true if the pointer is null
0177     */
0178     inline bool isNull() const {
0179         return (d == 0);
0180     }
0181 
0182     inline static void ref(const KisSharedPtr<T>* sp, T* t)
0183     {
0184 #ifndef HAVE_MEMORY_LEAK_TRACKER
0185         Q_UNUSED(sp);
0186 #else
0187         KisMemoryLeakTracker::instance()->reference(t, sp);
0188 #endif
0189         if (t) {
0190             t->ref();
0191         }
0192     }
0193 
0194     inline static bool deref(const KisSharedPtr<T>* sp, T* t)
0195     {
0196 #ifndef HAVE_MEMORY_LEAK_TRACKER
0197         Q_UNUSED(sp);
0198 #else
0199         KisMemoryLeakTracker::instance()->dereference(t, sp);
0200 #endif
0201         if (t && !t->deref()) {
0202             delete t;
0203             return false;
0204         }
0205         return true;
0206     }
0207 
0208 private:    
0209     inline void ref() const
0210     {
0211         ref(this, d);
0212     }
0213 
0214     inline void deref() const
0215     {
0216         bool v = deref(this, d);
0217 #ifndef NDEBUG
0218         if (!v) {
0219             d = 0;
0220         }
0221 #else
0222     Q_UNUSED(v);
0223 #endif
0224     }
0225 
0226 private:
0227     mutable T* d;
0228 };
0229 
0230 /**
0231  * A weak shared ptr is an ordinary shared ptr, with two differences:
0232  * it doesn't delete the contained pointer if the refcount drops to
0233  * zero and it doesn't prevent the contained pointer from being
0234  * deleted if the last strong shared pointer goes out of scope.
0235  */
0236 template<class T>
0237 class KisWeakSharedPtr
0238 {
0239     friend class KisSharedPtr<T>;
0240 public:
0241     using element_type = T;
0242 
0243     /**
0244      * Creates a null pointer.
0245      */
0246     inline KisWeakSharedPtr()
0247         : d(0), weakReference(0) { }
0248 
0249     /**
0250      * Creates a new pointer.
0251      * @param p the pointer
0252      */
0253     inline KisWeakSharedPtr(T* p) {
0254         load(p);
0255     }
0256 
0257     inline KisWeakSharedPtr<T>(const KisSharedPtr<T>& o) {
0258         load(o.d);
0259     }
0260 
0261     /**
0262      * Copies a pointer.
0263      * @param o the pointer to copy
0264      */
0265     inline KisWeakSharedPtr<T>(const KisWeakSharedPtr<T>& o) {
0266         if (o.isConsistent()) {
0267             load(o.d);
0268         }
0269         else {
0270             d = 0;
0271             weakReference = 0;
0272         }
0273     }
0274 
0275     inline ~KisWeakSharedPtr() {
0276         detach();
0277     }
0278 
0279     inline KisWeakSharedPtr<T>& operator= (const KisWeakSharedPtr& o) {
0280         attach(o);
0281         return *this;
0282     }
0283 
0284     inline bool operator== (const T* p) const {
0285         return (d == p);
0286     }
0287     inline bool operator!= (const T* p) const {
0288         return (d != p);
0289     }
0290     inline bool operator== (const KisWeakSharedPtr& o) const {
0291         return (d == o.d);
0292     }
0293     inline bool operator!= (const KisWeakSharedPtr& o) const {
0294         return (d != o.d);
0295     }
0296 
0297     inline KisWeakSharedPtr<T>& operator= (T* p) {
0298         attach(p);
0299         return *this;
0300     }
0301 
0302     template< class T2> inline operator KisWeakSharedPtr<T2>() const {
0303         return KisWeakSharedPtr<T2>(d);
0304     }
0305 
0306     /**
0307      * Note that if you use this function, the pointer might be destroyed
0308      * if KisSharedPtr pointing to this pointer are deleted, resulting in
0309      * a segmentation fault. Use with care.
0310      * @return a const pointer to the shared object.
0311      */
0312     inline T* data() {
0313         if (!isConsistent()) {
0314             warnKrita.noquote() << kisBacktrace();
0315             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0316         }
0317 
0318         return d;
0319     }
0320 
0321     /**
0322      * @see data()
0323      */
0324     inline const T* data() const {
0325         if (!isConsistent()) {
0326             warnKrita.noquote() << kisBacktrace();
0327             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0328         }
0329 
0330         return d;
0331     }
0332 
0333     /**
0334      * @see data()
0335      */
0336     inline const T* constData() const {
0337         if (!isConsistent()) {
0338             warnKrita.noquote() << kisBacktrace();
0339             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0340         }
0341 
0342         return d;
0343     }
0344 
0345     /**
0346      * @see data()
0347      */
0348     inline operator const T*() const {
0349         /**
0350          * This operator is used in boolean expressions where we check
0351          * for pointer consistency, so return 0 instead of asserting.
0352          */
0353 
0354         return isConsistent() ? d : 0;
0355     }
0356 
0357     inline const T& operator*() const {
0358         if (!isValid()) {
0359             warnKrita.noquote() << kisBacktrace();
0360             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0361         }
0362 
0363         return *d;
0364     }
0365 
0366     inline T& operator*() {
0367         if (!isValid()) {
0368             warnKrita.noquote() << kisBacktrace();
0369             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0370         }
0371 
0372         return *d;
0373     }
0374 
0375     inline const T* operator->() const {
0376         if (!isValid()) {
0377             warnKrita.noquote() << kisBacktrace();
0378             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0379         }
0380 
0381         return d;
0382     }
0383 
0384     inline T* operator->() {
0385         if (!isValid()) {
0386             warnKrita.noquote() << kisBacktrace();
0387             Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!");
0388         }
0389 
0390         return d;
0391     }
0392 
0393     /**
0394     * @return true if the pointer is null
0395     */
0396     inline bool isNull() const {
0397         return (d == 0);
0398     }
0399 
0400     /**
0401      * @return true if the weak pointer points to a valid pointer
0402      *         and false if the data has been deleted or is null
0403      */
0404     inline bool isValid() const {
0405         Q_ASSERT(!d || weakReference);
0406 
0407         return d && weakReference && isOdd((int)*weakReference);
0408     }
0409 
0410     /**
0411      * @brief toStrongRef returns a KisSharedPtr which may be dereferenced.
0412      *
0413      * Weak pointers should only be used to track ownership but never be used as pointers.
0414      * This has historically not been the case, but in new API this function should be used
0415      * instead of directly using a weak pointer as pointer.
0416      * @return a KisSharedPtr, which may be null
0417      */
0418     inline KisSharedPtr<T> toStrongRef() const {
0419         return KisSharedPtr<T>(*this);
0420     }
0421 
0422 private:
0423     static const qint32 WEAK_REF = 2;
0424     static inline bool isOdd(const qint32 &x) {
0425         return x & 0x01;
0426     }
0427 
0428     inline bool isConsistent() const {
0429         Q_ASSERT(!d || weakReference);
0430 
0431         return !d || (weakReference && isOdd((int)*weakReference));
0432     }
0433 
0434     void load(T* newValue) {
0435         d = newValue;
0436 
0437         if (d) {
0438             weakReference = d->sharedWeakReference();
0439             weakReference->fetchAndAddOrdered(WEAK_REF);
0440         }
0441         else {
0442             weakReference = 0;
0443         }
0444     }
0445 
0446     // see note in kis_shared.cc
0447     inline void attach(T* newValue) {
0448         detach();
0449         load(newValue);
0450     }
0451 
0452     inline void attach(const KisWeakSharedPtr& o) {
0453         detach();
0454         if (o.isConsistent()) {
0455             load(o.d);
0456         }
0457         else {
0458             d = 0;
0459             weakReference = 0;
0460         }
0461     }
0462 
0463     // see note in kis_shared.cc
0464     void detach() {
0465         d = 0;
0466 
0467         if (weakReference &&
0468             weakReference->fetchAndAddOrdered(-WEAK_REF) <= WEAK_REF) {
0469 
0470             // sanity check:
0471             Q_ASSERT((int)*weakReference == 0);
0472 
0473             delete weakReference;
0474             weakReference = 0;
0475         }
0476     }
0477 
0478     mutable T* d;
0479     QAtomicInt *weakReference;
0480 };
0481 
0482 
0483 template <class T>
0484 Q_INLINE_TEMPLATE  KisSharedPtr<T>::KisSharedPtr(const KisWeakSharedPtr<T>& o)
0485         : d(o.d)
0486 {
0487     if (o.isValid()) {
0488         ref();
0489 
0490         /**
0491          * Thread safety:
0492          * Is the object we have just referenced still valid?
0493          */
0494         Q_ASSERT(o.isConsistent());
0495     }
0496     else {
0497         d = 0;
0498     }
0499 }
0500 
0501 
0502 template <class T>
0503 Q_INLINE_TEMPLATE void KisSharedPtr<T>::attach(T* p)
0504 {
0505     if (d != p) {
0506         ref(this, p);
0507         T* old = d;
0508         d = p;
0509         deref(this, old);
0510     }
0511 }
0512 
0513 template <class T>
0514 Q_INLINE_TEMPLATE void KisSharedPtr<T>::clear()
0515 {
0516     attach((T*)0);
0517 }
0518 
0519 #endif