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 Q_CORE_EXPORT QSharedData
56{
57public:
58 mutable QAtomicInt ref;
59
60 inline QSharedData() : ref(0) { }
61 inline QSharedData(const QSharedData &) : ref(0) { }
62
63private:
64 // using the assignment operator would lead to corruption in the ref-counting
65 QSharedData &operator=(const QSharedData &);
66};
67
68template <class T> class QSharedDataPointer
69{
70public:
71 typedef T Type;
72 typedef T *pointer;
73
74 inline void detach() { if (d && d->ref.load() != 1) detach_helper(); }
75 inline T &operator*() { detach(); return *d; }
76 inline const T &operator*() const { return *d; }
77 inline T *operator->() { detach(); return d; }
78 inline const T *operator->() const { return d; }
79 inline operator T *() { detach(); return d; }
80 inline operator const T *() const { return d; }
81 inline T *data() { detach(); return d; }
82 inline const T *data() const { return d; }
83 inline const T *constData() const { return d; }
84
85 inline bool operator==(const QSharedDataPointer<T> &other) const { return d == other.d; }
86 inline bool operator!=(const QSharedDataPointer<T> &other) const { return d != other.d; }
87
88 inline QSharedDataPointer() { d = nullptr; }
89 inline ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
90
91 explicit QSharedDataPointer(T *data) Q_DECL_NOTHROW;
92 inline QSharedDataPointer(const QSharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
93 inline QSharedDataPointer<T> & operator=(const QSharedDataPointer<T> &o) {
94 if (o.d != d) {
95 if (o.d)
96 o.d->ref.ref();
97 T *old = d;
98 d = o.d;
99 if (old && !old->ref.deref())
100 delete old;
101 }
102 return *this;
103 }
104 inline QSharedDataPointer &operator=(T *o) {
105 if (o != d) {
106 if (o)
107 o->ref.ref();
108 T *old = d;
109 d = o;
110 if (old && !old->ref.deref())
111 delete old;
112 }
113 return *this;
114 }
115#ifdef Q_COMPILER_RVALUE_REFS
116 QSharedDataPointer(QSharedDataPointer &&o) Q_DECL_NOTHROW : d(o.d) { o.d = nullptr; }
117 inline QSharedDataPointer<T> &operator=(QSharedDataPointer<T> &&other) Q_DECL_NOTHROW
118 {
119 QSharedDataPointer moved(std::move(other));
120 swap(moved);
121 return *this;
122 }
123#endif
124
125 inline bool operator!() const { return !d; }
126
127 inline void swap(QSharedDataPointer &other) Q_DECL_NOTHROW
128 { qSwap(d, other.d); }
129
130protected:
131 T *clone();
132
133private:
134 void detach_helper();
135
136 T *d;
137};
138
139template <class T> inline bool operator==(std::nullptr_t p1, const QSharedDataPointer<T> &p2)
140{
141 Q_UNUSED(p1);
142 return !p2;
143}
144
145template <class T> inline bool operator==(const QSharedDataPointer<T> &p1, std::nullptr_t p2)
146{
147 Q_UNUSED(p2);
148 return !p1;
149}
150
151template <class T> class QExplicitlySharedDataPointer
152{
153public:
154 typedef T Type;
155 typedef T *pointer;
156
157 inline T &operator*() const { return *d; }
158 inline T *operator->() { return d; }
159 inline T *operator->() const { return d; }
160 inline T *data() const { return d; }
161 inline const T *constData() const { return d; }
162 inline T *take() { T *x = d; d = nullptr; return x; }
163
164 inline void detach() { if (d && d->ref.load() != 1) detach_helper(); }
165
166 inline void reset()
167 {
168 if(d && !d->ref.deref())
169 delete d;
170
171 d = nullptr;
172 }
173
174 inline operator bool () const { return d != nullptr; }
175
176 inline bool operator==(const QExplicitlySharedDataPointer<T> &other) const { return d == other.d; }
177 inline bool operator!=(const QExplicitlySharedDataPointer<T> &other) const { return d != other.d; }
178 inline bool operator==(const T *ptr) const { return d == ptr; }
179 inline bool operator!=(const T *ptr) const { return d != ptr; }
180
181 inline QExplicitlySharedDataPointer() { d = nullptr; }
182 inline ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
183
184 explicit QExplicitlySharedDataPointer(T *data) Q_DECL_NOTHROW;
185 inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
186
187 template<class X>
188 inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o)
189#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
190 : d(static_cast<T *>(o.data()))
191#else
192 : d(o.data())
193#endif
194 {
195 if(d)
196 d->ref.ref();
197 }
198
199 inline QExplicitlySharedDataPointer<T> & operator=(const QExplicitlySharedDataPointer<T> &o) {
200 if (o.d != d) {
201 if (o.d)
202 o.d->ref.ref();
203 T *old = d;
204 d = o.d;
205 if (old && !old->ref.deref())
206 delete old;
207 }
208 return *this;
209 }
210 inline QExplicitlySharedDataPointer &operator=(T *o) {
211 if (o != d) {
212 if (o)
213 o->ref.ref();
214 T *old = d;
215 d = o;
216 if (old && !old->ref.deref())
217 delete old;
218 }
219 return *this;
220 }
221#ifdef Q_COMPILER_RVALUE_REFS
222 inline QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) Q_DECL_NOTHROW : d(o.d) { o.d = nullptr; }
223 inline QExplicitlySharedDataPointer<T> &operator=(QExplicitlySharedDataPointer<T> &&other) Q_DECL_NOTHROW
224 {
225 QExplicitlySharedDataPointer moved(std::move(other));
226 swap(moved);
227 return *this;
228 }
229#endif
230
231 inline bool operator!() const { return !d; }
232
233 inline void swap(QExplicitlySharedDataPointer &other) Q_DECL_NOTHROW
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) Q_DECL_NOTHROW
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) Q_DECL_NOTHROW
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) Q_DECL_NOTHROW
321{
322 return qHash(ptr.data(), seed);
323}
324template <class T>
325Q_INLINE_TEMPLATE uint qHash(const QExplicitlySharedDataPointer<T> &ptr, uint seed = 0) Q_DECL_NOTHROW
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