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
13QT_BEGIN_NAMESPACE
14
15
16template <class T> class QSharedDataPointer;
17
18class QSharedData
19{
20public:
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
31struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; };
32
33template <typename T>
34class QSharedDataPointer
35{
36public:
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 qExchange(d, nullptr); }
53
54 QSharedDataPointer() noexcept : d(nullptr) { }
55 ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
56
57 explicit QSharedDataPointer(T *data) noexcept : d(data)
58 { if (d) d->ref.ref(); }
59 QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
60 {}
61 QSharedDataPointer(const QSharedDataPointer &o) noexcept : d(o.d)
62 { if (d) d->ref.ref(); }
63
64 void reset(T *ptr = nullptr) noexcept
65 {
66 if (ptr != d) {
67 if (ptr)
68 ptr->ref.ref();
69 T *old = qExchange(d, ptr);
70 if (old && !old->ref.deref())
71 delete old;
72 }
73 }
74
75 QSharedDataPointer &operator=(const QSharedDataPointer &o) noexcept
76 {
77 reset(ptr: o.d);
78 return *this;
79 }
80 inline QSharedDataPointer &operator=(T *o) noexcept
81 {
82 reset(ptr: o);
83 return *this;
84 }
85 QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(qExchange(o.d, nullptr)) {}
86 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer)
87
88 operator bool () const noexcept { return d != nullptr; }
89 bool operator!() const noexcept { return d == nullptr; }
90
91 void swap(QSharedDataPointer &other) noexcept
92 { qt_ptr_swap(d, other.d); }
93
94#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \
95 friend bool operator<(T1, T2) noexcept \
96 { return std::less<T*>{}(A1, A2); } \
97 friend bool operator<=(T1, T2) noexcept \
98 { return !std::less<T*>{}(A2, A1); } \
99 friend bool operator>(T1, T2) noexcept \
100 { return std::less<T*>{}(A2, A1); } \
101 friend bool operator>=(T1, T2) noexcept \
102 { return !std::less<T*>{}(A1, A2); } \
103 friend bool operator==(T1, T2) noexcept \
104 { return A1 == A2; } \
105 friend bool operator!=(T1, T2) noexcept \
106 { return A1 != A2; } \
107
108 DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, const QSharedDataPointer &p2, p2.d)
109 DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, const T *ptr, ptr)
110 DECLARE_COMPARE_SET(const T *ptr, ptr, const QSharedDataPointer &p2, p2.d)
111 DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, std::nullptr_t, nullptr)
112 DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QSharedDataPointer &p2, p2.d)
113
114protected:
115 T *clone();
116
117private:
118 void detach_helper();
119
120 T *d;
121};
122
123template <typename T>
124class QExplicitlySharedDataPointer
125{
126public:
127 typedef T Type;
128 typedef T *pointer;
129
130 T &operator*() const { return *d; }
131 T *operator->() noexcept { return d; }
132 T *operator->() const noexcept { return d; }
133 explicit operator T *() { return d; }
134 explicit operator const T *() const noexcept { return d; }
135 T *data() const noexcept { return d; }
136 T *get() const noexcept { return d; }
137 const T *constData() const noexcept { return d; }
138 T *take() noexcept { return qExchange(d, nullptr); }
139
140 void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
141
142 QExplicitlySharedDataPointer() noexcept : d(nullptr) { }
143 ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
144
145 explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data)
146 { if (d) d->ref.ref(); }
147 QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
148 {}
149 QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : d(o.d)
150 { if (d) d->ref.ref(); }
151
152 template<typename X>
153 QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o) noexcept
154#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
155 : d(static_cast<T *>(o.data()))
156#else
157 : d(o.data())
158#endif
159 { if (d) d->ref.ref(); }
160
161 void reset(T *ptr = nullptr) noexcept
162 {
163 if (ptr != d) {
164 if (ptr)
165 ptr->ref.ref();
166 T *old = qExchange(d, ptr);
167 if (old && !old->ref.deref())
168 delete old;
169 }
170 }
171
172 QExplicitlySharedDataPointer &operator=(const QExplicitlySharedDataPointer &o) noexcept
173 {
174 reset(ptr: o.d);
175 return *this;
176 }
177 QExplicitlySharedDataPointer &operator=(T *o) noexcept
178 {
179 reset(ptr: o);
180 return *this;
181 }
182 QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(qExchange(o.d, nullptr)) {}
183 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QExplicitlySharedDataPointer)
184
185 operator bool () const noexcept { return d != nullptr; }
186 bool operator!() const noexcept { return d == nullptr; }
187
188 void swap(QExplicitlySharedDataPointer &other) noexcept
189 { qt_ptr_swap(d, other.d); }
190
191 DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const QExplicitlySharedDataPointer &p2, p2.d)
192 DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const T *ptr, ptr)
193 DECLARE_COMPARE_SET(const T *ptr, ptr, const QExplicitlySharedDataPointer &p2, p2.d)
194 DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, std::nullptr_t, nullptr)
195 DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QExplicitlySharedDataPointer &p2, p2.d)
196
197#undef DECLARE_COMPARE_SET
198
199protected:
200 T *clone();
201
202private:
203 void detach_helper();
204
205 T *d;
206};
207
208// Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time.
209template <typename T>
210Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
211{
212 return new T(*d);
213}
214
215template <typename T>
216Q_OUTOFLINE_TEMPLATE void QSharedDataPointer<T>::detach_helper()
217{
218 T *x = clone();
219 x->ref.ref();
220 if (!d->ref.deref())
221 delete d;
222 d = x;
223}
224
225template <typename T>
226Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
227{
228 return new T(*d);
229}
230
231template <typename T>
232Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer<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
241template <typename T>
242void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2) noexcept
243{ p1.swap(p2); }
244
245template <typename T>
246void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2) noexcept
247{ p1.swap(p2); }
248
249template <typename T>
250size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept
251{
252 return qHash(ptr.data(), seed);
253}
254template <typename T>
255size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept
256{
257 return qHash(ptr.data(), seed);
258}
259
260template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE);
261template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_RELOCATABLE_TYPE);
262
263#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR(Class) \
264 template<> QSharedDataPointer<Class>::~QSharedDataPointer();
265
266#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \
267 template<> ExportMacro QSharedDataPointer<Class>::~QSharedDataPointer();
268
269#define QT_DEFINE_QSDP_SPECIALIZATION_DTOR(Class) \
270 template<> QSharedDataPointer<Class>::~QSharedDataPointer() \
271 { \
272 if (d && !d->ref.deref()) \
273 delete d; \
274 }
275
276#define QT_DECLARE_QESDP_SPECIALIZATION_DTOR(Class) \
277 template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer();
278
279#define QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \
280 template<> ExportMacro QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer();
281
282#define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class) \
283 template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer() \
284 { \
285 if (d && !d->ref.deref()) \
286 delete d; \
287 }
288
289QT_END_NAMESPACE
290
291#endif // QSHAREDDATA_H
292

source code of qtbase/src/corelib/tools/qshareddata.h