1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QDEFERREDPOINTER_P_H
5#define QDEFERREDPOINTER_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16
17#include <private/qtqmlcompilerexports_p.h>
18
19#include <QtCore/private/qglobal_p.h>
20#include <QtCore/qsharedpointer.h>
21
22QT_BEGIN_NAMESPACE
23
24template<typename T>
25class QDeferredSharedPointer;
26
27template<typename T>
28class QDeferredWeakPointer;
29
30template<typename T>
31class QDeferredFactory
32{
33public:
34 bool isValid() const;
35
36private:
37 friend class QDeferredSharedPointer<const T>;
38 friend class QDeferredWeakPointer<const T>;
39 friend class QDeferredSharedPointer<T>;
40 friend class QDeferredWeakPointer<T>;
41 void populate(const QSharedPointer<T> &) const;
42};
43
44template<typename T>
45class QDeferredSharedPointer
46{
47public:
48 using Factory = QDeferredFactory<std::remove_const_t<T>>;
49
50 Q_NODISCARD_CTOR QDeferredSharedPointer() = default;
51
52 Q_NODISCARD_CTOR QDeferredSharedPointer(QSharedPointer<T> data)
53 : m_data(std::move(data))
54 {}
55
56 Q_NODISCARD_CTOR QDeferredSharedPointer(QWeakPointer<T> data)
57 : m_data(std::move(data))
58 {}
59
60 Q_NODISCARD_CTOR QDeferredSharedPointer(QSharedPointer<T> data, QSharedPointer<Factory> factory)
61 : m_data(std::move(data)), m_factory(std::move(factory))
62 {
63 // You have to provide a valid pointer if you provide a factory. We cannot allocate the
64 // pointer for you because then two copies of the same QDeferredSharedPointer will diverge
65 // and lazy-load two separate data objects.
66 Q_ASSERT(!m_data.isNull() || m_factory.isNull());
67 }
68
69 [[nodiscard]] operator QSharedPointer<T>() const
70 {
71 lazyLoad();
72 return m_data;
73 }
74
75 operator QDeferredSharedPointer<const T>() const { return { m_data, m_factory }; }
76
77 [[nodiscard]] T &operator*() const { return QSharedPointer<T>(*this).operator*(); }
78 [[nodiscard]] T *operator->() const { return QSharedPointer<T>(*this).operator->(); }
79
80 bool isNull() const
81 {
82 return m_data.isNull();
83 }
84
85 explicit operator bool() const noexcept { return !isNull(); }
86 bool operator !() const noexcept { return isNull(); }
87
88 [[nodiscard]] T *data() const { return QSharedPointer<T>(*this).data(); }
89 [[nodiscard]] T *get() const { return data(); }
90
91 friend size_t qHash(const QDeferredSharedPointer &ptr, size_t seed = 0)
92 {
93 // This is a hash of the pointer, not the data.
94 return qHash(ptr.m_data, seed);
95 }
96
97 friend bool operator==(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
98 {
99 // This is a comparison of the pointers, not their data. As we require the pointers to
100 // be given in the ctor, we can do this.
101 return a.m_data == b.m_data;
102 }
103
104 friend bool operator!=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
105 {
106 return !(a == b);
107 }
108
109 friend bool operator<(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
110 {
111 return a.m_data < b.m_data;
112 }
113
114 friend bool operator<=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
115 {
116 return a.m_data <= b.m_data;
117 }
118
119 friend bool operator>(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
120 {
121 return a.m_data > b.m_data;
122 }
123
124 friend bool operator>=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
125 {
126 return a.m_data >= b.m_data;
127 }
128
129 template <typename U>
130 friend bool operator==(const QDeferredSharedPointer &a, const QSharedPointer<U> &b)
131 {
132 return a.m_data == b;
133 }
134
135 template <typename U>
136 friend bool operator!=(const QDeferredSharedPointer &a, const QSharedPointer<U> &b)
137 {
138 return !(a == b);
139 }
140
141 template <typename U>
142 friend bool operator==(const QSharedPointer<U> &a, const QDeferredSharedPointer &b)
143 {
144 return b == a;
145 }
146
147 template <typename U>
148 friend bool operator!=(const QSharedPointer<U> &a, const QDeferredSharedPointer &b)
149 {
150 return b != a;
151 }
152
153 Factory *factory() const
154 {
155 return (m_factory && m_factory->isValid()) ? m_factory.data() : nullptr;
156 }
157
158private:
159 friend class QDeferredWeakPointer<T>;
160
161 void lazyLoad() const
162 {
163 if (Factory *f = factory()) {
164 Factory localFactory;
165 std::swap(localFactory, *f); // Swap before executing, to avoid recursion
166 localFactory.populate(m_data.template constCast<std::remove_const_t<T>>());
167 }
168 }
169
170 QSharedPointer<T> m_data;
171 QSharedPointer<Factory> m_factory;
172};
173
174template<typename T>
175class QDeferredWeakPointer
176{
177public:
178 using Factory = QDeferredFactory<std::remove_const_t<T>>;
179
180 Q_NODISCARD_CTOR QDeferredWeakPointer() = default;
181
182 Q_NODISCARD_CTOR QDeferredWeakPointer(const QDeferredSharedPointer<T> &strong)
183 : m_data(strong.m_data), m_factory(strong.m_factory)
184 {
185 }
186
187 Q_NODISCARD_CTOR QDeferredWeakPointer(QWeakPointer<T> data, QWeakPointer<Factory> factory)
188 : m_data(data), m_factory(factory)
189 {}
190
191 [[nodiscard]] operator QWeakPointer<T>() const
192 {
193 lazyLoad();
194 return m_data;
195 }
196
197 [[nodiscard]] operator QDeferredSharedPointer<T>() const
198 {
199 return QDeferredSharedPointer<T>(m_data.toStrongRef(), m_factory.toStrongRef());
200 }
201
202 operator QDeferredWeakPointer<const T>() const { return {m_data, m_factory}; }
203
204 [[nodiscard]] QSharedPointer<T> toStrongRef() const
205 {
206 return QWeakPointer<T>(*this).toStrongRef();
207 }
208
209 bool isNull() const { return m_data.isNull(); }
210
211 explicit operator bool() const noexcept { return !isNull(); }
212 bool operator !() const noexcept { return isNull(); }
213
214 friend bool operator==(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b)
215 {
216 return a.m_data == b.m_data;
217 }
218
219 friend bool operator!=(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b)
220 {
221 return !(a == b);
222 }
223
224private:
225 void lazyLoad() const
226 {
227 if (m_factory) {
228 auto factory = m_factory.toStrongRef();
229 if (factory->isValid()) {
230 Factory localFactory;
231 std::swap(localFactory, *factory); // Swap before executing, to avoid recursion
232 localFactory.populate(
233 m_data.toStrongRef().template constCast<std::remove_const_t<T>>());
234 }
235 }
236 }
237
238 QWeakPointer<T> m_data;
239 QWeakPointer<Factory> m_factory;
240};
241
242
243QT_END_NAMESPACE
244
245#endif // QDEFERREDPOINTER_P_H
246

source code of qtdeclarative/src/qmlcompiler/qdeferredpointer_p.h