File indexing completed on 2024-06-30 05:51:32
0001 /* 0002 This file is part of the Okteta Kasten Framework, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2013 Alex Richardson <alex.richardson@gmx.de> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #ifndef KASTEN_SAFEREFERENCE_HPP 0010 #define KASTEN_SAFEREFERENCE_HPP 0011 0012 #include <structureslogging.hpp> 0013 0014 #include <QMultiHash> 0015 #include <QMetaType> 0016 0017 class DataInformation; 0018 class SafeReference; 0019 0020 class SafeReferenceHolder 0021 { 0022 SafeReferenceHolder(); 0023 ~SafeReferenceHolder(); 0024 0025 public: 0026 SafeReferenceHolder(const SafeReferenceHolder&) = delete; 0027 SafeReferenceHolder& operator=(const SafeReferenceHolder&) = delete; 0028 0029 public: 0030 /** sets all refereces to this object to null */ 0031 void invalidateAll(DataInformation* data); 0032 void safeReferenceDestroyed(SafeReference* ref); 0033 void registerSafeReference(SafeReference* ref, DataInformation* data); 0034 static SafeReferenceHolder instance; 0035 0036 private: 0037 using Container = QMultiHash<DataInformation*, SafeReference*>; 0038 int safeRefDestroyCnt = 0; 0039 int safeRefRegisterCnt = 0; 0040 Container mRefs; 0041 }; 0042 0043 /** A class wrapping a DataInformation* 0044 * As soon as that DataInformation is destroyed all references to it are invalidated 0045 */ 0046 class SafeReference 0047 { 0048 public: 0049 SafeReference(); 0050 explicit SafeReference(DataInformation* data); 0051 SafeReference(const SafeReference& other); 0052 ~SafeReference(); 0053 0054 SafeReference& operator=(const SafeReference& other) = delete; 0055 0056 inline DataInformation* data() const; 0057 0058 private: 0059 friend class SafeReferenceHolder; 0060 inline void invalidate(); 0061 0062 private: 0063 DataInformation* mData = nullptr; 0064 }; 0065 0066 Q_DECLARE_METATYPE(SafeReference) 0067 0068 inline SafeReference::SafeReference() 0069 { 0070 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "default constructed safe reference"; 0071 } 0072 0073 inline SafeReference::SafeReference(DataInformation* data) : mData(data) 0074 { 0075 SafeReferenceHolder::instance.registerSafeReference(this, mData); 0076 } 0077 0078 inline SafeReference::SafeReference(const SafeReference& other) : mData(other.mData) 0079 { 0080 SafeReferenceHolder::instance.registerSafeReference(this, mData); 0081 } 0082 0083 inline SafeReference::~SafeReference() 0084 { 0085 SafeReferenceHolder::instance.safeReferenceDestroyed(this); 0086 } 0087 0088 inline DataInformation* SafeReference::data() const 0089 { 0090 return mData; 0091 } 0092 0093 inline void SafeReference::invalidate() 0094 { 0095 mData = nullptr; 0096 } 0097 0098 inline void SafeReferenceHolder::safeReferenceDestroyed(SafeReference* ref) 0099 { 0100 if (!ref->data()) { 0101 return; // has been invalidated -> was already removed 0102 } 0103 int removed = mRefs.remove(ref->data(), ref); 0104 // qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "safe ref destroyed " << ref; 0105 if (removed <= 0) { 0106 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "safe refenrece could not be removed:" << ref; 0107 } else { 0108 safeRefDestroyCnt += removed; 0109 } 0110 } 0111 0112 inline void SafeReferenceHolder::registerSafeReference(SafeReference* ref, DataInformation* data) 0113 { 0114 if (Q_LIKELY(data)) { 0115 mRefs.insert(data, ref); 0116 // qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "registered safe ref" << ref << data; 0117 safeRefRegisterCnt++; 0118 } else { 0119 qCWarning(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "invalid ref copied"; 0120 } 0121 } 0122 0123 #endif // KASTEN_SAFEREFERENCE_HPP