Change the representation of meta-object string data

Up to and including meta-object revision 6, string data have been
stored as 0-terminated C-style strings, that were made directly
accessible as const char pointers through the public API
(QMetaMethod and friends).

This commit changes moc to generate an array of QByteArrayData
instead, and adapts the QObject kernel accordingly.

Generating an array of QByteArrayData (byte array literals)
means that the strings can now be returned from public (or private)
API as QByteArrays, rather than const char *, with zero allocation or
copying. Also, the string length is now computed at compile time
(it's part of the QByteArrayData).

This commit only changes the internal representation, and does
not affect existing public API. The actual (C) string data that the
byte array literals reference still consists of zero-terminated
strings. The benefit of having the QByteArrayData array will only
become apparent in the upcoming meta-object data format change, which
changes the format of property and method descriptors.

Support for the old meta-object string data format was kept; the
codepaths for old revisions (6 and below) will be removed in a
separate commit, once all the other meta-object changes are done and
affected code has been adapted accordingly.

Task-number: QTBUG-24154
Change-Id: I4ec3b363bbc31b8192e5d8915ef091c442c2efad
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
Kent Hansen 2012-02-18 20:36:06 +01:00 committed by Qt by Nokia
parent 02c1863485
commit 3f7a222414
9 changed files with 274 additions and 121 deletions

View File

@ -146,6 +146,43 @@ QT_BEGIN_NAMESPACE
static inline const QMetaObjectPrivate *priv(const uint* data) static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
static inline const QByteArrayData &stringData(const QMetaObject *mo, int index)
{
Q_ASSERT(priv(mo->d.data)->revision >= 7);
const QByteArrayData &data = mo->d.stringdata[index];
Q_ASSERT(data.ref.isStatic());
Q_ASSERT(data.alloc == 0);
Q_ASSERT(data.capacityReserved == 0);
Q_ASSERT(data.size >= 0);
return data;
}
static inline const char *legacyString(const QMetaObject *mo, int index)
{
Q_ASSERT(priv(mo->d.data)->revision <= 6);
return reinterpret_cast<const char *>(mo->d.stringdata) + index;
}
static inline const char *rawStringData(const QMetaObject *mo, int index)
{
if (priv(mo->d.data)->revision >= 7)
return stringData(mo, index).data();
else
return legacyString(mo, index);
}
const char *QMetaObjectPrivate::rawStringData(const QMetaObject *mo, int index)
{
return QT_PREPEND_NAMESPACE(rawStringData)(mo, index);
}
static inline int stringSize(const QMetaObject *mo, int index)
{
if (priv(mo->d.data)->revision >= 7)
return stringData(mo, index).size;
else
return qstrlen(legacyString(mo, index));
}
/*! /*!
\since 4.5 \since 4.5
@ -249,12 +286,14 @@ int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
} }
/*! /*!
\fn const char *QMetaObject::className() const
Returns the class name. Returns the class name.
\sa superClass() \sa superClass()
*/ */
const char *QMetaObject::className() const
{
return rawStringData(this, 0);
}
/*! /*!
\fn QMetaObject *QMetaObject::superClass() const \fn QMetaObject *QMetaObject::superClass() const
@ -307,7 +346,7 @@ const QObject *QMetaObject::cast(const QObject *obj) const
*/ */
QString QMetaObject::tr(const char *s, const char *c, int n) const QString QMetaObject::tr(const char *s, const char *c, int n) const
{ {
return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr, n); return QCoreApplication::translate(rawStringData(this, 0), s, c, QCoreApplication::CodecForTr, n);
} }
/*! /*!
@ -315,7 +354,7 @@ QString QMetaObject::tr(const char *s, const char *c, int n) const
*/ */
QString QMetaObject::trUtf8(const char *s, const char *c, int n) const QString QMetaObject::trUtf8(const char *s, const char *c, int n) const
{ {
return QCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8, n); return QCoreApplication::translate(rawStringData(this, 0), s, c, QCoreApplication::UnicodeUTF8, n);
} }
#endif // QT_NO_TRANSLATION #endif // QT_NO_TRANSLATION
@ -513,7 +552,7 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
? (priv(m->d.data)->signalCount) : 0; ? (priv(m->d.data)->signalCount) : 0;
if (!normalizeStringData) { if (!normalizeStringData) {
for (; i >= end; --i) { for (; i >= end; --i) {
const char *stringdata = m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5*i]; const char *stringdata = rawStringData(m, m->d.data[priv(m->d.data)->methodData + 5*i]);
if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) { if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) {
*baseObject = m; *baseObject = m;
return i; return i;
@ -521,7 +560,7 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
} }
} else if (priv(m->d.data)->revision < 5) { } else if (priv(m->d.data)->revision < 5) {
for (; i >= end; --i) { for (; i >= end; --i) {
const char *stringdata = (m->d.stringdata + m->d.data[priv(m->d.data)->methodData + 5 * i]); const char *stringdata = legacyString(m, m->d.data[priv(m->d.data)->methodData + 5 * i]);
const QByteArray normalizedSignature = QMetaObject::normalizedSignature(stringdata); const QByteArray normalizedSignature = QMetaObject::normalizedSignature(stringdata);
if (normalizedSignature == method) { if (normalizedSignature == method) {
*baseObject = m; *baseObject = m;
@ -549,7 +588,7 @@ int QMetaObject::indexOfConstructor(const char *constructor) const
if (priv(d.data)->revision < 2) if (priv(d.data)->revision < 2)
return -1; return -1;
for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) { for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) {
const char *data = d.stringdata + d.data[priv(d.data)->constructorData + 5*i]; const char *data = rawStringData(this, d.data[priv(d.data)->constructorData + 5*i]);
if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) { if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) {
return i; return i;
} }
@ -618,7 +657,7 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
int conflict = m->d.superdata->indexOfMethod(signal); int conflict = m->d.superdata->indexOfMethod(signal);
if (conflict >= 0) if (conflict >= 0)
qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s", qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
signal, m->d.superdata->d.stringdata, m->d.stringdata); signal, rawStringData(m->d.superdata, 0), rawStringData(m, 0));
} }
#endif #endif
return i; return i;
@ -654,7 +693,7 @@ int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name) static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
{ {
while (self) { while (self) {
if (strcmp(self->d.stringdata, name) == 0) if (strcmp(rawStringData(self, 0), name) == 0)
return self; return self;
if (self->d.extradata) { if (self->d.extradata) {
const QMetaObject **e; const QMetaObject **e;
@ -690,7 +729,7 @@ int QMetaObject::indexOfEnumerator(const char *name) const
while (m) { while (m) {
const QMetaObjectPrivate *d = priv(m->d.data); const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = d->enumeratorCount - 1; i >= 0; --i) { for (int i = d->enumeratorCount - 1; i >= 0; --i) {
const char *prop = m->d.stringdata + m->d.data[d->enumeratorData + 4*i]; const char *prop = rawStringData(m, m->d.data[d->enumeratorData + 4*i]);
if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) { if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) {
i += m->enumeratorOffset(); i += m->enumeratorOffset();
return i; return i;
@ -713,7 +752,7 @@ int QMetaObject::indexOfProperty(const char *name) const
while (m) { while (m) {
const QMetaObjectPrivate *d = priv(m->d.data); const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = d->propertyCount-1; i >= 0; --i) { for (int i = d->propertyCount-1; i >= 0; --i) {
const char *prop = m->d.stringdata + m->d.data[d->propertyData + 3*i]; const char *prop = rawStringData(m, m->d.data[d->propertyData + 3*i]);
if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) { if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) {
i += m->propertyOffset(); i += m->propertyOffset();
return i; return i;
@ -744,8 +783,7 @@ int QMetaObject::indexOfClassInfo(const char *name) const
const QMetaObject *m = this; const QMetaObject *m = this;
while (m && i < 0) { while (m && i < 0) {
for (i = priv(m->d.data)->classInfoCount-1; i >= 0; --i) for (i = priv(m->d.data)->classInfoCount-1; i >= 0; --i)
if (strcmp(name, m->d.stringdata if (strcmp(name, rawStringData(m, m->d.data[priv(m->d.data)->classInfoData + 2*i])) == 0) {
+ m->d.data[priv(m->d.data)->classInfoData + 2*i]) == 0) {
i += m->classInfoOffset(); i += m->classInfoOffset();
break; break;
} }
@ -829,7 +867,7 @@ QMetaProperty QMetaObject::property(int index) const
if (i >= 0 && i < priv(d.data)->propertyCount) { if (i >= 0 && i < priv(d.data)->propertyCount) {
int handle = priv(d.data)->propertyData + 3*i; int handle = priv(d.data)->propertyData + 3*i;
int flags = d.data[handle + 2]; int flags = d.data[handle + 2];
const char *type = d.stringdata + d.data[handle + 1]; const char *type = rawStringData(this, d.data[handle + 1]);
result.mobj = this; result.mobj = this;
result.handle = handle; result.handle = handle;
result.idx = i; result.idx = i;
@ -838,7 +876,7 @@ QMetaProperty QMetaObject::property(int index) const
result.menum = enumerator(indexOfEnumerator(type)); result.menum = enumerator(indexOfEnumerator(type));
if (!result.menum.isValid()) { if (!result.menum.isValid()) {
const char *enum_name = type; const char *enum_name = type;
const char *scope_name = d.stringdata; const char *scope_name = rawStringData(this, 0);
char *scope_buffer = 0; char *scope_buffer = 0;
const char *colon = strrchr(enum_name, ':'); const char *colon = strrchr(enum_name, ':');
@ -1285,7 +1323,7 @@ const char *QMetaMethod::signature() const
{ {
if (!mobj) if (!mobj)
return 0; return 0;
return mobj->d.stringdata + mobj->d.data[handle]; return rawStringData(mobj, mobj->d.data[handle]);
} }
/*! /*!
@ -1298,7 +1336,7 @@ QList<QByteArray> QMetaMethod::parameterTypes() const
if (!mobj) if (!mobj)
return QList<QByteArray>(); return QList<QByteArray>();
return QMetaObjectPrivate::parameterTypeNamesFromSignature( return QMetaObjectPrivate::parameterTypeNamesFromSignature(
mobj->d.stringdata + mobj->d.data[handle]); rawStringData(mobj, mobj->d.data[handle]));
} }
/*! /*!
@ -1311,10 +1349,10 @@ QList<QByteArray> QMetaMethod::parameterNames() const
QList<QByteArray> list; QList<QByteArray> list;
if (!mobj) if (!mobj)
return list; return list;
const char *names = mobj->d.stringdata + mobj->d.data[handle + 1]; const char *names = rawStringData(mobj, mobj->d.data[handle + 1]);
if (*names == 0) { if (*names == 0) {
// do we have one or zero arguments? // do we have one or zero arguments?
const char *signature = mobj->d.stringdata + mobj->d.data[handle]; const char *signature = rawStringData(mobj, mobj->d.data[handle]);
while (*signature && *signature != '(') while (*signature && *signature != '(')
++signature; ++signature;
if (*++signature != ')') if (*++signature != ')')
@ -1340,7 +1378,7 @@ const char *QMetaMethod::typeName() const
{ {
if (!mobj) if (!mobj)
return 0; return 0;
return mobj->d.stringdata + mobj->d.data[handle + 2]; return rawStringData(mobj, mobj->d.data[handle + 2]);
} }
/*! /*!
@ -1377,7 +1415,7 @@ const char *QMetaMethod::tag() const
{ {
if (!mobj) if (!mobj)
return 0; return 0;
return mobj->d.stringdata + mobj->d.data[handle + 3]; return rawStringData(mobj, mobj->d.data[handle + 3]);
} }
@ -1580,10 +1618,10 @@ bool QMetaMethod::invoke(QObject *object,
int metaMethodArgumentCount = 0; int metaMethodArgumentCount = 0;
{ {
// based on QMetaObject::parameterNames() // based on QMetaObject::parameterNames()
const char *names = mobj->d.stringdata + mobj->d.data[handle + 1]; const char *names = rawStringData(mobj, mobj->d.data[handle + 1]);
if (*names == 0) { if (*names == 0) {
// do we have one or zero arguments? // do we have one or zero arguments?
const char *signature = mobj->d.stringdata + mobj->d.data[handle]; const char *signature = rawStringData(mobj, mobj->d.data[handle]);
while (*signature && *signature != '(') while (*signature && *signature != '(')
++signature; ++signature;
if (*++signature != ')') if (*++signature != ')')
@ -1803,7 +1841,7 @@ const char *QMetaEnum::name() const
{ {
if (!mobj) if (!mobj)
return 0; return 0;
return mobj->d.stringdata + mobj->d.data[handle]; return rawStringData(mobj, mobj->d.data[handle]);
} }
/*! /*!
@ -1831,7 +1869,7 @@ const char *QMetaEnum::key(int index) const
int count = mobj->d.data[handle + 2]; int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3]; int data = mobj->d.data[handle + 3];
if (index >= 0 && index < count) if (index >= 0 && index < count)
return mobj->d.stringdata + mobj->d.data[data + 2*index]; return rawStringData(mobj, mobj->d.data[data + 2*index]);
return 0; return 0;
} }
@ -1878,7 +1916,7 @@ bool QMetaEnum::isFlag() const
*/ */
const char *QMetaEnum::scope() const const char *QMetaEnum::scope() const
{ {
return mobj?mobj->d.stringdata : 0; return mobj?rawStringData(mobj, 0) : 0;
} }
/*! /*!
@ -1910,8 +1948,8 @@ int QMetaEnum::keyToValue(const char *key, bool *ok) const
int count = mobj->d.data[handle + 2]; int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3]; int data = mobj->d.data[handle + 3];
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
if ((!scope || (qstrlen(mobj->d.stringdata) == scope && strncmp(qualified_key, mobj->d.stringdata, scope) == 0)) if ((!scope || (stringSize(mobj, 0) == int(scope) && strncmp(qualified_key, rawStringData(mobj, 0), scope) == 0))
&& strcmp(key, mobj->d.stringdata + mobj->d.data[data + 2*i]) == 0) { && strcmp(key, rawStringData(mobj, mobj->d.data[data + 2*i])) == 0) {
if (ok != 0) if (ok != 0)
*ok = true; *ok = true;
return mobj->d.data[data + 2*i + 1]; return mobj->d.data[data + 2*i + 1];
@ -1936,7 +1974,7 @@ const char* QMetaEnum::valueToKey(int value) const
int data = mobj->d.data[handle + 3]; int data = mobj->d.data[handle + 3];
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
if (value == (int)mobj->d.data[data + 2*i + 1]) if (value == (int)mobj->d.data[data + 2*i + 1])
return mobj->d.stringdata + mobj->d.data[data + 2*i]; return rawStringData(mobj, mobj->d.data[data + 2*i]);
return 0; return 0;
} }
@ -1979,8 +2017,8 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
} }
int i; int i;
for (i = count-1; i >= 0; --i) for (i = count-1; i >= 0; --i)
if ((!scope || (qstrlen(mobj->d.stringdata) == scope && strncmp(qualified_key.constData(), mobj->d.stringdata, scope) == 0)) if ((!scope || (stringSize(mobj, 0) == int(scope) && strncmp(qualified_key.constData(), rawStringData(mobj, 0), scope) == 0))
&& strcmp(key, mobj->d.stringdata + mobj->d.data[data + 2*i]) == 0) { && strcmp(key, rawStringData(mobj, mobj->d.data[data + 2*i])) == 0) {
value |= mobj->d.data[data + 2*i + 1]; value |= mobj->d.data[data + 2*i + 1];
break; break;
} }
@ -2013,7 +2051,7 @@ QByteArray QMetaEnum::valueToKeys(int value) const
v = v & ~k; v = v & ~k;
if (!keys.isEmpty()) if (!keys.isEmpty())
keys += '|'; keys += '|';
keys += mobj->d.stringdata + mobj->d.data[data + 2*i]; keys += rawStringData(mobj, mobj->d.data[data + 2*i]);
} }
} }
return keys; return keys;
@ -2092,7 +2130,7 @@ const char *QMetaProperty::name() const
if (!mobj) if (!mobj)
return 0; return 0;
int handle = priv(mobj->d.data)->propertyData + 3*idx; int handle = priv(mobj->d.data)->propertyData + 3*idx;
return mobj->d.stringdata + mobj->d.data[handle]; return rawStringData(mobj, mobj->d.data[handle]);
} }
/*! /*!
@ -2105,7 +2143,7 @@ const char *QMetaProperty::typeName() const
if (!mobj) if (!mobj)
return 0; return 0;
int handle = priv(mobj->d.data)->propertyData + 3*idx; int handle = priv(mobj->d.data)->propertyData + 3*idx;
return mobj->d.stringdata + mobj->d.data[handle + 1]; return rawStringData(mobj, mobj->d.data[handle + 1]);
} }
/*! /*!
@ -2254,7 +2292,7 @@ QVariant QMetaProperty::read(const QObject *object) const
} else { } else {
int handle = priv(mobj->d.data)->propertyData + 3*idx; int handle = priv(mobj->d.data)->propertyData + 3*idx;
uint flags = mobj->d.data[handle + 2]; uint flags = mobj->d.data[handle + 2];
const char *typeName = mobj->d.stringdata + mobj->d.data[handle + 1]; const char *typeName = rawStringData(mobj, mobj->d.data[handle + 1]);
t = (flags >> 24); t = (flags >> 24);
if (t == QVariant::Invalid) if (t == QVariant::Invalid)
t = QMetaType::type(typeName); t = QMetaType::type(typeName);
@ -2325,7 +2363,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
uint flags = mobj->d.data[handle + 2]; uint flags = mobj->d.data[handle + 2];
t = flags >> 24; t = flags >> 24;
if (t == QVariant::Invalid) { if (t == QVariant::Invalid) {
const char *typeName = mobj->d.stringdata + mobj->d.data[handle + 1]; const char *typeName = rawStringData(mobj, mobj->d.data[handle + 1]);
const char *vtypeName = value.typeName(); const char *vtypeName = value.typeName();
if (vtypeName && strcmp(typeName, vtypeName) == 0) if (vtypeName && strcmp(typeName, vtypeName) == 0)
t = value.userType(); t = value.userType();
@ -2691,7 +2729,7 @@ const char *QMetaClassInfo::name() const
{ {
if (!mobj) if (!mobj)
return 0; return 0;
return mobj->d.stringdata + mobj->d.data[handle]; return rawStringData(mobj, mobj->d.data[handle]);
} }
/*! /*!
@ -2703,7 +2741,7 @@ const char* QMetaClassInfo::value() const
{ {
if (!mobj) if (!mobj)
return 0; return 0;
return mobj->d.stringdata + mobj->d.data[handle + 1]; return rawStringData(mobj, mobj->d.data[handle + 1]);
} }
/*! /*!

View File

@ -109,7 +109,7 @@ class QMutex;
struct QMetaObjectPrivate struct QMetaObjectPrivate
{ {
enum { OutputRevision = 6 }; // Used by moc and qmetaobjectbuilder enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision; int revision;
int className; int className;
@ -122,10 +122,13 @@ struct QMetaObjectPrivate
int signalCount; //since revision 4 int signalCount; //since revision 4
// revision 5 introduces changes in normalized signatures, no new members // revision 5 introduces changes in normalized signatures, no new members
// revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself // revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself
// revision 7 is Qt 5
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject) static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); } { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
static const char *rawStringData(const QMetaObject *mo, int index);
static int indexOfSignalRelative(const QMetaObject **baseObject, static int indexOfSignalRelative(const QMetaObject **baseObject,
const char* name, const char* name,
bool normalizeStringData); bool normalizeStringData);

View File

@ -4036,9 +4036,9 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
locker.unlock(); locker.unlock();
// reconstruct the signature to call connectNotify // reconstruct the signature to call connectNotify
const char *sig = senderMetaObject->d.stringdata + senderMetaObject->d.data[ const char *sig = QMetaObjectPrivate::rawStringData(senderMetaObject, senderMetaObject->d.data[
reinterpret_cast<const QMetaObjectPrivate*>(senderMetaObject->d.data)->methodData reinterpret_cast<const QMetaObjectPrivate*>(senderMetaObject->d.data)->methodData
+ 5 * (signal_index - signalOffset)]; + 5 * (signal_index - signalOffset)]);
QVarLengthArray<char> signalSignature(qstrlen(sig) + 2); QVarLengthArray<char> signalSignature(qstrlen(sig) + 2);
signalSignature.data()[0] = char(QSIGNAL_CODE + '0'); signalSignature.data()[0] = char(QSIGNAL_CODE + '0');
strcpy(signalSignature.data() + 1 , sig); strcpy(signalSignature.data() + 1 , sig);

View File

@ -50,11 +50,12 @@ QT_BEGIN_NAMESPACE
class QByteArray; class QByteArray;
struct QByteArrayData;
class QString; class QString;
#ifndef Q_MOC_OUTPUT_REVISION #ifndef Q_MOC_OUTPUT_REVISION
#define Q_MOC_OUTPUT_REVISION 64 #define Q_MOC_OUTPUT_REVISION 65
#endif #endif
// The following macros are our "extensions" to C++ // The following macros are our "extensions" to C++
@ -437,7 +438,7 @@ struct Q_CORE_EXPORT QMetaObject
struct { // private data struct { // private data
const QMetaObject *superdata; const QMetaObject *superdata;
const char *stringdata; const QByteArrayData *stringdata;
const uint *data; const uint *data;
const void *extradata; const void *extradata;
} d; } d;
@ -478,9 +479,6 @@ struct QMetaObjectExtraData
StaticMetacallFunction static_metacall; StaticMetacallFunction static_metacall;
}; };
inline const char *QMetaObject::className() const
{ return d.stringdata; }
inline const QMetaObject *QMetaObject::superClass() const inline const QMetaObject *QMetaObject::superClass() const
{ return d.superdata; } { return d.superdata; }

View File

@ -109,24 +109,17 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
return i - startPos; return i - startPos;
} }
int Generator::strreg(const QByteArray &s) void Generator::strreg(const QByteArray &s)
{ {
int idx = 0; if (!strings.contains(s))
for (int i = 0; i < strings.size(); ++i) {
const QByteArray &str = strings.at(i);
if (str == s)
return idx;
idx += str.length() + 1;
for (int i = 0; i < str.length(); ++i) {
if (str.at(i) == '\\') {
int cnt = lengthOfEscapeSequence(str, i) - 1;
idx -= cnt;
i += cnt;
}
}
}
strings.append(s); strings.append(s);
return idx; }
int Generator::stridx(const QByteArray &s)
{
int i = strings.indexOf(s);
Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
return i;
} }
void Generator::generateCode() void Generator::generateCode()
@ -135,10 +128,6 @@ void Generator::generateCode()
bool isQObject = (cdef->classname == "QObject"); bool isQObject = (cdef->classname == "QObject");
bool isConstructible = !cdef->constructorList.isEmpty(); bool isConstructible = !cdef->constructorList.isEmpty();
//
// build the data array
//
// filter out undeclared enumerators and sets // filter out undeclared enumerators and sets
{ {
QList<EnumDef> enumList; QList<EnumDef> enumList;
@ -156,15 +145,119 @@ void Generator::generateCode()
cdef->enumList = enumList; cdef->enumList = enumList;
} }
//
// Register all strings used in data section
//
strreg(cdef->qualified);
registerClassInfoStrings();
registerFunctionStrings(cdef->signalList);
registerFunctionStrings(cdef->slotList);
registerFunctionStrings(cdef->methodList);
registerFunctionStrings(cdef->constructorList);
registerPropertyStrings();
registerEnumStrings();
QByteArray qualifiedClassNameIdentifier = cdef->qualified; QByteArray qualifiedClassNameIdentifier = cdef->qualified;
qualifiedClassNameIdentifier.replace(':', '_'); qualifiedClassNameIdentifier.replace(':', '_');
//
// Build stringdata struct
//
fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, " QByteArrayData data[%d];\n", strings.size());
{
int len = 0;
for (int i = 0; i < strings.size(); ++i)
len += strings.at(i).length() + 1;
fprintf(out, " char stringdata[%d];\n", len + 1);
}
fprintf(out, "};\n");
// Macro that expands into a QByteArrayData. The offset member is
// calculated from 1) the offset of the actual characters in the
// stringdata.stringdata member, and 2) the stringdata.data index of the
// QByteArrayData being defined. This calculation relies on the
// QByteArrayData::data() implementation returning simply "this + offset".
fprintf(out, "#define QT_MOC_LITERAL(idx, ofs, len) { \\\n"
" Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \\\n"
" offsetof(qt_meta_stringdata_%s_t, stringdata) + ofs \\\n"
" - idx * sizeof(QByteArrayData) \\\n"
" }\n",
qualifiedClassNameIdentifier.constData());
fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
fprintf(out, " {\n");
{
int idx = 0;
for (int i = 0; i < strings.size(); ++i) {
if (i)
fprintf(out, ",\n");
const QByteArray &str = strings.at(i);
fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length());
idx += str.length() + 1;
for (int j = 0; j < str.length(); ++j) {
if (str.at(j) == '\\') {
int cnt = lengthOfEscapeSequence(str, j) - 1;
idx -= cnt;
j += cnt;
}
}
}
fprintf(out, "\n },\n");
}
//
// Build stringdata array
//
fprintf(out, " \"");
int col = 0;
int len = 0;
for (int i = 0; i < strings.size(); ++i) {
QByteArray s = strings.at(i);
len = s.length();
if (col && col + len >= 72) {
fprintf(out, "\"\n \"");
col = 0;
} else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
fprintf(out, "\"\"");
len += 2;
}
int idx = 0;
while (idx < s.length()) {
if (idx > 0) {
col = 0;
fprintf(out, "\"\n \"");
}
int spanLen = qMin(70, s.length() - idx);
// don't cut escape sequences at the end of a line
int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
if (backSlashPos >= idx) {
int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
}
fwrite(s.constData() + idx, 1, spanLen, out);
idx += spanLen;
col += spanLen;
}
fputs("\\0", out);
col += len + 2;
}
// Terminate stringdata struct
fprintf(out, "\"\n};\n");
fprintf(out, "#undef QT_MOC_LITERAL\n\n");
//
// build the data array
//
int index = MetaObjectPrivateFieldCount; int index = MetaObjectPrivateFieldCount;
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData()); fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n"); fprintf(out, "\n // content:\n");
fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision)); fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision));
fprintf(out, " %4d, // classname\n", strreg(cdef->qualified)); fprintf(out, " %4d, // classname\n", stridx(cdef->qualified));
fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0); fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
index += cdef->classInfoList.count() * 2; index += cdef->classInfoList.count() * 2;
@ -241,46 +334,6 @@ void Generator::generateCode()
// //
fprintf(out, "\n 0 // eod\n};\n\n"); fprintf(out, "\n 0 // eod\n};\n\n");
//
// Build stringdata array
//
fprintf(out, "static const char qt_meta_stringdata_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, " \"");
int col = 0;
int len = 0;
for (int i = 0; i < strings.size(); ++i) {
QByteArray s = strings.at(i);
len = s.length();
if (col && col + len >= 72) {
fprintf(out, "\"\n \"");
col = 0;
} else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
fprintf(out, "\"\"");
len += 2;
}
int idx = 0;
while (idx < s.length()) {
if (idx > 0) {
col = 0;
fprintf(out, "\"\n \"");
}
int spanLen = qMin(70, s.length() - idx);
// don't cut escape sequences at the end of a line
int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
if (backSlashPos >= idx) {
int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
}
fwrite(s.constData() + idx, 1, spanLen, out);
idx += spanLen;
col += spanLen;
}
fputs("\\0", out);
col += len + 2;
}
fprintf(out, "\"\n};\n\n");
// //
// Generate internal qt_static_metacall() function // Generate internal qt_static_metacall() function
// //
@ -356,8 +409,9 @@ void Generator::generateCode()
fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData()); fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
else else
fprintf(out, " { 0, "); fprintf(out, " { 0, ");
fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ", fprintf(out, "qt_meta_stringdata_%s.data,\n"
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); " qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(),
qualifiedClassNameIdentifier.constData());
if (!hasExtraData) if (!hasExtraData)
fprintf(out, "0 }\n"); fprintf(out, "0 }\n");
else else
@ -379,7 +433,7 @@ void Generator::generateCode()
// //
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData()); fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
fprintf(out, " if (!_clname) return 0;\n"); fprintf(out, " if (!_clname) return 0;\n");
fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s))\n" fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata))\n"
" return static_cast<void*>(const_cast< %s*>(this));\n", " return static_cast<void*>(const_cast< %s*>(this));\n",
qualifiedClassNameIdentifier.constData(), cdef->classname.constData()); qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
@ -430,6 +484,15 @@ void Generator::generateCode()
} }
void Generator::registerClassInfoStrings()
{
for (int i = 0; i < cdef->classInfoList.size(); ++i) {
const ClassInfoDef &c = cdef->classInfoList.at(i);
strreg(c.name);
strreg(c.value);
}
}
void Generator::generateClassInfos() void Generator::generateClassInfos()
{ {
if (cdef->classInfoList.isEmpty()) if (cdef->classInfoList.isEmpty())
@ -439,7 +502,33 @@ void Generator::generateClassInfos()
for (int i = 0; i < cdef->classInfoList.size(); ++i) { for (int i = 0; i < cdef->classInfoList.size(); ++i) {
const ClassInfoDef &c = cdef->classInfoList.at(i); const ClassInfoDef &c = cdef->classInfoList.at(i);
fprintf(out, " %4d, %4d,\n", strreg(c.name), strreg(c.value)); fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value));
}
}
void Generator::registerFunctionStrings(const QList<FunctionDef>& list)
{
for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i);
QByteArray sig = f.name + '(';
QByteArray arguments;
for (int j = 0; j < f.arguments.count(); ++j) {
const ArgumentDef &a = f.arguments.at(j);
if (j) {
sig += ",";
arguments += ",";
}
sig += a.normalizedType;
arguments += a.name;
}
sig += ')';
strreg(sig);
strreg(arguments);
strreg(f.normalizedType);
strreg(f.tag);
} }
} }
@ -487,8 +576,8 @@ void Generator::generateFunctions(const QList<FunctionDef>& list, const char *fu
flags |= MethodScriptable; flags |= MethodScriptable;
if (f.revision > 0) if (f.revision > 0)
flags |= MethodRevisioned; flags |= MethodRevisioned;
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig), fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", stridx(sig),
strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags); stridx(arguments), stridx(f.normalizedType), stridx(f.tag), flags);
} }
} }
@ -502,6 +591,15 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef>& list, const
} }
} }
void Generator::registerPropertyStrings()
{
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
strreg(p.name);
strreg(p.type);
}
}
void Generator::generateProperties() void Generator::generateProperties()
{ {
// //
@ -568,8 +666,8 @@ void Generator::generateProperties()
flags |= Final; flags |= Final;
fprintf(out, " %4d, %4d, ", fprintf(out, " %4d, %4d, ",
strreg(p.name), stridx(p.name),
strreg(p.type)); stridx(p.type));
if (!(flags >> 24) && isQRealType(p.type)) if (!(flags >> 24) && isQRealType(p.type))
fprintf(out, "(QMetaType::QReal << 24) | "); fprintf(out, "(QMetaType::QReal << 24) | ");
fprintf(out, "0x%.8x,\n", flags); fprintf(out, "0x%.8x,\n", flags);
@ -596,6 +694,16 @@ void Generator::generateProperties()
} }
} }
void Generator::registerEnumStrings()
{
for (int i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
strreg(e.name);
for (int j = 0; j < e.values.count(); ++j)
strreg(e.values.at(j));
}
}
void Generator::generateEnums(int index) void Generator::generateEnums(int index)
{ {
if (cdef->enumDeclarations.isEmpty()) if (cdef->enumDeclarations.isEmpty())
@ -607,7 +715,7 @@ void Generator::generateEnums(int index)
for (i = 0; i < cdef->enumList.count(); ++i) { for (i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i); const EnumDef &e = cdef->enumList.at(i);
fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n", fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
strreg(e.name), stridx(e.name),
cdef->enumDeclarations.value(e.name) ? 1 : 0, cdef->enumDeclarations.value(e.name) ? 1 : 0,
e.values.count(), e.values.count(),
index); index);
@ -624,7 +732,7 @@ void Generator::generateEnums(int index)
code += "::" + e.name; code += "::" + e.name;
code += "::" + val; code += "::" + val;
fprintf(out, " %4d, uint(%s),\n", fprintf(out, " %4d, uint(%s),\n",
strreg(val), code.constData()); stridx(val), code.constData());
} }
} }
} }

View File

@ -55,17 +55,22 @@ public:
Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile = 0); Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile = 0);
void generateCode(); void generateCode();
private: private:
void registerClassInfoStrings();
void generateClassInfos(); void generateClassInfos();
void registerFunctionStrings(const QList<FunctionDef> &list);
void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type); void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type);
void generateFunctionRevisions(const QList<FunctionDef>& list, const char *functype); void generateFunctionRevisions(const QList<FunctionDef>& list, const char *functype);
void registerEnumStrings();
void generateEnums(int index); void generateEnums(int index);
void registerPropertyStrings();
void generateProperties(); void generateProperties();
void generateMetacall(); void generateMetacall();
void generateStaticMetacall(); void generateStaticMetacall();
void generateSignal(FunctionDef *def, int index); void generateSignal(FunctionDef *def, int index);
void generatePluginMetaData(); void generatePluginMetaData();
int strreg(const QByteArray &); // registers a string and returns its id void strreg(const QByteArray &); // registers a string
int stridx(const QByteArray &); // returns a string's id
QList<QByteArray> strings; QList<QByteArray> strings;
QByteArray purestSuperClass; QByteArray purestSuperClass;
QList<QByteArray> metaTypes; QList<QByteArray> metaTypes;

View File

@ -818,6 +818,7 @@ void Moc::generate(FILE *out)
if (classList.size() && classList.first().classname == "Qt") if (classList.size() && classList.first().classname == "Qt")
fprintf(out, "#include <QtCore/qobject.h>\n"); fprintf(out, "#include <QtCore/qobject.h>\n");
fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
if (mustIncludeQMetaTypeH) if (mustIncludeQMetaTypeH)
fprintf(out, "#include <QtCore/qmetatype.h>\n"); fprintf(out, "#include <QtCore/qmetatype.h>\n");
if (mustIncludeQPluginH) if (mustIncludeQPluginH)

View File

@ -43,6 +43,6 @@
#define OUTPUTREVISION_H #define OUTPUTREVISION_H
// if the output revision changes, you MUST change it in qobjectdefs.h too // if the output revision changes, you MUST change it in qobjectdefs.h too
enum { mocOutputRevision = 64 }; // moc format output revision enum { mocOutputRevision = 65 }; // moc format output revision
#endif // OUTPUTREVISION_H #endif // OUTPUTREVISION_H

View File

@ -90,7 +90,7 @@ static const char qt_meta_stringdata_OldNormalizeObject[] = {
}; };
const QMetaObject OldNormalizeObject::staticMetaObject = { const QMetaObject OldNormalizeObject::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_OldNormalizeObject, { &QObject::staticMetaObject, reinterpret_cast<const QByteArrayData *>(qt_meta_stringdata_OldNormalizeObject),
qt_meta_data_OldNormalizeObject, 0 } qt_meta_data_OldNormalizeObject, 0 }
}; };