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