// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef QDEFERREDPOINTER_P_H #define QDEFERREDPOINTER_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 QDeferredSharedPointer; template class QDeferredWeakPointer; template class QDeferredFactory { public: bool isValid() const; private: friend class QDeferredSharedPointer; friend class QDeferredWeakPointer; friend class QDeferredSharedPointer; friend class QDeferredWeakPointer; void populate(const QSharedPointer &) const; }; template class QDeferredSharedPointer { public: using Factory = QDeferredFactory>; QDeferredSharedPointer() = default; QDeferredSharedPointer(QSharedPointer data) : m_data(std::move(data)) {} QDeferredSharedPointer(QWeakPointer data) : m_data(std::move(data)) {} QDeferredSharedPointer(QSharedPointer data, QSharedPointer factory) : m_data(std::move(data)), m_factory(std::move(factory)) { // You have to provide a valid pointer if you provide a factory. We cannot allocate the // pointer for you because then two copies of the same QDeferredSharedPointer will diverge // and lazy-load two separate data objects. Q_ASSERT(!m_data.isNull() || m_factory.isNull()); } operator QSharedPointer() const { lazyLoad(); return m_data; } operator QDeferredSharedPointer() const { return { m_data, m_factory }; } T &operator*() const { return QSharedPointer(*this).operator*(); } T *operator->() const { return QSharedPointer(*this).operator->(); } bool isNull() const { return m_data.isNull(); } explicit operator bool() const noexcept { return !isNull(); } bool operator !() const noexcept { return isNull(); } T *data() const { return QSharedPointer(*this).data(); } T *get() const { return data(); } friend size_t qHash(const QDeferredSharedPointer &ptr, size_t seed = 0) { // This is a hash of the pointer, not the data. return qHash(ptr.m_data, seed); } friend bool operator==(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) { // This is a comparison of the pointers, not their data. As we require the pointers to // be given in the ctor, we can do this. return a.m_data == b.m_data; } friend bool operator!=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) { return !(a == b); } friend bool operator<(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) { return a.m_data < b.m_data; } friend bool operator<=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) { return a.m_data <= b.m_data; } friend bool operator>(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) { return a.m_data > b.m_data; } friend bool operator>=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) { return a.m_data >= b.m_data; } template friend bool operator==(const QDeferredSharedPointer &a, const QSharedPointer &b) { return a.m_data == b; } template friend bool operator!=(const QDeferredSharedPointer &a, const QSharedPointer &b) { return !(a == b); } template friend bool operator==(const QSharedPointer &a, const QDeferredSharedPointer &b) { return b == a; } template friend bool operator!=(const QSharedPointer &a, const QDeferredSharedPointer &b) { return b != a; } Factory *factory() const { return (m_factory && m_factory->isValid()) ? m_factory.data() : nullptr; } private: friend class QDeferredWeakPointer; void lazyLoad() const { if (Factory *f = factory()) { Factory localFactory; std::swap(localFactory, *f); // Swap before executing, to avoid recursion localFactory.populate(m_data.template constCast>()); } } QSharedPointer m_data; QSharedPointer m_factory; }; template class QDeferredWeakPointer { public: using Factory = QDeferredFactory>; QDeferredWeakPointer() = default; QDeferredWeakPointer(const QDeferredSharedPointer &strong) : m_data(strong.m_data), m_factory(strong.m_factory) { } QDeferredWeakPointer(QWeakPointer data, QWeakPointer factory) : m_data(data), m_factory(factory) {} operator QWeakPointer() const { lazyLoad(); return m_data; } operator QDeferredSharedPointer() const { return QDeferredSharedPointer(m_data.toStrongRef(), m_factory.toStrongRef()); } operator QDeferredWeakPointer() const { return {m_data, m_factory}; } QSharedPointer toStrongRef() const { return QWeakPointer(*this).toStrongRef(); } bool isNull() const { return m_data.isNull(); } explicit operator bool() const noexcept { return !isNull(); } bool operator !() const noexcept { return isNull(); } friend bool operator==(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b) { return a.m_data == b.m_data; } friend bool operator!=(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b) { return !(a == b); } private: void lazyLoad() const { if (m_factory) { auto factory = m_factory.toStrongRef(); if (factory->isValid()) { Factory localFactory; std::swap(localFactory, *factory); // Swap before executing, to avoid recursion localFactory.populate( m_data.toStrongRef().template constCast>()); } } } QWeakPointer m_data; QWeakPointer m_factory; }; QT_END_NAMESPACE #endif // QDEFERREDPOINTER_P_H