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 | |
22 | QT_BEGIN_NAMESPACE |
23 | |
24 | template <typename T> |
25 | class QQmlRefCounted; |
26 | |
27 | class Q_QML_PRIVATE_EXPORT QQmlRefCount |
28 | { |
29 | Q_DISABLE_COPY_MOVE(QQmlRefCount) |
30 | public: |
31 | inline QQmlRefCount(); |
32 | inline void addref() const; |
33 | inline void release() const; |
34 | inline int count() const; |
35 | |
36 | private: |
37 | inline virtual ~QQmlRefCount(); |
38 | template <typename T> friend class QQmlRefCounted; |
39 | |
40 | private: |
41 | mutable QAtomicInt refCount; |
42 | }; |
43 | |
44 | template <typename T> |
45 | class QQmlRefCounted : public QQmlRefCount |
46 | { |
47 | protected: |
48 | ~QQmlRefCounted() = default; |
49 | }; |
50 | |
51 | template<class T> |
52 | class QQmlRefPointer |
53 | { |
54 | public: |
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 | |
95 | private: |
96 | T *o; |
97 | }; |
98 | |
99 | namespace 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 | */ |
106 | template <typename T, typename ...Args> |
107 | QQmlRefPointer<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 | |
114 | template <typename T> |
115 | Q_DECLARE_TYPEINFO_BODY(QQmlRefPointer<T>, Q_RELOCATABLE_TYPE); |
116 | |
117 | QQmlRefCount::QQmlRefCount() |
118 | : refCount(1) |
119 | { |
120 | } |
121 | |
122 | QQmlRefCount::~QQmlRefCount() |
123 | { |
124 | Q_ASSERT(refCount.loadRelaxed() == 0); |
125 | } |
126 | |
127 | void QQmlRefCount::addref() const |
128 | { |
129 | Q_ASSERT(refCount.loadRelaxed() > 0); |
130 | refCount.ref(); |
131 | } |
132 | |
133 | void QQmlRefCount::release() const |
134 | { |
135 | Q_ASSERT(refCount.loadRelaxed() > 0); |
136 | if (!refCount.deref()) |
137 | delete this; |
138 | } |
139 | |
140 | int QQmlRefCount::count() const |
141 | { |
142 | return refCount.loadRelaxed(); |
143 | } |
144 | |
145 | template<class T> |
146 | QQmlRefPointer<T>::QQmlRefPointer() |
147 | : o(nullptr) |
148 | { |
149 | } |
150 | |
151 | template<class T> |
152 | QQmlRefPointer<T>::QQmlRefPointer(T *o, Mode m) |
153 | : o(o) |
154 | { |
155 | if (m == AddRef && o) |
156 | o->addref(); |
157 | } |
158 | |
159 | template<class T> |
160 | QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other) |
161 | : o(other.o) |
162 | { |
163 | if (o) o->addref(); |
164 | } |
165 | |
166 | template <class T> |
167 | QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other) |
168 | : o(other.take()) |
169 | { |
170 | } |
171 | |
172 | template<class T> |
173 | QQmlRefPointer<T>::~QQmlRefPointer() |
174 | { |
175 | if (o) o->release(); |
176 | } |
177 | |
178 | template<class T> |
179 | QQmlRefPointer<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 | |
191 | template <class T> |
192 | QQmlRefPointer<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 | /*! |
200 | Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership |
201 | of the callers reference of other. |
202 | */ |
203 | template<class T> |
204 | QQmlRefPointer<T> &QQmlRefPointer<T>::adopt(T *other) |
205 | { |
206 | if (o) o->release(); |
207 | o = other; |
208 | return *this; |
209 | } |
210 | |
211 | QT_END_NAMESPACE |
212 | |
213 | #endif // QQMLREFCOUNT_P_H |
214 | |