Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlpropertycache_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLPROPERTYCACHE_P_H
5#define QQMLPROPERTYCACHE_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
18#include <private/qlinkedstringhash_p.h>
19#include <private/qqmlenumdata_p.h>
20#include <private/qqmlenumvalue_p.h>
21#include <private/qqmlpropertydata_p.h>
22#include <private/qqmlrefcount_p.h>
23
24#include <QtCore/qvarlengtharray.h>
25#include <QtCore/qvector.h>
26#include <QtCore/qversionnumber.h>
27
28#include <limits>
29
30QT_BEGIN_NAMESPACE
31
32class QCryptographicHash;
33class QJSEngine;
34class QMetaObjectBuilder;
35class QQmlContextData;
36class QQmlPropertyCache;
38class QQmlVMEMetaObject;
39
41{
42public:
44
50
52 {
53 const auto dd = d.loadAcquire();
54 if (dd & Shared)
55 reinterpret_cast<SharedHolder *>(dd ^ Shared)->release();
56 }
57
58private:
59 friend class QQmlPropertyCache;
61 : d(other.d.loadRelaxed())
62 {
63 // other has to survive until this ctor is done. So d cannot disappear before.
64 const auto od = other.d.loadRelaxed();
65 if (od & Shared)
66 reinterpret_cast<SharedHolder *>(od ^ Shared)->addref();
67 }
68
69 QQmlMetaObjectPointer(QQmlMetaObjectPointer &&other) = delete;
70 QQmlMetaObjectPointer &operator=(QQmlMetaObjectPointer &&other) = delete;
71 QQmlMetaObjectPointer &operator=(const QQmlMetaObjectPointer &other) = delete;
72
73public:
74 void setSharedOnce(QMetaObject *shared) const
75 {
76 SharedHolder *holder = new SharedHolder(shared);
77 if (!d.testAndSetRelease(0, quintptr(holder) | Shared))
78 holder->release();
79 }
80
81 const QMetaObject *metaObject() const
82 {
83 const auto dd = d.loadAcquire();
84 if (dd & Shared)
85 return reinterpret_cast<SharedHolder *>(dd ^ Shared)->metaObject;
86 return reinterpret_cast<const QMetaObject *>(dd);
87 }
88
89 bool isShared() const
90 {
91 // This works because static metaobjects need to be set in the ctor and once a shared
92 // metaobject has been set, it cannot be removed anymore.
93 const auto dd = d.loadRelaxed();
94 return !dd || (dd & Shared);
95 }
96
97 bool isNull() const
98 {
99 return d.loadRelaxed() == 0;
100 }
101
102private:
103 enum Tag {
104 Static = 0,
105 Shared = 1
106 };
107
108 struct SharedHolder final : public QQmlRefCounted<SharedHolder>
109 {
110 Q_DISABLE_COPY_MOVE(SharedHolder)
111 SharedHolder(QMetaObject *shared) : metaObject(shared) {}
112 ~SharedHolder() { free(metaObject); }
113 QMetaObject *metaObject;
114 };
115
116 mutable QBasicAtomicInteger<quintptr> d = 0;
117};
118
119class Q_QML_EXPORT QQmlPropertyCache final
120 : public QQmlRefCounted<QQmlPropertyCache>
121{
122public:
123 using Ptr = QQmlRefPointer<QQmlPropertyCache>;
124
125 struct ConstPtr : public QQmlRefPointer<const QQmlPropertyCache>
126 {
127 using QQmlRefPointer<const QQmlPropertyCache>::QQmlRefPointer;
128
129 ConstPtr(const Ptr &ptr) : ConstPtr(ptr.data(), AddRef) {}
130 ConstPtr(Ptr &&ptr) : ConstPtr(ptr.take(), Adopt) {}
131 ConstPtr &operator=(const Ptr &ptr) { return operator=(ConstPtr(ptr)); }
132 ConstPtr &operator=(Ptr &&ptr) { return operator=(ConstPtr(std::move(ptr))); }
133 };
134
135 static Ptr createStandalone(
136 const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
137
138 QQmlPropertyCache() = default;
139 ~QQmlPropertyCache();
140
141 void update(const QMetaObject *);
142 void invalidate(const QMetaObject *);
143
144 QQmlPropertyCache::Ptr copy() const;
145
146 QQmlPropertyCache::Ptr copyAndAppend(
147 const QMetaObject *, QTypeRevision typeVersion,
148 QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
149 QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
150 QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()) const;
151
152 QQmlPropertyCache::Ptr copyAndReserve(
153 int propertyCount, int methodCount, int signalCount, int enumCount) const;
154
155 enum OverrideResult { NoOverride, InvalidOverride, ValidOverride };
156 OverrideResult appendAlias(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
157 QMetaType propType, QTypeRevision version, int notifyIndex,
158 int encodedTargetIndex);
159 void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex,
160 const QMetaType *types = nullptr,
161 const QList<QByteArray> &names = QList<QByteArray>());
162 void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
163 QMetaType returnType, const QList<QByteArray> &names,
164 const QVector<QMetaType> &parameterTypes);
165 void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
166
167 const QMetaObject *metaObject() const;
168 const QMetaObject *createMetaObject() const;
169 const QMetaObject *firstCppMetaObject() const;
170
171 template<typename K>
172 const QQmlPropertyData *property(const K &key, QObject *object,
173 const QQmlRefPointer<QQmlContextData> &context) const
174 {
175 return findProperty(stringCache.find(key), object, context);
176 }
177
178 const QQmlPropertyData *property(int) const;
179 const QQmlPropertyData *maybeUnresolvedProperty(int) const;
180 const QQmlPropertyData *method(int) const;
181 const QQmlPropertyData *signal(int index) const;
182 QQmlEnumData *qmlEnum(int) const;
183 int methodIndexToSignalIndex(int) const;
184
185 QString defaultPropertyName() const;
186 const QQmlPropertyData *defaultProperty() const;
187
188 // Return a reference here so that we don't have to addref/release all the time
189 inline const QQmlPropertyCache::ConstPtr &parent() const;
190
191 // is used by the Qml Designer
192 void setParent(QQmlPropertyCache::ConstPtr newParent);
193
194 inline const QQmlPropertyData *overrideData(const QQmlPropertyData *) const;
195 inline bool isAllowedInRevision(const QQmlPropertyData *) const;
196
197 static const QQmlPropertyData *property(
198 QObject *, QStringView, const QQmlRefPointer<QQmlContextData> &,
199 QQmlPropertyData *);
200 static const QQmlPropertyData *property(QObject *, const QLatin1String &, const QQmlRefPointer<QQmlContextData> &,
201 QQmlPropertyData *);
202 static const QQmlPropertyData *property(QObject *, const QV4::String *, const QQmlRefPointer<QQmlContextData> &,
203 QQmlPropertyData *);
204
205 //see QMetaObjectPrivate::originalClone
206 int originalClone(int index) const;
207 static int originalClone(const QObject *, int index);
208
209 QList<QByteArray> signalParameterNames(int index) const;
210 static QString signalParameterStringForJS(
211 const QList<QByteArray> &parameterNameList, QString *errorString = nullptr);
212
213 const char *className() const;
214
215 inline int propertyCount() const;
216 inline int ownPropertyCount() const { return int(propertyIndexCache.count()); }
217 inline int propertyOffset() const;
218 inline int methodCount() const;
219 inline int ownMethodCount() const { return int(methodIndexCache.count()); }
220 inline int methodOffset() const;
221 inline int signalCount() const;
222 inline int ownSignalCount() const { return int(signalHandlerIndexCache.count()); }
223 inline int signalOffset() const;
224 inline int qmlEnumCount() const;
225
226 void toMetaObjectBuilder(QMetaObjectBuilder &) const;
227
228 inline bool callJSFactoryMethod(QObject *object, void **args) const;
229
230 static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
231 static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
232
233 QByteArray checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const;
234
235 QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; }
236 void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; }
237
238private:
239 friend class QQmlEnginePrivate;
240 friend class QQmlCompiler;
241 template <typename T> friend class QQmlPropertyCacheCreator;
242 template <typename T> friend class QQmlPropertyCacheAliasCreator;
243 template <typename T> friend class QQmlComponentAndAliasResolver;
244 friend class QQmlMetaObject;
245
246 QQmlPropertyCache(const QQmlMetaObjectPointer &metaObject) : _metaObject(metaObject) {}
247
248 inline QQmlPropertyCache::Ptr copy(const QQmlMetaObjectPointer &mo, int reserve) const;
249
250 void append(const QMetaObject *, QTypeRevision typeVersion,
251 QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
252 QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
253 QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
254
255 QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names);
256
257 typedef QVector<QQmlPropertyData> IndexCache;
258 typedef QLinkedStringMultiHash<std::pair<int, QQmlPropertyData *> > StringCache;
259 typedef QVector<QTypeRevision> AllowedRevisionCache;
260
261 const QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *,
262 const QQmlRefPointer<QQmlContextData> &) const;
263 const QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
264 const QQmlRefPointer<QQmlContextData> &) const;
265
266 template<typename K>
267 QQmlPropertyData *findNamedProperty(const K &key) const
268 {
269 StringCache::mapped_type *it = stringCache.value(key);
270 return it ? it->second : 0;
271 }
272
273 template<typename K>
274 void setNamedProperty(const K &key, int index, QQmlPropertyData *data)
275 {
276 stringCache.insert(key, std::make_pair(index, data));
277 }
278
279private:
280 template<typename String>
281 OverrideResult handleOverride(const String &name, QQmlPropertyData *data, QQmlPropertyData *old)
282 {
283 if (!old)
284 return NoOverride;
285
286 if (old->isFinal()) {
287 // TODO improve warning message
288 qWarning("Final member %s is overridden in class %s. The override won't be used.",
289 qPrintable(name), className());
290 return InvalidOverride;
291 }
292
293 data->markAsOverrideOf(old);
294 return ValidOverride;
295 }
296
297 // TODO consider making public
298 OverrideResult doAppendPropertyData(const QString &name, QQmlPropertyData &&data)
299 {
300 QQmlPropertyData *old = findNamedProperty(name);
301 const OverrideResult overrideResult = handleOverride(name, &data, old);
302 if (overrideResult == InvalidOverride) {
303 // Insert the overridden member once more, to keep the counts in sync
304 propertyIndexCache.append(*old);
305 return overrideResult;
306 }
307
308 const int index = propertyIndexCache.size();
309 propertyIndexCache.append(std::move(data));
310
311 setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index);
312 return overrideResult;
313 }
314
315 int propertyIndexCacheStart = 0; // placed here to avoid gap between QQmlRefCount and _parent
316 QQmlPropertyCache::ConstPtr _parent;
317
318 IndexCache propertyIndexCache;
319 IndexCache methodIndexCache;
320 IndexCache signalHandlerIndexCache;
321 StringCache stringCache;
322 AllowedRevisionCache allowedRevisionCache;
323 QVector<QQmlEnumData> enumCache;
324
325 QQmlMetaObjectPointer _metaObject;
326 QByteArray _dynamicClassName;
327 QByteArray _dynamicStringData;
328 QByteArray _listPropertyAssignBehavior;
329 QString _defaultPropertyName;
330 QQmlPropertyCacheMethodArguments *argumentsCache = nullptr;
331 int methodIndexCacheStart = 0;
332 int signalHandlerIndexCacheStart = 0;
333 int _jsFactoryMethodIndex = -1;
334};
335
336// Returns this property cache's metaObject. May be null if it hasn't been created yet.
337inline const QMetaObject *QQmlPropertyCache::metaObject() const
338{
339 return _metaObject.metaObject();
340}
341
342// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
343// QML
344inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
345{
346 const QQmlPropertyCache *p = this;
347 while (p->_metaObject.isShared())
348 p = p->parent().data();
349 return p->_metaObject.metaObject();
350}
351
352inline const QQmlPropertyData *QQmlPropertyCache::property(int index) const
353{
354 if (index < 0 || index >= propertyCount())
355 return nullptr;
356
357 if (index < propertyIndexCacheStart)
358 return _parent->property(index);
359
360 return &propertyIndexCache.at(index - propertyIndexCacheStart);
361}
362
363inline const QQmlPropertyData *QQmlPropertyCache::method(int index) const
364{
365 if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
366 return nullptr;
367
368 if (index < methodIndexCacheStart)
369 return _parent->method(index);
370
371 return const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
372}
373
374/*! \internal
375 \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
376 This is different from QMetaMethod::methodIndex().
377*/
378inline const QQmlPropertyData *QQmlPropertyCache::signal(int index) const
379{
380 if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.size()))
381 return nullptr;
382
383 if (index < signalHandlerIndexCacheStart)
384 return _parent->signal(index);
385
386 const QQmlPropertyData *rv = const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
387 Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1);
388 return rv;
389}
390
391inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
392{
393 if (index < 0 || index >= enumCache.size())
394 return nullptr;
395
396 return const_cast<QQmlEnumData *>(&enumCache.at(index));
397}
398
399inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
400{
401 if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
402 return index;
403
404 if (index < methodIndexCacheStart)
405 return _parent->methodIndexToSignalIndex(index);
406
407 return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
408}
409
410// Returns the name of the default property for this cache
411inline QString QQmlPropertyCache::defaultPropertyName() const
412{
413 return _defaultPropertyName;
414}
415
416inline const QQmlPropertyCache::ConstPtr &QQmlPropertyCache::parent() const
417{
418 return _parent;
419}
420
421const QQmlPropertyData *
422QQmlPropertyCache::overrideData(const QQmlPropertyData *data) const
423{
424 if (!data->hasOverride())
425 return nullptr;
426
427 if (data->overrideIndexIsProperty())
428 return property(data->overrideIndex());
429 else
430 return method(data->overrideIndex());
431}
432
433bool QQmlPropertyCache::isAllowedInRevision(const QQmlPropertyData *data) const
434{
435 const QTypeRevision requested = data->revision();
436 const int offset = data->metaObjectOffset();
437 if (offset == -1 && requested == QTypeRevision::zero())
438 return true;
439
440 Q_ASSERT(offset >= 0);
441 Q_ASSERT(offset < allowedRevisionCache.size());
442 const QTypeRevision allowed = allowedRevisionCache[offset];
443
444 if (requested.hasMajorVersion()) {
445 if (requested.majorVersion() > allowed.majorVersion())
446 return false;
447 if (requested.majorVersion() < allowed.majorVersion())
448 return true;
449 }
450
451 return !requested.hasMinorVersion() || requested.minorVersion() <= allowed.minorVersion();
452}
453
454int QQmlPropertyCache::propertyCount() const
455{
456 return propertyIndexCacheStart + int(propertyIndexCache.size());
457}
458
459int QQmlPropertyCache::propertyOffset() const
460{
461 return propertyIndexCacheStart;
462}
463
464int QQmlPropertyCache::methodCount() const
465{
466 return methodIndexCacheStart + int(methodIndexCache.size());
467}
468
469int QQmlPropertyCache::methodOffset() const
470{
471 return methodIndexCacheStart;
472}
473
474int QQmlPropertyCache::signalCount() const
475{
476 return signalHandlerIndexCacheStart + int(signalHandlerIndexCache.size());
477}
478
479int QQmlPropertyCache::signalOffset() const
480{
481 return signalHandlerIndexCacheStart;
482}
483
484int QQmlPropertyCache::qmlEnumCount() const
485{
486 return int(enumCache.size());
487}
488
489bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const
490{
491 if (_jsFactoryMethodIndex != -1) {
492 if (const QMetaObject *mo = _metaObject.metaObject()) {
493 mo->d.static_metacall(object, QMetaObject::InvokeMetaMethod,
494 _jsFactoryMethodIndex, args);
495 return true;
496 }
497 return false;
498 }
499 if (_parent)
500 return _parent->callJSFactoryMethod(object, args);
501 return false;
502}
503
504QT_END_NAMESPACE
505
506#endif // QQMLPROPERTYCACHE_P_H
friend class QJSEngine
const QMetaObject * metaObject() const
void setSharedOnce(QMetaObject *shared) const
const QQmlPropertyData * qQmlPropertyCacheProperty(QObject *obj, T name, const QQmlRefPointer< QQmlContextData > &context, QQmlPropertyData *local)
static const QByteArray stringData(const QMetaObject *mo, int index)
static QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const T &propertyName)
#define Q_INT16_MAX
static const char * qQmlPropertyCacheToString(QLatin1String string)
static QByteArray qQmlPropertyCacheToString(const QV4::String *string)
static std::pair< bool, int > deriveEncodingAndLength(const char *str)
static QHashedString signalNameToHandlerName(const QHashedString &methodName)
static int metaObjectSignalCount(const QMetaObject *metaObject)