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 
50 QT_BEGIN_NAMESPACE
51 
52 
53 template <class T> class QSharedDataPointer;
54 
55 class
56 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
57 Q_CORE_EXPORT
58 #endif
59 QSharedData
60 {
61 public:
62     mutable QAtomicInt ref;
63 
QSharedData()64     inline QSharedData() noexcept : ref(0) { }
QSharedData(const QSharedData &)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 
72 template <class T> class QSharedDataPointer
73 {
74 public:
75     typedef T Type;
76     typedef T *pointer;
77 
detach()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; }
data()85     inline T *data() { detach(); return d; }
data()86     inline const T *data() const { return d; }
constData()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 
QSharedDataPointer()92     inline QSharedDataPointer() { d = nullptr; }
~QSharedDataPointer()93     inline ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
94 
95     explicit QSharedDataPointer(T *data) noexcept;
QSharedDataPointer(const QSharedDataPointer<T> & o)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     }
QSharedDataPointer(QSharedDataPointer && o)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 
swap(QSharedDataPointer & other)129     inline void swap(QSharedDataPointer &other) noexcept
130     { qSwap(d, other.d); }
131 
132 protected:
133     T *clone();
134 
135 private:
136     void detach_helper();
137 
138     T *d;
139 };
140 
141 template <class T> inline bool operator==(std::nullptr_t p1, const QSharedDataPointer<T> &p2)
142 {
143     Q_UNUSED(p1);
144     return !p2;
145 }
146 
147 template <class T> inline bool operator==(const QSharedDataPointer<T> &p1, std::nullptr_t p2)
148 {
149     Q_UNUSED(p2);
150     return !p1;
151 }
152 
153 template <class T> class QExplicitlySharedDataPointer
154 {
155 public:
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; }
data()162     inline T *data() const { return d; }
constData()163     inline const T *constData() const { return d; }
take()164     inline T *take() { T *x = d; d = nullptr; return x; }
165 
detach()166     inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
167 
reset()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 
QExplicitlySharedDataPointer()183     inline QExplicitlySharedDataPointer() { d = nullptr; }
~QExplicitlySharedDataPointer()184     inline ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
185 
186     explicit QExplicitlySharedDataPointer(T *data) noexcept;
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T> & o)187     inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
188 
189     template<class X>
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> & o)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     }
QExplicitlySharedDataPointer(QExplicitlySharedDataPointer && o)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 
swap(QExplicitlySharedDataPointer & other)233     inline void swap(QExplicitlySharedDataPointer &other) noexcept
234     { qSwap(d, other.d); }
235 
236 protected:
237     T *clone();
238 
239 private:
240     void detach_helper();
241 
242     T *d;
243 };
244 
245 template <class T>
QSharedDataPointer(T * adata)246 Q_INLINE_TEMPLATE QSharedDataPointer<T>::QSharedDataPointer(T *adata) noexcept
247     : d(adata)
248 { if (d) d->ref.ref(); }
249 
250 template <class T>
clone()251 Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
252 {
253     return new T(*d);
254 }
255 
256 template <class T>
detach_helper()257 Q_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 
266 template <class T>
clone()267 Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
268 {
269     return new T(*d);
270 }
271 
272 template <class T>
detach_helper()273 Q_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 
282 template <class T>
QExplicitlySharedDataPointer(T * adata)283 Q_INLINE_TEMPLATE QExplicitlySharedDataPointer<T>::QExplicitlySharedDataPointer(T *adata) noexcept
284     : d(adata)
285 { if (d) d->ref.ref(); }
286 
287 template <class T> inline bool operator==(std::nullptr_t p1, const QExplicitlySharedDataPointer<T> &p2)
288 {
289     Q_UNUSED(p1);
290     return !p2;
291 }
292 
293 template <class T> inline bool operator==(const QExplicitlySharedDataPointer<T> &p1, std::nullptr_t p2)
294 {
295     Q_UNUSED(p2);
296     return !p1;
297 }
298 
299 template <class T>
swap(QSharedDataPointer<T> & p1,QSharedDataPointer<T> & p2)300 Q_INLINE_TEMPLATE void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2)
301 { p1.swap(p2); }
302 
303 template <class T>
swap(QExplicitlySharedDataPointer<T> & p1,QExplicitlySharedDataPointer<T> & p2)304 Q_INLINE_TEMPLATE void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2)
305 { p1.swap(p2); }
306 
307 template <class T>
308 Q_INLINE_TEMPLATE uint qHash(const QSharedDataPointer<T> &ptr, uint seed = 0) noexcept
309 {
310     return qHash(ptr.data(), seed);
311 }
312 template <class T>
313 Q_INLINE_TEMPLATE uint qHash(const QExplicitlySharedDataPointer<T> &ptr, uint seed = 0) noexcept
314 {
315     return qHash(ptr.data(), seed);
316 }
317 
318 template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_MOVABLE_TYPE);
319 template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_MOVABLE_TYPE);
320 
321 QT_END_NAMESPACE
322 
323 #endif // QSHAREDDATA_H
324