File indexing completed on 2026-08-05 09:27:37
0001
0002
0003
0004
0005 #ifndef QSHAREDDATA_H
0006 #define QSHAREDDATA_H
0007
0008 #include <QtCore/qatomic.h>
0009 #include <QtCore/qcompare.h>
0010 #include <QtCore/qhashfunctions.h>
0011
0012 QT_BEGIN_NAMESPACE
0013
0014 template <class T> class QSharedDataPointer;
0015 template <class T> class QExplicitlySharedDataPointer;
0016
0017 namespace QtPrivate {
0018 template <template <typename> class P, typename T> struct QSharedDataPointerTraits;
0019 template <typename T> struct QSharedDataPointerTraits<QSharedDataPointer, T>
0020 {
0021 static constexpr bool ImplicitlyDetaches = true;
0022 using Type = T;
0023 using pointer = T *;
0024
0025 using constT = const T;
0026 };
0027
0028 template <typename T> struct QSharedDataPointerTraits<QExplicitlySharedDataPointer, T>
0029 {
0030 static constexpr bool ImplicitlyDetaches = false;
0031 using Type = T;
0032 using pointer = T *;
0033
0034 using constT = T;
0035 };
0036 }
0037
0038 class QSharedData
0039 {
0040 public:
0041 mutable QAtomicInt ref;
0042
0043 QSharedData() noexcept : ref(0) { }
0044 QSharedData(const QSharedData &) noexcept : ref(0) { }
0045
0046
0047 QSharedData &operator=(const QSharedData &) = delete;
0048 ~QSharedData() = default;
0049 };
0050
0051 struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; };
0052
0053
0054 template <template <typename> class P, typename T> class QSharedDataPointerBase
0055 {
0056 #ifndef Q_QDOC
0057 using Self = P<T>;
0058 using Traits = QtPrivate::QSharedDataPointerTraits<P, T>;
0059 using constT = typename Traits::constT;
0060
0061 protected:
0062 constexpr QSharedDataPointerBase(T *ptr = nullptr) noexcept : d(ptr) {}
0063 QT_DECLARE_RO5_SMF_AS_DEFAULTED(QSharedDataPointerBase)
0064
0065 public:
0066
0067
0068
0069 using Type = T;
0070 using pointer = T *;
0071
0072 void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
0073 T &operator*() { detachIfImplicit(); return *(d.get()); }
0074 constT &operator*() const { return *(d.get()); }
0075 T *operator->() { detachIfImplicit(); return d.get(); }
0076 constT *operator->() const noexcept { return d.get(); }
0077 operator T *() { detachIfImplicit(); return d.get(); }
0078 operator const T *() const noexcept { return d.get(); }
0079 T *data() { detachIfImplicit(); return d.get(); }
0080 T *get() { detachIfImplicit(); return d.get(); }
0081 const T *data() const noexcept { return d.get(); }
0082 const T *get() const noexcept { return d.get(); }
0083 const T *constData() const noexcept { return d.get(); }
0084 T *take() noexcept { return std::exchange(d, nullptr).get(); }
0085
0086 void reset(T *ptr = nullptr) noexcept
0087 {
0088 if (ptr != d.get()) {
0089 if (ptr)
0090 ptr->ref.ref();
0091 T *old = std::exchange(d, Qt::totally_ordered_wrapper(ptr)).get();
0092 if (old && !old->ref.deref())
0093 destroy(old);
0094 }
0095 }
0096
0097 operator bool () const noexcept { return d != nullptr; }
0098 bool operator!() const noexcept { return d == nullptr; }
0099
0100 void swap(Self &other) noexcept
0101 { qt_ptr_swap(d, other.d); }
0102
0103 private:
0104
0105
0106 T *clone() { return static_cast<Self *>(this)->clone(); }
0107 template <typename... Args> static T *create(Args &&... args)
0108 { return Self::create(std::forward(args)...); }
0109 static void destroy(T *ptr) { Self::destroy(ptr); }
0110
0111 void detachIfImplicit()
0112 {
0113 if constexpr (Traits::ImplicitlyDetaches)
0114 static_cast<Self *>(this)->detach();
0115 }
0116
0117 friend bool comparesEqual(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept
0118 { return lhs.d == rhs.d; }
0119 friend Qt::strong_ordering
0120 compareThreeWay(const QSharedDataPointerBase &lhs, const QSharedDataPointerBase &rhs) noexcept
0121 { return Qt::compareThreeWay(lhs.d, rhs.d); }
0122
0123 friend bool comparesEqual(const QSharedDataPointerBase &lhs, const T *rhs) noexcept
0124 { return lhs.d == rhs; }
0125 friend Qt::strong_ordering
0126 compareThreeWay(const QSharedDataPointerBase &lhs, const T *rhs) noexcept
0127 { return Qt::compareThreeWay(lhs.d, rhs); }
0128
0129 friend bool comparesEqual(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept
0130 { return lhs.d == nullptr; }
0131 friend Qt::strong_ordering
0132 compareThreeWay(const QSharedDataPointerBase &lhs, std::nullptr_t) noexcept
0133 { return Qt::compareThreeWay(lhs.d, nullptr); }
0134
0135 friend size_t qHash(const QSharedDataPointerBase &ptr, size_t seed = 0) noexcept
0136 { return qHash(ptr.data(), seed); }
0137
0138 protected:
0139 void detach_helper();
0140
0141 Qt::totally_ordered_wrapper<T *> d;
0142 #endif
0143 };
0144
0145 template <typename T>
0146 class QSharedDataPointer : public QSharedDataPointerBase<QSharedDataPointer, T>
0147 {
0148 using Base = QSharedDataPointerBase<QSharedDataPointer, T>;
0149 friend Base;
0150 public:
0151 typedef T Type;
0152 typedef T *pointer;
0153
0154 void detach() { Base::detach(); }
0155 #ifdef Q_QDOC
0156 T &operator*();
0157 const T &operator*() const;
0158 T *operator->();
0159 const T *operator->() const noexcept;
0160 operator T *();
0161 operator const T *() const noexcept;
0162 T *data();
0163 T *get();
0164 const T *data() const noexcept;
0165 const T *get() const noexcept;
0166 const T *constData() const noexcept;
0167 T *take() noexcept;
0168 #endif
0169
0170 Q_NODISCARD_CTOR
0171 QSharedDataPointer() noexcept : Base(nullptr) { }
0172 ~QSharedDataPointer() { if (d && !d->ref.deref()) destroy(d.get()); }
0173
0174 Q_NODISCARD_CTOR
0175 explicit QSharedDataPointer(T *data) noexcept : Base(data)
0176 { if (d) d->ref.ref(); }
0177 Q_NODISCARD_CTOR
0178 QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : Base(data)
0179 {}
0180 Q_NODISCARD_CTOR
0181 QSharedDataPointer(const QSharedDataPointer &o) noexcept : Base(o.d.get())
0182 { if (d) d->ref.ref(); }
0183
0184 QSharedDataPointer &operator=(const QSharedDataPointer &o) noexcept
0185 {
0186 reset(o.d.get());
0187 return *this;
0188 }
0189 inline QSharedDataPointer &operator=(T *o) noexcept
0190 {
0191 reset(o);
0192 return *this;
0193 }
0194 Q_NODISCARD_CTOR
0195 QSharedDataPointer(QSharedDataPointer &&o) noexcept
0196 : Base(std::exchange(o.d, nullptr).get())
0197 {}
0198 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer)
0199
0200 #ifdef Q_QDOC
0201 void reset(T *ptr = nullptr) noexcept;
0202
0203 operator bool () const noexcept;
0204 bool operator!() const noexcept;
0205
0206 void swap(QSharedDataPointer &other) noexcept;
0207 #else
0208 using Base::reset;
0209 using Base::swap;
0210 #endif
0211
0212 protected:
0213 T *clone();
0214 template <typename... Args> static T *create(Args &&... args)
0215 { return new T(std::forward(args)...); }
0216 static void destroy(T *ptr) { delete ptr; }
0217
0218 private:
0219 Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer)
0220 Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer, T*)
0221 Q_DECLARE_STRONGLY_ORDERED(QSharedDataPointer, std::nullptr_t)
0222
0223 using Base::d;
0224 };
0225
0226 template <typename T>
0227 class QExplicitlySharedDataPointer : public QSharedDataPointerBase<QExplicitlySharedDataPointer, T>
0228 {
0229 using Base = QSharedDataPointerBase<QExplicitlySharedDataPointer, T>;
0230 friend Base;
0231 public:
0232 typedef T Type;
0233 typedef T *pointer;
0234
0235
0236
0237 explicit operator T *() { return d.get(); }
0238 explicit operator const T *() const noexcept { return d.get(); }
0239
0240
0241
0242 T *data() const noexcept { return d.get(); }
0243 T *get() const noexcept { return d.get(); }
0244
0245 #ifdef Q_QDOC
0246 T &operator*() const;
0247 T *operator->() noexcept;
0248 T *operator->() const noexcept;
0249 T *data() const noexcept;
0250 T *get() const noexcept;
0251 const T *constData() const noexcept;
0252 T *take() noexcept;
0253 #endif
0254
0255 void detach() { Base::detach(); }
0256
0257 Q_NODISCARD_CTOR
0258 QExplicitlySharedDataPointer() noexcept : Base(nullptr) { }
0259 ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d.get(); }
0260
0261 Q_NODISCARD_CTOR
0262 explicit QExplicitlySharedDataPointer(T *data) noexcept : Base(data)
0263 { if (d) d->ref.ref(); }
0264 Q_NODISCARD_CTOR
0265 QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : Base(data)
0266 {}
0267 Q_NODISCARD_CTOR
0268 QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : Base(o.d.get())
0269 { if (d) d->ref.ref(); }
0270
0271 template<typename X>
0272 Q_NODISCARD_CTOR
0273 QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o) noexcept
0274 #ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
0275 #error This macro has been removed in Qt 6.9.
0276 #endif
0277 : Base(o.data())
0278 { if (d) d->ref.ref(); }
0279
0280 QExplicitlySharedDataPointer &operator=(const QExplicitlySharedDataPointer &o) noexcept
0281 {
0282 reset(o.d.get());
0283 return *this;
0284 }
0285 QExplicitlySharedDataPointer &operator=(T *o) noexcept
0286 {
0287 reset(o);
0288 return *this;
0289 }
0290 Q_NODISCARD_CTOR
0291 QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept
0292 : Base(std::exchange(o.d, nullptr).get())
0293 {}
0294 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QExplicitlySharedDataPointer)
0295
0296 #ifdef Q_QDOC
0297 void reset(T *ptr = nullptr) noexcept;
0298
0299 operator bool () const noexcept;
0300 bool operator!() const noexcept;
0301
0302 void swap(QExplicitlySharedDataPointer &other) noexcept;
0303 #else
0304 using Base::swap;
0305 using Base::reset;
0306 #endif
0307
0308 protected:
0309 T *clone();
0310 template <typename... Args> static T *create(Args &&... args)
0311 { return new T(std::forward(args)...); }
0312 static void destroy(T *ptr) { delete ptr; }
0313
0314 private:
0315 Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer)
0316 Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer, const T*)
0317 Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer, std::nullptr_t)
0318
0319 using Base::d;
0320 };
0321
0322
0323 template <typename T>
0324 Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
0325 {
0326 return new T(*this->d);
0327 }
0328
0329 template <typename T>
0330 Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
0331 {
0332 return new T(*this->d.get());
0333 }
0334
0335 template <template <typename> class P, typename T> Q_OUTOFLINE_TEMPLATE void
0336 QSharedDataPointerBase<P, T>::detach_helper()
0337 {
0338 T *x = clone();
0339 x->ref.ref();
0340 if (!d->ref.deref())
0341 destroy(d.get());
0342 d.reset(x);
0343 }
0344
0345 template <typename T>
0346 void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2) noexcept
0347 { p1.swap(p2); }
0348
0349 template <typename T>
0350 void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2) noexcept
0351 { p1.swap(p2); }
0352
0353 template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE);
0354 template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_RELOCATABLE_TYPE);
0355
0356 #define QT_DECLARE_QSDP_SPECIALIZATION_DTOR(Class) \
0357 template<> QSharedDataPointer<Class>::~QSharedDataPointer();
0358
0359 #define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \
0360 template<> ExportMacro QSharedDataPointer<Class>::~QSharedDataPointer();
0361
0362 #define QT_DEFINE_QSDP_SPECIALIZATION_DTOR(Class) \
0363 template<> QSharedDataPointer<Class>::~QSharedDataPointer() \
0364 { \
0365 if (d && !d->ref.deref()) \
0366 delete d.get(); \
0367 }
0368
0369 #define QT_DECLARE_QESDP_SPECIALIZATION_DTOR(Class) \
0370 template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer();
0371
0372 #define QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \
0373 template<> ExportMacro QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer();
0374
0375 #define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class) \
0376 template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer() \
0377 { \
0378 if (d && !d->ref.deref()) \
0379 delete d.get(); \
0380 }
0381
0382 QT_END_NAMESPACE
0383
0384 #endif