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 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
119protected:
120 T *clone();
121
122private:
123 void detach_helper();
124
125 T *d;
126};
127
128template <typename T>
129class QExplicitlySharedDataPointer
130{
131public:
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
210protected:
211 T *clone();
212
213private:
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.
225template <typename T>
226Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
227{
228 return new T(*d);
229}
230
231template <typename T>
232Q_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
241template <typename T>
242Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
243{
244 return new T(*d);
245}
246
247template <typename T>
248Q_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
257template <typename T>
258void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2) noexcept
259{ p1.swap(p2); }
260
261template <typename T>
262void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2) noexcept
263{ p1.swap(p2); }
264
265template <typename T>
266size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept
267{
268 return qHash(ptr.data(), seed);
269}
270template <typename T>
271size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept
272{
273 return qHash(ptr.data(), seed);
274}
275
276template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE);
277template<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
305QT_END_NAMESPACE
306
307#endif // QSHAREDDATA_H
308

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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