File indexing completed on 2024-12-22 04:40:14
0001 /* 0002 SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef OBJECTREF_H 0008 #define OBJECTREF_H 0009 0010 #include <QObject> 0011 #include <QVector> 0012 #include <QDebug> 0013 #include <utility> 0014 0015 namespace SubtitleComposer { 0016 0017 template<class T> 0018 class ObjectRef { 0019 // Class T must have a ObjectRef<T> *m_ref and implement "const QVector<ObjectRef<T>> * T::refContainer();". 0020 // T::refContainer() will return "QVector *" in which we are supposed to be. We will set *m_ref to our location 0021 // in container. That way we can know the index in QVector while holding a pointer without iterating through all 0022 // elements. 0023 friend T; 0024 0025 public: 0026 // param ctor/dtor 0027 ObjectRef(T *obj) : m_obj(obj) { ref(); } 0028 virtual ~ObjectRef() { unref(); } 0029 0030 // copy ctor/oper 0031 ObjectRef(const ObjectRef<T> &other) : m_obj(other.m_obj) { ref(); } 0032 ObjectRef & operator=(const ObjectRef &other) { unref(); m_obj = other.m_obj, ref(); return *this; } 0033 0034 // move ctor/oper 0035 ObjectRef(ObjectRef &&other) noexcept : m_obj(other.m_obj) { moveref(&other); } 0036 ObjectRef & operator=(ObjectRef &&other) noexcept { unref(); m_obj = other.m_obj; moveref(&other); return *this; } 0037 0038 // default ctor 0039 ObjectRef() : m_obj(nullptr) { } 0040 0041 private: 0042 inline void ref() 0043 { 0044 if(m_obj && inContainer()) 0045 m_obj->m_ref = this; 0046 } 0047 0048 inline void unref() 0049 { 0050 // if(m_obj && m_obj->m_ref == this) 0051 // m_obj->m_ref = nullptr; 0052 } 0053 0054 inline void moveref(ObjectRef *other) 0055 { 0056 Q_ASSERT(m_obj != nullptr); 0057 other->m_obj = nullptr; 0058 if(m_obj->m_ref == other || inContainer()) 0059 m_obj->m_ref = this; 0060 } 0061 0062 inline const QVector<SubtitleComposer::ObjectRef<T>> *container() 0063 { 0064 Q_ASSERT(m_obj != nullptr); 0065 const QVector<SubtitleComposer::ObjectRef<T>> *container = m_obj->refContainer(); 0066 Q_ASSERT(container != nullptr); 0067 return container; 0068 } 0069 0070 inline bool inContainer() 0071 { 0072 const QVector<SubtitleComposer::ObjectRef<T>> *vec = container(); 0073 const SubtitleComposer::ObjectRef<T> *data = vec->constData(); 0074 return this >= data && this < data + vec->capacity(); 0075 } 0076 0077 public: 0078 // helpers 0079 inline T * operator->() const { Q_ASSERT(m_obj != nullptr); return m_obj; } 0080 inline operator T & () const { Q_ASSERT(m_obj != nullptr); return *m_obj; } 0081 inline operator T * () const { return m_obj; } 0082 inline T * obj() const { return m_obj; } 0083 0084 private: 0085 T *m_obj; 0086 }; 0087 0088 } 0089 0090 // If we declare ObjectRef as Q_MOVABLE_TYPE, QVector will just memcpy() the data on resize without calling any constructors 0091 //template<class T> 0092 //Q_DECLARE_TYPEINFO_BODY(SubtitleComposer::ObjectRef<T>, Q_MOVABLE_TYPE); 0093 0094 // QVector should probably declare this 0095 //template<class T> 0096 //Q_DECLARE_TYPEINFO_BODY(QVector<SubtitleComposer::ObjectRef<T>>, Q_MOVABLE_TYPE); 0097 0098 #endif // OBJECTREF_H