1 | // Copyright (C) 2020 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 QSHAREDDATA_H |
5 | #define QSHAREDDATA_H |
6 | |
7 | #include <QtCore/qglobal.h> |
8 | #include <QtCore/qatomic.h> |
9 | #include <QtCore/qhashfunctions.h> |
10 | |
11 | #include <functional> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | |
16 | template <class T> class QSharedDataPointer; |
17 | |
18 | class QSharedData |
19 | { |
20 | public: |
21 | mutable QAtomicInt ref; |
22 | |
23 | QSharedData() noexcept : ref(0) { } |
24 | QSharedData(const QSharedData &) noexcept : ref(0) { } |
25 | |
26 | // using the assignment operator would lead to corruption in the ref-counting |
27 | QSharedData &operator=(const QSharedData &) = delete; |
28 | ~QSharedData() = default; |
29 | }; |
30 | |
31 | struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; }; |
32 | |
33 | template <typename T> |
34 | class QSharedDataPointer |
35 | { |
36 | public: |
37 | typedef T Type; |
38 | typedef T *pointer; |
39 | |
40 | void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } |
41 | T &operator*() { detach(); return *d; } |
42 | const T &operator*() const { return *d; } |
43 | T *operator->() { detach(); return d; } |
44 | const T *operator->() const noexcept { return d; } |
45 | operator T *() { detach(); return d; } |
46 | operator const T *() const noexcept { return d; } |
47 | T *data() { detach(); return d; } |
48 | T *get() { detach(); return d; } |
49 | const T *data() const noexcept { return d; } |
50 | const T *get() const noexcept { return d; } |
51 | const T *constData() const noexcept { return d; } |
52 | T *take() noexcept { return std::exchange(d, nullptr); } |
53 | |
54 | Q_NODISCARD_CTOR |
55 | QSharedDataPointer() noexcept : d(nullptr) { } |
56 | ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; } |
57 | |
58 | Q_NODISCARD_CTOR |
59 | explicit QSharedDataPointer(T *data) noexcept : d(data) |
60 | { if (d) d->ref.ref(); } |
61 | Q_NODISCARD_CTOR |
62 | QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data) |
63 | {} |
64 | Q_NODISCARD_CTOR |
65 | QSharedDataPointer(const QSharedDataPointer &o) noexcept : d(o.d) |
66 | { if (d) d->ref.ref(); } |
67 | |
68 | void reset(T *ptr = nullptr) noexcept |
69 | { |
70 | if (ptr != d) { |
71 | if (ptr) |
72 | ptr->ref.ref(); |
73 | T *old = std::exchange(d, ptr); |
74 | if (old && !old->ref.deref()) |
75 | delete old; |
76 | } |
77 | } |
78 | |
79 | QSharedDataPointer &operator=(const QSharedDataPointer &o) noexcept |
80 | { |
81 | reset(ptr: o.d); |
82 | return *this; |
83 | } |
84 | inline QSharedDataPointer &operator=(T *o) noexcept |
85 | { |
86 | reset(ptr: o); |
87 | return *this; |
88 | } |
89 | Q_NODISCARD_CTOR |
90 | QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {} |
91 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer) |
92 | |
93 | operator bool () const noexcept { return d != nullptr; } |
94 | bool operator!() const noexcept { return d == nullptr; } |
95 | |
96 | void swap(QSharedDataPointer &other) noexcept |
97 | { qt_ptr_swap(d, other.d); } |
98 | |
99 | #define DECLARE_COMPARE_SET(T1, A1, T2, A2) \ |
100 | friend bool operator<(T1, T2) noexcept \ |
101 | { return std::less<T*>{}(A1, A2); } \ |
102 | friend bool operator<=(T1, T2) noexcept \ |
103 | { return !std::less<T*>{}(A2, A1); } \ |
104 | friend bool operator>(T1, T2) noexcept \ |
105 | { return std::less<T*>{}(A2, A1); } \ |
106 | friend bool operator>=(T1, T2) noexcept \ |
107 | { return !std::less<T*>{}(A1, A2); } \ |
108 | friend bool operator==(T1, T2) noexcept \ |
109 | { return A1 == A2; } \ |
110 | friend bool operator!=(T1, T2) noexcept \ |
111 | { return A1 != A2; } \ |
112 | |
113 | DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, const QSharedDataPointer &p2, p2.d) |
114 | DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, const T *ptr, ptr) |
115 | DECLARE_COMPARE_SET(const T *ptr, ptr, const QSharedDataPointer &p2, p2.d) |
116 | DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, std::nullptr_t, nullptr) |
117 | DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QSharedDataPointer &p2, p2.d) |
118 | |
119 | protected: |
120 | T *clone(); |
121 | |
122 | private: |
123 | void detach_helper(); |
124 | |
125 | T *d; |
126 | }; |
127 | |
128 | template <typename T> |
129 | class QExplicitlySharedDataPointer |
130 | { |
131 | public: |
132 | typedef T Type; |
133 | typedef T *pointer; |
134 | |
135 | T &operator*() const { return *d; } |
136 | T *operator->() noexcept { return d; } |
137 | T *operator->() const noexcept { return d; } |
138 | explicit operator T *() { return d; } |
139 | explicit operator const T *() const noexcept { return d; } |
140 | T *data() const noexcept { return d; } |
141 | T *get() const noexcept { return d; } |
142 | const T *constData() const noexcept { return d; } |
143 | T *take() noexcept { return std::exchange(d, nullptr); } |
144 | |
145 | void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } |
146 | |
147 | Q_NODISCARD_CTOR |
148 | QExplicitlySharedDataPointer() noexcept : d(nullptr) { } |
149 | ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; } |
150 | |
151 | Q_NODISCARD_CTOR |
152 | explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data) |
153 | { if (d) d->ref.ref(); } |
154 | Q_NODISCARD_CTOR |
155 | QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data) |
156 | {} |
157 | Q_NODISCARD_CTOR |
158 | QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : d(o.d) |
159 | { if (d) d->ref.ref(); } |
160 | |
161 | template<typename X> |
162 | Q_NODISCARD_CTOR |
163 | QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o) noexcept |
164 | #ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST |
165 | : d{(warnIfQExplicitlySharedDataPointerStaticCastMacroDefined(), static_cast<T *>(o.data()))} |
166 | #else |
167 | : d(o.data()) |
168 | #endif |
169 | { if (d) d->ref.ref(); } |
170 | |
171 | void reset(T *ptr = nullptr) noexcept |
172 | { |
173 | if (ptr != d) { |
174 | if (ptr) |
175 | ptr->ref.ref(); |
176 | T *old = std::exchange(d, ptr); |
177 | if (old && !old->ref.deref()) |
178 | delete old; |
179 | } |
180 | } |
181 | |
182 | QExplicitlySharedDataPointer &operator=(const QExplicitlySharedDataPointer &o) noexcept |
183 | { |
184 | reset(ptr: o.d); |
185 | return *this; |
186 | } |
187 | QExplicitlySharedDataPointer &operator=(T *o) noexcept |
188 | { |
189 | reset(ptr: o); |
190 | return *this; |
191 | } |
192 | Q_NODISCARD_CTOR |
193 | QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {} |
194 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QExplicitlySharedDataPointer) |
195 | |
196 | operator bool () const noexcept { return d != nullptr; } |
197 | bool operator!() const noexcept { return d == nullptr; } |
198 | |
199 | void swap(QExplicitlySharedDataPointer &other) noexcept |
200 | { qt_ptr_swap(d, other.d); } |
201 | |
202 | DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const QExplicitlySharedDataPointer &p2, p2.d) |
203 | DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const T *ptr, ptr) |
204 | DECLARE_COMPARE_SET(const T *ptr, ptr, const QExplicitlySharedDataPointer &p2, p2.d) |
205 | DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, std::nullptr_t, nullptr) |
206 | DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QExplicitlySharedDataPointer &p2, p2.d) |
207 | |
208 | #undef DECLARE_COMPARE_SET |
209 | |
210 | protected: |
211 | T *clone(); |
212 | |
213 | private: |
214 | void detach_helper(); |
215 | |
216 | #ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST |
217 | [[deprecated("Usage of QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST is deprecated.")]] |
218 | constexpr void warnIfQExplicitlySharedDataPointerStaticCastMacroDefined() {} |
219 | #endif |
220 | |
221 | T *d; |
222 | }; |
223 | |
224 | // Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time. |
225 | template <typename T> |
226 | Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone() |
227 | { |
228 | return new T(*d); |
229 | } |
230 | |
231 | template <typename T> |
232 | Q_OUTOFLINE_TEMPLATE void QSharedDataPointer<T>::detach_helper() |
233 | { |
234 | T *x = clone(); |
235 | x->ref.ref(); |
236 | if (!d->ref.deref()) |
237 | delete d; |
238 | d = x; |
239 | } |
240 | |
241 | template <typename T> |
242 | Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone() |
243 | { |
244 | return new T(*d); |
245 | } |
246 | |
247 | template <typename T> |
248 | Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer<T>::detach_helper() |
249 | { |
250 | T *x = clone(); |
251 | x->ref.ref(); |
252 | if (!d->ref.deref()) |
253 | delete d; |
254 | d = x; |
255 | } |
256 | |
257 | template <typename T> |
258 | void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2) noexcept |
259 | { p1.swap(p2); } |
260 | |
261 | template <typename T> |
262 | void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2) noexcept |
263 | { p1.swap(p2); } |
264 | |
265 | template <typename T> |
266 | size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept |
267 | { |
268 | return qHash(ptr.data(), seed); |
269 | } |
270 | template <typename T> |
271 | size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept |
272 | { |
273 | return qHash(ptr.data(), seed); |
274 | } |
275 | |
276 | template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE); |
277 | template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_RELOCATABLE_TYPE); |
278 | |
279 | #define QT_DECLARE_QSDP_SPECIALIZATION_DTOR(Class) \ |
280 | template<> QSharedDataPointer<Class>::~QSharedDataPointer(); |
281 | |
282 | #define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \ |
283 | template<> ExportMacro QSharedDataPointer<Class>::~QSharedDataPointer(); |
284 | |
285 | #define QT_DEFINE_QSDP_SPECIALIZATION_DTOR(Class) \ |
286 | template<> QSharedDataPointer<Class>::~QSharedDataPointer() \ |
287 | { \ |
288 | if (d && !d->ref.deref()) \ |
289 | delete d; \ |
290 | } |
291 | |
292 | #define QT_DECLARE_QESDP_SPECIALIZATION_DTOR(Class) \ |
293 | template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer(); |
294 | |
295 | #define QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \ |
296 | template<> ExportMacro QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer(); |
297 | |
298 | #define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class) \ |
299 | template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer() \ |
300 | { \ |
301 | if (d && !d->ref.deref()) \ |
302 | delete d; \ |
303 | } |
304 | |
305 | QT_END_NAMESPACE |
306 | |
307 | #endif // QSHAREDDATA_H |
308 |
Definitions
- QSharedData
- QSharedData
- QSharedData
- operator=
- ~QSharedData
- QAdoptSharedDataTag
- QAdoptSharedDataTag
- QSharedDataPointer
- detach
- operator*
- operator*
- operator->
- operator->
- operator T *
- operator const T *
- data
- get
- data
- get
- constData
- take
- QSharedDataPointer
- ~QSharedDataPointer
- QSharedDataPointer
- QSharedDataPointer
- QSharedDataPointer
- reset
- operator=
- operator=
- QSharedDataPointer
- operator bool
- operator!
- swap
- QExplicitlySharedDataPointer
- operator*
- operator->
- operator->
- operator T *
- operator const T *
- data
- get
- constData
- take
- detach
- QExplicitlySharedDataPointer
- ~QExplicitlySharedDataPointer
- QExplicitlySharedDataPointer
- QExplicitlySharedDataPointer
- QExplicitlySharedDataPointer
- QExplicitlySharedDataPointer
- reset
- operator=
- operator=
- QExplicitlySharedDataPointer
- operator bool
- operator!
- swap
- clone
- detach_helper
- clone
- detach_helper
- swap
- swap
- qHash
Learn Advanced QML with KDAB
Find out more