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