Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qshareddata.h
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#ifndef QSHAREDDATA_H
6#define QSHAREDDATA_H
7
8#include <QtCore/qatomic.h>
9#include <QtCore/qcompare.h>
10#include <QtCore/qhashfunctions.h>
11
13
14template <class T> class QSharedDataPointer;
15template <class T> class QExplicitlySharedDataPointer;
16
17namespace QtPrivate {
18template <template <typename> class P, typename T> struct QSharedDataPointerTraits;
19template <typename T> struct QSharedDataPointerTraits<QSharedDataPointer, T>
20{
21 static constexpr bool ImplicitlyDetaches = true;
22 using Type = T;
23 using pointer = T *;
24 // for const-qualified functions:
25 using constT = const T;
26};
27
29{
30 static constexpr bool ImplicitlyDetaches = false;
31 using Type = T;
32 using pointer = T *;
33 // for const-qualified functions:
34 using constT = T;
35};
36}
37
39{
40public:
41 mutable QAtomicInt ref;
42
43 QSharedData() noexcept : ref(0) { }
44 QSharedData(const QSharedData &) noexcept : ref(0) { }
45
46 // using the assignment operator would lead to corruption in the ref-counting
47 QSharedData &operator=(const QSharedData &) = delete;
48 ~QSharedData() = default;
49};
50
51struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; };
52
53// CRTP common base class for both QSharedDataPointer and QExplicitlySharedDataPointer
54template <template <typename> class P, typename T> class QSharedDataPointerBase
55{
56#ifndef Q_QDOC
57 using Self = P<T>;
59 using constT = typename Traits::constT;
60
61protected:
62 constexpr QSharedDataPointerBase(T *ptr = nullptr) noexcept : d(ptr) {}
64
65public:
66 // When adding anything public to this class, make sure to add the doc version to
67 // both QSharedDataPointer and QExplicitlySharedDataPointer.
68
69 using Type = T;
70 using pointer = T *;
71
72 void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
73 T &operator*() { detachIfImplicit(); return *(d.get()); }
74 constT &operator*() const { return *(d.get()); }
75 T *operator->() { detachIfImplicit(); return d.get(); }
76 constT *operator->() const noexcept { return d.get(); }
77 operator T *() { detachIfImplicit(); return d.get(); }
78 operator const T *() const noexcept { return d.get(); }
79 T *data() { detachIfImplicit(); return d.get(); }
80 T *get() { detachIfImplicit(); return d.get(); }
81 const T *data() const noexcept { return d.get(); }
82 const T *get() const noexcept { return d.get(); }
83 const T *constData() const noexcept { return d.get(); }
84 T *take() noexcept { return std::exchange(d, nullptr).get(); }
85
86 void reset(T *ptr = nullptr) noexcept
87 {
88 if (ptr != d.get()) {
89 if (ptr)
90 ptr->ref.ref();
91 T *old = std::exchange(d, Qt::totally_ordered_wrapper(ptr)).get();
92 if (old && !old->ref.deref())
93 destroy(old);
94 }
95 }
96
98 {
99 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
100 // reference was 1, so we can reuse the storage
101 d->ref.storeRelaxed(1);
102 d->clear();
103 } else {
104 // reference was >= 2 before we dropped the count
105 d.reset(nullptr); // in case new or T::T() throws
106 T *x = create();
107 x->ref.ref();
108 d.reset(x);
109 }
110 }
111
112 operator bool () const noexcept { return d != nullptr; }
113 bool operator!() const noexcept { return d == nullptr; }
114
115 void swap(Self &other) noexcept
116 { qt_ptr_swap(d, other.d); }
117
118private:
119 // The concrete class MUST override these, otherwise we will be calling
120 // ourselves.
121 T *clone() { return static_cast<Self *>(this)->clone(); }
122 template <typename... Args> static T *create(Args &&... args)
123 { return Self::create(std::forward(args)...); }
124 static void destroy(T *ptr) { Self::destroy(ptr); }
125
126 void detachIfImplicit()
127 {
128 if constexpr (Traits::ImplicitlyDetaches)
129 static_cast<Self *>(this)->detach();
130 }
131
132 friend bool comparesEqual(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept
133 { return lhs.d == rhs.d; }
134 friend Qt::strong_ordering
136 { return Qt::compareThreeWay(lhs.d, rhs.d); }
137
138 friend bool comparesEqual(const QSharedDataPointerBase &lhs, const T *rhs) noexcept
139 { return lhs.d == rhs; }
140 friend Qt::strong_ordering
141 compareThreeWay(const QSharedDataPointerBase &lhs, const T *rhs) noexcept
142 { return Qt::compareThreeWay(lhs.d, rhs); }
143
144 friend bool comparesEqual(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept
145 { return lhs.d == nullptr; }
146 friend Qt::strong_ordering
147 compareThreeWay(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept
148 { return Qt::compareThreeWay(lhs.d, nullptr); }
149
150 friend size_t qHash(const QSharedDataPointerBase &ptr, size_t seed = 0) noexcept
151 { return qHash(ptr.data(), seed); }
152
153protected:
155
157#endif // !Q_QDOC
158};
159
160template <typename T>
161class QSharedDataPointer : public QSharedDataPointerBase<QSharedDataPointer, T>
162{
163 using Base = QSharedDataPointerBase<QSharedDataPointer, T>;
164 friend Base;
165public:
166 typedef T Type;
167 typedef T *pointer;
168
169 void detach() { Base::detach(); }
170#ifdef Q_QDOC
171 T &operator*();
172 const T &operator*() const;
173 T *operator->();
174 const T *operator->() const noexcept;
175 operator T *();
176 operator const T *() const noexcept;
177 T *data();
178 T *get();
179 const T *data() const noexcept;
180 const T *get() const noexcept;
181 const T *constData() const noexcept;
182 T *take() noexcept;
183#endif
184
185 Q_NODISCARD_CTOR
186 QSharedDataPointer() noexcept : Base(nullptr) { }
187 ~QSharedDataPointer() { if (d && !d->ref.deref()) destroy(d.get()); }
188
189 Q_NODISCARD_CTOR
190 explicit QSharedDataPointer(T *data) noexcept : Base(data)
191 { if (d) d->ref.ref(); }
192 Q_NODISCARD_CTOR
193 QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : Base(data)
194 {}
195 Q_NODISCARD_CTOR
196 QSharedDataPointer(const QSharedDataPointer &o) noexcept : Base(o.d.get())
197 { if (d) d->ref.ref(); }
198
199 QSharedDataPointer &operator=(const QSharedDataPointer &o) noexcept
200 {
201 reset(o.d.get());
202 return *this;
203 }
204 inline QSharedDataPointer &operator=(T *o) noexcept
205 {
206 reset(o);
207 return *this;
208 }
209 Q_NODISCARD_CTOR
210 QSharedDataPointer(QSharedDataPointer &&o) noexcept
211 : Base(std::exchange(o.d, nullptr).get())
212 {}
213 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer)
214
215#ifdef Q_QDOC
216 void reset(T *ptr = nullptr) noexcept;
217 void clearPayload();
218
219 operator bool () const noexcept;
220 bool operator!() const noexcept;
221
222 void swap(QSharedDataPointer &other) noexcept;
223#else
224 using Base::reset;
225 using Base::swap;
226#endif
227
228protected:
229 T *clone();
230 template <typename... Args> static T *create(Args &&... args)
231 { return new T(std::forward(args)...); }
232 static void destroy(T *ptr) { delete ptr; }
233
234private:
235 Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer)
236 Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer, T*)
237 Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer, std::nullptr_t)
238
239 using Base::d;
240};
241
242template <typename T>
244{
246 friend Base;
247public:
248 typedef T Type;
249 typedef T *pointer;
250
251 // override to make explicit. Can use explicit(!ImplicitlyShared) once we
252 // can depend on C++20.
253 explicit operator T *() { return d.get(); }
254 explicit operator const T *() const noexcept { return d.get(); }
255
256 // override to make const. There is no const(cond), but we could use
257 // requires(!ImplicitlyShared)
258 T *data() const noexcept { return d.get(); }
259 T *get() const noexcept { return d.get(); }
260
261#ifdef Q_QDOC
262 T &operator*() const;
263 T *operator->() noexcept;
264 T *operator->() const noexcept;
265 T *data() const noexcept;
266 T *get() const noexcept;
267 const T *constData() const noexcept;
268 T *take() noexcept;
269#endif
270
271 void detach() { Base::detach(); }
272
274 QExplicitlySharedDataPointer() noexcept : Base(nullptr) { }
275 ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d.get(); }
276
279 { if (d) d->ref.ref(); }
286
287 template<typename X>
290#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
291#error This macro has been removed in Qt 6.9.
292#endif
293 : Base(o.data())
294 { if (d) d->ref.ref(); }
295
297 {
298 reset(o.d.get());
299 return *this;
300 }
302 {
303 reset(o);
304 return *this;
305 }
311
312#ifdef Q_QDOC
313 void reset(T *ptr = nullptr) noexcept;
314 void clearPayload();
315
316 operator bool () const noexcept;
317 bool operator!() const noexcept;
318
320#else
321 using Base::swap;
322 using Base::reset;
323#endif
324
325protected:
326 T *clone();
327 template <typename... Args> static T *create(Args &&... args)
328 { return new T(std::forward(args)...); }
329 static void destroy(T *ptr) { delete ptr; }
330
331private:
335
336 using Base::d;
337};
338
339// Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time.
340template <typename T>
341Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
342{
343 return new T(*this->d);
344}
345
346template <typename T>
347Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
348{
349 return new T(*this->d.get());
350}
351
352template <template <typename> class P, typename T> Q_OUTOFLINE_TEMPLATE void
353QSharedDataPointerBase<P, T>::detach_helper()
354{
355 T *x = clone();
356 x->ref.ref();
357 if (!d->ref.deref())
358 destroy(d.get());
359 d.reset(x);
360}
361
362template <typename T>
363void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2) noexcept
364{ p1.swap(p2); }
365
366template <typename T>
368{ p1.swap(p2); }
369
370template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE);
372
373#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_COMMON(Pointer, Class, ExportMacro)
374 template<> ExportMacro Pointer<Class>::~Pointer();
375#define QT_DEFINE_QSDP_SPECIALIZATION_DTOR_COMMON(Pointer, Class, Inline)
376 template<> Inline Pointer<Class>::~Pointer()
377 {
378 if (d && !d->ref.deref())
379 delete d.get();
380 }
381
382#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR(Class)
383 QT_DECLARE_QSDP_SPECIALIZATION_DTOR_COMMON(QSharedDataPointer, Class, )
384
385#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro)
386 QT_DECLARE_QSDP_SPECIALIZATION_DTOR_COMMON(QSharedDataPointer, Class, ExportMacro)
387
388#define QT_DEFINE_QSDP_SPECIALIZATION_DTOR(Class)
389 QT_DEFINE_QSDP_SPECIALIZATION_DTOR_COMMON(QSharedDataPointer, Class, )
390
391#define QT_DECLARE_QESDP_SPECIALIZATION_DTOR(Class)
392 QT_DECLARE_QSDP_SPECIALIZATION_DTOR_COMMON(QExplicitlySharedDataPointer, Class, )
393
394#define QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro)
395 QT_DECLARE_QSDP_SPECIALIZATION_DTOR_COMMON(QExplicitlySharedDataPointer, Class, ExportMacro)
396
397#define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class)
398 QT_DEFINE_QSDP_SPECIALIZATION_DTOR_COMMON(QExplicitlySharedDataPointer, Class, )
399
400QT_END_NAMESPACE
401
402#endif // QSHAREDDATA_H
\inmodule QtCore
Definition qatomic.h:114
constexpr QAtomicInt(int value=0) noexcept
Constructs a QAtomicInt with the given value.
Definition qatomic.h:119
\macro Q_ATOMIC_INTnn_IS_SUPPORTED
Definition qatomic.h:125
QAtomicPointer(const QAtomicPointer< T > &other) noexcept
Constructs a copy of other.
Definition qatomic.h:129
QAtomicPointer< T > & operator=(const QAtomicPointer< T > &other) noexcept
Assigns other to this QAtomicPointer and returns a reference to this QAtomicPointer.
Definition qatomic.h:135
constexpr QAtomicPointer(T *value=nullptr) noexcept
Constructs a QAtomicPointer with the given value.
Definition qatomic.h:127
T * get() const noexcept
~QExplicitlySharedDataPointer()
Decrements the reference count of the shared data object.
static void destroy(T *ptr)
operator const T *() const noexcept
T Type
This is the type of the shared data object.
static T * create(Args &&... args)
QExplicitlySharedDataPointer & operator=(const QExplicitlySharedDataPointer &o) noexcept
Sets the {d pointer} of this to the {d pointer} of o and increments the reference count of the shared...
T * data() const noexcept
Returns a pointer to the shared data object.
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
QExplicitlySharedDataPointer & operator=(T *o) noexcept
Sets the {d pointer} of this to o and increments {o}'s reference count.
QFileInfoPrivate(const QFileSystemEntry &file, const QFileSystemMetaData &data, std::unique_ptr< QAbstractFileEngine > engine)
Definition qfileinfo_p.h:98
bool const isDefaultConstructed
QFileInfoPrivate(const QFileSystemEntry &file, const QFileSystemMetaData &data)
Definition qfileinfo_p.h:83
Ret checkAttribute(QFileSystemMetaData::MetaDataFlags fsFlags, FSLambda fsLambda, EngineLambda engineLambda) const
QFileSystemMetaData metaData
QDateTime & getFileTime(QFile::FileTime) const
std::unique_ptr< QAbstractFileEngine > const fileEngine
QDateTime fileTimes[4]
uint getFileFlags(QAbstractFileEngine::FileFlags) const
void clearFlags() const
void setCachedFlag(uint c) const
QString getFileOwner(QAbstractFileEngine::FileOwner own) const
Definition qfileinfo.cpp:79
QString fileOwners[2]
bool getCachedFlag(uint c) const
QFileInfoPrivate(const QFileInfoPrivate &copy)
Definition qfileinfo_p.h:57
QFileSystemEntry fileEntry
static QFileInfoPrivate * get(QFileInfo *fi)
Definition qfileinfo_p.h:49
QString getFileName(QAbstractFileEngine::FileName) const
Definition qfileinfo.cpp:19
QString fileNames[QAbstractFileEngine::NFileNames]
QFileInfoPrivate(const QString &file)
Definition qfileinfo_p.h:70
Ret checkAttribute(Ret defaultValue, QFileSystemMetaData::MetaDataFlags fsFlags, FSLambda fsLambda, EngineLambda engineLambda) const
Qt::totally_ordered_wrapper< T * > d
constexpr QSharedDataPointerBase(T *ptr=nullptr) noexcept
Definition qshareddata.h:62
friend bool comparesEqual(const QSharedDataPointerBase &lhs, const T *rhs) noexcept
friend bool comparesEqual(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept
T * take() noexcept
Definition qshareddata.h:84
void reset(T *ptr=nullptr) noexcept
Definition qshareddata.h:86
const T * data() const noexcept
Definition qshareddata.h:81
void swap(Self &other) noexcept
bool operator!() const noexcept
friend Qt::strong_ordering compareThreeWay(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept
friend Qt::strong_ordering compareThreeWay(const QSharedDataPointerBase &lhs, const T *rhs) noexcept
friend size_t qHash(const QSharedDataPointerBase &ptr, size_t seed=0) noexcept
constT & operator*() const
Definition qshareddata.h:74
constT * operator->() const noexcept
Definition qshareddata.h:76
friend bool comparesEqual(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept
const T * get() const noexcept
Definition qshareddata.h:82
operator bool() const noexcept
friend Qt::strong_ordering compareThreeWay(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept
operator const T *() const noexcept
Definition qshareddata.h:78
const T * constData() const noexcept
Definition qshareddata.h:83
T Type
This is the type of the shared data object.
~QSharedDataPointer()
Decrements the reference count of the shared data object.
QSharedDataPointer & operator=(const QSharedDataPointer &o) noexcept
Sets the {d pointer} of this to the {d pointer} of o and increments the reference count of the shared...
static void destroy(T *ptr)
static T * create(Args &&... args)
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
QSharedDataPointer & operator=(T *o) noexcept
Sets the {d pointer} og this to o and increments {o}'s reference count.
\inmodule QtCore
Definition qshareddata.h:39
QSharedData() noexcept
Constructs a QSharedData object with a reference count of 0.
Definition qshareddata.h:43
~QSharedData()=default
QAtomicInt ref
Definition qshareddata.h:41
QSharedData & operator=(const QSharedData &)=delete
QSharedData(const QSharedData &) noexcept
Constructs a QSharedData object with reference count 0.
Definition qshareddata.h:44
Combined button and popup list for selecting options.
void qAtomicDetach(T *&d)
This is a helper for the detach method of implicitly shared classes.
Definition qatomic.h:206
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
#define QT_DEFINE_QSDP_SPECIALIZATION_DTOR_COMMON(Pointer, Class, Inline)
Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer< T >, Q_RELOCATABLE_TYPE)
void swap(QExplicitlySharedDataPointer< T > &p1, QExplicitlySharedDataPointer< T > &p2) noexcept
void swap(QSharedDataPointer< T > &p1, QSharedDataPointer< T > &p2) noexcept
#define QT_DEFINE_QSDP_SPECIALIZATION_DTOR(Class)
#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_COMMON(Pointer, Class, ExportMacro)
Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer< T >, Q_RELOCATABLE_TYPE)
\inmodule QtCore \threadsafe
Definition qshareddata.h:51