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 <qtqmlcompilerexports.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
158 void resetFactory(const Factory& newFactory)
159 {
160 m_data.reset();
161 *m_factory = newFactory;
162 }
163
164private:
165 friend class QDeferredWeakPointer<T>;
166
167 void lazyLoad() const
168 {
169 if (Factory *f = factory()) {
170 Factory localFactory;
171 std::swap(localFactory, *f); // Swap before executing, to avoid recursion
172 localFactory.populate(m_data.template constCast<std::remove_const_t<T>>());
173 }
174 }
175
176 QSharedPointer<T> m_data;
177 QSharedPointer<Factory> m_factory;
178};
179
180template<typename T>
181class QDeferredWeakPointer
182{
183public:
184 using Factory = QDeferredFactory<std::remove_const_t<T>>;
185
186 Q_NODISCARD_CTOR QDeferredWeakPointer() = default;
187
188 Q_NODISCARD_CTOR QDeferredWeakPointer(const QDeferredSharedPointer<T> &strong)
189 : m_data(strong.m_data), m_factory(strong.m_factory)
190 {
191 }
192
193 Q_NODISCARD_CTOR QDeferredWeakPointer(QWeakPointer<T> data, QWeakPointer<Factory> factory)
194 : m_data(data), m_factory(factory)
195 {}
196
197 [[nodiscard]] operator QWeakPointer<T>() const
198 {
199 lazyLoad();
200 return m_data;
201 }
202
203 [[nodiscard]] operator QDeferredSharedPointer<T>() const
204 {
205 return QDeferredSharedPointer<T>(m_data.toStrongRef(), m_factory.toStrongRef());
206 }
207
208 operator QDeferredWeakPointer<const T>() const { return {m_data, m_factory}; }
209
210 [[nodiscard]] QSharedPointer<T> toStrongRef() const
211 {
212 return QWeakPointer<T>(*this).toStrongRef();
213 }
214
215 bool isNull() const { return m_data.isNull(); }
216
217 explicit operator bool() const noexcept { return !isNull(); }
218 bool operator !() const noexcept { return isNull(); }
219
220 friend bool operator==(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b)
221 {
222 return a.m_data == b.m_data;
223 }
224
225 friend bool operator!=(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b)
226 {
227 return !(a == b);
228 }
229
230private:
231 void lazyLoad() const
232 {
233 if (m_factory) {
234 auto factory = m_factory.toStrongRef();
235 if (factory->isValid()) {
236 Factory localFactory;
237 std::swap(localFactory, *factory); // Swap before executing, to avoid recursion
238 localFactory.populate(
239 m_data.toStrongRef().template constCast<std::remove_const_t<T>>());
240 }
241 }
242 }
243
244 QWeakPointer<T> m_data;
245 QWeakPointer<Factory> m_factory;
246};
247
248
249QT_END_NAMESPACE
250
251#endif // QDEFERREDPOINTER_P_H
252

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