Add a function to QQmlPropertyCache to calculate the meta-object sizes
This will be used later for calculating checksums of the meta-object data. Change-Id: Iba925eae298cbfc7b89196f4dd6fb2854ce75e2e Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
7ddb47f3ae
commit
897eb7f129
|
@ -1246,6 +1246,173 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename StringVisitor, typename TypeInfoVisitor>
|
||||
int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
|
||||
StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
|
||||
{
|
||||
const int intsPerMethod = 5;
|
||||
|
||||
int fieldsForParameterData = 0;
|
||||
|
||||
bool hasRevisionedMethods = false;
|
||||
|
||||
for (int i = 0; i < methodCount; ++i) {
|
||||
const int handle = methodOffset + i * intsPerMethod;
|
||||
|
||||
const uint flags = mo.d.data[handle + 4];
|
||||
if (flags & MethodRevisioned)
|
||||
hasRevisionedMethods = true;
|
||||
|
||||
visitString(mo.d.data[handle + 0]); // name
|
||||
visitString(mo.d.data[handle + 3]); // tag
|
||||
|
||||
const int argc = mo.d.data[handle + 1];
|
||||
const int paramIndex = mo.d.data[handle + 2];
|
||||
|
||||
fieldsForParameterData += argc * 2; // type and name
|
||||
fieldsForParameterData += 1; // + return type
|
||||
|
||||
// return type + args
|
||||
for (int i = 0; i < 1 + argc; ++i) {
|
||||
// type name (maybe)
|
||||
visitTypeInfo(mo.d.data[paramIndex + i]);
|
||||
|
||||
// parameter name
|
||||
if (i > 0)
|
||||
visitString(mo.d.data[paramIndex + argc + i]);
|
||||
}
|
||||
}
|
||||
|
||||
int fieldsForRevisions = 0;
|
||||
if (hasRevisionedMethods)
|
||||
fieldsForRevisions = methodCount;
|
||||
|
||||
return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData;
|
||||
}
|
||||
|
||||
template <typename StringVisitor, typename TypeInfoVisitor>
|
||||
int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
|
||||
{
|
||||
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
|
||||
const int intsPerProperty = 3;
|
||||
|
||||
bool hasRevisionedProperties = false;
|
||||
bool hasNotifySignals = false;
|
||||
|
||||
for (int i = 0; i < priv->propertyCount; ++i) {
|
||||
const int handle = priv->propertyData + i * intsPerProperty;
|
||||
|
||||
const auto flags = mo.d.data[handle + 2];
|
||||
if (flags & Revisioned) {
|
||||
hasRevisionedProperties = true;
|
||||
}
|
||||
if (flags & Notify)
|
||||
hasNotifySignals = true;
|
||||
|
||||
visitString(mo.d.data[handle]); // name
|
||||
visitTypeInfo(mo.d.data[handle + 1]);
|
||||
}
|
||||
|
||||
int fieldsForPropertyRevisions = 0;
|
||||
if (hasRevisionedProperties)
|
||||
fieldsForPropertyRevisions = priv->propertyCount;
|
||||
|
||||
int fieldsForNotifySignals = 0;
|
||||
if (hasNotifySignals)
|
||||
fieldsForNotifySignals = priv->propertyCount;
|
||||
|
||||
return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions
|
||||
+ fieldsForNotifySignals;
|
||||
}
|
||||
|
||||
template <typename StringVisitor>
|
||||
int visitClassInfo(const QMetaObject &mo, StringVisitor visitString)
|
||||
{
|
||||
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
|
||||
const int intsPerClassInfo = 2;
|
||||
|
||||
for (int i = 0; i < priv->classInfoCount; ++i) {
|
||||
const int handle = priv->classInfoData + i * intsPerClassInfo;
|
||||
|
||||
visitString(mo.d.data[handle]); // key
|
||||
visitString(mo.d.data[handle + 1]); // value
|
||||
}
|
||||
|
||||
return priv->classInfoCount * intsPerClassInfo;
|
||||
}
|
||||
|
||||
template <typename StringVisitor>
|
||||
int visitEnumerations(const QMetaObject &mo, StringVisitor visitString)
|
||||
{
|
||||
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
|
||||
const int intsPerEnumerator = 4;
|
||||
|
||||
int fieldCount = priv->enumeratorCount * intsPerEnumerator;
|
||||
|
||||
for (int i = 0; i < priv->enumeratorCount; ++i) {
|
||||
const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator;
|
||||
|
||||
const uint keyCount = enumeratorData[2];
|
||||
fieldCount += keyCount * 2;
|
||||
|
||||
visitString(enumeratorData[0]); // name
|
||||
|
||||
const uint keyOffset = enumeratorData[3];
|
||||
|
||||
for (uint j = 0; j < keyCount; ++j) {
|
||||
visitString(mo.d.data[keyOffset + 2 * j]);
|
||||
}
|
||||
}
|
||||
|
||||
return fieldCount;
|
||||
}
|
||||
|
||||
template <typename StringVisitor>
|
||||
int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor)
|
||||
{
|
||||
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
|
||||
|
||||
const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
|
||||
if (typeInfo & IsUnresolvedType)
|
||||
stringVisitor(typeInfo & TypeNameIndexMask);
|
||||
};
|
||||
|
||||
int fieldCount = MetaObjectPrivateFieldCount;
|
||||
|
||||
fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
|
||||
typeInfoVisitor);
|
||||
fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
|
||||
typeInfoVisitor);
|
||||
|
||||
fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
|
||||
fieldCount += visitClassInfo(mo, stringVisitor);
|
||||
fieldCount += visitEnumerations(mo, stringVisitor);
|
||||
|
||||
return fieldCount;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount,
|
||||
int *stringCount)
|
||||
{
|
||||
const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
|
||||
if (priv->revision != 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint highestStringIndex = 0;
|
||||
const auto stringIndexVisitor = [&highestStringIndex](uint index) {
|
||||
highestStringIndex = qMax(highestStringIndex, index);
|
||||
};
|
||||
|
||||
*fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
|
||||
*stringCount = highestStringIndex + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
|
||||
This is different from QMetaMethod::methodIndex().
|
||||
|
|
|
@ -366,6 +366,8 @@ public:
|
|||
|
||||
void toMetaObjectBuilder(QMetaObjectBuilder &);
|
||||
|
||||
static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
|
||||
|
||||
protected:
|
||||
virtual void destroy();
|
||||
virtual void clear();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <private/qqmlpropertycache_p.h>
|
||||
#include <QtQml/qqmlengine.h>
|
||||
#include <private/qv8engine_p.h>
|
||||
#include <private/qmetaobjectbuilder_p.h>
|
||||
#include "../../shared/util.h"
|
||||
|
||||
class tst_qqmlpropertycache : public QObject
|
||||
|
@ -45,6 +46,8 @@ private slots:
|
|||
void methodsDerived();
|
||||
void signalHandlers();
|
||||
void signalHandlersDerived();
|
||||
void metaObjectSize_data();
|
||||
void metaObjectSize();
|
||||
|
||||
private:
|
||||
QQmlEngine engine;
|
||||
|
@ -105,16 +108,16 @@ void tst_qqmlpropertycache::properties()
|
|||
QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
|
||||
QQmlPropertyData *data;
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyA"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyB"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyC"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyC")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyD"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyD")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD"));
|
||||
}
|
||||
|
||||
|
@ -129,16 +132,16 @@ void tst_qqmlpropertycache::propertiesDerived()
|
|||
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
|
||||
QQmlPropertyData *data;
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyA"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyB"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyC"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyC")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyD"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyD")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD"));
|
||||
}
|
||||
|
||||
|
@ -152,28 +155,28 @@ void tst_qqmlpropertycache::methods()
|
|||
QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
|
||||
QQmlPropertyData *data;
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "slotA"));
|
||||
QVERIFY((data = cacheProperty(cache, "slotA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "slotB"));
|
||||
QVERIFY((data = cacheProperty(cache, "slotB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "signalA"));
|
||||
QVERIFY((data = cacheProperty(cache, "signalA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "signalB"));
|
||||
QVERIFY((data = cacheProperty(cache, "signalB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyAChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyAChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyBChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyBChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyCChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyCChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyDChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyDChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
|
||||
}
|
||||
|
||||
|
@ -188,28 +191,28 @@ void tst_qqmlpropertycache::methodsDerived()
|
|||
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
|
||||
QQmlPropertyData *data;
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "slotA"));
|
||||
QVERIFY((data = cacheProperty(cache, "slotA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "slotB"));
|
||||
QVERIFY((data = cacheProperty(cache, "slotB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "signalA"));
|
||||
QVERIFY((data = cacheProperty(cache, "signalA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "signalB"));
|
||||
QVERIFY((data = cacheProperty(cache, "signalB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyAChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyAChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyBChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyBChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyCChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyCChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "propertyDChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "propertyDChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
|
||||
}
|
||||
|
||||
|
@ -223,22 +226,22 @@ void tst_qqmlpropertycache::signalHandlers()
|
|||
QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
|
||||
QQmlPropertyData *data;
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onSignalA"));
|
||||
QVERIFY((data = cacheProperty(cache, "onSignalA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onSignalB"));
|
||||
QVERIFY((data = cacheProperty(cache, "onSignalB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyAChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyAChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyBChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyBChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyCChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyCChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyDChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyDChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
|
||||
}
|
||||
|
||||
|
@ -253,25 +256,109 @@ void tst_qqmlpropertycache::signalHandlersDerived()
|
|||
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
|
||||
QQmlPropertyData *data;
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onSignalA"));
|
||||
QVERIFY((data = cacheProperty(cache, "onSignalA")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onSignalB"));
|
||||
QVERIFY((data = cacheProperty(cache, "onSignalB")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyAChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyAChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyBChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyBChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyCChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyCChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()"));
|
||||
|
||||
QVERIFY(data = cacheProperty(cache, "onPropertyDChanged"));
|
||||
QVERIFY((data = cacheProperty(cache, "onPropertyDChanged")));
|
||||
QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlpropertycache)
|
||||
class TestClass : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged)
|
||||
int m_prop;
|
||||
|
||||
public:
|
||||
enum MyEnum {
|
||||
First, Second
|
||||
};
|
||||
Q_ENUM(MyEnum)
|
||||
|
||||
Q_CLASSINFO("Foo", "Bar")
|
||||
|
||||
TestClass() {}
|
||||
|
||||
int prop() const
|
||||
{
|
||||
return m_prop;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void setProp(int prop)
|
||||
{
|
||||
if (m_prop == prop)
|
||||
return;
|
||||
|
||||
m_prop = prop;
|
||||
emit propChanged(prop);
|
||||
}
|
||||
signals:
|
||||
void propChanged(int prop);
|
||||
};
|
||||
|
||||
class TestClassWithParameters : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void slotWithArguments(int firstArg) {
|
||||
Q_UNUSED(firstArg);
|
||||
}
|
||||
};
|
||||
|
||||
class TestClassWithClassInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("Key", "Value")
|
||||
};
|
||||
|
||||
#include "tst_qqmlpropertycache.moc"
|
||||
|
||||
#define ARRAY_SIZE(arr) \
|
||||
int(sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
#define TEST_CLASS(Class) \
|
||||
QTest::newRow(#Class) << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) << ARRAY_SIZE(qt_meta_stringdata_##Class.data)
|
||||
|
||||
Q_DECLARE_METATYPE(const QMetaObject*);
|
||||
|
||||
void tst_qqmlpropertycache::metaObjectSize_data()
|
||||
{
|
||||
QTest::addColumn<const QMetaObject*>("metaObject");
|
||||
QTest::addColumn<int>("expectedFieldCount");
|
||||
QTest::addColumn<int>("expectedStringCount");
|
||||
|
||||
TEST_CLASS(TestClass);
|
||||
TEST_CLASS(TestClassWithParameters);
|
||||
TEST_CLASS(TestClassWithClassInfo);
|
||||
}
|
||||
|
||||
void tst_qqmlpropertycache::metaObjectSize()
|
||||
{
|
||||
QFETCH(const QMetaObject *, metaObject);
|
||||
QFETCH(int, expectedFieldCount);
|
||||
QFETCH(int, expectedStringCount);
|
||||
|
||||
int size = 0;
|
||||
int stringDataSize = 0;
|
||||
bool valid = QQmlPropertyCache::determineMetaObjectSizes(*metaObject, &size, &stringDataSize);
|
||||
QVERIFY(valid);
|
||||
|
||||
QCOMPARE(size, expectedFieldCount - 1); // Remove trailing zero field until fixed in moc.
|
||||
QCOMPARE(stringDataSize, expectedStringCount);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlpropertycache)
|
||||
|
|
Loading…
Reference in New Issue