1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLREFCOUNT_P_H
5#define QQMLREFCOUNT_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qglobal.h>
19#include <QtCore/qatomic.h>
20#include <private/qv4global_p.h>
21
22QT_BEGIN_NAMESPACE
23
24template <typename T>
25class QQmlRefCounted;
26
27class Q_QML_PRIVATE_EXPORT QQmlRefCount
28{
29 Q_DISABLE_COPY_MOVE(QQmlRefCount)
30public:
31 inline QQmlRefCount();
32 inline void addref() const;
33 inline void release() const;
34 inline int count() const;
35
36private:
37 inline virtual ~QQmlRefCount();
38 template <typename T> friend class QQmlRefCounted;
39
40private:
41 mutable QAtomicInt refCount;
42};
43
44template <typename T>
45class QQmlRefCounted : public QQmlRefCount
46{
47protected:
48 ~QQmlRefCounted() = default;
49};
50
51template<class T>
52class QQmlRefPointer
53{
54public:
55 enum Mode {
56 AddRef,
57 Adopt
58 };
59 Q_NODISCARD_CTOR inline QQmlRefPointer();
60 Q_NODISCARD_CTOR inline QQmlRefPointer(T *, Mode m = AddRef);
61 Q_NODISCARD_CTOR inline QQmlRefPointer(const QQmlRefPointer &);
62 Q_NODISCARD_CTOR inline QQmlRefPointer(QQmlRefPointer &&);
63 inline ~QQmlRefPointer();
64
65 void swap(QQmlRefPointer &other) noexcept { qt_ptr_swap(o, other.o); }
66
67 inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
68 inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o);
69
70 inline bool isNull() const { return !o; }
71
72 inline T* operator->() const { return o; }
73 inline T& operator*() const { return *o; }
74 explicit inline operator bool() const { return o != nullptr; }
75 inline T* data() const { return o; }
76
77 inline QQmlRefPointer<T> &adopt(T *);
78
79 inline T* take() { T *res = o; o = nullptr; return res; }
80
81 friend bool operator==(const QQmlRefPointer &a, const QQmlRefPointer &b) { return a.o == b.o; }
82 friend bool operator!=(const QQmlRefPointer &a, const QQmlRefPointer &b) { return !(a == b); }
83
84 void reset(T *t = nullptr)
85 {
86 if (t == o)
87 return;
88 if (o)
89 o->release();
90 if (t)
91 t->addref();
92 o = t;
93 }
94
95private:
96 T *o;
97};
98
99namespace QQml {
100/*!
101 \internal
102 Creates a QQmlRefPointer which takes ownership of a newly constructed T.
103 T must derive from QQmlRefCounted<T> (as we rely on an initial refcount of _1_).
104 T will be constructed by forwarding \a args to its constructor.
105 */
106template <typename T, typename ...Args>
107QQmlRefPointer<T> makeRefPointer(Args&&... args)
108{
109 static_assert(std::is_base_of_v<QQmlRefCount, T>);
110 return QQmlRefPointer<T>(new T(std::forward<Args>(args)...), QQmlRefPointer<T>::Adopt);
111}
112}
113
114template <typename T>
115Q_DECLARE_TYPEINFO_BODY(QQmlRefPointer<T>, Q_RELOCATABLE_TYPE);
116
117QQmlRefCount::QQmlRefCount()
118: refCount(1)
119{
120}
121
122QQmlRefCount::~QQmlRefCount()
123{
124 Q_ASSERT(refCount.loadRelaxed() == 0);
125}
126
127void QQmlRefCount::addref() const
128{
129 Q_ASSERT(refCount.loadRelaxed() > 0);
130 refCount.ref();
131}
132
133void QQmlRefCount::release() const
134{
135 Q_ASSERT(refCount.loadRelaxed() > 0);
136 if (!refCount.deref())
137 delete this;
138}
139
140int QQmlRefCount::count() const
141{
142 return refCount.loadRelaxed();
143}
144
145template<class T>
146QQmlRefPointer<T>::QQmlRefPointer()
147: o(nullptr)
148{
149}
150
151template<class T>
152QQmlRefPointer<T>::QQmlRefPointer(T *o, Mode m)
153: o(o)
154{
155 if (m == AddRef && o)
156 o->addref();
157}
158
159template<class T>
160QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
161: o(other.o)
162{
163 if (o) o->addref();
164}
165
166template <class T>
167QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other)
168 : o(other.take())
169{
170}
171
172template<class T>
173QQmlRefPointer<T>::~QQmlRefPointer()
174{
175 if (o) o->release();
176}
177
178template<class T>
179QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
180{
181 if (o == other.o)
182 return *this;
183 if (other.o)
184 other.o->addref();
185 if (o)
186 o->release();
187 o = other.o;
188 return *this;
189}
190
191template <class T>
192QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other)
193{
194 QQmlRefPointer<T> m(std::move(other));
195 swap(other&: m);
196 return *this;
197}
198
199/*!
200Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
201of the callers reference of other.
202*/
203template<class T>
204QQmlRefPointer<T> &QQmlRefPointer<T>::adopt(T *other)
205{
206 if (o) o->release();
207 o = other;
208 return *this;
209}
210
211QT_END_NAMESPACE
212
213#endif // QQMLREFCOUNT_P_H
214

source code of qtdeclarative/src/qml/qml/ftw/qqmlrefcount_p.h