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