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)
{ 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
@ -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.
\sa superClass()
*/
const char *QMetaObject::className() const
{
return rawStringData(this, 0);
}
/*!
\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
{
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
{
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
@ -513,7 +552,7 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
? (priv(m->d.data)->signalCount) : 0;
if (!normalizeStringData) {
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) {
*baseObject = m;
return i;
@ -521,7 +560,7 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
}
} else if (priv(m->d.data)->revision < 5) {
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);
if (normalizedSignature == method) {
*baseObject = m;
@ -549,7 +588,7 @@ int QMetaObject::indexOfConstructor(const char *constructor) const
if (priv(d.data)->revision < 2)
return -1;
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) {
return i;
}
@ -618,7 +657,7 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
int conflict = m->d.superdata->indexOfMethod(signal);
if (conflict >= 0)
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
return i;
@ -654,7 +693,7 @@ int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
{
while (self) {
if (strcmp(self->d.stringdata, name) == 0)
if (strcmp(rawStringData(self, 0), name) == 0)
return self;
if (self->d.extradata) {
const QMetaObject **e;
@ -690,7 +729,7 @@ int QMetaObject::indexOfEnumerator(const char *name) const
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
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) {
i += m->enumeratorOffset();
return i;
@ -713,7 +752,7 @@ int QMetaObject::indexOfProperty(const char *name) const
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
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) {
i += m->propertyOffset();
return i;
@ -744,8 +783,7 @@ int QMetaObject::indexOfClassInfo(const char *name) const
const QMetaObject *m = this;
while (m && i < 0) {
for (i = priv(m->d.data)->classInfoCount-1; i >= 0; --i)
if (strcmp(name, m->d.stringdata
+ m->d.data[priv(m->d.data)->classInfoData + 2*i]) == 0) {
if (strcmp(name, rawStringData(m, m->d.data[priv(m->d.data)->classInfoData + 2*i])) == 0) {
i += m->classInfoOffset();
break;
}
@ -829,7 +867,7 @@ QMetaProperty QMetaObject::property(int index) const
if (i >= 0 && i < priv(d.data)->propertyCount) {
int handle = priv(d.data)->propertyData + 3*i;
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.handle = handle;
result.idx = i;
@ -838,7 +876,7 @@ QMetaProperty QMetaObject::property(int index) const
result.menum = enumerator(indexOfEnumerator(type));
if (!result.menum.isValid()) {
const char *enum_name = type;
const char *scope_name = d.stringdata;
const char *scope_name = rawStringData(this, 0);
char *scope_buffer = 0;
const char *colon = strrchr(enum_name, ':');
@ -1285,7 +1323,7 @@ const char *QMetaMethod::signature() const
{
if (!mobj)
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)
return QList<QByteArray>();
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;
if (!mobj)
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) {
// 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 != '(')
++signature;
if (*++signature != ')')
@ -1340,7 +1378,7 @@ const char *QMetaMethod::typeName() const
{
if (!mobj)
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)
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;
{
// 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) {
// 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 != '(')
++signature;
if (*++signature != ')')
@ -1803,7 +1841,7 @@ const char *QMetaEnum::name() const
{
if (!mobj)
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 data = mobj->d.data[handle + 3];
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;
}
@ -1878,7 +1916,7 @@ bool QMetaEnum::isFlag() 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 data = mobj->d.data[handle + 3];
for (int i = 0; i < count; ++i) {
if ((!scope || (qstrlen(mobj->d.stringdata) == scope && strncmp(qualified_key, mobj->d.stringdata, scope) == 0))
&& strcmp(key, mobj->d.stringdata + mobj->d.data[data + 2*i]) == 0) {
if ((!scope || (stringSize(mobj, 0) == int(scope) && strncmp(qualified_key, rawStringData(mobj, 0), scope) == 0))
&& strcmp(key, rawStringData(mobj, mobj->d.data[data + 2*i])) == 0) {
if (ok != 0)
*ok = true;
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];
for (int i = 0; i < count; ++i)
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;
}
@ -1979,8 +2017,8 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
}
int i;
for (i = count-1; i >= 0; --i)
if ((!scope || (qstrlen(mobj->d.stringdata) == scope && strncmp(qualified_key.constData(), mobj->d.stringdata, scope) == 0))
&& strcmp(key, mobj->d.stringdata + mobj->d.data[data + 2*i]) == 0) {
if ((!scope || (stringSize(mobj, 0) == int(scope) && strncmp(qualified_key.constData(), rawStringData(mobj, 0), scope) == 0))
&& strcmp(key, rawStringData(mobj, mobj->d.data[data + 2*i])) == 0) {
value |= mobj->d.data[data + 2*i + 1];
break;
}
@ -2013,7 +2051,7 @@ QByteArray QMetaEnum::valueToKeys(int value) const
v = v & ~k;
if (!keys.isEmpty())
keys += '|';
keys += mobj->d.stringdata + mobj->d.data[data + 2*i];
keys += rawStringData(mobj, mobj->d.data[data + 2*i]);
}
}
return keys;
@ -2092,7 +2130,7 @@ const char *QMetaProperty::name() const
if (!mobj)
return 0;
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)
return 0;
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 {
int handle = priv(mobj->d.data)->propertyData + 3*idx;
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);
if (t == QVariant::Invalid)
t = QMetaType::type(typeName);
@ -2325,7 +2363,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
uint flags = mobj->d.data[handle + 2];
t = flags >> 24;
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();
if (vtypeName && strcmp(typeName, vtypeName) == 0)
t = value.userType();
@ -2691,7 +2729,7 @@ const char *QMetaClassInfo::name() const
{
if (!mobj)
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)
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
{
enum { OutputRevision = 6 }; // Used by moc and qmetaobjectbuilder
enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision;
int className;
@ -122,10 +122,13 @@ struct QMetaObjectPrivate
int signalCount; //since revision 4
// 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 7 is Qt 5
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
static const char *rawStringData(const QMetaObject *mo, int index);
static int indexOfSignalRelative(const QMetaObject **baseObject,
const char* name,
bool normalizeStringData);

View File

@ -4036,9 +4036,9 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
locker.unlock();
// 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
+ 5 * (signal_index - signalOffset)];
+ 5 * (signal_index - signalOffset)]);
QVarLengthArray<char> signalSignature(qstrlen(sig) + 2);
signalSignature.data()[0] = char(QSIGNAL_CODE + '0');
strcpy(signalSignature.data() + 1 , sig);

View File

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

View File

@ -109,24 +109,17 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
return i - startPos;
}
int Generator::strreg(const QByteArray &s)
void Generator::strreg(const QByteArray &s)
{
int idx = 0;
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);
return idx;
if (!strings.contains(s))
strings.append(s);
}
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()
@ -135,10 +128,6 @@ void Generator::generateCode()
bool isQObject = (cdef->classname == "QObject");
bool isConstructible = !cdef->constructorList.isEmpty();
//
// build the data array
//
// filter out undeclared enumerators and sets
{
QList<EnumDef> enumList;
@ -156,15 +145,119 @@ void Generator::generateCode()
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;
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;
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n");
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);
index += cdef->classInfoList.count() * 2;
@ -241,46 +334,6 @@ void Generator::generateCode()
//
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
//
@ -356,8 +409,9 @@ void Generator::generateCode()
fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
else
fprintf(out, " { 0, ");
fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ",
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
fprintf(out, "qt_meta_stringdata_%s.data,\n"
" qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(),
qualifiedClassNameIdentifier.constData());
if (!hasExtraData)
fprintf(out, "0 }\n");
else
@ -379,7 +433,7 @@ void Generator::generateCode()
//
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
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",
qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
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()
{
if (cdef->classInfoList.isEmpty())
@ -439,7 +502,33 @@ void Generator::generateClassInfos()
for (int i = 0; i < cdef->classInfoList.size(); ++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;
if (f.revision > 0)
flags |= MethodRevisioned;
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig),
strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags);
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", stridx(sig),
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()
{
//
@ -568,8 +666,8 @@ void Generator::generateProperties()
flags |= Final;
fprintf(out, " %4d, %4d, ",
strreg(p.name),
strreg(p.type));
stridx(p.name),
stridx(p.type));
if (!(flags >> 24) && isQRealType(p.type))
fprintf(out, "(QMetaType::QReal << 24) | ");
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)
{
if (cdef->enumDeclarations.isEmpty())
@ -607,7 +715,7 @@ void Generator::generateEnums(int index)
for (i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
strreg(e.name),
stridx(e.name),
cdef->enumDeclarations.value(e.name) ? 1 : 0,
e.values.count(),
index);
@ -624,7 +732,7 @@ void Generator::generateEnums(int index)
code += "::" + e.name;
code += "::" + val;
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);
void generateCode();
private:
void registerClassInfoStrings();
void generateClassInfos();
void registerFunctionStrings(const QList<FunctionDef> &list);
void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type);
void generateFunctionRevisions(const QList<FunctionDef>& list, const char *functype);
void registerEnumStrings();
void generateEnums(int index);
void registerPropertyStrings();
void generateProperties();
void generateMetacall();
void generateStaticMetacall();
void generateSignal(FunctionDef *def, int index);
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;
QByteArray purestSuperClass;
QList<QByteArray> metaTypes;

View File

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

View File

@ -43,6 +43,6 @@
#define OUTPUTREVISION_H
// 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

View File

@ -90,7 +90,7 @@ static const char qt_meta_stringdata_OldNormalizeObject[] = {
};
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 }
};