1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QSHAREDDATA_H
41#define QSHAREDDATA_H
42
43#include <QtCore/qglobal.h>
44#include <QtCore/qatomic.h>
45#if QT_DEPRECATED_SINCE(5, 6)
46#include <QtCore/qhash.h>
47#endif
48#include <QtCore/qhashfunctions.h>
49
50QT_BEGIN_NAMESPACE
51
52
53template <class T> class QSharedDataPointer;
54
55class
56#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
57Q_CORE_EXPORT
58#endif
59QSharedData
60{
61public:
62 mutable QAtomicInt ref;
63
64 inline QSharedData() noexcept : ref(0) { }
65 inline QSharedData(const QSharedData &) noexcept : ref(0) { }
66
67 // using the assignment operator would lead to corruption in the ref-counting
68 QSharedData &operator=(const QSharedData &) = delete;
69 ~QSharedData() = default;
70};
71
72template <class T> class QSharedDataPointer
73{
74public:
75 typedef T Type;
76 typedef T *pointer;
77
78 inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
79 inline T &operator*() { detach(); return *d; }
80 inline const T &operator*() const { return *d; }
81 inline T *operator->() { detach(); return d; }
82 inline const T *operator->() const { return d; }
83 inline operator T *() { detach(); return d; }
84 inline operator const T *() const { return d; }
85 inline T *data() { detach(); return d; }
86 inline const T *data() const { return d; }
87 inline const T *constData() const { return d; }
88
89 inline bool operator==(const QSharedDataPointer<T> &other) const { return d == other.d; }
90 inline bool operator!=(const QSharedDataPointer<T> &other) const { return d != other.d; }
91
92 inline QSharedDataPointer() { d = nullptr; }
93 inline ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
94
95 explicit QSharedDataPointer(T *data) noexcept;
96 inline QSharedDataPointer(const QSharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
97 inline QSharedDataPointer<T> & operator=(const QSharedDataPointer<T> &o) {
98 if (o.d != d) {
99 if (o.d)
100 o.d->ref.ref();
101 T *old = d;
102 d = o.d;
103 if (old && !old->ref.deref())
104 delete old;
105 }
106 return *this;
107 }
108 inline QSharedDataPointer &operator=(T *o) {
109 if (o != d) {
110 if (o)
111 o->ref.ref();
112 T *old = d;
113 d = o;
114 if (old && !old->ref.deref())
115 delete old;
116 }
117 return *this;
118 }
119 QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(o.d) { o.d = nullptr; }
120 inline QSharedDataPointer<T> &operator=(QSharedDataPointer<T> &&other) noexcept
121 {
122 QSharedDataPointer moved(std::move(other));
123 swap(moved);
124 return *this;
125 }
126
127 inline bool operator!() const { return !d; }
128
129 inline void swap(QSharedDataPointer &other) noexcept
130 { qSwap(d, other.d); }
131
132protected:
133 T *clone();
134
135private:
136 void detach_helper();
137
138 T *d;
139};
140
141template <class T> inline bool operator==(std::nullptr_t p1, const QSharedDataPointer<T> &p2)
142{
143 Q_UNUSED(p1);
144 return !p2;
145}
146
147template <class T> inline bool operator==(const QSharedDataPointer<T> &p1, std::nullptr_t p2)
148{
149 Q_UNUSED(p2);
150 return !p1;
151}
152
153template <class T> class QExplicitlySharedDataPointer
154{
155public:
156 typedef T Type;
157 typedef T *pointer;
158
159 inline T &operator*() const { return *d; }
160 inline T *operator->() { return d; }
161 inline T *operator->() const { return d; }
162 inline T *data() const { return d; }
163 inline const T *constData() const { return d; }
164 inline T *take() { T *x = d; d = nullptr; return x; }
165
166 inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
167
168 inline void reset()
169 {
170 if(d && !d->ref.deref())
171 delete d;
172
173 d = nullptr;
174 }
175
176 inline operator bool () const { return d != nullptr; }
177
178 inline bool operator==(const QExplicitlySharedDataPointer<T> &other) const { return d == other.d; }
179 inline bool operator!=(const QExplicitlySharedDataPointer<T> &other) const { return d != other.d; }
180 inline bool operator==(const T *ptr) const { return d == ptr; }
181 inline bool operator!=(const T *ptr) const { return d != ptr; }
182
183 inline QExplicitlySharedDataPointer() { d = nullptr; }
184 inline ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
185
186 explicit QExplicitlySharedDataPointer(T *data) noexcept;
187 inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
188
189 template<class X>
190 inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o)
191#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
192 : d(static_cast<T *>(o.data()))
193#else
194 : d(o.data())
195#endif
196 {
197 if(d)
198 d->ref.ref();
199 }
200
201 inline QExplicitlySharedDataPointer<T> & operator=(const QExplicitlySharedDataPointer<T> &o) {
202 if (o.d != d) {
203 if (o.d)
204 o.d->ref.ref();
205 T *old = d;
206 d = o.d;
207 if (old && !old->ref.deref())
208 delete old;
209 }
210 return *this;
211 }
212 inline QExplicitlySharedDataPointer &operator=(T *o) {
213 if (o != d) {
214 if (o)
215 o->ref.ref();
216 T *old = d;
217 d = o;
218 if (old && !old->ref.deref())
219 delete old;
220 }
221 return *this;
222 }
223 inline QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(o.d) { o.d = nullptr; }
224 inline QExplicitlySharedDataPointer<T> &operator=(QExplicitlySharedDataPointer<T> &&other) noexcept
225 {
226 QExplicitlySharedDataPointer moved(std::move(other));
227 swap(moved);
228 return *this;
229 }
230
231 inline bool operator!() const { return !d; }
232
233 inline void swap(QExplicitlySharedDataPointer &other) noexcept
234 { qSwap(d, other.d); }
235
236protected:
237 T *clone();
238
239private:
240 void detach_helper();
241
242 T *d;
243};
244
245template <class T>
246Q_INLINE_TEMPLATE QSharedDataPointer<T>::QSharedDataPointer(T *adata) noexcept
247 : d(adata)
248{ if (d) d->ref.ref(); }
249
250template <class T>
251Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
252{
253 return new T(*d);
254}
255
256template <class T>
257Q_OUTOFLINE_TEMPLATE void QSharedDataPointer<T>::detach_helper()
258{
259 T *x = clone();
260 x->ref.ref();
261 if (!d->ref.deref())
262 delete d;
263 d = x;
264}
265
266template <class T>
267Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
268{
269 return new T(*d);
270}
271
272template <class T>
273Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer<T>::detach_helper()
274{
275 T *x = clone();
276 x->ref.ref();
277 if (!d->ref.deref())
278 delete d;
279 d = x;
280}
281
282template <class T>
283Q_INLINE_TEMPLATE QExplicitlySharedDataPointer<T>::QExplicitlySharedDataPointer(T *adata) noexcept
284 : d(adata)
285{ if (d) d->ref.ref(); }
286
287template <class T> inline bool operator==(std::nullptr_t p1, const QExplicitlySharedDataPointer<T> &p2)
288{
289 Q_UNUSED(p1);
290 return !p2;
291}
292
293template <class T> inline bool operator==(const QExplicitlySharedDataPointer<T> &p1, std::nullptr_t p2)
294{
295 Q_UNUSED(p2);
296 return !p1;
297}
298
299template <class T>
300Q_INLINE_TEMPLATE void qSwap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2)
301{ p1.swap(p2); }
302
303template <class T>
304Q_INLINE_TEMPLATE void qSwap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2)
305{ p1.swap(p2); }
306
307QT_END_NAMESPACE
308namespace std {
309 template <class T>
310 Q_INLINE_TEMPLATE void swap(QT_PREPEND_NAMESPACE(QSharedDataPointer)<T> &p1, QT_PREPEND_NAMESPACE(QSharedDataPointer)<T> &p2)
311 { p1.swap(p2); }
312
313 template <class T>
314 Q_INLINE_TEMPLATE void swap(QT_PREPEND_NAMESPACE(QExplicitlySharedDataPointer)<T> &p1, QT_PREPEND_NAMESPACE(QExplicitlySharedDataPointer)<T> &p2)
315 { p1.swap(p2); }
316}
317QT_BEGIN_NAMESPACE
318
319template <class T>
320Q_INLINE_TEMPLATE uint qHash(const QSharedDataPointer<T> &ptr, uint seed = 0) noexcept
321{
322 return qHash(ptr.data(), seed);
323}
324template <class T>
325Q_INLINE_TEMPLATE uint qHash(const QExplicitlySharedDataPointer<T> &ptr, uint seed = 0) noexcept
326{
327 return qHash(ptr.data(), seed);
328}
329
330template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_MOVABLE_TYPE);
331template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_MOVABLE_TYPE);
332
333QT_END_NAMESPACE
334
335#endif // QSHAREDDATA_H
336