Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-05 09:27:37

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 // Qt-Security score:significant reason:default
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     // for const-qualified functions:
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     // for const-qualified functions:
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     // using the assignment operator would lead to corruption in the ref-counting
0047     QSharedData &operator=(const QSharedData &) = delete;
0048     ~QSharedData() = default;
0049 };
0050 
0051 struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; };
0052 
0053 // CRTP common base class for both QSharedDataPointer and QExplicitlySharedDataPointer
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     // When adding anything public to this class, make sure to add the doc version to
0067     // both QSharedDataPointer and QExplicitlySharedDataPointer.
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     // The concrete class MUST override these, otherwise we will be calling
0105     // ourselves.
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 // !Q_QDOC
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     // override to make explicit. Can use explicit(!ImplicitlyShared) once we
0236     // can depend on C++20.
0237     explicit operator T *() { return d.get(); }
0238     explicit operator const T *() const noexcept { return d.get(); }
0239 
0240     // override to make const. There is no const(cond), but we could use
0241     // requires(!ImplicitlyShared)
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 // Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time.
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 // QSHAREDDATA_H