// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLREFCOUNT_P_H #define QQMLREFCOUNT_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include QT_BEGIN_NAMESPACE template class QQmlRefCounted; class QQmlRefCount { Q_DISABLE_COPY_MOVE(QQmlRefCount) public: inline QQmlRefCount(); inline void addref() const; inline int count() const; private: inline ~QQmlRefCount(); template friend class QQmlRefCounted; private: mutable QAtomicInt refCount; }; template class QQmlRefCounted : public QQmlRefCount { public: inline void release() const; protected: inline ~QQmlRefCounted(); }; template class QQmlRefPointer { public: enum Mode { AddRef, Adopt }; Q_NODISCARD_CTOR inline QQmlRefPointer() noexcept; Q_NODISCARD_CTOR inline QQmlRefPointer(T *, Mode m = AddRef); Q_NODISCARD_CTOR inline QQmlRefPointer(const QQmlRefPointer &); Q_NODISCARD_CTOR inline QQmlRefPointer(QQmlRefPointer &&) noexcept; inline ~QQmlRefPointer(); void swap(QQmlRefPointer &other) noexcept { qt_ptr_swap(o, other.o); } inline QQmlRefPointer &operator=(const QQmlRefPointer &o); inline QQmlRefPointer &operator=(QQmlRefPointer &&o) noexcept; inline bool isNull() const { return !o; } inline T* operator->() const { return o; } inline T& operator*() const { return *o; } explicit inline operator bool() const { return o != nullptr; } inline T* data() const { return o; } inline QQmlRefPointer &adopt(T *); inline T* take() { T *res = o; o = nullptr; return res; } friend bool operator==(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept { return a.o == b.o; } friend bool operator!=(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept { return !(a == b); } friend size_t qHash(const QQmlRefPointer &v, size_t seed = 0) noexcept { return qHash(v.o, seed); } void reset(T *t = nullptr) { if (t == o) return; if (o) o->release(); if (t) t->addref(); o = t; } private: T *o; }; namespace QQml { /*! \internal Creates a QQmlRefPointer which takes ownership of a newly constructed T. T must derive from QQmlRefCounted (as we rely on an initial refcount of _1_). T will be constructed by forwarding \a args to its constructor. */ template QQmlRefPointer makeRefPointer(Args&&... args) { static_assert(std::is_base_of_v); return QQmlRefPointer(new T(std::forward(args)...), QQmlRefPointer::Adopt); } } template Q_DECLARE_TYPEINFO_BODY(QQmlRefPointer, Q_RELOCATABLE_TYPE); QQmlRefCount::QQmlRefCount() : refCount(1) { } QQmlRefCount::~QQmlRefCount() { Q_ASSERT(refCount.loadRelaxed() == 0); } void QQmlRefCount::addref() const { Q_ASSERT(refCount.loadRelaxed() > 0); refCount.ref(); } template void QQmlRefCounted::release() const { static_assert(std::is_base_of_v, "QQmlRefCounted must be a base of T (CRTP)"); Q_ASSERT(refCount.loadRelaxed() > 0); if (!refCount.deref()) delete static_cast(this); } template QQmlRefCounted::~QQmlRefCounted() { static_assert(std::is_final_v || std::has_virtual_destructor_v, "T must either be marked final or have a virtual dtor, " "lest release() runs into UB."); } int QQmlRefCount::count() const { return refCount.loadRelaxed(); } template QQmlRefPointer::QQmlRefPointer() noexcept : o(nullptr) { } template QQmlRefPointer::QQmlRefPointer(T *o, Mode m) : o(o) { if (m == AddRef && o) o->addref(); } template QQmlRefPointer::QQmlRefPointer(const QQmlRefPointer &other) : o(other.o) { if (o) o->addref(); } template QQmlRefPointer::QQmlRefPointer(QQmlRefPointer &&other) noexcept : o(other.take()) { } template QQmlRefPointer::~QQmlRefPointer() { if (o) o->release(); } template QQmlRefPointer &QQmlRefPointer::operator=(const QQmlRefPointer &other) { if (o == other.o) return *this; if (other.o) other.o->addref(); if (o) o->release(); o = other.o; return *this; } template QQmlRefPointer &QQmlRefPointer::operator=(QQmlRefPointer &&other) noexcept { QQmlRefPointer m(std::move(other)); swap(m); return *this; } /*! Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership of the callers reference of other. */ template QQmlRefPointer &QQmlRefPointer::adopt(T *other) { if (o) o->release(); o = other; return *this; } QT_END_NAMESPACE #endif // QQMLREFCOUNT_P_H