summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/json/qjsonvalue.cpp2
-rw-r--r--src/corelib/kernel/qmetaobject.cpp822
-rw-r--r--src/corelib/kernel/qmetaobject.h15
-rw-r--r--src/corelib/kernel/qmetaobject_p.h77
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp304
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h19
-rw-r--r--src/corelib/kernel/qmetatype.cpp62
-rw-r--r--src/corelib/kernel/qmetatype.h9
-rw-r--r--src/corelib/kernel/qmetatypeswitcher_p.h7
-rw-r--r--src/corelib/kernel/qobject.cpp266
-rw-r--r--src/corelib/kernel/qobjectdefs.h10
-rw-r--r--src/corelib/kernel/qvariant.cpp2
-rw-r--r--src/corelib/kernel/qvariant.h2
-rw-r--r--src/corelib/kernel/qvariant_p.h29
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp38
-rw-r--r--src/corelib/tools/qarraydata.cpp111
-rw-r--r--src/corelib/tools/qarraydata.h275
-rw-r--r--src/corelib/tools/qarraydataops.h322
-rw-r--r--src/corelib/tools/qarraydatapointer.h220
-rw-r--r--src/corelib/tools/qbytearray.cpp159
-rw-r--r--src/corelib/tools/qbytearray.h57
-rw-r--r--src/corelib/tools/qhash.cpp4
-rw-r--r--src/corelib/tools/qhash.h4
-rw-r--r--src/corelib/tools/qlinkedlist.cpp2
-rw-r--r--src/corelib/tools/qlinkedlist.h22
-rw-r--r--src/corelib/tools/qlist.cpp24
-rw-r--r--src/corelib/tools/qlist.h60
-rw-r--r--src/corelib/tools/qmap.cpp4
-rw-r--r--src/corelib/tools/qmap.h6
-rw-r--r--src/corelib/tools/qrefcount.h58
-rw-r--r--src/corelib/tools/qstring.cpp143
-rw-r--r--src/corelib/tools/qstring.h73
-rw-r--r--src/corelib/tools/qstringbuilder.h13
-rw-r--r--src/corelib/tools/qvector.cpp16
-rw-r--r--src/corelib/tools/qvector.h370
-rw-r--r--src/corelib/tools/tools.pri4
36 files changed, 2757 insertions, 854 deletions
diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp
index b4a689da60..2eedef67ce 100644
--- a/src/corelib/json/qjsonvalue.cpp
+++ b/src/corelib/json/qjsonvalue.cpp
@@ -400,7 +400,7 @@ QString QJsonValue::toString() const
if (t != String)
return QString();
stringData->ref.ref(); // the constructor below doesn't add a ref.
- return QString(*(const QConstStringData<1> *)stringData);
+ return QString(*(const QStaticStringData<1> *)stringData);
}
/*!
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index cacd999869..a8c21657cb 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -146,6 +146,90 @@ 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 QByteArray toByteArray(const QByteArrayData &d)
+{
+ return QByteArray(reinterpret_cast<const QStaticByteArrayData<0> &>(d));
+}
+
+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);
+}
+
+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));
+}
+
+static inline QByteArray typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+{
+ if (typeInfo & IsUnresolvedType) {
+ return toByteArray(stringData(mo, typeInfo & TypeNameIndexMask));
+ } else {
+ // ### Use the QMetaType::typeName() that returns QByteArray
+ const char *t = QMetaType::typeName(typeInfo);
+ return QByteArray::fromRawData(t, qstrlen(t));
+ }
+}
+
+static inline const char *rawTypeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+{
+ return typeNameFromTypeInfo(mo, typeInfo).constData();
+}
+
+static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+{
+ if (!(typeInfo & IsUnresolvedType))
+ return typeInfo;
+ return QMetaType::type(toByteArray(stringData(mo, typeInfo & TypeNameIndexMask)));
+}
+
+class QMetaMethodPrivate : public QMetaMethod
+{
+public:
+ static const QMetaMethodPrivate *get(const QMetaMethod *q)
+ { return static_cast<const QMetaMethodPrivate *>(q); }
+
+ inline QByteArray signature() const;
+ inline QByteArray name() const;
+ inline int typesDataIndex() const;
+ inline const char *rawReturnTypeName() const;
+ inline int returnType() const;
+ inline int parameterCount() const;
+ inline int parametersDataIndex() const;
+ inline uint parameterTypeInfo(int index) const;
+ inline int parameterType(int index) const;
+ inline void getParameterTypes(int *types) const;
+ inline QList<QByteArray> parameterTypes() const;
+ inline QList<QByteArray> parameterNames() const;
+ inline QByteArray tag() const;
+
+private:
+ QMetaMethodPrivate();
+};
/*!
\since 4.5
@@ -249,12 +333,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 +393,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::DefaultCodec, n);
+ return QCoreApplication::translate(rawStringData(this, 0), s, c, QCoreApplication::DefaultCodec, n);
}
/*!
@@ -315,7 +401,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
@@ -495,7 +581,37 @@ int QMetaObject::classInfoCount() const
return n;
}
+// Returns true if the method defined by the given meta-object&handle
+// matches the given name, argument count and argument types, otherwise
+// returns false.
+static bool methodMatch(const QMetaObject *m, int handle,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ Q_ASSERT(priv(m->d.data)->revision >= 7);
+ if (int(m->d.data[handle + 1]) != argc)
+ return false;
+
+ if (toByteArray(stringData(m, m->d.data[handle])) != name)
+ return false;
+
+ int paramsIndex = m->d.data[handle + 2] + 1;
+ for (int i = 0; i < argc; ++i) {
+ uint typeInfo = m->d.data[paramsIndex + i];
+ if (types[i].type()) {
+ if (types[i].type() != typeFromTypeInfo(m, typeInfo))
+ return false;
+ } else {
+ if (types[i].name() != typeNameFromTypeInfo(m, typeInfo))
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** \internal
+* \obsolete
* helper function for indexOf{Method,Slot,Signal}, returns the relative index of the method within
* the baseObject
* \a MethodType might be MethodSignal or MethodSlot, or 0 to match everything.
@@ -506,6 +622,8 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
const char *method,
bool normalizeStringData)
{
+ QByteArray methodName;
+ QArgumentTypeArray methodArgumentTypes;
for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
int i = (MethodType == MethodSignal && priv(m->d.data)->revision >= 4)
? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);
@@ -513,15 +631,26 @@ 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];
- if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) {
- *baseObject = m;
- return i;
+ if (priv(m->d.data)->revision >= 7) {
+ if (methodName.isEmpty())
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodArgumentTypes);
+ int handle = priv(m->d.data)->methodData + 5*i;
+ if (methodMatch(m, handle, methodName, methodArgumentTypes.size(),
+ methodArgumentTypes.constData())) {
+ *baseObject = m;
+ return i;
+ }
+ } else {
+ const char *stringdata = legacyString(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;
+ }
}
}
} 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;
@@ -533,6 +662,34 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
return -1;
}
+/** \internal
+* helper function for indexOf{Method,Slot,Signal}, returns the relative index of the method within
+* the baseObject
+* \a MethodType might be MethodSignal or MethodSlot, or 0 to match everything.
+*/
+template<int MethodType>
+static inline int indexOfMethodRelative(const QMetaObject **baseObject,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
+ Q_ASSERT(priv(m->d.data)->revision >= 7);
+ int i = (MethodType == MethodSignal)
+ ? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);
+ const int end = (MethodType == MethodSlot)
+ ? (priv(m->d.data)->signalCount) : 0;
+
+ for (; i >= end; --i) {
+ int handle = priv(m->d.data)->methodData + 5*i;
+ if (methodMatch(m, handle, name, argc, types)) {
+ *baseObject = m;
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
/*!
\since 4.5
@@ -548,10 +705,16 @@ 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];
- if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) {
- return i;
+ else if (priv(d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(constructor, types);
+ return QMetaObjectPrivate::indexOfConstructor(this, name, types.size(), types.constData());
+ } else {
+ for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) {
+ const char *data = legacyString(this, d.data[priv(d.data)->constructorData + 5*i]);
+ if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) {
+ return i;
+ }
}
}
return -1;
@@ -568,16 +731,60 @@ int QMetaObject::indexOfConstructor(const char *constructor) const
int QMetaObject::indexOfMethod(const char *method) const
{
const QMetaObject *m = this;
- int i = indexOfMethodRelative<0>(&m, method, false);
- if (i < 0) {
- m = this;
- i = indexOfMethodRelative<0>(&m, method, true);
+ int i;
+ if (priv(m->d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(method, types);
+ i = indexOfMethodRelative<0>(&m, name, types.size(), types.constData());
+ } else {
+ i = indexOfMethodRelative<0>(&m, method, false);
+ if (i < 0) {
+ m = this;
+ i = indexOfMethodRelative<0>(&m, method, true);
+ }
}
if (i >= 0)
i += m->methodOffset();
return i;
}
+// Parses a string of comma-separated types into QArgumentTypes.
+static void argumentTypesFromString(const char *str, const char *end,
+ QArgumentTypeArray &types)
+{
+ Q_ASSERT(str <= end);
+ while (str != end) {
+ if (!types.isEmpty())
+ ++str; // Skip comma
+ const char *begin = str;
+ int level = 0;
+ while (str != end && (level > 0 || *str != ',')) {
+ if (*str == '<')
+ ++level;
+ else if (*str == '>')
+ --level;
+ ++str;
+ }
+ types += QArgumentType(QByteArray(begin, str - begin));
+ }
+}
+
+// Given a method \a signature (e.g. "foo(int,double)"), this function
+// populates the argument \a types array and returns the method name.
+QByteArray QMetaObjectPrivate::decodeMethodSignature(
+ const char *signature, QArgumentTypeArray &types)
+{
+ const char *lparens = strchr(signature, '(');
+ if (!lparens)
+ return QByteArray();
+ const char *rparens = strchr(lparens + 1, ')');
+ if (!rparens || *(rparens+1))
+ return QByteArray();
+ int nameLength = lparens - signature;
+ argumentTypesFromString(lparens + 1, rparens, types);
+ return QByteArray::fromRawData(signature, nameLength);
+}
+
/*!
Finds \a signal and returns its index; otherwise returns -1.
@@ -592,10 +799,17 @@ int QMetaObject::indexOfMethod(const char *method) const
int QMetaObject::indexOfSignal(const char *signal) const
{
const QMetaObject *m = this;
- int i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, false);
- if (i < 0) {
- m = this;
- i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, true);
+ int i;
+ if (priv(m->d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signal, types);
+ i = QMetaObjectPrivate::indexOfSignalRelative(&m, name, types.size(), types.constData());
+ } else {
+ i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, false);
+ if (i < 0) {
+ m = this;
+ i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, true);
+ }
}
if (i >= 0)
i += m->methodOffset();
@@ -603,6 +817,7 @@ int QMetaObject::indexOfSignal(const char *signal) const
}
/*! \internal
+ \obsolete
Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
\a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found
@@ -618,12 +833,37 @@ 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;
}
+/*! \internal
+ Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
+
+ \a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found
+*/
+int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ int i = indexOfMethodRelative<MethodSignal>(baseObject, name, argc, types);
+#ifndef QT_NO_DEBUG
+ const QMetaObject *m = *baseObject;
+ if (i >= 0 && m && m->d.superdata) {
+ int conflict = indexOfMethod(m->d.superdata, name, argc, types);
+ if (conflict >= 0) {
+ QMetaMethod conflictMethod = m->d.superdata->method(conflict);
+ qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
+ conflictMethod.methodSignature().constData(),
+ rawStringData(m->d.superdata, 0), rawStringData(m, 0));
+ }
+ }
+ #endif
+ return i;
+}
+
/*!
Finds \a slot and returns its index; otherwise returns -1.
@@ -635,9 +875,16 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
int QMetaObject::indexOfSlot(const char *slot) const
{
const QMetaObject *m = this;
- int i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, false);
- if (i < 0)
- i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, true);
+ int i;
+ if (priv(m->d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(slot, types);
+ i = QMetaObjectPrivate::indexOfSlotRelative(&m, name, types.size(), types.constData());
+ } else {
+ i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, false);
+ if (i < 0)
+ i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, true);
+ }
if (i >= 0)
i += m->methodOffset();
return i;
@@ -651,10 +898,108 @@ int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
return indexOfMethodRelative<MethodSlot>(m, slot, normalizeStringData);
}
+// same as indexOfSignalRelative but for slots.
+int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ return indexOfMethodRelative<MethodSlot>(m, name, argc, types);
+}
+
+int QMetaObjectPrivate::indexOfSignal(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ int i = indexOfSignalRelative(&m, name, argc, types);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ int i = indexOfSlotRelative(&m, name, argc, types);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+int QMetaObjectPrivate::indexOfMethod(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ int i = indexOfMethodRelative<0>(&m, name, argc, types);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ for (int i = priv(m->d.data)->constructorCount-1; i >= 0; --i) {
+ int handle = priv(m->d.data)->constructorData + 5*i;
+ if (methodMatch(m, handle, name, argc, types))
+ return i;
+ }
+ return -1;
+}
+
+/*!
+ \internal
+
+ Returns true if the \a signalTypes and \a methodTypes are
+ compatible; otherwise returns false.
+*/
+bool QMetaObjectPrivate::checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
+ int methodArgc, const QArgumentType *methodTypes)
+{
+ if (signalArgc < methodArgc)
+ return false;
+ for (int i = 0; i < methodArgc; ++i) {
+ if (signalTypes[i] != methodTypes[i])
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+
+ Returns true if the \a signal and \a method arguments are
+ compatible; otherwise returns false.
+*/
+bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
+ const QMetaMethodPrivate *method)
+{
+ if (signal->methodType() != QMetaMethod::Signal)
+ return false;
+ if (signal->parameterCount() < method->parameterCount())
+ return false;
+ const QMetaObject *smeta = signal->enclosingMetaObject();
+ const QMetaObject *rmeta = method->enclosingMetaObject();
+ for (int i = 0; i < method->parameterCount(); ++i) {
+ uint sourceTypeInfo = signal->parameterTypeInfo(i);
+ uint targetTypeInfo = method->parameterTypeInfo(i);
+ if ((sourceTypeInfo & IsUnresolvedType)
+ || (targetTypeInfo & IsUnresolvedType)) {
+ QByteArray sourceName = typeNameFromTypeInfo(smeta, sourceTypeInfo);
+ QByteArray targetName = typeNameFromTypeInfo(rmeta, targetTypeInfo);
+ if (sourceName != targetName)
+ return false;
+ } else {
+ int sourceType = typeFromTypeInfo(smeta, sourceTypeInfo);
+ int targetType = typeFromTypeInfo(rmeta, targetTypeInfo);
+ if (sourceType != targetType)
+ return false;
+ }
+ }
+ return true;
+}
+
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 +1035,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 +1058,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 +1089,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,16 +1173,20 @@ 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];
result.mobj = this;
result.handle = handle;
result.idx = i;
if (flags & EnumOrFlag) {
+ const char *type;
+ if (priv(d.data)->revision >= 7)
+ type = rawTypeNameFromTypeInfo(this, d.data[handle + 1]);
+ else
+ type = legacyString(this, d.data[handle + 1]);
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, ':');
@@ -934,6 +1282,21 @@ bool QMetaObject::checkConnectArgs(const char *signal, const char *method)
return false;
}
+/*!
+ \since 5.0
+ \overload
+
+ Returns true if the \a signal and \a method arguments are
+ compatible; otherwise returns false.
+*/
+bool QMetaObject::checkConnectArgs(const QMetaMethod &signal,
+ const QMetaMethod &method)
+{
+ return QMetaObjectPrivate::checkConnectArgs(
+ QMetaMethodPrivate::get(&signal),
+ QMetaMethodPrivate::get(&method));
+}
+
static void qRemoveWhitespace(const char *s, char *d)
{
char last = 0;
@@ -1230,7 +1593,7 @@ bool QMetaObject::invokeMethod(QObject *obj,
\ingroup objectmodel
- A QMetaMethod has a methodType(), a signature(), a list of
+ A QMetaMethod has a methodType(), a methodSignature(), a list of
parameterTypes() and parameterNames(), a return typeName(), a
tag(), and an access() specifier. You can use invoke() to invoke
the method on an arbitrary QObject.
@@ -1275,72 +1638,284 @@ bool QMetaObject::invokeMethod(QObject *obj,
\internal
*/
+QByteArray QMetaMethodPrivate::signature() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ QByteArray result;
+ result.reserve(256);
+ result += name();
+ result += '(';
+ QList<QByteArray> argTypes = parameterTypes();
+ for (int i = 0; i < argTypes.size(); ++i) {
+ if (i)
+ result += ',';
+ result += argTypes.at(i);
+ }
+ result += ')';
+ return result;
+}
+
+QByteArray QMetaMethodPrivate::name() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return toByteArray(stringData(mobj, mobj->d.data[handle]));
+}
+
+int QMetaMethodPrivate::typesDataIndex() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return mobj->d.data[handle + 2];
+}
+
+const char *QMetaMethodPrivate::rawReturnTypeName() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ uint typeInfo = mobj->d.data[typesDataIndex()];
+ if (typeInfo & IsUnresolvedType)
+ return rawStringData(mobj, typeInfo & TypeNameIndexMask);
+ else {
+ if (typeInfo == QMetaType::Void) {
+ // QMetaMethod::typeName() is documented to return an empty string
+ // if the return type is void, but QMetaType::typeName() returns
+ // "void".
+ return "";
+ }
+ return QMetaType::typeName(typeInfo);
+ }
+}
+
+int QMetaMethodPrivate::returnType() const
+{
+ return parameterType(-1);
+}
+
+int QMetaMethodPrivate::parameterCount() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return mobj->d.data[handle + 1];
+}
+
+int QMetaMethodPrivate::parametersDataIndex() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return typesDataIndex() + 1;
+}
+
+uint QMetaMethodPrivate::parameterTypeInfo(int index) const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return mobj->d.data[parametersDataIndex() + index];
+}
+
+int QMetaMethodPrivate::parameterType(int index) const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return typeFromTypeInfo(mobj, parameterTypeInfo(index));
+}
+
+void QMetaMethodPrivate::getParameterTypes(int *types) const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ int dataIndex = parametersDataIndex();
+ int argc = parameterCount();
+ for (int i = 0; i < argc; ++i) {
+ int id = typeFromTypeInfo(mobj, mobj->d.data[dataIndex++]);
+ *(types++) = id;
+ }
+}
+
+QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ QList<QByteArray> list;
+ int argc = parameterCount();
+ int paramsIndex = parametersDataIndex();
+ for (int i = 0; i < argc; ++i)
+ list += typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
+ return list;
+}
+
+QList<QByteArray> QMetaMethodPrivate::parameterNames() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ QList<QByteArray> list;
+ int argc = parameterCount();
+ int namesIndex = parametersDataIndex() + argc;
+ for (int i = 0; i < argc; ++i)
+ list += toByteArray(stringData(mobj, mobj->d.data[namesIndex + i]));
+ return list;
+}
+
+QByteArray QMetaMethodPrivate::tag() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return toByteArray(stringData(mobj, mobj->d.data[handle + 3]));
+}
+
/*!
+ \since 5.0
+
Returns the signature of this method (e.g.,
\c{setValue(double)}).
\sa parameterTypes(), parameterNames()
*/
-const char *QMetaMethod::signature() const
+QByteArray QMetaMethod::methodSignature() const
+{
+ if (!mobj)
+ return QByteArray();
+ if (priv(mobj->d.data)->revision >= 7) {
+ return QMetaMethodPrivate::get(this)->signature();
+ } else {
+ const char *sig = rawStringData(mobj, mobj->d.data[handle]);
+ return QByteArray::fromRawData(sig, qstrlen(sig));
+ }
+}
+
+/*!
+ \since 5.0
+
+ Returns the name of this method.
+
+ \sa methodSignature(), parameterCount()
+*/
+QByteArray QMetaMethod::name() const
+{
+ if (!mobj)
+ return QByteArray();
+ return QMetaMethodPrivate::get(this)->name();
+}
+
+/*!
+ \since 5.0
+
+ Returns the return type of this method.
+
+ The return value is one of the types that are registered
+ with QMetaType, or QMetaType::UnknownType if the type is not registered.
+
+ \sa parameterType(), QMetaType, typeName()
+*/
+int QMetaMethod::returnType() const
+ {
+ if (!mobj)
+ return QMetaType::UnknownType;
+ return QMetaMethodPrivate::get(this)->returnType();
+}
+
+/*!
+ \since 5.0
+
+ Returns the number of parameters of this method.
+
+ \sa parameterType(), parameterNames()
+*/
+int QMetaMethod::parameterCount() const
{
if (!mobj)
return 0;
- return mobj->d.stringdata + mobj->d.data[handle];
+ return QMetaMethodPrivate::get(this)->parameterCount();
+}
+
+/*!
+ \since 5.0
+
+ Returns the type of the parameter at the given \a index.
+
+ The return value is one of the types that are registered
+ with QMetaType, or QMetaType::UnknownType if the type is not registered.
+
+ \sa parameterCount(), returnType(), QMetaType
+*/
+int QMetaMethod::parameterType(int index) const
+{
+ if (!mobj || index < 0)
+ return QMetaType::UnknownType;
+ if (index >= QMetaMethodPrivate::get(this)->parameterCount())
+ return QMetaType::UnknownType;
+ return QMetaMethodPrivate::get(this)->parameterType(index);
+}
+
+/*!
+ \since 5.0
+ \internal
+
+ Gets the parameter \a types of this method. The storage
+ for \a types must be able to hold parameterCount() items.
+
+ \sa parameterCount(), returnType(), parameterType()
+*/
+void QMetaMethod::getParameterTypes(int *types) const
+{
+ if (!mobj)
+ return;
+ QMetaMethodPrivate::get(this)->getParameterTypes(types);
}
/*!
Returns a list of parameter types.
- \sa parameterNames(), signature()
+ \sa parameterNames(), methodSignature()
*/
QList<QByteArray> QMetaMethod::parameterTypes() const
{
if (!mobj)
return QList<QByteArray>();
- return QMetaObjectPrivate::parameterTypeNamesFromSignature(
- mobj->d.stringdata + mobj->d.data[handle]);
+ if (priv(mobj->d.data)->revision >= 7) {
+ return QMetaMethodPrivate::get(this)->parameterTypes();
+ } else {
+ return QMetaObjectPrivate::parameterTypeNamesFromSignature(
+ legacyString(mobj, mobj->d.data[handle]));
+ }
}
/*!
Returns a list of parameter names.
- \sa parameterTypes(), signature()
+ \sa parameterTypes(), methodSignature()
*/
QList<QByteArray> QMetaMethod::parameterNames() const
{
QList<QByteArray> list;
if (!mobj)
return list;
- const char *names = mobj->d.stringdata + 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];
- while (*signature && *signature != '(')
- ++signature;
- if (*++signature != ')')
- list += QByteArray();
+ if (priv(mobj->d.data)->revision >= 7) {
+ return QMetaMethodPrivate::get(this)->parameterNames();
} else {
- --names;
- do {
- const char *begin = ++names;
- while (*names && *names != ',')
- ++names;
- list += QByteArray(begin, names - begin);
- } while (*names);
+ const char *names = rawStringData(mobj, mobj->d.data[handle + 1]);
+ if (*names == 0) {
+ // do we have one or zero arguments?
+ const char *signature = rawStringData(mobj, mobj->d.data[handle]);
+ while (*signature && *signature != '(')
+ ++signature;
+ if (*++signature != ')')
+ list += QByteArray();
+ } else {
+ --names;
+ do {
+ const char *begin = ++names;
+ while (*names && *names != ',')
+ ++names;
+ list += QByteArray(begin, names - begin);
+ } while (*names);
+ }
+ return list;
}
- return list;
}
/*!
- Returns the return type of this method, or an empty string if the
+ Returns the return type name of this method, or an empty string if the
return type is \e void.
*/
const char *QMetaMethod::typeName() const
{
if (!mobj)
return 0;
- return mobj->d.stringdata + mobj->d.data[handle + 2];
+ if (priv(mobj->d.data)->revision >= 7)
+ return QMetaMethodPrivate::get(this)->rawReturnTypeName();
+ else
+ return legacyString(mobj, mobj->d.data[handle + 2]);
}
/*!
@@ -1377,7 +1952,10 @@ const char *QMetaMethod::tag() const
{
if (!mobj)
return 0;
- return mobj->d.stringdata + mobj->d.data[handle + 3];
+ if (priv(mobj->d.data)->revision >= 7)
+ return QMetaMethodPrivate::get(this)->tag().constData();
+ else
+ return legacyString(mobj, mobj->d.data[handle + 3]);
}
@@ -1578,12 +2156,14 @@ bool QMetaMethod::invoke(QObject *object,
break;
}
int metaMethodArgumentCount = 0;
- {
+ if (priv(mobj->d.data)->revision >= 7) {
+ metaMethodArgumentCount = QMetaMethodPrivate::get(this)->parameterCount();
+ } else {
// 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 != ')')
@@ -1661,7 +2241,7 @@ bool QMetaMethod::invoke(QObject *object,
for (int i = 1; i < paramCount; ++i) {
types[i] = QMetaType::type(typeNames[i]);
- if (types[i]) {
+ if (types[i] != QMetaType::UnknownType) {
args[i] = QMetaType::create(types[i], param[i]);
++nargs;
} else if (param[i]) {
@@ -1803,7 +2383,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 +2411,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 +2458,7 @@ bool QMetaEnum::isFlag() const
*/
const char *QMetaEnum::scope() const
{
- return mobj?mobj->d.stringdata : 0;
+ return mobj?rawStringData(mobj, 0) : 0;
}
/*!
@@ -1910,8 +2490,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 +2516,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 +2559,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 +2593,10 @@ QByteArray QMetaEnum::valueToKeys(int value) const
v = v & ~k;
if (!keys.isEmpty())
keys += '|';
- keys += mobj->d.stringdata + mobj->d.data[data + 2*i];
+ if (priv(mobj->d.data)->revision >= 7)
+ keys += toByteArray(stringData(mobj, mobj->d.data[data + 2*i]));
+ else
+ keys += legacyString(mobj, mobj->d.data[data + 2*i]);
}
}
return keys;
@@ -2092,7 +2675,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 +2688,10 @@ 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];
+ if (priv(mobj->d.data)->revision >= 7)
+ return rawTypeNameFromTypeInfo(mobj, mobj->d.data[handle + 1]);
+ else
+ return legacyString(mobj, mobj->d.data[handle + 1]);
}
/*!
@@ -2119,14 +2705,21 @@ QVariant::Type QMetaProperty::type() const
if (!mobj)
return QVariant::Invalid;
int handle = priv(mobj->d.data)->propertyData + 3*idx;
- uint flags = mobj->d.data[handle + 2];
- uint type = flags >> 24;
- if (type)
+ uint type;
+ if (priv(mobj->d.data)->revision >= 7) {
+ type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]);
+ if (type >= QMetaType::User)
+ return QVariant::UserType;
+ } else {
+ uint flags = mobj->d.data[handle + 2];
+ type = flags >> 24;
+ }
+ if (type != QMetaType::UnknownType)
return QVariant::Type(type);
if (isEnumType()) {
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
- if (enumMetaTypeId == 0)
+ if (enumMetaTypeId == QMetaType::UnknownType)
return QVariant::Int;
}
#ifdef QT_COORD_TYPE
@@ -2142,18 +2735,29 @@ QVariant::Type QMetaProperty::type() const
\since 4.2
Returns this property's user type. The return value is one
- of the values that are registered with QMetaType, or 0 if
+ of the values that are registered with QMetaType, or QMetaType::UnknownType if
the type is not registered.
\sa type(), QMetaType, typeName()
*/
int QMetaProperty::userType() const
{
- QVariant::Type tp = type();
- if (tp != QVariant::UserType)
- return tp;
+ if (!mobj)
+ return QMetaType::UnknownType;
+ if (priv(mobj->d.data)->revision >= 7) {
+ int handle = priv(mobj->d.data)->propertyData + 3*idx;
+ int type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]);
+ if (type != QMetaType::UnknownType)
+ return type;
+ } else {
+ QVariant::Type tp = type();
+ if (tp != QVariant::UserType)
+ return tp;
+ }
if (isEnumType()) {
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
+ if (enumMetaTypeId == QMetaType::UnknownType)
+ return QVariant::Int; // Match behavior of QMetaType::type()
return enumMetaTypeId;
}
return QMetaType::type(typeName());
@@ -2249,18 +2853,30 @@ QVariant QMetaProperty::read(const QObject *object) const
with QMetaType)
*/
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
- if (enumMetaTypeId != 0)
+ if (enumMetaTypeId != QMetaType::UnknownType)
t = enumMetaTypeId;
} 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];
- t = (flags >> 24);
- if (t == QVariant::Invalid)
- t = QMetaType::type(typeName);
- if (t == QVariant::Invalid)
- t = QVariant::nameToType(typeName);
- if (t == QVariant::Invalid) {
+ const char *typeName = 0;
+ if (priv(mobj->d.data)->revision >= 7) {
+ uint typeInfo = mobj->d.data[handle + 1];
+ if (!(typeInfo & IsUnresolvedType))
+ t = typeInfo;
+ else {
+ typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask);
+ t = QMetaType::type(typeName);
+ }
+ } else {
+ uint flags = mobj->d.data[handle + 2];
+ t = (flags >> 24);
+ if (t == QMetaType::UnknownType) {
+ typeName = legacyString(mobj, mobj->d.data[handle + 1]);
+ t = QMetaType::type(typeName);
+ if (t == QMetaType::UnknownType)
+ t = QVariant::nameToType(typeName);
+ }
+ }
+ if (t == QMetaType::UnknownType) {
qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property '%s::%s'", typeName, mobj->className(), name());
return QVariant();
}
@@ -2315,17 +2931,29 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
return false;
} else if (v.type() != QVariant::Int && v.type() != QVariant::UInt) {
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
- if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
+ if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
return false;
v = QVariant(*reinterpret_cast<const int *>(v.constData()));
}
v.convert(QVariant::Int);
} else {
int handle = priv(mobj->d.data)->propertyData + 3*idx;
- 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 = 0;
+ if (priv(mobj->d.data)->revision >= 7) {
+ uint typeInfo = mobj->d.data[handle + 1];
+ if (!(typeInfo & IsUnresolvedType))
+ t = typeInfo;
+ else {
+ typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask);
+ t = QMetaType::type(typeName);
+ }
+ } else {
+ uint flags = mobj->d.data[handle + 2];
+ t = flags >> 24;
+ typeName = legacyString(mobj, mobj->d.data[handle + 1]);
+ }
+ if (t == QMetaType::UnknownType) {
+ 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 +3319,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 +3331,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]);
}
/*!
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 9e51af7556..095b196dca 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -57,8 +57,13 @@ class Q_CORE_EXPORT QMetaMethod
public:
inline QMetaMethod() : mobj(0),handle(0) {}
- const char *signature() const;
+ QByteArray methodSignature() const;
+ QByteArray name() const;
const char *typeName() const;
+ int returnType() const;
+ int parameterCount() const;
+ int parameterType(int index) const;
+ void getParameterTypes(int *types) const;
QList<QByteArray> parameterTypes() const;
QList<QByteArray> parameterNames() const;
const char *tag() const;
@@ -137,8 +142,16 @@ public:
inline bool isValid() const { return mobj != 0; }
private:
+#if QT_DEPRECATED_SINCE(5,0)
+ // signature() has been renamed to methodSignature() in Qt 5.
+ // Warning, that function returns a QByteArray; check the life time if
+ // you convert to char*.
+ char *signature(struct renamedInQt5_warning_checkTheLifeTime * = 0) Q_DECL_EQ_DELETE;
+#endif
+
const QMetaObject *mobj;
uint handle;
+ friend class QMetaMethodPrivate;
friend struct QMetaObject;
friend struct QMetaObjectPrivate;
friend class QObject;
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 59a5c5f280..ff8dccc4dd 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -105,11 +105,64 @@ enum MetaObjectFlags {
RequiresVariantMetaObject = 0x02
};
+enum MetaDataFlags {
+ IsUnresolvedType = 0x80000000,
+ TypeNameIndexMask = 0x7FFFFFFF
+};
+
+class QArgumentType
+{
+public:
+ QArgumentType(int type)
+ : _type(type)
+ {}
+ QArgumentType(const QByteArray &name)
+ : _type(QMetaType::type(name.constData())), _name(name)
+ {}
+ QArgumentType()
+ : _type(0)
+ {}
+ int type() const
+ { return _type; }
+ QByteArray name() const
+ {
+ if (_type && _name.isEmpty())
+ const_cast<QArgumentType *>(this)->_name = QMetaType::typeName(_type);
+ return _name;
+ }
+ bool operator==(const QArgumentType &other) const
+ {
+ if (_type)
+ return _type == other._type;
+ else if (other._type)
+ return false;
+ else
+ return _name == other._name;
+ }
+ bool operator!=(const QArgumentType &other) const
+ {
+ if (_type)
+ return _type != other._type;
+ else if (other._type)
+ return true;
+ else
+ return _name != other._name;
+ }
+
+private:
+ int _type;
+ QByteArray _name;
+};
+
+template <class T, int> class QVarLengthArray;
+typedef QVarLengthArray<QArgumentType, 10> QArgumentTypeArray;
+
+class QMetaMethodPrivate;
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,6 +175,7 @@ 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); }
@@ -134,6 +188,27 @@ struct QMetaObjectPrivate
bool normalizeStringData);
static int originalClone(const QMetaObject *obj, int local_method_index);
+ static QByteArray decodeMethodSignature(const char *signature,
+ QArgumentTypeArray &types);
+ static int indexOfSignalRelative(const QMetaObject **baseObject,
+ const QByteArray &name, int argc,
+ const QArgumentType *types);
+ static int indexOfSlotRelative(const QMetaObject **m,
+ const QByteArray &name, int argc,
+ const QArgumentType *types);
+ static int indexOfSignal(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static int indexOfSlot(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static int indexOfMethod(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static int indexOfConstructor(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
+ int methodArgc, const QArgumentType *methodTypes);
+ static bool checkConnectArgs(const QMetaMethodPrivate *signal,
+ const QMetaMethodPrivate *method);
+
static QList<QByteArray> parameterTypeNamesFromSignature(const char *signature);
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index 8bece6636b..13cd1a684a 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -78,26 +78,17 @@ QT_BEGIN_NAMESPACE
*/
// copied from moc's generator.cpp
-uint qvariant_nameToType(const char* name)
+bool isBuiltinType(const QByteArray &type)
{
- if (!name)
- return 0;
-
- uint tp = QMetaType::type(name);
- return tp < QMetaType::User ? tp : 0;
-}
-
-/*
- Returns true if the type is a QVariant types.
-*/
-bool isVariantType(const char* type)
-{
- return qvariant_nameToType(type) != 0;
+ int id = QMetaType::type(type);
+ if (!id && !type.isEmpty() && type != "void")
+ return false;
+ return (id < QMetaType::User);
}
+// copied from qmetaobject.cpp
static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
-// end of copied lines from qmetaobject.cpp
class QMetaMethodBuilderPrivate
{
@@ -136,6 +127,21 @@ public:
{
attributes = ((attributes & ~AccessMask) | (int)value);
}
+
+ QList<QByteArray> parameterTypes() const
+ {
+ return QMetaObjectPrivate::parameterTypeNamesFromSignature(signature);
+ }
+
+ int parameterCount() const
+ {
+ return parameterTypes().size();
+ }
+
+ QByteArray name() const
+ {
+ return signature.left(qMax(signature.indexOf('('), 0));
+ }
};
class QMetaPropertyBuilderPrivate
@@ -458,13 +464,13 @@ QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype)
{
QMetaMethodBuilder method;
if (prototype.methodType() == QMetaMethod::Method)
- method = addMethod(prototype.signature());
+ method = addMethod(prototype.methodSignature());
else if (prototype.methodType() == QMetaMethod::Signal)
- method = addSignal(prototype.signature());
+ method = addSignal(prototype.methodSignature());
else if (prototype.methodType() == QMetaMethod::Slot)
- method = addSlot(prototype.signature());
+ method = addSlot(prototype.methodSignature());
else if (prototype.methodType() == QMetaMethod::Constructor)
- method = addConstructor(prototype.signature());
+ method = addConstructor(prototype.methodSignature());
method.setReturnType(prototype.typeName());
method.setParameterNames(prototype.parameterNames());
method.setTag(prototype.tag());
@@ -535,7 +541,7 @@ QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signatur
QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype)
{
Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor);
- QMetaMethodBuilder ctor = addConstructor(prototype.signature());
+ QMetaMethodBuilder ctor = addConstructor(prototype.methodSignature());
ctor.setReturnType(prototype.typeName());
ctor.setParameterNames(prototype.parameterNames());
ctor.setTag(prototype.tag());
@@ -588,7 +594,7 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& protot
if (prototype.hasNotifySignal()) {
// Find an existing method for the notify signal, or add a new one.
QMetaMethod method = prototype.notifySignal();
- int index = indexOfMethod(method.signature());
+ int index = indexOfMethod(method.methodSignature());
if (index == -1)
index = addMethod(method).index();
d->properties[property._index].notifySignal = index;
@@ -1070,75 +1076,82 @@ int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name)
#define ALIGN(size,type) \
(size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1)
-class MetaStringTable
+/*!
+ \class QMetaStringTable
+ \internal
+ \brief The QMetaStringTable class can generate a meta-object string table at runtime.
+*/
+
+QMetaStringTable::QMetaStringTable()
+ : m_index(0) {}
+
+// Enters the given value into the string table (if it hasn't already been
+// entered). Returns the index of the string.
+int QMetaStringTable::enter(const QByteArray &value)
{
-public:
- typedef QHash<QByteArray, int> Entries; // string --> offset mapping
- typedef Entries::const_iterator const_iterator;
- Entries::const_iterator constBegin() const
- { return m_entries.constBegin(); }
- Entries::const_iterator constEnd() const
- { return m_entries.constEnd(); }
+ Entries::iterator it = m_entries.find(value);
+ if (it != m_entries.end())
+ return it.value();
+ int pos = m_index;
+ m_entries.insert(value, pos);
+ ++m_index;
+ return pos;
+}
- MetaStringTable() : m_offset(0) {}
+int QMetaStringTable::preferredAlignment()
+{
+#ifdef Q_ALIGNOF
+ return Q_ALIGNOF(QByteArrayData);
+#else
+ return sizeof(void *);
+#endif
+}
- int enter(const QByteArray &value)
- {
- Entries::iterator it = m_entries.find(value);
- if (it != m_entries.end())
- return it.value();
- int pos = m_offset;
- m_entries.insert(value, pos);
- m_offset += value.size() + 1;
- return pos;
- }
+// Returns the size (in bytes) required for serializing this string table.
+int QMetaStringTable::blobSize() const
+{
+ int size = m_entries.size() * sizeof(QByteArrayData);
+ Entries::const_iterator it;
+ for (it = m_entries.constBegin(); it != m_entries.constEnd(); ++it)
+ size += it.key().size() + 1;
+ return size;
+}
- int arraySize() const { return m_offset; }
+// Writes strings to string data struct.
+// The struct consists of an array of QByteArrayData, followed by a char array
+// containing the actual strings. This format must match the one produced by
+// moc (see generator.cpp).
+void QMetaStringTable::writeBlob(char *out)
+{
+ Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (preferredAlignment()-1)));
-private:
- Entries m_entries;
- int m_offset;
-};
+ int offsetOfStringdataMember = m_entries.size() * sizeof(QByteArrayData);
+ int stringdataOffset = 0;
+ for (int i = 0; i < m_entries.size(); ++i) {
+ const QByteArray &str = m_entries.key(i);
+ int size = str.size();
+ qptrdiff offset = offsetOfStringdataMember + stringdataOffset
+ - i * sizeof(QByteArrayData);
+ const QByteArrayData data = { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset };
-// Build the parameter array string for a method.
-static QByteArray buildParameterNames
- (const QByteArray& signature, const QList<QByteArray>& parameterNames)
-{
- // If the parameter name list is specified, then concatenate them.
- if (!parameterNames.isEmpty()) {
- QByteArray names;
- bool first = true;
- foreach (const QByteArray &name, parameterNames) {
- if (first)
- first = false;
- else
- names += (char)',';
- names += name;
- }
- return names;
- }
+ memcpy(out + i * sizeof(QByteArrayData), &data, sizeof(QByteArrayData));
- // Count commas in the signature, excluding those inside template arguments.
- int index = signature.indexOf('(');
- if (index < 0)
- return QByteArray();
- ++index;
- if (index >= signature.size())
- return QByteArray();
- if (signature[index] == ')')
- return QByteArray();
- int count = 1;
- int brackets = 0;
- while (index < signature.size() && signature[index] != ',') {
- char ch = signature[index++];
- if (ch == '<')
- ++brackets;
- else if (ch == '>')
- --brackets;
- else if (ch == ',' && brackets <= 0)
- ++count;
+ memcpy(out + offsetOfStringdataMember + stringdataOffset, str.constData(), size);
+ out[offsetOfStringdataMember + stringdataOffset + size] = '\0';
+
+ stringdataOffset += size + 1;
}
- return QByteArray(count - 1, ',');
+}
+
+// Returns the sum of all parameters (including return type) for the given
+// \a methods. This is needed for calculating the size of the methods'
+// parameter type/name meta-data.
+static int aggregateParameterCount(const QList<QMetaMethodBuilderPrivate> &methods)
+{
+ int sum = 0;
+ for (int i = 0; i < methods.size(); ++i)
+ sum += methods.at(i).parameterCount() + 1; // +1 for return type
+ return sum;
}
// Build a QMetaObject in "buf" based on the information in "d".
@@ -1151,6 +1164,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_UNUSED(expectedSize); // Avoid warning in release mode
int size = 0;
int dataIndex;
+ int paramsIndex;
int enumIndex;
int index;
bool hasRevisionedMethods = d->hasRevisionedMethods();
@@ -1181,8 +1195,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
break;
}
}
+ int methodParametersDataSize =
+ ((aggregateParameterCount(d->methods)
+ + aggregateParameterCount(d->constructors)) * 2) // types and parameter names
+ - d->methods.size() // return "parameters" don't have names
+ - d->constructors.size(); // "this" parameters don't have names
if (buf) {
- Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 6, "QMetaObjectBuilder should generate the same version as moc");
+ Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "QMetaObjectBuilder should generate the same version as moc");
pmeta->revision = QMetaObjectPrivate::OutputRevision;
pmeta->flags = d->flags;
pmeta->className = 0; // Class name is always the first string.
@@ -1197,6 +1216,8 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
dataIndex += 5 * d->methods.size();
if (hasRevisionedMethods)
dataIndex += d->methods.size();
+ paramsIndex = dataIndex;
+ dataIndex += methodParametersDataSize;
pmeta->propertyCount = d->properties.size();
pmeta->propertyData = dataIndex;
@@ -1218,6 +1239,8 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
dataIndex += 5 * d->methods.size();
if (hasRevisionedMethods)
dataIndex += d->methods.size();
+ paramsIndex = dataIndex;
+ dataIndex += methodParametersDataSize;
dataIndex += 3 * d->properties.size();
if (hasNotifySignals)
dataIndex += d->properties.size();
@@ -1240,13 +1263,14 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
// Find the start of the data and string tables.
int *data = reinterpret_cast<int *>(pmeta);
size += dataIndex * sizeof(int);
+ ALIGN(size, void *);
char *str = reinterpret_cast<char *>(buf + size);
if (buf) {
if (relocatable) {
- meta->d.stringdata = reinterpret_cast<const char *>((quintptr)size);
+ meta->d.stringdata = reinterpret_cast<const QByteArrayData *>((quintptr)size);
meta->d.data = reinterpret_cast<uint *>((quintptr)pmetaSize);
} else {
- meta->d.stringdata = str;
+ meta->d.stringdata = reinterpret_cast<const QByteArrayData *>(str);
meta->d.data = reinterpret_cast<uint *>(data);
}
}
@@ -1254,7 +1278,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
// Reset the current data position to just past the QMetaObjectPrivate.
dataIndex = MetaObjectPrivateFieldCount;
- MetaStringTable strings;
+ QMetaStringTable strings;
strings.enter(d->className);
// Output the class infos,
@@ -1273,24 +1297,21 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->methodData);
for (index = 0; index < d->methods.size(); ++index) {
QMetaMethodBuilderPrivate *method = &(d->methods[index]);
- int sig = strings.enter(method->signature);
- int params;
- QByteArray names = buildParameterNames
- (method->signature, method->parameterNames);
- params = strings.enter(names);
- int ret = strings.enter(method->returnType);
+ int name = strings.enter(method->name());
+ int argc = method->parameterCount();
int tag = strings.enter(method->tag);
int attrs = method->attributes;
if (buf) {
- data[dataIndex] = sig;
- data[dataIndex + 1] = params;
- data[dataIndex + 2] = ret;
+ data[dataIndex] = name;
+ data[dataIndex + 1] = argc;
+ data[dataIndex + 2] = paramsIndex;
data[dataIndex + 3] = tag;
data[dataIndex + 4] = attrs;
if (method->methodType() == QMetaMethod::Signal)
pmeta->signalCount++;
}
dataIndex += 5;
+ paramsIndex += 1 + argc * 2;
}
if (hasRevisionedMethods) {
for (index = 0; index < d->methods.size(); ++index) {
@@ -1301,23 +1322,59 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
}
}
+ // Output the method parameters in the class.
+ Q_ASSERT(!buf || dataIndex == pmeta->methodData + d->methods.size() * 5
+ + (hasRevisionedMethods ? d->methods.size() : 0));
+ for (int x = 0; x < 2; ++x) {
+ QList<QMetaMethodBuilderPrivate> &methods = (x == 0) ? d->methods : d->constructors;
+ for (index = 0; index < methods.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(methods[index]);
+ QList<QByteArray> paramTypeNames = method->parameterTypes();
+ int paramCount = paramTypeNames.size();
+ for (int i = -1; i < paramCount; ++i) {
+ const QByteArray &typeName = (i < 0) ? method->returnType : paramTypeNames.at(i);
+ int typeInfo;
+ if (isBuiltinType(typeName))
+ typeInfo = QMetaType::type(typeName);
+ else
+ typeInfo = IsUnresolvedType | strings.enter(typeName);
+ if (buf)
+ data[dataIndex] = typeInfo;
+ ++dataIndex;
+ }
+
+ QList<QByteArray> paramNames = method->parameterNames;
+ while (paramNames.size() < paramCount)
+ paramNames.append(QByteArray());
+ for (int i = 0; i < paramCount; ++i) {
+ int stringIndex = strings.enter(paramNames.at(i));
+ if (buf)
+ data[dataIndex] = stringIndex;
+ ++dataIndex;
+ }
+ }
+ }
+
// Output the properties in the class.
Q_ASSERT(!buf || dataIndex == pmeta->propertyData);
for (index = 0; index < d->properties.size(); ++index) {
QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
int name = strings.enter(prop->name);
- int type = strings.enter(prop->type);
+
+ int typeInfo;
+ if (isBuiltinType(prop->type))
+ typeInfo = QMetaType::type(prop->type);
+ else
+ typeInfo = IsUnresolvedType | strings.enter(prop->type);
+
int flags = prop->flags;
- if (!isVariantType(prop->type)) {
+ if (!isBuiltinType(prop->type))
flags |= EnumOrFlag;
- } else {
- flags |= qvariant_nameToType(prop->type) << 24;
- }
if (buf) {
data[dataIndex] = name;
- data[dataIndex + 1] = type;
+ data[dataIndex + 1] = typeInfo;
data[dataIndex + 2] = flags;
}
dataIndex += 3;
@@ -1372,34 +1429,25 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->constructorData);
for (index = 0; index < d->constructors.size(); ++index) {
QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
- int sig = strings.enter(method->signature);
- int params;
- QByteArray names = buildParameterNames
- (method->signature, method->parameterNames);
- params = strings.enter(names);
- int ret = strings.enter(method->returnType);
+ int name = strings.enter(method->name());
+ int argc = method->parameterCount();
int tag = strings.enter(method->tag);
int attrs = method->attributes;
if (buf) {
- data[dataIndex] = sig;
- data[dataIndex + 1] = params;
- data[dataIndex + 2] = ret;
+ data[dataIndex] = name;
+ data[dataIndex + 1] = argc;
+ data[dataIndex + 2] = paramsIndex;
data[dataIndex + 3] = tag;
data[dataIndex + 4] = attrs;
}
dataIndex += 5;
+ paramsIndex += 1 + argc * 2;
}
- size += strings.arraySize();
+ size += strings.blobSize();
- if (buf) {
- // Write strings to string data array.
- MetaStringTable::const_iterator it;
- for (it = strings.constBegin(); it != strings.constEnd(); ++it) {
- memcpy(str + it.value(), it.key().constData(), it.key().size());
- str[it.value() + it.key().size()] = '\0';
- }
- }
+ if (buf)
+ strings.writeBlob(str);
// Output the zero terminator in the data array.
if (buf)
@@ -1508,7 +1556,7 @@ void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output,
quintptr dataOffset = (quintptr)dataMo->d.data;
output->d.superdata = superclass;
- output->d.stringdata = buf + stringdataOffset;
+ output->d.stringdata = reinterpret_cast<const QByteArrayData *>(buf + stringdataOffset);
output->d.data = reinterpret_cast<const uint *>(buf + dataOffset);
output->d.extradata = 0;
}
@@ -1896,7 +1944,7 @@ QByteArray QMetaMethodBuilder::returnType() const
is empty, then the method's return type is \c{void}. The \a value
will be normalized before it is added to the method.
- \sa returnType(), signature()
+ \sa returnType(), parameterTypes(), signature()
*/
void QMetaMethodBuilder::setReturnType(const QByteArray& value)
{
@@ -1906,6 +1954,20 @@ void QMetaMethodBuilder::setReturnType(const QByteArray& value)
}
/*!
+ Returns the list of parameter types for this method.
+
+ \sa returnType(), parameterNames()
+*/
+QList<QByteArray> QMetaMethodBuilder::parameterTypes() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->parameterTypes();
+ else
+ return QList<QByteArray>();
+}
+
+/*!
Returns the list of parameter names for this method.
\sa setParameterNames()
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index 86bc354164..4d766a9197 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -56,6 +56,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qdatastream.h>
+#include <QtCore/qhash.h>
#include <QtCore/qmap.h>
@@ -203,6 +204,7 @@ public:
QByteArray returnType() const;
void setReturnType(const QByteArray& value);
+ QList<QByteArray> parameterTypes() const;
QList<QByteArray> parameterNames() const;
void setParameterNames(const QList<QByteArray>& value);
@@ -318,6 +320,23 @@ private:
QMetaEnumBuilderPrivate *d_func() const;
};
+class Q_CORE_EXPORT QMetaStringTable
+{
+public:
+ QMetaStringTable();
+
+ int enter(const QByteArray &value);
+
+ static int preferredAlignment();
+ int blobSize() const;
+ void writeBlob(char *out);
+
+private:
+ typedef QHash<QByteArray, int> Entries; // string --> index mapping
+ Entries m_entries;
+ int m_index;
+};
+
Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers)
Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags)
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 410a5cc712..a5dc179113 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -242,6 +242,7 @@ template<> struct TypeDefinition<QRegExp> { static const bool IsAvailable = fals
\value QEasingCurve QEasingCurve
\value User Base value for user types
+ \value UnknownType This is an invalid type id. It is returned from QMetaType for types that are not registered
\omitvalue FirstGuiType
\omitvalue FirstWidgetsType
@@ -311,7 +312,7 @@ static const struct { const char * typeName; int typeNameLength; int type; } typ
QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE)
QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER)
QT_FOR_EACH_STATIC_HACKS_TYPE(QT_ADD_STATIC_METATYPE_HACKS_ITER)
- {0, 0, QMetaType::Void}
+ {0, 0, QMetaType::UnknownType}
};
Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper = 0;
@@ -348,10 +349,7 @@ Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveOp,
LoadOperator loadOp)
{
- int idx = type(typeName);
- if (!idx)
- return;
- registerStreamOperators(idx, saveOp, loadOp);
+ registerStreamOperators(type(typeName), saveOp, loadOp);
}
/*! \internal
@@ -434,7 +432,7 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length)
{
const QVector<QCustomTypeInfo> * const ct = customTypes();
if (!ct)
- return 0;
+ return QMetaType::UnknownType;
for (int v = 0; v < ct->count(); ++v) {
const QCustomTypeInfo &customInfo = ct->at(v);
@@ -445,7 +443,7 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length)
return v + QMetaType::User;
}
}
- return 0;
+ return QMetaType::UnknownType;
}
/*! \internal
@@ -488,11 +486,11 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
int previousSize = 0;
int previousFlags = 0;
- if (!idx) {
+ if (idx == UnknownType) {
QWriteLocker locker(customTypesLock());
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size());
- if (!idx) {
+ if (idx == UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
inf.creator = creator;
@@ -558,12 +556,12 @@ int QMetaType::registerTypedef(const char* typeName, int aliasId)
int idx = qMetaTypeStaticType(normalizedTypeName.constData(),
normalizedTypeName.size());
- if (!idx) {
+ if (idx == UnknownType) {
QWriteLocker locker(customTypesLock());
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size());
- if (!idx) {
+ if (idx == UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
inf.alias = aliasId;
@@ -592,17 +590,20 @@ int QMetaType::registerTypedef(const char* typeName, int aliasId)
*/
bool QMetaType::isRegistered(int type)
{
- if (type >= 0 && type < User) {
- // predefined type
+ // predefined type
+ if ((type >= FirstCoreType && type <= LastCoreType)
+ || (type >= FirstGuiType && type <= LastGuiType)
+ || (type >= FirstWidgetsType && type <= LastWidgetsType)) {
return true;
}
+
QReadLocker locker(customTypesLock());
const QVector<QCustomTypeInfo> * const ct = customTypes();
return ((type >= User) && (ct && ct->count() > type - User) && !ct->at(type - User).typeName.isEmpty());
}
/*!
- Returns a handle to the type called \a typeName, or 0 if there is
+ Returns a handle to the type called \a typeName, or QMetaType::UnknownType if there is
no such type.
\sa isRegistered(), typeName(), Type
@@ -611,17 +612,17 @@ int QMetaType::type(const char *typeName)
{
int length = qstrlen(typeName);
if (!length)
- return 0;
+ return UnknownType;
int type = qMetaTypeStaticType(typeName, length);
- if (!type) {
+ if (type == UnknownType) {
QReadLocker locker(customTypesLock());
type = qMetaTypeCustomType_unlocked(typeName, length);
#ifndef QT_NO_QOBJECT
- if (!type) {
+ if (type == UnknownType) {
const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName);
type = qMetaTypeStaticType(normalizedTypeName.constData(),
normalizedTypeName.size());
- if (!type) {
+ if (type == UnknownType) {
type = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size());
}
@@ -652,6 +653,7 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
return false;
switch(type) {
+ case QMetaType::UnknownType:
case QMetaType::Void:
case QMetaType::VoidStar:
case QMetaType::QObjectStar:
@@ -857,6 +859,7 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
return false;
switch(type) {
+ case QMetaType::UnknownType:
case QMetaType::Void:
case QMetaType::VoidStar:
case QMetaType::QObjectStar:
@@ -1154,6 +1157,7 @@ void *QMetaType::create(int type, const void *copy)
case QMetaType::QModelIndex:
return new NS(QModelIndex)(*static_cast<const NS(QModelIndex)*>(copy));
#endif
+ case QMetaType::UnknownType:
case QMetaType::Void:
return 0;
default:
@@ -1257,6 +1261,7 @@ void *QMetaType::create(int type, const void *copy)
case QMetaType::QModelIndex:
return new NS(QModelIndex);
#endif
+ case QMetaType::UnknownType:
case QMetaType::Void:
return 0;
default:
@@ -1318,6 +1323,7 @@ public:
template<typename T>
void delegate(const T *where) { DestroyerImpl<T>::Destroy(m_type, const_cast<T*>(where)); }
void delegate(const void *) {}
+ void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestroyer(m_type, (void*)where); }
private:
@@ -1381,6 +1387,7 @@ public:
template<typename T>
void *delegate(const T *copy) { return ConstructorImpl<T>::Construct(m_type, m_where, copy); }
void *delegate(const void *) { return m_where; }
+ void *delegate(const QMetaTypeSwitcher::UnknownType*) { return m_where; }
void *delegate(const QMetaTypeSwitcher::NotBuiltinType *copy) { return customTypeConstructor(m_type, m_where, copy); }
private:
@@ -1470,6 +1477,7 @@ public:
template<typename T>
void delegate(const T *where) { DestructorImpl<T>::Destruct(m_type, const_cast<T*>(where)); }
void delegate(const void *) {}
+ void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestructor(m_type, (void*)where); }
private:
@@ -1539,6 +1547,7 @@ public:
template<typename T>
int delegate(const T*) { return SizeOfImpl<T>::Size(m_type); }
+ int delegate(const QMetaTypeSwitcher::UnknownType*) { return 0; }
int delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeSizeOf(m_type); }
private:
static int customTypeSizeOf(const int type)
@@ -1609,13 +1618,14 @@ public:
template<typename T>
quint32 delegate(const T*) { return FlagsImpl<T>::Flags(m_type); }
quint32 delegate(const void*) { return 0; }
+ quint32 delegate(const QMetaTypeSwitcher::UnknownType*) { return 0; }
quint32 delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeFlags(m_type); }
private:
const int m_type;
static quint32 customTypeFlags(const int type)
{
const QVector<QCustomTypeInfo> * const ct = customTypes();
- if (Q_UNLIKELY(!ct))
+ if (Q_UNLIKELY(!ct || type < QMetaType::User))
return 0;
QReadLocker locker(customTypesLock());
if (Q_UNLIKELY(ct->count() <= type - QMetaType::User))
@@ -1796,6 +1806,7 @@ public:
template<typename T>
void delegate(const T*) { TypeInfoImpl<T>(m_type, info); }
void delegate(const void*) {}
+ void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType*) { customTypeInfo(m_type); }
private:
void customTypeInfo(const uint type)
@@ -1816,7 +1827,7 @@ QMetaType QMetaType::typeInfo(const int type)
{
TypeInfo typeInfo(type);
QMetaTypeSwitcher::switcher<void>(typeInfo, type, 0);
- return typeInfo.info.creator || !type ? QMetaType(QMetaType::NoExtensionFlags
+ return typeInfo.info.creator || type == Void ? QMetaType(QMetaType::NoExtensionFlags
, static_cast<const QMetaTypeInterface *>(0) // typeInfo::info is a temporary variable, we can't return address of it.
, typeInfo.info.creator
, typeInfo.info.deleter
@@ -1827,26 +1838,23 @@ QMetaType QMetaType::typeInfo(const int type)
, typeInfo.info.size
, typeInfo.info.flags
, type)
- : QMetaType(-1);
+ : QMetaType(UnknownType);
}
QMetaType::QMetaType(const int typeId)
: m_typeId(typeId)
{
- if (Q_UNLIKELY(typeId == -1)) {
+ if (Q_UNLIKELY(typeId == UnknownType)) {
// Constructs invalid QMetaType instance.
m_extensionFlags = 0xffffffff;
Q_ASSERT(!isValid());
} else {
// TODO it can be better.
*this = QMetaType::typeInfo(typeId);
- if (m_typeId > 0 && !m_creator) {
+ if (m_typeId == UnknownType)
m_extensionFlags = 0xffffffff;
- m_typeId = -1;
- }
- if (m_typeId == QMetaType::Void) {
+ else if (m_typeId == QMetaType::Void)
m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx;
- }
}
}
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 8dc45bb2ed..fb2bce7d7b 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
- F(Void, 0, void) \
+ F(Void, 43, void) \
F(Bool, 1, bool) \
F(Int, 2, int) \
F(UInt, 3, uint) \
@@ -192,8 +192,8 @@ public:
// these are merged with QVariant
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
- FirstCoreType = Void,
- LastCoreType = QModelIndex,
+ FirstCoreType = Bool,
+ LastCoreType = Void,
FirstGuiType = QFont,
LastGuiType = QPolygonF,
FirstWidgetsType = QIcon,
@@ -202,6 +202,7 @@ public:
QReal = sizeof(qreal) == sizeof(double) ? Double : Float,
+ UnknownType = 0,
User = 256
};
@@ -677,7 +678,7 @@ inline QMetaType::~QMetaType()
inline bool QMetaType::isValid() const
{
- return m_typeId >= 0;
+ return m_typeId != UnknownType;
}
inline bool QMetaType::isRegistered() const
diff --git a/src/corelib/kernel/qmetatypeswitcher_p.h b/src/corelib/kernel/qmetatypeswitcher_p.h
index e9c15ea214..ffd188c972 100644
--- a/src/corelib/kernel/qmetatypeswitcher_p.h
+++ b/src/corelib/kernel/qmetatypeswitcher_p.h
@@ -59,7 +59,8 @@ QT_BEGIN_NAMESPACE
class QMetaTypeSwitcher {
public:
- class NotBuiltinType;
+ class NotBuiltinType; // type is not a built-in type, but it may be a custom type or an unknown type
+ class UnknownType; // type not known to QMetaType system
template<class ReturnType, class DelegateObject>
static ReturnType switcher(DelegateObject &logic, int type, const void *data);
};
@@ -74,7 +75,11 @@ ReturnType QMetaTypeSwitcher::switcher(DelegateObject &logic, int type, const vo
switch (QMetaType::Type(type)) {
QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_SWICHER_CASE)
+ case QMetaType::UnknownType:
+ return logic.delegate(static_cast<UnknownType const *>(data));
default:
+ if (type < QMetaType::User)
+ return logic.delegate(static_cast<UnknownType const *>(data));
return logic.delegate(static_cast<NotBuiltinType const *>(data));
}
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 3a4d1da592..edbb84a657 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -105,6 +105,30 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
return types;
}
+static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc)
+{
+ QScopedArrayPointer<int> types(new int [argc + 1]);
+ for (int i = 0; i < argc; ++i) {
+ const QArgumentType &type = argumentTypes[i];
+ if (type.type())
+ types[i] = type.type();
+ else if (type.name().endsWith('*'))
+ types[i] = QMetaType::VoidStar;
+ else
+ types[i] = QMetaType::type(type.name());
+
+ if (!types[i]) {
+ qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
+ "(Make sure '%s' is registered using qRegisterMetaType().)",
+ type.name().constData(), type.name().constData());
+ return 0;
+ }
+ }
+ types[argc] = 0;
+
+ return types.take();
+}
+
static QBasicMutex _q_ObjectMutexPool[131];
/** \internal
@@ -2179,12 +2203,12 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
if (signal.attributes() & QMetaMethod::Compatibility) {
if (!(method.attributes() & QMetaMethod::Compatibility))
qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)",
- sender->className(), signal.signature());
+ sender->className(), signal.methodSignature().constData());
} else if ((method.attributes() & QMetaMethod::Compatibility) &&
method.methodType() == QMetaMethod::Signal) {
qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
- sender->className(), signal.signature(),
- receiver->className(), method.signature());
+ sender->className(), signal.methodSignature().constData(),
+ receiver->className(), method.methodSignature().constData());
}
}
@@ -2283,20 +2307,40 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
const QMetaObject *smeta = sender->metaObject();
const char *signal_arg = signal;
++signal; //skip code
- int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
- if (signal_index < 0) {
- // check for normalized signatures
- tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
- signal = tmp_signal_name.constData() + 1;
-
- smeta = sender->metaObject();
+ QByteArray signalName;
+ QArgumentTypeArray signalTypes;
+ int signal_index;
+ if (QMetaObjectPrivate::get(smeta)->revision >= 7) {
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &smeta, signalName, signalTypes.size(), signalTypes.constData());
+ if (signal_index < 0) {
+ // check for normalized signatures
+ tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
+ signal = tmp_signal_name.constData() + 1;
+
+ signalTypes.clear();
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &smeta, signalName, signalTypes.size(), signalTypes.constData());
+ }
+ } else {
signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
- }
- if (signal_index < 0) {
- // re-use tmp_signal_name and signal from above
+ if (signal_index < 0) {
+ // check for normalized signatures
+ tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
+ signal = tmp_signal_name.constData() + 1;
+
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
+ if (signal_index < 0) {
+ // re-use tmp_signal_name and signal from above
- smeta = sender->metaObject();
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ }
+ }
}
if (signal_index < 0) {
err_method_notfound(sender, signal_arg, "connect");
@@ -2317,36 +2361,71 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
const char *method_arg = method;
++method; // skip code
+ QByteArray methodName;
+ QArgumentTypeArray methodTypes;
const QMetaObject *rmeta = receiver->metaObject();
int method_index_relative = -1;
- switch (membcode) {
- case QSLOT_CODE:
- method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
- break;
- case QSIGNAL_CODE:
- method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
- break;
- }
-
- if (method_index_relative < 0) {
- // check for normalized methods
- tmp_method_name = QMetaObject::normalizedSignature(method);
- method = tmp_method_name.constData();
-
- // rmeta may have been modified above
- rmeta = receiver->metaObject();
+ if (QMetaObjectPrivate::get(rmeta)->revision >= 7) {
+ switch (membcode) {
+ case QSLOT_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ case QSIGNAL_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ }
+ if (method_index_relative < 0) {
+ // check for normalized methods
+ tmp_method_name = QMetaObject::normalizedSignature(method);
+ method = tmp_method_name.constData();
+
+ methodTypes.clear();
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
+ // rmeta may have been modified above
+ rmeta = receiver->metaObject();
+ switch (membcode) {
+ case QSLOT_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ case QSIGNAL_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ }
+ }
+ } else {
switch (membcode) {
case QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
- if (method_index_relative < 0)
- method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
break;
case QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
- if (method_index_relative < 0)
- method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
break;
}
+
+ if (method_index_relative < 0) {
+ // check for normalized methods
+ tmp_method_name = QMetaObject::normalizedSignature(method);
+ method = tmp_method_name.constData();
+
+ // rmeta may have been modified above
+ rmeta = receiver->metaObject();
+ switch (membcode) {
+ case QSLOT_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
+ if (method_index_relative < 0)
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
+ break;
+ case QSIGNAL_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
+ if (method_index_relative < 0)
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
+ break;
+ }
+ }
}
if (method_index_relative < 0) {
@@ -2355,7 +2434,18 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
return QMetaObject::Connection(0);
}
- if (!QMetaObject::checkConnectArgs(signal, method)) {
+ bool compatibleArgs = true;
+ if ((QMetaObjectPrivate::get(smeta)->revision < 7) && (QMetaObjectPrivate::get(rmeta)->revision < 7)) {
+ compatibleArgs = QMetaObject::checkConnectArgs(signal, method);
+ } else {
+ if (signalName.isEmpty())
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ if (methodName.isEmpty())
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
+ compatibleArgs = QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
+ methodTypes.size(), methodTypes.constData());
+ }
+ if (!compatibleArgs) {
qWarning("QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s",
sender->metaObject()->className(), signal,
@@ -2365,8 +2455,11 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
int *types = 0;
if ((type == Qt::QueuedConnection)
- && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))
+ && ((QMetaObjectPrivate::get(smeta)->revision >= 7)
+ ? !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))
+ : !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))) {
return QMetaObject::Connection(0);
+ }
#ifndef QT_NO_DEBUG
if (warnCompat) {
@@ -2424,17 +2517,17 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho
|| method.methodType() == QMetaMethod::Constructor) {
qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
sender ? sender->metaObject()->className() : "(null)",
- signal.signature(),
+ signal.methodSignature().constData(),
receiver ? receiver->metaObject()->className() : "(null)",
- method.signature() );
+ method.methodSignature().constData() );
return QMetaObject::Connection(0);
}
- // Reconstructing SIGNAL() macro result for signal.signature() string
+ // Reconstructing SIGNAL() macro result for signal.methodSignature() string
QByteArray signalSignature;
- signalSignature.reserve(qstrlen(signal.signature())+1);
+ signalSignature.reserve(signal.methodSignature().size()+1);
signalSignature.append((char)(QSIGNAL_CODE + '0'));
- signalSignature.append(signal.signature());
+ signalSignature.append(signal.methodSignature());
int signal_index;
int method_index;
@@ -2448,20 +2541,20 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho
const QMetaObject *rmeta = receiver->metaObject();
if (signal_index == -1) {
qWarning("QObject::connect: Can't find signal %s on instance of class %s",
- signal.signature(), smeta->className());
+ signal.methodSignature().constData(), smeta->className());
return QMetaObject::Connection(0);
}
if (method_index == -1) {
qWarning("QObject::connect: Can't find method %s on instance of class %s",
- method.signature(), rmeta->className());
+ method.methodSignature().constData(), rmeta->className());
return QMetaObject::Connection(0);
}
- if (!QMetaObject::checkConnectArgs(signal.signature(), method.signature())) {
+ if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(), method.methodSignature().constData())) {
qWarning("QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s",
- smeta->className(), signal.signature(),
- rmeta->className(), method.signature());
+ smeta->className(), signal.methodSignature().constData(),
+ rmeta->className(), method.methodSignature().constData());
return QMetaObject::Connection(0);
}
@@ -2609,12 +2702,25 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
*/
bool res = false;
const QMetaObject *smeta = sender->metaObject();
+ QByteArray signalName;
+ QArgumentTypeArray signalTypes;
+ if (signal && (QMetaObjectPrivate::get(smeta)->revision >= 7))
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ QByteArray methodName;
+ QArgumentTypeArray methodTypes;
+ if (method && (QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7))
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
do {
int signal_index = -1;
if (signal) {
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
- if (signal_index < 0)
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ if (QMetaObjectPrivate::get(smeta)->revision >= 7) {
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &smeta, signalName, signalTypes.size(), signalTypes.constData());
+ } else {
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
+ if (signal_index < 0)
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ }
if (signal_index < 0)
break;
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
@@ -2629,7 +2735,13 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
} else {
const QMetaObject *rmeta = receiver->metaObject();
do {
- int method_index = rmeta->indexOfMethod(method);
+ int method_index;
+ if (QMetaObjectPrivate::get(rmeta)->revision >= 7) {
+ method_index = QMetaObjectPrivate::indexOfMethod(
+ rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ } else {
+ method_index = rmeta->indexOfMethod(method);
+ }
if (method_index >= 0)
while (method_index < rmeta->methodOffset())
rmeta = rmeta->superClass();
@@ -2693,24 +2805,24 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
if(signal.methodType() != QMetaMethod::Signal) {
qWarning("QObject::%s: Attempt to %s non-signal %s::%s",
"disconnect","unbind",
- sender->metaObject()->className(), signal.signature());
+ sender->metaObject()->className(), signal.methodSignature().constData());
return false;
}
}
if (method.mobj) {
if(method.methodType() == QMetaMethod::Constructor) {
qWarning("QObject::disconect: cannot use constructor as argument %s::%s",
- receiver->metaObject()->className(), method.signature());
+ receiver->metaObject()->className(), method.methodSignature().constData());
return false;
}
}
- // Reconstructing SIGNAL() macro result for signal.signature() string
+ // Reconstructing SIGNAL() macro result for signal.methodSignature() string
QByteArray signalSignature;
if (signal.mobj) {
- signalSignature.reserve(qstrlen(signal.signature())+1);
+ signalSignature.reserve(signal.methodSignature().size()+1);
signalSignature.append((char)(QSIGNAL_CODE + '0'));
- signalSignature.append(signal.signature());
+ signalSignature.append(signal.methodSignature());
}
int signal_index;
@@ -2724,13 +2836,13 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
// is -1 then this signal is not a member of sender.
if (signal.mobj && signal_index == -1) {
qWarning("QObject::disconect: signal %s not found on class %s",
- signal.signature(), sender->metaObject()->className());
+ signal.methodSignature().constData(), sender->metaObject()->className());
return false;
}
// If this condition is true then method is not a member of receeiver.
if (receiver && method.mobj && method_index == -1) {
qWarning("QObject::disconect: method %s not found on class %s",
- method.signature(), receiver->metaObject()->className());
+ method.methodSignature().constData(), receiver->metaObject()->className());
return false;
}
@@ -3045,7 +3157,8 @@ void QMetaObject::connectSlotsByName(QObject *o)
Q_ASSERT(mo);
const QObjectList list = o->findChildren<QObject *>(QString());
for (int i = 0; i < mo->methodCount(); ++i) {
- const char *slot = mo->method(i).signature();
+ QByteArray slotSignature = mo->method(i).methodSignature();
+ const char *slot = slotSignature.constData();
Q_ASSERT(slot);
if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
continue;
@@ -3065,7 +3178,7 @@ void QMetaObject::connectSlotsByName(QObject *o)
if (method.methodType() != QMetaMethod::Signal)
continue;
- if (!qstrncmp(method.signature(), slot + len + 4, slotlen)) {
+ if (!qstrncmp(method.methodSignature().constData(), slot + len + 4, slotlen)) {
int signalOffset, methodOffset;
computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset);
sigIndex = k + - methodOffset + signalOffset;
@@ -3311,9 +3424,17 @@ int QObjectPrivate::signalIndex(const char *signalName) const
{
Q_Q(const QObject);
const QMetaObject *base = q->metaObject();
- int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false);
- if (relative_index < 0)
- relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true);
+ int relative_index;
+ if (QMetaObjectPrivate::get(base)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);
+ relative_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &base, name, types.size(), types.constData());
+ } else {
+ relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false);
+ if (relative_index < 0)
+ relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true);
+ }
if (relative_index < 0)
return relative_index;
relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
@@ -3536,7 +3657,7 @@ void QObject::dumpObjectInfo()
offset = methodOffset - signalOffset;
}
const QMetaMethod signal = metaObject()->method(signal_index + offset);
- qDebug(" signal: %s", signal.signature());
+ qDebug(" signal: %s", signal.methodSignature().constData());
// receivers
const QObjectPrivate::Connection *c =
@@ -3552,7 +3673,7 @@ void QObject::dumpObjectInfo()
qDebug(" --> %s::%s %s",
receiverMetaObject->className(),
c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()),
- method.signature());
+ method.methodSignature().constData());
c = c->nextConnectionList;
}
}
@@ -3569,7 +3690,7 @@ void QObject::dumpObjectInfo()
qDebug(" <-- %s::%s %s",
s->sender->metaObject()->className(),
s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
- slot.signature());
+ slot.methodSignature().constData());
}
} else {
qDebug(" <None>");
@@ -4041,9 +4162,16 @@ 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[
- reinterpret_cast<const QMetaObjectPrivate*>(senderMetaObject->d.data)->methodData
- + 5 * (signal_index - signalOffset)];
+ QByteArray tmp_sig;
+ const char *sig;
+ if (QMetaObjectPrivate::get(senderMetaObject)->revision >= 7) {
+ tmp_sig = senderMetaObject->method(signal_index - signalOffset + methodOffset).methodSignature();
+ sig = tmp_sig.constData();
+ } else {
+ sig = reinterpret_cast<const char *>(senderMetaObject->d.stringdata)
+ + senderMetaObject->d.data[QMetaObjectPrivate::get(senderMetaObject)->methodData
+ + 5 * (signal_index - signalOffset)];
+ }
QVarLengthArray<char> signalSignature(qstrlen(sig) + 2);
signalSignature.data()[0] = char(QSIGNAL_CODE + '0');
strcpy(signalSignature.data() + 1 , sig);
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 4b3829b53e..4c98bad0f9 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -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++
@@ -326,6 +327,8 @@ struct Q_CORE_EXPORT QMetaObject
QMetaProperty userProperty() const;
static bool checkConnectArgs(const char *signal, const char *method);
+ static bool checkConnectArgs(const QMetaMethod &signal,
+ const QMetaMethod &method);
static QByteArray normalizedSignature(const char *method);
static QByteArray normalizedType(const char *type);
@@ -439,7 +442,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;
@@ -480,9 +483,6 @@ struct QMetaObjectExtraData
StaticMetacallFunction static_metacall;
};
-inline const char *QMetaObject::className() const
-{ return d.stringdata; }
-
inline const QMetaObject *QMetaObject::superClass() const
{ return d.superdata; }
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 029a261faf..39e8b4360f 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1697,7 +1697,7 @@ void QVariant::load(QDataStream &s)
QByteArray name;
s >> name;
typeId = QMetaType::type(name.constData());
- if (!typeId) {
+ if (typeId == QMetaType::UnknownType) {
s.setStatus(QDataStream::ReadCorruptData);
return;
}
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 5da482d5cd..4d4b2d51ab 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -126,7 +126,7 @@ class Q_CORE_EXPORT QVariant
{
public:
enum Type {
- Invalid = QMetaType::Void,
+ Invalid = QMetaType::UnknownType,
Bool = QMetaType::Bool,
Int = QMetaType::Int,
UInt = QMetaType::UInt,
diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h
index a754bc4363..b28aaf3c20 100644
--- a/src/corelib/kernel/qvariant_p.h
+++ b/src/corelib/kernel/qvariant_p.h
@@ -187,7 +187,11 @@ public:
return FilteredComparator<T>::compare(m_a, m_b);
}
- bool delegate(const void*) { return true; }
+ bool delegate(const void*) { Q_ASSERT(false); return true; }
+ bool delegate(const QMetaTypeSwitcher::UnknownType*)
+ {
+ return true; // for historical reason invalid variant == invalid variant
+ }
bool delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return false; }
protected:
const QVariant::Private *m_a;
@@ -281,7 +285,8 @@ public:
return CallIsNull<T>::isNull(m_d);
}
// we need that as sizof(void) is undefined and it is needed in HasIsNullMethod
- bool delegate(const void *) { return m_d->is_null; }
+ bool delegate(const void *) { Q_ASSERT(false); return m_d->is_null; }
+ bool delegate(const QMetaTypeSwitcher::UnknownType *) { return m_d->is_null; }
bool delegate(const QMetaTypeSwitcher::NotBuiltinType *) { return m_d->is_null; }
protected:
const QVariant::Private *m_d;
@@ -354,8 +359,18 @@ public:
void delegate(const void*)
{
- // QMetaType::Void == QVariant::Invalid, creating an invalid value creates invalid QVariant
- // TODO it might go away, check is needed
+ qWarning("Trying to create a QVariant instance of QMetaType::Void type, an invalid QVariant will be constructed instead");
+ m_x->type = QMetaType::UnknownType;
+ m_x->is_shared = false;
+ m_x->is_null = !m_copy;
+ }
+
+ void delegate(const QMetaTypeSwitcher::UnknownType*)
+ {
+ if (m_x->type != QMetaType::UnknownType) {
+ qWarning("Trying to construct an instance of an invalid type, type id: %i", m_x->type);
+ m_x->type = QMetaType::UnknownType;
+ }
m_x->is_shared = false;
m_x->is_null = !m_copy;
}
@@ -401,7 +416,8 @@ public:
qWarning("Trying to destruct an instance of an invalid type, type id: %i", m_d->type);
}
// Ignore nonconstructible type
- void delegate(const void*) {}
+ void delegate(const QMetaTypeSwitcher::UnknownType*) {}
+ void delegate(const void*) { Q_ASSERT(false); }
private:
QVariant::Private *m_d;
};
@@ -446,10 +462,11 @@ public:
{
qWarning("Trying to stream an instance of an invalid type, type id: %i", m_d->type);
}
- void delegate(const void*)
+ void delegate(const QMetaTypeSwitcher::UnknownType*)
{
m_debugStream.nospace() << "QVariant::Invalid";
}
+ void delegate(const void*) { Q_ASSERT(false); }
private:
QDebug m_debugStream;
QVariant::Private *m_d;
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 7ff005f9a1..be96d895a2 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -1657,7 +1657,7 @@ void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalInd
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q_func() << ": sending signal event ( sender =" << sender
- << ", signal =" << sender->metaObject()->method(signalIndex).signature() << ')';
+ << ", signal =" << sender->metaObject()->method(signalIndex).methodSignature().constData() << ')';
#endif
postInternalEvent(new QStateMachine::SignalEvent(sender, signalIndex, vargs));
processEvents(DirectProcessing);
@@ -2211,10 +2211,29 @@ void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation)
// Begin moc-generated code -- modify carefully (check "HAND EDIT" parts)!
+struct qt_meta_stringdata_QSignalEventGenerator_t {
+ QByteArrayData data[3];
+ char stringdata[32];
+};
+#define QT_MOC_LITERAL(idx, ofs, len) { \
+ Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \
+ offsetof(qt_meta_stringdata_QSignalEventGenerator_t, stringdata) + ofs \
+ - idx * sizeof(QByteArrayData) \
+ }
+static const qt_meta_stringdata_QSignalEventGenerator_t qt_meta_stringdata_QSignalEventGenerator = {
+ {
+QT_MOC_LITERAL(0, 0, 21),
+QT_MOC_LITERAL(1, 22, 7),
+QT_MOC_LITERAL(2, 30, 0)
+ },
+ "QSignalEventGenerator\0execute\0\0"
+};
+#undef QT_MOC_LITERAL
+
static const uint qt_meta_data_QSignalEventGenerator[] = {
// content:
- 6, // revision
+ 7, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -2224,14 +2243,13 @@ static const uint qt_meta_data_QSignalEventGenerator[] = {
0, // flags
0, // signalCount
- // slots: signature, parameters, type, tag, flags
- 23, 22, 22, 22, 0x0a,
+ // slots: name, argc, parameters, tag, flags
+ 1, 0, 19, 2, 0x0a,
- 0 // eod
-};
+ // slots: parameters
+ QMetaType::Void,
-static const char qt_meta_stringdata_QSignalEventGenerator[] = {
- "QSignalEventGenerator\0\0execute()\0"
+ 0 // eod
};
void QSignalEventGenerator::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
@@ -2252,7 +2270,7 @@ const QMetaObjectExtraData QSignalEventGenerator::staticMetaObjectExtraData = {
};
const QMetaObject QSignalEventGenerator::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator,
+ { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator.data,
qt_meta_data_QSignalEventGenerator, &staticMetaObjectExtraData }
};
@@ -2264,7 +2282,7 @@ const QMetaObject *QSignalEventGenerator::metaObject() const
void *QSignalEventGenerator::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_QSignalEventGenerator))
+ if (!strcmp(_clname, qt_meta_stringdata_QSignalEventGenerator.stringdata))
return static_cast<void*>(const_cast< QSignalEventGenerator*>(this));
return QObject::qt_metacast(_clname);
}
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
new file mode 100644
index 0000000000..8498d0e4d5
--- /dev/null
+++ b/src/corelib/tools/qarraydata.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qarraydata.h>
+#include <QtCore/private/qtools_p.h>
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+const QArrayData QArrayData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, 0 };
+
+static const QArrayData qt_array_empty = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, 0 };
+static const QArrayData qt_array_unsharable_empty = { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, 0 };
+
+QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
+ size_t capacity, AllocationOptions options)
+{
+ // Alignment is a power of two
+ Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData)
+ && !(alignment & (alignment - 1)));
+
+ // Don't allocate empty headers
+ if (!(options & RawData) && !capacity)
+ return !(options & Unsharable)
+ ? const_cast<QArrayData *>(&qt_array_empty)
+ : const_cast<QArrayData *>(&qt_array_unsharable_empty);
+
+ size_t headerSize = sizeof(QArrayData);
+
+ // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
+ // can properly align the data array. This assumes malloc is able to
+ // provide appropriate alignment for the header -- as it should!
+ // Padding is skipped when allocating a header for RawData.
+ if (!(options & RawData))
+ headerSize += (alignment - Q_ALIGNOF(QArrayData));
+
+ // Allocate additional space if array is growing
+ if (options & Grow)
+ capacity = qAllocMore(objectSize * capacity, headerSize) / objectSize;
+
+ size_t allocSize = headerSize + objectSize * capacity;
+
+ QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
+ if (header) {
+ quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
+ & ~(alignment - 1);
+
+ header->ref.atomic.store(bool(!(options & Unsharable)));
+ header->size = 0;
+ header->alloc = capacity;
+ header->capacityReserved = bool(options & CapacityReserved);
+ header->offset = data - quintptr(header);
+ }
+
+ return header;
+}
+
+void QArrayData::deallocate(QArrayData *data, size_t objectSize,
+ size_t alignment)
+{
+ // Alignment is a power of two
+ Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData)
+ && !(alignment & (alignment - 1)));
+ Q_UNUSED(objectSize) Q_UNUSED(alignment)
+
+ if (data == &qt_array_unsharable_empty)
+ return;
+
+ ::free(data);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
new file mode 100644
index 0000000000..351a75aade
--- /dev/null
+++ b/src/corelib/tools/qarraydata.h
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QARRAYDATA_H
+#define QARRAYDATA_H
+
+#include <QtCore/qrefcount.h>
+#include <string.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct Q_CORE_EXPORT QArrayData
+{
+ QtPrivate::RefCount ref;
+ int size;
+ uint alloc : 31;
+ uint capacityReserved : 1;
+
+ qptrdiff offset; // in bytes from beginning of header
+
+ void *data()
+ {
+ Q_ASSERT(size == 0
+ || offset < 0 || size_t(offset) >= sizeof(QArrayData));
+ return reinterpret_cast<char *>(this) + offset;
+ }
+
+ const void *data() const
+ {
+ Q_ASSERT(size == 0
+ || offset < 0 || size_t(offset) >= sizeof(QArrayData));
+ return reinterpret_cast<const char *>(this) + offset;
+ }
+
+ // This refers to array data mutability, not "header data" represented by
+ // data members in QArrayData. Shared data (array and header) must still
+ // follow COW principles.
+ bool isMutable() const
+ {
+ return alloc != 0;
+ }
+
+ enum AllocationOption {
+ CapacityReserved = 0x1,
+ Unsharable = 0x2,
+ RawData = 0x4,
+ Grow = 0x8,
+
+ Default = 0
+ };
+
+ Q_DECLARE_FLAGS(AllocationOptions, AllocationOption)
+
+ AllocationOptions detachFlags() const
+ {
+ AllocationOptions result;
+ if (!ref.isSharable())
+ result |= Unsharable;
+ if (capacityReserved)
+ result |= CapacityReserved;
+ return result;
+ }
+
+ AllocationOptions cloneFlags() const
+ {
+ AllocationOptions result;
+ if (capacityReserved)
+ result |= CapacityReserved;
+ return result;
+ }
+
+ static QArrayData *allocate(size_t objectSize, size_t alignment,
+ size_t capacity, AllocationOptions options = Default)
+ Q_REQUIRED_RESULT;
+ static void deallocate(QArrayData *data, size_t objectSize,
+ size_t alignment);
+
+ static const QArrayData shared_null;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocationOptions)
+
+template <class T>
+struct QTypedArrayData
+ : QArrayData
+{
+ typedef T *iterator;
+ typedef const T *const_iterator;
+
+ T *data() { return static_cast<T *>(QArrayData::data()); }
+ const T *data() const { return static_cast<const T *>(QArrayData::data()); }
+
+ T *begin() { return data(); }
+ T *end() { return data() + size; }
+ const T *begin() const { return data(); }
+ const T *end() const { return data() + size; }
+
+ class AlignmentDummy { QArrayData header; T data; };
+
+ static QTypedArrayData *allocate(size_t capacity,
+ AllocationOptions options = Default) Q_REQUIRED_RESULT
+ {
+ return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T),
+ Q_ALIGNOF(AlignmentDummy), capacity, options));
+ }
+
+ static void deallocate(QArrayData *data)
+ {
+ QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy));
+ }
+
+ static QTypedArrayData *fromRawData(const T *data, size_t n,
+ AllocationOptions options = Default)
+ {
+ QTypedArrayData *result = allocate(0, options | RawData);
+ if (result) {
+ Q_ASSERT(!result->ref.isShared()); // No shared empty, please!
+
+ result->offset = reinterpret_cast<const char *>(data)
+ - reinterpret_cast<const char *>(result);
+ result->size = n;
+ }
+ return result;
+ }
+
+ static QTypedArrayData *sharedNull()
+ {
+ return static_cast<QTypedArrayData *>(
+ const_cast<QArrayData *>(&QArrayData::shared_null));
+ }
+};
+
+template <class T, size_t N>
+struct QStaticArrayData
+{
+ QArrayData header;
+ T data[N];
+};
+
+// Support for returning QArrayDataPointer<T> from functions
+template <class T>
+struct QArrayDataPointerRef
+{
+ QTypedArrayData<T> *ptr;
+};
+
+#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) { \
+ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, \
+ (sizeof(QArrayData) + (Q_ALIGNOF(type) - 1)) \
+ & ~(Q_ALIGNOF(type) - 1) } \
+ /**/
+
+////////////////////////////////////////////////////////////////////////////////
+// Q_ARRAY_LITERAL
+
+// The idea here is to place a (read-only) copy of header and array data in an
+// mmappable portion of the executable (typically, .rodata section). This is
+// accomplished by hiding a static const instance of QStaticArrayData, which is
+// POD.
+
+#if defined(Q_COMPILER_VARIADIC_MACROS)
+#if defined(Q_COMPILER_LAMBDA)
+// Hide array inside a lambda
+#define Q_ARRAY_LITERAL(Type, ...) \
+ ([]() -> QArrayDataPointerRef<Type> { \
+ /* MSVC 2010 Doesn't support static variables in a lambda, but */ \
+ /* happily accepts them in a static function of a lambda-local */ \
+ /* struct :-) */ \
+ struct StaticWrapper { \
+ static QArrayDataPointerRef<Type> get() \
+ { \
+ Q_ARRAY_LITERAL_IMPL(Type, __VA_ARGS__) \
+ return ref; \
+ } \
+ }; \
+ return StaticWrapper::get(); \
+ }()) \
+ /**/
+#elif defined(Q_CC_GNU)
+// Hide array within GCC's __extension__ {( )} block
+#define Q_ARRAY_LITERAL(Type, ...) \
+ __extension__ ({ \
+ Q_ARRAY_LITERAL_IMPL(Type, __VA_ARGS__) \
+ ref; \
+ }) \
+ /**/
+#endif
+#endif // defined(Q_COMPILER_VARIADIC_MACROS)
+
+#if defined(Q_ARRAY_LITERAL)
+#define Q_ARRAY_LITERAL_IMPL(Type, ...) \
+ union { Type type_must_be_POD; } dummy; Q_UNUSED(dummy) \
+ \
+ /* Portable compile-time array size computation */ \
+ Type data[] = { __VA_ARGS__ }; Q_UNUSED(data) \
+ enum { Size = sizeof(data) / sizeof(data[0]) }; \
+ \
+ static const QStaticArrayData<Type, Size> literal = { \
+ Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } }; \
+ \
+ QArrayDataPointerRef<Type> ref = \
+ { static_cast<QTypedArrayData<Type> *>( \
+ const_cast<QArrayData *>(&literal.header)) }; \
+ /**/
+#else
+// As a fallback, memory is allocated and data copied to the heap.
+
+// The fallback macro does NOT use variadic macros and does NOT support
+// variable number of arguments. It is suitable for char arrays.
+
+namespace QtPrivate {
+ template <class T, size_t N>
+ inline QArrayDataPointerRef<T> qMakeArrayLiteral(const T (&array)[N])
+ {
+ union { T type_must_be_POD; } dummy; Q_UNUSED(dummy)
+
+ QArrayDataPointerRef<T> result = { QTypedArrayData<T>::allocate(N) };
+ Q_CHECK_PTR(result.ptr);
+
+ ::memcpy(result.ptr->data(), array, N * sizeof(T));
+ result.ptr->size = N;
+
+ return result;
+ }
+}
+
+#define Q_ARRAY_LITERAL(Type, Array) \
+ QT_PREPEND_NAMESPACE(QtPrivate::qMakeArrayLiteral)<Type>( Array )
+#endif // !defined(Q_ARRAY_LITERAL)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // include guard
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
new file mode 100644
index 0000000000..1b8ed3372d
--- /dev/null
+++ b/src/corelib/tools/qarraydataops.h
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QARRAYDATAOPS_H
+#define QARRAYDATAOPS_H
+
+#include <QtCore/qarraydata.h>
+
+#include <new>
+#include <string.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+template <class T>
+struct QPodArrayOps
+ : QTypedArrayData<T>
+{
+ void copyAppend(const T *b, const T *e)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(b < e);
+ Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+
+ ::memcpy(this->end(), b, (e - b) * sizeof(T));
+ this->size += e - b;
+ }
+
+ void copyAppend(size_t n, const T &t)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(n <= this->alloc - uint(this->size));
+
+ T *iter = this->end();
+ const T *const end = iter + n;
+ for (; iter != end; ++iter)
+ ::memcpy(iter, &t, sizeof(T));
+ this->size += n;
+ }
+
+ void destroyAll() // Call from destructors, ONLY!
+ {
+ Q_ASSERT(this->ref.atomic.load() == 0);
+
+ // As this is to be called only from destructor, it doesn't need to be
+ // exception safe; size not updated.
+ }
+
+ void insert(T *where, const T *b, const T *e)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
+ Q_ASSERT(b < e);
+ Q_ASSERT(e <= where || b > this->end()); // No overlap
+ Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+
+ ::memmove(where + (e - b), where, (this->end() - where) * sizeof(T));
+ ::memcpy(where, b, (e - b) * sizeof(T));
+ this->size += (e - b);
+ }
+};
+
+template <class T>
+struct QGenericArrayOps
+ : QTypedArrayData<T>
+{
+ void copyAppend(const T *b, const T *e)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(b < e);
+ Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+
+ T *iter = this->end();
+ for (; b != e; ++iter, ++b) {
+ new (iter) T(*b);
+ ++this->size;
+ }
+ }
+
+ void copyAppend(size_t n, const T &t)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(n <= this->alloc - uint(this->size));
+
+ T *iter = this->end();
+ const T *const end = iter + n;
+ for (; iter != end; ++iter) {
+ new (iter) T(t);
+ ++this->size;
+ }
+ }
+
+ void destroyAll() // Call from destructors, ONLY
+ {
+ // As this is to be called only from destructor, it doesn't need to be
+ // exception safe; size not updated.
+
+ Q_ASSERT(this->ref.atomic.load() == 0);
+
+ const T *const b = this->begin();
+ const T *i = this->end();
+
+ while (i != b)
+ (--i)->~T();
+ }
+
+ void insert(T *where, const T *b, const T *e)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
+ Q_ASSERT(b < e);
+ Q_ASSERT(e <= where || b > this->end()); // No overlap
+ Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+
+ // Array may be truncated at where in case of exceptions
+
+ T *const end = this->end();
+ const T *readIter = end;
+ T *writeIter = end + (e - b);
+
+ const T *const step1End = where + qMax(e - b, end - where);
+
+ struct Destructor
+ {
+ Destructor(T *&it)
+ : iter(&it)
+ , end(it)
+ {
+ }
+
+ void commit()
+ {
+ iter = &end;
+ }
+
+ ~Destructor()
+ {
+ for (; *iter != end; --*iter)
+ (*iter)->~T();
+ }
+
+ T **iter;
+ T *end;
+ } destroyer(writeIter);
+
+ // Construct new elements in array
+ do {
+ --readIter, --writeIter;
+ new (writeIter) T(*readIter);
+ } while (writeIter != step1End);
+
+ while (writeIter != end) {
+ --e, --writeIter;
+ new (writeIter) T(*e);
+ }
+
+ destroyer.commit();
+ this->size += destroyer.end - end;
+
+ // Copy assign over existing elements
+ while (readIter != where) {
+ --readIter, --writeIter;
+ *writeIter = *readIter;
+ }
+
+ while (writeIter != where) {
+ --e, --writeIter;
+ *writeIter = *e;
+ }
+ }
+};
+
+template <class T>
+struct QMovableArrayOps
+ : QGenericArrayOps<T>
+{
+ // using QGenericArrayOps<T>::copyAppend;
+ // using QGenericArrayOps<T>::destroyAll;
+
+ void insert(T *where, const T *b, const T *e)
+ {
+ Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
+ Q_ASSERT(b < e);
+ Q_ASSERT(e <= where || b > this->end()); // No overlap
+ Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+
+ // Provides strong exception safety guarantee,
+ // provided T::~T() nothrow
+
+ struct ReversibleDisplace
+ {
+ ReversibleDisplace(T *start, T *finish, size_t diff)
+ : begin(start)
+ , end(finish)
+ , displace(diff)
+ {
+ ::memmove(begin + displace, begin, (end - begin) * sizeof(T));
+ }
+
+ void commit() { displace = 0; }
+
+ ~ReversibleDisplace()
+ {
+ if (displace)
+ ::memmove(begin, begin + displace, (end - begin) * sizeof(T));
+ }
+
+ T *const begin;
+ T *const end;
+ size_t displace;
+
+ } displace(where, this->end(), size_t(e - b));
+
+ struct CopyConstructor
+ {
+ CopyConstructor(T *w) : where(w) {}
+
+ void copy(const T *src, const T *const srcEnd)
+ {
+ n = 0;
+ for (; src != srcEnd; ++src) {
+ new (where + n) T(*src);
+ ++n;
+ }
+ n = 0;
+ }
+
+ ~CopyConstructor()
+ {
+ while (n)
+ where[--n].~T();
+ }
+
+ T *const where;
+ size_t n;
+ } copier(where);
+
+ copier.copy(b, e);
+ displace.commit();
+ this->size += (e - b);
+ }
+};
+
+template <class T, class = void>
+struct QArrayOpsSelector
+{
+ typedef QGenericArrayOps<T> Type;
+};
+
+template <class T>
+struct QArrayOpsSelector<T,
+ typename QEnableIf<
+ !QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
+ >::Type>
+{
+ typedef QPodArrayOps<T> Type;
+};
+
+template <class T>
+struct QArrayOpsSelector<T,
+ typename QEnableIf<
+ QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
+ >::Type>
+{
+ typedef QMovableArrayOps<T> Type;
+};
+
+} // namespace QtPrivate
+
+template <class T>
+struct QArrayDataOps
+ : QtPrivate::QArrayOpsSelector<T>::Type
+{
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // include guard
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
new file mode 100644
index 0000000000..f5ad53aa54
--- /dev/null
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QARRAYDATAPOINTER_H
+#define QARRAYDATAPOINTER_H
+
+#include <QtCore/qarraydataops.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+template <class T>
+struct QArrayDataPointer
+{
+private:
+ typedef QTypedArrayData<T> Data;
+ typedef QArrayDataOps<T> DataOps;
+
+public:
+ QArrayDataPointer()
+ : d(Data::sharedNull())
+ {
+ }
+
+ QArrayDataPointer(const QArrayDataPointer &other)
+ : d(other.d->ref.ref()
+ ? other.d
+ : other.clone(other.d->cloneFlags()))
+ {
+ }
+
+ explicit QArrayDataPointer(QTypedArrayData<T> *ptr)
+ : d(ptr)
+ {
+ Q_CHECK_PTR(ptr);
+ }
+
+ QArrayDataPointer(QArrayDataPointerRef<T> ref)
+ : d(ref.ptr)
+ {
+ }
+
+ QArrayDataPointer &operator=(const QArrayDataPointer &other)
+ {
+ QArrayDataPointer tmp(other);
+ this->swap(tmp);
+ return *this;
+ }
+
+#ifdef Q_COMPILER_RVALUE_REFS
+ QArrayDataPointer(QArrayDataPointer &&other)
+ : d(other.d)
+ {
+ other.d = Data::sharedNull();
+ }
+
+ QArrayDataPointer &operator=(QArrayDataPointer &&other)
+ {
+ this->swap(other);
+ return *this;
+ }
+#endif
+
+ DataOps &operator*() const
+ {
+ Q_ASSERT(d);
+ return *static_cast<DataOps *>(d);
+ }
+
+ DataOps *operator->() const
+ {
+ Q_ASSERT(d);
+ return static_cast<DataOps *>(d);
+ }
+
+ ~QArrayDataPointer()
+ {
+ if (!d->ref.deref()) {
+ (*this)->destroyAll();
+ Data::deallocate(d);
+ }
+ }
+
+ bool isNull() const
+ {
+ return d == Data::sharedNull();
+ }
+
+ Data *data() const
+ {
+ return d;
+ }
+
+ void setSharable(bool sharable)
+ {
+ // Can't call setSharable on static read-only data, like shared_null
+ // and the internal shared-empties.
+ if (d->alloc == 0 && d->size == 0) {
+ d = Data::allocate(0, sharable
+ ? QArrayData::Default
+ : QArrayData::Unsharable);
+ return;
+ }
+
+ detach();
+ d->ref.setSharable(sharable);
+ }
+
+ void swap(QArrayDataPointer &other)
+ {
+ qSwap(d, other.d);
+ }
+
+ void clear()
+ {
+ QArrayDataPointer tmp(d);
+ d = Data::sharedNull();
+ }
+
+ bool detach()
+ {
+ if (!d->isMutable() || d->ref.isShared()) {
+ Data *copy = clone(d->detachFlags());
+ QArrayDataPointer old(d);
+ d = copy;
+ return true;
+ }
+
+ return false;
+ }
+
+private:
+ Data *clone(QArrayData::AllocationOptions options) const Q_REQUIRED_RESULT
+ {
+ QArrayDataPointer copy(Data::allocate(d->alloc ? d->alloc : d->size,
+ options));
+ if (d->size)
+ copy->copyAppend(d->begin(), d->end());
+
+ Data *result = copy.d;
+ copy.d = Data::sharedNull();
+ return result;
+ }
+
+ Data *d;
+};
+
+template <class T>
+inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs)
+{
+ return lhs.data() == rhs.data();
+}
+
+template <class T>
+inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs)
+{
+ return lhs.data() != rhs.data();
+}
+
+template <class T>
+inline void qSwap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2)
+{
+ p1.swap(p2);
+}
+
+QT_END_NAMESPACE
+
+namespace std
+{
+ template <class T>
+ inline void swap(
+ QT_PREPEND_NAMESPACE(QArrayDataPointer)<T> &p1,
+ QT_PREPEND_NAMESPACE(QArrayDataPointer)<T> &p2)
+ {
+ p1.swap(p2);
+ }
+}
+
+QT_END_HEADER
+
+#endif // include guard
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index b6719c9536..ac936b1d0a 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -57,7 +57,7 @@
#include <string.h>
#include <stdlib.h>
-#define IS_RAW_DATA(d) ((d)->offset != 0)
+#define IS_RAW_DATA(d) ((d)->offset != sizeof(QByteArrayData))
QT_BEGIN_NAMESPACE
@@ -69,24 +69,25 @@ int qFindByteArray(
int qAllocMore(int alloc, int extra)
{
- if (alloc == 0 && extra == 0)
- return 0;
- const int page = 1 << 12;
- int nalloc;
- alloc += extra;
- if (alloc < 1<<6) {
- nalloc = (1<<3) + ((alloc >>3) << 3);
- } else {
- // don't do anything if the loop will overflow signed int.
- if (alloc >= INT_MAX/2)
- return INT_MAX;
- nalloc = (alloc < page) ? 1 << 3 : page;
- while (nalloc < alloc) {
- if (nalloc <= 0)
- return INT_MAX;
- nalloc *= 2;
- }
- }
+ Q_ASSERT(alloc >= 0 && extra >= 0);
+ Q_ASSERT(alloc < (1 << 30) - extra);
+
+ unsigned nalloc = alloc + extra;
+
+ // Round up to next power of 2
+
+ // Assuming container is growing, always overshoot
+ //--nalloc;
+
+ nalloc |= nalloc >> 1;
+ nalloc |= nalloc >> 2;
+ nalloc |= nalloc >> 4;
+ nalloc |= nalloc >> 8;
+ nalloc |= nalloc >> 16;
+ ++nalloc;
+
+ Q_ASSERT(nalloc > unsigned(alloc + extra));
+
return nalloc - extra;
}
@@ -554,7 +555,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
}
d.take(); // realloc was successful
d.reset(p);
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
int res = ::uncompress((uchar*)d->data(), &len,
(uchar*)data+4, nbytes-4);
@@ -576,11 +577,11 @@ QByteArray qUncompress(const uchar* data, int nbytes)
d.take(); // realloc was successful
d.reset(p);
}
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = len;
d->alloc = len;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
return QByteArray(d.take(), 0, 0);
@@ -614,10 +615,10 @@ static inline char qToLower(char c)
return c;
}
-const QConstByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZER(-1),
- 0, 0, 0, { 0 } }, { 0 } };
-const QConstByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1),
- 0, 0, 0, { 0 } }, { 0 } };
+const QStaticByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZE_STATIC,
+ 0, 0, 0, sizeof(QByteArrayData) }, { 0 } };
+const QStaticByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZE_STATIC,
+ 0, 0, 0, sizeof(QByteArrayData) }, { 0 } };
/*!
\class QByteArray
@@ -904,7 +905,7 @@ QByteArray &QByteArray::operator=(const char *str)
x = const_cast<Data *>(&shared_empty.ba);
} else {
int len = qstrlen(str);
- if (d->ref != 1 || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1))
+ if (d->ref.isShared() || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1))
realloc(len);
x = d;
memcpy(x->data(), str, len + 1); // include null terminator
@@ -1289,38 +1290,16 @@ void QByteArray::chop(int n)
\sa isEmpty()
*/
-/*! \fn QByteArray::QByteArray(const char *str)
-
- Constructs a byte array initialized with the string \a str.
-
- QByteArray makes a deep copy of the string data.
-*/
-
-QByteArray::QByteArray(const char *str)
-{
- if (!str) {
- d = const_cast<Data *>(&shared_null.ba);
- } else if (!*str) {
- d = const_cast<Data *>(&shared_empty.ba);
- } else {
- int len = qstrlen(str);
- d = static_cast<Data *>(malloc(sizeof(Data) + len + 1));
- Q_CHECK_PTR(d);
- d->ref = 1;
- d->size = len;
- d->alloc = len;
- d->capacityReserved = false;
- d->offset = 0;
- memcpy(d->data(), str, len+1); // include null terminator
- }
-}
-
/*!
Constructs a byte array containing the first \a size bytes of
array \a data.
If \a data is 0, a null byte array is constructed.
+ If \a size is negative, \a data is assumed to point to a nul-terminated
+ string and its length is determined dynamically. The terminating
+ nul-character is not considered part of the byte array.
+
QByteArray makes a deep copy of the string data.
\sa fromRawData()
@@ -1330,18 +1309,22 @@ QByteArray::QByteArray(const char *data, int size)
{
if (!data) {
d = const_cast<Data *>(&shared_null.ba);
- } else if (size <= 0) {
- d = const_cast<Data *>(&shared_empty.ba);
} else {
- d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
- Q_CHECK_PTR(d);
- d->ref = 1;
- d->size = size;
- d->alloc = size;
- d->capacityReserved = false;
- d->offset = 0;
- memcpy(d->data(), data, size);
- d->data()[size] = '\0';
+ if (size < 0)
+ size = strlen(data);
+ if (!size) {
+ d = const_cast<Data *>(&shared_empty.ba);
+ } else {
+ d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
+ Q_CHECK_PTR(d);
+ d->ref.initializeOwned();
+ d->size = size;
+ d->alloc = size;
+ d->capacityReserved = false;
+ d->offset = sizeof(QByteArrayData);
+ memcpy(d->data(), data, size);
+ d->data()[size] = '\0';
+ }
}
}
@@ -1359,11 +1342,11 @@ QByteArray::QByteArray(int size, char ch)
} else {
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d);
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = size;
d->alloc = size;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
memset(d->data(), ch, size);
d->data()[size] = '\0';
}
@@ -1379,11 +1362,11 @@ QByteArray::QByteArray(int size, Qt::Initialization)
{
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d);
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = size;
d->alloc = size;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
d->data()[size] = '\0';
}
@@ -1405,7 +1388,7 @@ void QByteArray::resize(int size)
if (size < 0)
size = 0;
- if (d->offset && d->ref == 1 && size < d->size) {
+ if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) {
d->size = size;
return;
}
@@ -1426,15 +1409,15 @@ void QByteArray::resize(int size)
//
Data *x = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(x);
- x->ref = 1;
+ x->ref.initializeOwned();
x->size = size;
x->alloc = size;
x->capacityReserved = false;
- x->offset = 0;
+ x->offset = sizeof(QByteArrayData);
x->data()[size] = '\0';
d = x;
} else {
- if (d->ref != 1 || size > int(d->alloc)
+ if (d->ref.isShared() || size > int(d->alloc)
|| (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
realloc(qAllocMore(size, sizeof(Data)));
if (int(d->alloc) >= size) {
@@ -1465,14 +1448,14 @@ QByteArray &QByteArray::fill(char ch, int size)
void QByteArray::realloc(int alloc)
{
- if (d->ref != 1 || d->offset) {
+ if (d->ref.isShared() || IS_RAW_DATA(d)) {
Data *x = static_cast<Data *>(malloc(sizeof(Data) + alloc + 1));
Q_CHECK_PTR(x);
- x->ref = 1;
+ x->ref.initializeOwned();
x->size = qMin(alloc, d->size);
x->alloc = alloc;
x->capacityReserved = d->capacityReserved;
- x->offset = 0;
+ x->offset = sizeof(QByteArrayData);
::memcpy(x->data(), d->data(), x->size);
x->data()[x->size] = '\0';
if (!d->ref.deref())
@@ -1482,7 +1465,7 @@ void QByteArray::realloc(int alloc)
Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc + 1));
Q_CHECK_PTR(x);
x->alloc = alloc;
- x->offset = 0;
+ x->offset = sizeof(QByteArrayData);
d = x;
}
}
@@ -1504,7 +1487,7 @@ void QByteArray::expand(int i)
QByteArray QByteArray::nulTerminated() const
{
// is this fromRawData?
- if (!d->offset)
+ if (!IS_RAW_DATA(d))
return *this; // no, then we're sure we're zero terminated
QByteArray copy(*this);
@@ -1566,7 +1549,7 @@ QByteArray &QByteArray::prepend(const char *str)
QByteArray &QByteArray::prepend(const char *str, int len)
{
if (str) {
- if (d->ref != 1 || d->size + len > int(d->alloc))
+ if (d->ref.isShared() || d->size + len > int(d->alloc))
realloc(qAllocMore(d->size + len, sizeof(Data)));
memmove(d->data()+len, d->data(), d->size);
memcpy(d->data(), str, len);
@@ -1584,7 +1567,7 @@ QByteArray &QByteArray::prepend(const char *str, int len)
QByteArray &QByteArray::prepend(char ch)
{
- if (d->ref != 1 || d->size + 1 > int(d->alloc))
+ if (d->ref.isShared() || d->size + 1 > int(d->alloc))
realloc(qAllocMore(d->size + 1, sizeof(Data)));
memmove(d->data()+1, d->data(), d->size);
d->data()[0] = ch;
@@ -1622,7 +1605,7 @@ QByteArray &QByteArray::append(const QByteArray &ba)
if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
*this = ba;
} else if (ba.d != &shared_null.ba) {
- if (d->ref != 1 || d->size + ba.d->size > int(d->alloc))
+ if (d->ref.isShared() || d->size + ba.d->size > int(d->alloc))
realloc(qAllocMore(d->size + ba.d->size, sizeof(Data)));
memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size;
@@ -1656,7 +1639,7 @@ QByteArray& QByteArray::append(const char *str)
{
if (str) {
int len = qstrlen(str);
- if (d->ref != 1 || d->size + len > int(d->alloc))
+ if (d->ref.isShared() || d->size + len > int(d->alloc))
realloc(qAllocMore(d->size + len, sizeof(Data)));
memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len;
@@ -1681,7 +1664,7 @@ QByteArray &QByteArray::append(const char *str, int len)
if (len < 0)
len = qstrlen(str);
if (str && len) {
- if (d->ref != 1 || d->size + len > int(d->alloc))
+ if (d->ref.isShared() || d->size + len > int(d->alloc))
realloc(qAllocMore(d->size + len, sizeof(Data)));
memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len;
@@ -1698,7 +1681,7 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch)
{
- if (d->ref != 1 || d->size + 1 > int(d->alloc))
+ if (d->ref.isShared() || d->size + 1 > int(d->alloc))
realloc(qAllocMore(d->size + 1, sizeof(Data)));
d->data()[d->size++] = ch;
d->data()[d->size] = '\0';
@@ -3889,11 +3872,11 @@ QByteArray QByteArray::fromRawData(const char *data, int size)
} else {
x = static_cast<Data *>(malloc(sizeof(Data) + 1));
Q_CHECK_PTR(x);
- x->ref = 1;
+ x->ref.initializeOwned();
x->size = size;
x->alloc = 0;
x->capacityReserved = false;
- x->offset = data - (x->d + sizeof(qptrdiff));
+ x->offset = data - reinterpret_cast<char *>(x);
}
return QByteArray(x, 0, 0);
}
@@ -3914,14 +3897,14 @@ QByteArray QByteArray::fromRawData(const char *data, int size)
*/
QByteArray &QByteArray::setRawData(const char *data, uint size)
{
- if (d->ref != 1 || d->alloc) {
+ if (d->ref.isShared() || d->alloc) {
*this = fromRawData(data, size);
} else {
if (data) {
d->size = size;
- d->offset = data - (d->d + sizeof(qptrdiff));
+ d->offset = data - reinterpret_cast<char *>(d);
} else {
- d->offset = 0;
+ d->offset = sizeof(QByteArrayData);
d->size = 0;
*d->data() = 0;
}
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 09c43988fd..e65a9201c2 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -124,32 +124,31 @@ struct QByteArrayData
int size;
uint alloc : 31;
uint capacityReserved : 1;
- union {
- qptrdiff offset; // will always work as we add/subtract from a ushort ptr
- char d[sizeof(qptrdiff)];
- };
- inline char *data() { return d + sizeof(qptrdiff) + offset; }
- inline const char *data() const { return d + sizeof(qptrdiff) + offset; }
+
+ qptrdiff offset;
+
+ inline char *data() { return reinterpret_cast<char *>(this) + offset; }
+ inline const char *data() const { return reinterpret_cast<const char *>(this) + offset; }
};
-template<int N> struct QConstByteArrayData
+template<int N> struct QStaticByteArrayData
{
- const QByteArrayData ba;
- const char data[N + 1];
+ QByteArrayData ba;
+ char data[N + 1];
};
-template<int N> struct QConstByteArrayDataPtr
+template<int N> struct QStaticByteArrayDataPtr
{
- const QConstByteArrayData<N> *ptr;
+ const QStaticByteArrayData<N> *ptr;
};
#if defined(Q_COMPILER_LAMBDA)
-# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr<sizeof(str) - 1> { \
+# define QByteArrayLiteral(str) ([]() -> QStaticByteArrayDataPtr<sizeof(str) - 1> { \
enum { Size = sizeof(str) - 1 }; \
- static const QConstByteArrayData<Size> qbytearray_literal = \
- { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \
- QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
+ static const QStaticByteArrayData<Size> qbytearray_literal = \
+ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QByteArrayData) }, str }; \
+ QStaticByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
return holder; }())
#elif defined(Q_CC_GNU)
@@ -160,9 +159,9 @@ template<int N> struct QConstByteArrayDataPtr
# define QByteArrayLiteral(str) \
__extension__ ({ \
enum { Size = sizeof(str) - 1 }; \
- static const QConstByteArrayData<Size> qbytearray_literal = \
- { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \
- QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
+ static const QStaticByteArrayData<Size> qbytearray_literal = \
+ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QByteArrayData) }, str }; \
+ QStaticByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
holder; })
#endif
@@ -180,8 +179,7 @@ private:
public:
inline QByteArray();
- QByteArray(const char *);
- QByteArray(const char *, int size);
+ QByteArray(const char *, int size = -1);
QByteArray(int size, char c);
QByteArray(int size, Qt::Initialization);
inline QByteArray(const QByteArray &);
@@ -379,16 +377,16 @@ public:
bool isNull() const;
template <int n>
- inline QByteArray(const QConstByteArrayData<n> &dd)
+ inline QByteArray(const QStaticByteArrayData<n> &dd)
: d(const_cast<QByteArrayData *>(&dd.ba)) {}
template <int N>
- Q_DECL_CONSTEXPR inline QByteArray(QConstByteArrayDataPtr<N> dd)
+ Q_DECL_CONSTEXPR inline QByteArray(QStaticByteArrayDataPtr<N> dd)
: d(const_cast<QByteArrayData *>(&dd.ptr->ba)) {}
private:
operator QNoImplicitBoolCast() const;
- static const QConstByteArrayData<1> shared_null;
- static const QConstByteArrayData<1> shared_empty;
+ static const QStaticByteArrayData<1> shared_null;
+ static const QStaticByteArrayData<1> shared_empty;
Data *d;
QByteArray(Data *dd, int /*dummy*/, int /*dummy*/) : d(dd) {}
void realloc(int alloc);
@@ -424,9 +422,9 @@ inline const char *QByteArray::data() const
inline const char *QByteArray::constData() const
{ return d->data(); }
inline void QByteArray::detach()
-{ if (d->ref != 1 || d->offset) realloc(d->size); }
+{ if (d->ref.isShared() || (d->offset != sizeof(QByteArrayData))) realloc(d->size); }
inline bool QByteArray::isDetached() const
-{ return d->ref == 1; }
+{ return !d->ref.isShared(); }
inline QByteArray::QByteArray(const QByteArray &a) : d(a.d)
{ d->ref.ref(); }
@@ -435,7 +433,7 @@ inline int QByteArray::capacity() const
inline void QByteArray::reserve(int asize)
{
- if (d->ref != 1 || asize > int(d->alloc))
+ if (d->ref.isShared() || asize > int(d->alloc))
realloc(asize);
if (!d->capacityReserved) {
@@ -446,11 +444,12 @@ inline void QByteArray::reserve(int asize)
inline void QByteArray::squeeze()
{
- if (d->ref > 1 || d->size < int(d->alloc))
+ if (d->ref.isShared() || d->size < int(d->alloc))
realloc(d->size);
if (d->capacityReserved) {
- // cannot set unconditionally, since d could be the shared_null/shared_empty (which is const)
+ // cannot set unconditionally, since d could be shared_null or
+ // otherwise static.
d->capacityReserved = false;
}
}
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index d5703e8b2a..897de77f2e 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -166,7 +166,7 @@ static int countBits(int hint)
const int MinNumBits = 4;
const QHashData QHashData::shared_null = {
- 0, 0, Q_REFCOUNT_INITIALIZER(-1), 0, 0, MinNumBits, 0, 0, true, false, 0
+ 0, 0, Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, MinNumBits, 0, 0, true, false, 0
};
void *QHashData::allocateNode(int nodeAlign)
@@ -196,7 +196,7 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *),
d = new QHashData;
d->fakeNext = 0;
d->buckets = 0;
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = size;
d->nodeSize = nodeSize;
d->userNumBits = userNumBits;
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 9e4007c26e..91d015c394 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -288,8 +288,8 @@ public:
void reserve(int size);
inline void squeeze() { reserve(1); }
- inline void detach() { if (d->ref != 1) detach_helper(); }
- inline bool isDetached() const { return d->ref == 1; }
+ inline void detach() { if (d->ref.isShared()) detach_helper(); }
+ inline bool isDetached() const { return !d->ref.isShared(); }
inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QHashData::shared_null) d->sharable = sharable; }
inline bool isSharedWith(const QHash<Key, T> &other) const { return d == other.d; }
diff --git a/src/corelib/tools/qlinkedlist.cpp b/src/corelib/tools/qlinkedlist.cpp
index b31ef3e5e9..6e66f804c0 100644
--- a/src/corelib/tools/qlinkedlist.cpp
+++ b/src/corelib/tools/qlinkedlist.cpp
@@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE
const QLinkedListData QLinkedListData::shared_null = {
const_cast<QLinkedListData *>(&QLinkedListData::shared_null),
const_cast<QLinkedListData *>(&QLinkedListData::shared_null),
- Q_REFCOUNT_INITIALIZER(-1), 0, true
+ Q_REFCOUNT_INITIALIZE_STATIC, 0, true
};
/*! \class QLinkedList
diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h
index 2e6d05ac35..28f190c7fa 100644
--- a/src/corelib/tools/qlinkedlist.h
+++ b/src/corelib/tools/qlinkedlist.h
@@ -94,8 +94,8 @@ public:
inline int size() const { return d->size; }
inline void detach()
- { if (d->ref != 1) detach_helper(); }
- inline bool isDetached() const { return d->ref == 1; }
+ { if (d->ref.isShared()) detach_helper(); }
+ inline bool isDetached() const { return !d->ref.isShared(); }
inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QLinkedListData::shared_null) d->sharable = sharable; }
inline bool isSharedWith(const QLinkedList<T> &other) const { return d == other.d; }
@@ -241,8 +241,6 @@ private:
template <typename T>
inline QLinkedList<T>::~QLinkedList()
{
- if (!d)
- return;
if (!d->ref.deref())
free(d);
}
@@ -252,7 +250,7 @@ void QLinkedList<T>::detach_helper()
{
union { QLinkedListData *d; Node *e; } x;
x.d = new QLinkedListData;
- x.d->ref = 1;
+ x.d->ref.initializeOwned();
x.d->size = d->size;
x.d->sharable = true;
Node *original = e->n;
@@ -265,6 +263,7 @@ void QLinkedList<T>::detach_helper()
copy = copy->n;
} QT_CATCH(...) {
copy->n = x.e;
+ Q_ASSERT(!x.d->ref.deref()); // Don't trigger assert in free
free(x.d);
QT_RETHROW;
}
@@ -281,14 +280,13 @@ void QLinkedList<T>::free(QLinkedListData *x)
{
Node *y = reinterpret_cast<Node*>(x);
Node *i = y->n;
- if (x->ref == 0) {
- while(i != y) {
- Node *n = i;
- i = i->n;
- delete n;
- }
- delete x;
+ Q_ASSERT(x->ref.atomic.load() == 0);
+ while (i != y) {
+ Node *n = i;
+ i = i->n;
+ delete n;
}
+ delete x;
}
template <typename T>
diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp
index 263045a25d..9ee4c0a797 100644
--- a/src/corelib/tools/qlist.cpp
+++ b/src/corelib/tools/qlist.cpp
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
the number of elements in the list.
*/
-const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZER(-1), 0, 0, 0, true, { 0 } };
+const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, { 0 } };
static int grow(int size)
{
@@ -87,8 +87,7 @@ QListData::Data *QListData::detach_grow(int *idx, int num)
Data* t = static_cast<Data *>(::malloc(DataHeaderSize + alloc * sizeof(void *)));
Q_CHECK_PTR(t);
- t->ref = 1;
- t->sharable = true;
+ t->ref.initializeOwned();
t->alloc = alloc;
// The space reservation algorithm's optimization is biased towards appending:
// Something which looks like an append will put the data at the beginning,
@@ -129,8 +128,7 @@ QListData::Data *QListData::detach(int alloc)
Data* t = static_cast<Data *>(::malloc(DataHeaderSize + alloc * sizeof(void *)));
Q_CHECK_PTR(t);
- t->ref = 1;
- t->sharable = true;
+ t->ref.initializeOwned();
t->alloc = alloc;
if (!alloc) {
t->begin = 0;
@@ -146,7 +144,7 @@ QListData::Data *QListData::detach(int alloc)
void QListData::realloc(int alloc)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
Data *x = static_cast<Data *>(::realloc(d, DataHeaderSize + alloc * sizeof(void *)));
Q_CHECK_PTR(x);
@@ -159,7 +157,7 @@ void QListData::realloc(int alloc)
// ensures that enough space is available to append n elements
void **QListData::append(int n)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
int e = d->end;
if (e + n > d->alloc) {
int b = d->begin;
@@ -190,7 +188,7 @@ void **QListData::append(const QListData& l)
void **QListData::prepend()
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
if (d->begin == 0) {
if (d->end >= d->alloc / 3)
realloc(grow(d->alloc + 1));
@@ -208,7 +206,7 @@ void **QListData::prepend()
void **QListData::insert(int i)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
if (i <= 0)
return prepend();
int size = d->end - d->begin;
@@ -247,7 +245,7 @@ void **QListData::insert(int i)
void QListData::remove(int i)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
i += d->begin;
if (i - d->begin < d->end - i) {
if (int offset = i - d->begin)
@@ -262,7 +260,7 @@ void QListData::remove(int i)
void QListData::remove(int i, int n)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
i += d->begin;
int middle = i + n/2;
if (middle - d->begin < d->end - middle) {
@@ -278,7 +276,7 @@ void QListData::remove(int i, int n)
void QListData::move(int from, int to)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
if (from == to)
return;
@@ -318,7 +316,7 @@ void QListData::move(int from, int to)
void **QListData::erase(void **xi)
{
- Q_ASSERT(d->ref == 1);
+ Q_ASSERT(!d->ref.isShared());
int i = xi - (d->array + d->begin);
remove(i);
return d->array + d->begin + i;
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index bf6933732c..bc3350f42b 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -71,7 +71,6 @@ struct Q_CORE_EXPORT QListData {
struct Data {
QtPrivate::RefCount ref;
int alloc, begin, end;
- uint sharable : 1;
void *array[1];
};
enum { DataHeaderSize = sizeof(Data) - sizeof(void *) };
@@ -114,7 +113,7 @@ class QList
public:
inline QList() : d(const_cast<QListData::Data *>(&QListData::shared_null)) { }
- inline QList(const QList<T> &l) : d(l.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
+ QList(const QList<T> &l);
~QList();
QList<T> &operator=(const QList<T> &l);
#ifdef Q_COMPILER_RVALUE_REFS
@@ -132,17 +131,25 @@ public:
inline int size() const { return p.size(); }
- inline void detach() { if (d->ref != 1) detach_helper(); }
+ inline void detach() { if (d->ref.isShared()) detach_helper(); }
inline void detachShared()
{
// The "this->" qualification is needed for GCCE.
- if (d->ref != 1 && this->d != &QListData::shared_null)
+ if (d->ref.isShared() && this->d != &QListData::shared_null)
detach_helper();
}
- inline bool isDetached() const { return d->ref == 1; }
- inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QListData::shared_null) d->sharable = sharable; }
+ inline bool isDetached() const { return !d->ref.isShared(); }
+ inline void setSharable(bool sharable)
+ {
+ if (sharable == d->ref.isSharable())
+ return;
+ if (!sharable)
+ detach();
+ if (d != &QListData::shared_null)
+ d->ref.setSharable(sharable);
+ }
inline bool isSharedWith(const QList<T> &other) const { return d == other.d; }
inline bool isEmpty() const { return p.isEmpty(); }
@@ -419,13 +426,8 @@ template <typename T>
Q_INLINE_TEMPLATE QList<T> &QList<T>::operator=(const QList<T> &l)
{
if (d != l.d) {
- QListData::Data *o = l.d;
- o->ref.ref();
- if (!d->ref.deref())
- dealloc(d);
- d = o;
- if (!d->sharable)
- detach_helper();
+ QList<T> tmp(l);
+ tmp.swap(*this);
}
return *this;
}
@@ -478,7 +480,7 @@ template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc)
{
if (d->alloc < alloc) {
- if (d->ref != 1)
+ if (d->ref.isShared())
detach_helper(alloc);
else
p.realloc(alloc);
@@ -488,7 +490,7 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc)
template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
{
- if (d->ref != 1) {
+ if (d->ref.isShared()) {
Node *n = detach_helper_grow(INT_MAX, 1);
QT_TRY {
node_construct(n, t);
@@ -522,7 +524,7 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
template <typename T>
inline void QList<T>::prepend(const T &t)
{
- if (d->ref != 1) {
+ if (d->ref.isShared()) {
Node *n = detach_helper_grow(0, 1);
QT_TRY {
node_construct(n, t);
@@ -556,7 +558,7 @@ inline void QList<T>::prepend(const T &t)
template <typename T>
inline void QList<T>::insert(int i, const T &t)
{
- if (d->ref != 1) {
+ if (d->ref.isShared()) {
Node *n = detach_helper_grow(i, 1);
QT_TRY {
node_construct(n, t);
@@ -708,6 +710,28 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper()
}
template <typename T>
+Q_OUTOFLINE_TEMPLATE QList<T>::QList(const QList<T> &l)
+ : d(l.d)
+{
+ if (!d->ref.ref()) {
+ p.detach(d->alloc);
+
+ struct Cleanup
+ {
+ Cleanup(QListData::Data *d) : d_(d) {}
+ ~Cleanup() { if (d_) qFree(d_); }
+
+ QListData::Data *d_;
+ } tryCatch(d);
+
+ node_copy(reinterpret_cast<Node *>(p.begin()),
+ reinterpret_cast<Node *>(p.end()),
+ reinterpret_cast<Node *>(l.p.begin()));
+ tryCatch.d_ = 0;
+ }
+}
+
+template <typename T>
Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
{
if (!d->ref.deref())
@@ -802,7 +826,7 @@ Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l)
if (isEmpty()) {
*this = l;
} else {
- Node *n = (d->ref != 1)
+ Node *n = (d->ref.isShared())
? detach_helper_grow(INT_MAX, l.size())
: reinterpret_cast<Node *>(p.append(l.p));
QT_TRY {
diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp
index 103d074941..c922d7aab0 100644
--- a/src/corelib/tools/qmap.cpp
+++ b/src/corelib/tools/qmap.cpp
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
const QMapData QMapData::shared_null = {
const_cast<QMapData *>(&shared_null),
{ const_cast<QMapData *>(&shared_null), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- Q_REFCOUNT_INITIALIZER(-1), 0, 0, 0, false, true, false, 0
+ Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, false, true, false, 0
};
QMapData *QMapData::createData(int alignment)
@@ -63,7 +63,7 @@ QMapData *QMapData::createData(int alignment)
Node *e = reinterpret_cast<Node *>(d);
e->backward = e;
e->forward[0] = e;
- d->ref = 1;
+ d->ref.initializeOwned();
d->topLevel = 0;
d->size = 0;
d->randomBits = 0;
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 515b60bea6..dc358a8106 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -179,7 +179,7 @@ public:
inline QMap() : d(const_cast<QMapData *>(&QMapData::shared_null)) { }
inline QMap(const QMap<Key, T> &other) : d(other.d)
{ d->ref.ref(); if (!d->sharable) detach(); }
- inline ~QMap() { if (!d) return; if (!d->ref.deref()) freeData(d); }
+ inline ~QMap() { if (!d->ref.deref()) freeData(d); }
QMap<Key, T> &operator=(const QMap<Key, T> &other);
#ifdef Q_COMPILER_RVALUE_REFS
@@ -199,8 +199,8 @@ public:
inline bool isEmpty() const { return d->size == 0; }
- inline void detach() { if (d->ref != 1) detach_helper(); }
- inline bool isDetached() const { return d->ref == 1; }
+ inline void detach() { if (d->ref.isShared()) detach_helper(); }
+ inline bool isDetached() const { return !d->ref.isShared(); }
inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QMapData::shared_null) d->sharable = sharable; }
inline bool isSharedWith(const QMap<Key, T> &other) const { return d == other.d; }
inline void setInsertInOrder(bool ordered) { if (ordered) detach(); if (d != &QMapData::shared_null) d->insertInOrder = ordered; }
diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h
index bc673214fa..16b1d339b3 100644
--- a/src/corelib/tools/qrefcount.h
+++ b/src/corelib/tools/qrefcount.h
@@ -55,37 +55,61 @@ namespace QtPrivate
class RefCount
{
public:
- inline void ref() {
- if (atomic.load() > 0)
+ inline bool ref() {
+ int count = atomic.load();
+ if (count == 0) // !isSharable
+ return false;
+ if (count != -1) // !isStatic
atomic.ref();
+ return true;
}
inline bool deref() {
- if (atomic.load() <= 0)
+ int count = atomic.load();
+ if (count == 0) // !isSharable
+ return false;
+ if (count == -1) // isStatic
return true;
return atomic.deref();
}
- inline bool operator==(int value) const
- { return atomic.load() == value; }
- inline bool operator!=(int value) const
- { return atomic.load() != value; }
- inline bool operator!() const
- { return !atomic.load(); }
- inline operator int() const
- { return atomic.load(); }
- inline RefCount &operator=(int value)
- { atomic.store(value); return *this; }
- inline RefCount &operator=(const RefCount &other)
- { atomic.store(other.atomic.load()); return *this; }
+ bool setSharable(bool sharable)
+ {
+ Q_ASSERT(!isShared());
+ if (sharable)
+ return atomic.testAndSetRelaxed(0, 1);
+ else
+ return atomic.testAndSetRelaxed(1, 0);
+ }
+
+ bool isStatic() const
+ {
+ // Persistent object, never deleted
+ return atomic.load() == -1;
+ }
+
+ bool isSharable() const
+ {
+ // Sharable === Shared ownership.
+ return atomic.load() != 0;
+ }
+
+ bool isShared() const
+ {
+ int count = atomic.load();
+ return (count != 1) && (count != 0);
+ }
+
+ void initializeOwned() { atomic.store(1); }
+ void initializeUnsharable() { atomic.store(0); }
QBasicAtomicInt atomic;
};
-#define Q_REFCOUNT_INITIALIZER(a) { Q_BASIC_ATOMIC_INITIALIZER(a) }
-
}
+#define Q_REFCOUNT_INITIALIZE_STATIC { Q_BASIC_ATOMIC_INITIALIZER(-1) }
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 083abcbaad..58eb711168 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -94,6 +94,8 @@
#define ULLONG_MAX quint64_C(18446744073709551615)
#endif
+#define IS_RAW_DATA(d) ((d)->offset != sizeof(QStringData))
+
QT_BEGIN_NAMESPACE
#ifdef QT_USE_ICU
@@ -793,8 +795,8 @@ const QString::Null QString::null = { };
\sa split()
*/
-const QConstStringData<1> QString::shared_null = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } };
-const QConstStringData<1> QString::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } };
+const QStaticStringData<1> QString::shared_null = { { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, false, sizeof(QStringData) }, { 0 } };
+const QStaticStringData<1> QString::shared_empty = { { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, false, sizeof(QStringData) }, { 0 } };
int QString::grow(int size)
{
@@ -1015,63 +1017,44 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
Constructs a string initialized with the first \a size characters
of the QChar array \a unicode.
+ If \a unicode is 0, a null string is constructed.
+
+ If \a size is negative, \a unicode is assumed to point to a nul-terminated
+ array and its length is determined dynamically. The terminating
+ nul-character is not considered part of the string.
+
QString makes a deep copy of the string data. The unicode data is copied as
is and the Byte Order Mark is preserved if present.
+
+ \sa fromRawData()
*/
QString::QString(const QChar *unicode, int size)
{
if (!unicode) {
d = const_cast<Data *>(&shared_null.str);
- } else if (size <= 0) {
- d = const_cast<Data *>(&shared_empty.str);
} else {
- d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
- Q_CHECK_PTR(d);
- d->ref = 1;
- d->size = size;
- d->alloc = (uint) size;
- d->capacityReserved = false;
- d->offset = 0;
- memcpy(d->data(), unicode, size * sizeof(QChar));
- d->data()[size] = '\0';
+ if (size < 0) {
+ size = 0;
+ while (unicode[size] != 0)
+ ++size;
+ }
+ if (!size) {
+ d = const_cast<Data *>(&shared_empty.str);
+ } else {
+ d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
+ Q_CHECK_PTR(d);
+ d->ref.initializeOwned();
+ d->size = size;
+ d->alloc = (uint) size;
+ d->capacityReserved = false;
+ d->offset = sizeof(QStringData);
+ memcpy(d->data(), unicode, size * sizeof(QChar));
+ d->data()[size] = '\0';
+ }
}
}
/*!
- \since 4.7
-
- Constructs a string initialized with the characters of the QChar array
- \a unicode, which must be terminated with a 0.
-
- QString makes a deep copy of the string data. The unicode data is copied as
- is and the Byte Order Mark is preserved if present.
-*/
-QString::QString(const QChar *unicode)
-{
- if (!unicode) {
- d = const_cast<Data *>(&shared_null.str);
- } else {
- int size = 0;
- while (unicode[size] != 0)
- ++size;
- if (!size) {
- d = const_cast<Data *>(&shared_empty.str);
- } else {
- d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
- Q_CHECK_PTR(d);
- d->ref = 1;
- d->size = size;
- d->alloc = (uint) size;
- d->capacityReserved = false;
- d->offset = 0;
- memcpy(d->data(), unicode, size * sizeof(QChar));
- d->data()[size] = '\0';
- }
- }
-}
-
-
-/*!
Constructs a string of the given \a size with every character set
to \a ch.
@@ -1084,11 +1067,11 @@ QString::QString(int size, QChar ch)
} else {
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d);
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QStringData);
d->data()[size] = '\0';
ushort *i = d->data() + size;
ushort *b = d->data();
@@ -1108,11 +1091,11 @@ QString::QString(int size, Qt::Initialization)
{
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d);
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QStringData);
d->data()[size] = '\0';
}
@@ -1130,11 +1113,11 @@ QString::QString(QChar ch)
{
d = (Data *) ::malloc(sizeof(Data) + 2*sizeof(QChar));
Q_CHECK_PTR(d);
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = 1;
d->alloc = 1;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QStringData);
d->data()[0] = ch.unicode();
d->data()[1] = '\0';
}
@@ -1232,7 +1215,7 @@ void QString::resize(int size)
if (size < 0)
size = 0;
- if (d->offset && d->ref == 1 && size < d->size) {
+ if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) {
d->size = size;
return;
}
@@ -1243,7 +1226,7 @@ void QString::resize(int size)
QString::free(d);
d = x;
} else {
- if (d->ref != 1 || size > int(d->alloc) ||
+ if (d->ref.isShared() || size > int(d->alloc) ||
(!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
realloc(grow(size));
if (int(d->alloc) >= size) {
@@ -1306,14 +1289,14 @@ void QString::resize(int size)
// ### Qt 5: rename reallocData() to avoid confusion. 197625
void QString::realloc(int alloc)
{
- if (d->ref != 1 || d->offset) {
+ if (d->ref.isShared() || IS_RAW_DATA(d)) {
Data *x = static_cast<Data *>(::malloc(sizeof(Data) + (alloc+1) * sizeof(QChar)));
Q_CHECK_PTR(x);
- x->ref = 1;
+ x->ref.initializeOwned();
x->size = qMin(alloc, d->size);
x->alloc = (uint) alloc;
x->capacityReserved = d->capacityReserved;
- x->offset =0;
+ x->offset = sizeof(QStringData);
::memcpy(x->data(), d->data(), x->size * sizeof(QChar));
x->data()[x->size] = 0;
if (!d->ref.deref())
@@ -1324,7 +1307,7 @@ void QString::realloc(int alloc)
Q_CHECK_PTR(p);
d = p;
d->alloc = alloc;
- d->offset = 0;
+ d->offset = sizeof(QStringData);
}
}
@@ -1536,7 +1519,7 @@ QString &QString::append(const QString &str)
if (d == &shared_null.str) {
operator=(str);
} else {
- if (d->ref != 1 || d->size + str.d->size > int(d->alloc))
+ if (d->ref.isShared() || d->size + str.d->size > int(d->alloc))
realloc(grow(d->size + str.d->size));
memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar));
d->size += str.d->size;
@@ -1556,7 +1539,7 @@ QString &QString::append(const QLatin1String &str)
const uchar *s = (const uchar *)str.latin1();
if (s) {
int len = str.size();
- if (d->ref != 1 || d->size + len > int(d->alloc))
+ if (d->ref.isShared() || d->size + len > int(d->alloc))
realloc(grow(d->size + len));
ushort *i = d->data() + d->size;
while ((*i++ = *s++))
@@ -1599,7 +1582,7 @@ QString &QString::append(const QLatin1String &str)
*/
QString &QString::append(QChar ch)
{
- if (d->ref != 1 || d->size + 1 > int(d->alloc))
+ if (d->ref.isShared() || d->size + 1 > int(d->alloc))
realloc(grow(d->size + 1));
d->data()[d->size++] = ch.unicode();
d->data()[d->size] = '\0';
@@ -3390,15 +3373,11 @@ QString QString::right(int n) const
QString QString::mid(int position, int n) const
{
- if (d == &shared_null.str || position > d->size)
+ if (position > d->size)
return QString();
- if (n < 0)
- n = d->size - position;
- if (position < 0) {
- n += position;
+ if (position < 0)
position = 0;
- }
- if (n + position > d->size)
+ if (n < 0 || n > d->size - position)
n = d->size - position;
if (position == 0 && n == d->size)
return *this;
@@ -3753,11 +3732,11 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size)
size = qstrlen(str);
d = static_cast<Data *>(::malloc(sizeof(Data) + (size+1) * sizeof(QChar)));
Q_CHECK_PTR(d);
- d->ref = 1;
+ d->ref.initializeOwned();
d->size = size;
d->alloc = (uint) size;
d->capacityReserved = false;
- d->offset = 0;
+ d->offset = sizeof(QStringData);
d->data()[size] = '\0';
ushort *dst = d->data();
/* SIMD:
@@ -4765,7 +4744,7 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
const ushort *QString::utf16() const
{
- if (d->offset)
+ if (IS_RAW_DATA(d))
const_cast<QString*>(this)->realloc(); // ensure '\\0'-termination for ::fromRawData strings
return d->data();
}
@@ -7067,11 +7046,11 @@ QString QString::fromRawData(const QChar *unicode, int size)
} else {
x = static_cast<Data *>(::malloc(sizeof(Data) + sizeof(ushort)));
Q_CHECK_PTR(x);
- x->ref = 1;
+ x->ref.initializeOwned();
x->size = size;
x->alloc = 0;
x->capacityReserved = false;
- x->offset = (const ushort *)unicode - (x->d + sizeof(qptrdiff)/sizeof(ushort));
+ x->offset = reinterpret_cast<const char *>(unicode) - reinterpret_cast<char *>(x);
}
return QString(x, 0);
}
@@ -7092,14 +7071,14 @@ QString QString::fromRawData(const QChar *unicode, int size)
*/
QString &QString::setRawData(const QChar *unicode, int size)
{
- if (d->ref != 1 || d->alloc) {
+ if (d->ref.isShared() || d->alloc) {
*this = fromRawData(unicode, size);
} else {
if (unicode) {
d->size = size;
- d->offset = (const ushort *)unicode - (d->d + sizeof(qptrdiff)/sizeof(ushort));
+ d->offset = reinterpret_cast<const char *>(unicode) - reinterpret_cast<char *>(d);
} else {
- d->offset = 0;
+ d->offset = sizeof(QStringData);
d->size = 0;
}
}
@@ -8059,15 +8038,11 @@ QStringRef QString::rightRef(int n) const
QStringRef QString::midRef(int position, int n) const
{
- if (d == &shared_null.str || position > d->size)
+ if (position > d->size)
return QStringRef();
- if (n < 0)
- n = d->size - position;
- if (position < 0) {
- n += position;
+ if (position < 0)
position = 0;
- }
- if (n + position > d->size)
+ if (n < 0 || n > d->size - position)
n = d->size - position;
return QStringRef(this, position, n);
}
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 4d02fbe66d..26959d81f3 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -75,25 +75,24 @@ struct QStringData {
int size;
uint alloc : 31;
uint capacityReserved : 1;
- union {
- qptrdiff offset; // will always work as we add/subtract from a ushort ptr
- ushort d[sizeof(qptrdiff)/sizeof(ushort)];
- };
- inline ushort *data() { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; }
- inline const ushort *data() const { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; }
+
+ qptrdiff offset;
+
+ inline ushort *data() { return reinterpret_cast<ushort *>(reinterpret_cast<char *>(this) + offset); }
+ inline const ushort *data() const { return reinterpret_cast<const ushort *>(reinterpret_cast<const char *>(this) + offset); }
};
-template<int N> struct QConstStringData;
-template<int N> struct QConstStringDataPtr
+template<int N> struct QStaticStringData;
+template<int N> struct QStaticStringDataPtr
{
- const QConstStringData<N> *ptr;
+ const QStaticStringData<N> *ptr;
};
#if defined(Q_COMPILER_UNICODE_STRINGS)
-template<int N> struct QConstStringData
+template<int N> struct QStaticStringData
{
- const QStringData str;
- const char16_t data[N + 1];
+ QStringData str;
+ char16_t data[N + 1];
};
#define QT_UNICODE_LITERAL_II(str) u"" str
@@ -102,10 +101,10 @@ template<int N> struct QConstStringData
|| (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) \
|| (!defined(__SIZEOF_WCHAR_T__) && defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536))
// wchar_t is 2 bytes
-template<int N> struct QConstStringData
+template<int N> struct QStaticStringData
{
- const QStringData str;
- const wchar_t data[N + 1];
+ QStringData str;
+ wchar_t data[N + 1];
};
#if defined(Q_CC_MSVC)
@@ -115,21 +114,21 @@ template<int N> struct QConstStringData
#endif
#else
-template<int N> struct QConstStringData
+template<int N> struct QStaticStringData
{
- const QStringData str;
- const ushort data[N + 1];
+ QStringData str;
+ ushort data[N + 1];
};
#endif
#if defined(QT_UNICODE_LITERAL_II)
# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
# if defined(Q_COMPILER_LAMBDA)
-# define QStringLiteral(str) ([]() -> QConstStringDataPtr<sizeof(QT_UNICODE_LITERAL(str))/2 - 1> { \
+# define QStringLiteral(str) ([]() -> QStaticStringDataPtr<sizeof(QT_UNICODE_LITERAL(str))/2 - 1> { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
- static const QConstStringData<Size> qstring_literal = \
- { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \
- QConstStringDataPtr<Size> holder = { &qstring_literal }; \
+ static const QStaticStringData<Size> qstring_literal = \
+ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QStringData) }, QT_UNICODE_LITERAL(str) }; \
+ QStaticStringDataPtr<Size> holder = { &qstring_literal }; \
return holder; }())
# elif defined(Q_CC_GNU)
@@ -140,9 +139,9 @@ template<int N> struct QConstStringData
# define QStringLiteral(str) \
__extension__ ({ \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
- static const QConstStringData<Size> qstring_literal = \
- { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \
- QConstStringDataPtr<Size> holder = { &qstring_literal }; \
+ static const QStaticStringData<Size> qstring_literal = \
+ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QStringData) }, QT_UNICODE_LITERAL(str) }; \
+ QStaticStringDataPtr<Size> holder = { &qstring_literal }; \
holder; })
# endif
#endif
@@ -160,8 +159,7 @@ public:
typedef QStringData Data;
inline QString();
- QString(const QChar *unicode, int size); // Qt5: don't cap size < 0
- explicit QString(const QChar *unicode); // Qt5: merge with the above
+ explicit QString(const QChar *unicode, int size = -1);
QString(QChar c);
QString(int size, QChar c);
inline QString(const QLatin1String &latin1);
@@ -340,7 +338,7 @@ public:
inline QString &prepend(const QLatin1String &s) { return insert(0, s); }
inline QString &operator+=(QChar c) {
- if (d->ref != 1 || d->size + 1 > int(d->alloc))
+ if (d->ref.isShared() || d->size + 1 > int(d->alloc))
realloc(grow(d->size + 1));
d->data()[d->size++] = c.unicode();
d->data()[d->size] = '\0';
@@ -592,9 +590,9 @@ public:
QString(int size, Qt::Initialization);
template <int n>
- inline QString(const QConstStringData<n> &dd) : d(const_cast<QStringData *>(&dd.str)) {}
+ inline QString(const QStaticStringData<n> &dd) : d(const_cast<QStringData *>(&dd.str)) {}
template <int N>
- Q_DECL_CONSTEXPR inline QString(QConstStringDataPtr<N> dd) : d(const_cast<QStringData *>(&dd.ptr->str)) {}
+ Q_DECL_CONSTEXPR inline QString(QStaticStringDataPtr<N> dd) : d(const_cast<QStringData *>(&dd.ptr->str)) {}
private:
#if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED)
@@ -606,8 +604,8 @@ private:
QString &operator=(const QByteArray &a);
#endif
- static const QConstStringData<1> shared_null;
- static const QConstStringData<1> shared_empty;
+ static const QStaticStringData<1> shared_null;
+ static const QStaticStringData<1> shared_empty;
Data *d;
inline QString(Data *dd, int /*dummy*/) : d(dd) {}
@@ -709,9 +707,9 @@ inline QChar *QString::data()
inline const QChar *QString::constData() const
{ return reinterpret_cast<const QChar*>(d->data()); }
inline void QString::detach()
-{ if (d->ref != 1 || d->offset) realloc(); }
+{ if (d->ref.isShared() || (d->offset != sizeof(QStringData))) realloc(); }
inline bool QString::isDetached() const
-{ return d->ref == 1; }
+{ return !d->ref.isShared(); }
inline QString &QString::operator=(const QLatin1String &s)
{
*this = fromLatin1(s.latin1(), s.size());
@@ -874,7 +872,7 @@ inline QString::~QString() { if (!d->ref.deref()) free(d); }
inline void QString::reserve(int asize)
{
- if (d->ref != 1 || asize > int(d->alloc))
+ if (d->ref.isShared() || asize > int(d->alloc))
realloc(asize);
if (!d->capacityReserved) {
@@ -885,11 +883,12 @@ inline void QString::reserve(int asize)
inline void QString::squeeze()
{
- if (d->ref > 1 || d->size < int(d->alloc))
+ if (d->ref.isShared() || d->size < int(d->alloc))
realloc();
if (d->capacityReserved) {
- // cannot set unconditionally, since d could be the shared_null/shared_empty (which is const)
+ // cannot set unconditionally, since d could be shared_null or
+ // otherwise static.
d->capacityReserved = false;
}
}
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
index e34425be7e..0eb8aa8903 100644
--- a/src/corelib/tools/qstringbuilder.h
+++ b/src/corelib/tools/qstringbuilder.h
@@ -219,9 +219,9 @@ template <> struct QConcatenable<QString> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<QConstStringDataPtr<N> > : private QAbstractConcatenable
+template <int N> struct QConcatenable<QStaticStringDataPtr<N> > : private QAbstractConcatenable
{
- typedef QConstStringDataPtr<N> type;
+ typedef QStaticStringDataPtr<N> type;
typedef QString ConvertTo;
enum { ExactSize = true };
static int size(const type &) { return N; }
@@ -324,9 +324,9 @@ template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<QConstByteArrayDataPtr<N> > : private QAbstractConcatenable
+template <int N> struct QConcatenable<QStaticByteArrayDataPtr<N> > : private QAbstractConcatenable
{
- typedef QConstByteArrayDataPtr<N> type;
+ typedef QStaticByteArrayDataPtr<N> type;
typedef QByteArray ConvertTo;
enum { ExactSize = false };
static int size(const type &) { return N; }
@@ -338,9 +338,8 @@ template <int N> struct QConcatenable<QConstByteArrayDataPtr<N> > : private QAbs
#endif
static inline void appendTo(const type &ba, char *&out)
{
- const char *a = ba.ptr->data;
- while (*a)
- *out++ = *a++;
+ ::memcpy(out, ba.ptr->data, N);
+ out += N;
}
};
diff --git a/src/corelib/tools/qvector.cpp b/src/corelib/tools/qvector.cpp
index 75c219bbc9..1a746dc061 100644
--- a/src/corelib/tools/qvector.cpp
+++ b/src/corelib/tools/qvector.cpp
@@ -54,15 +54,7 @@ static inline int alignmentThreshold()
return 2 * sizeof(void*);
}
-const QVectorData QVectorData::shared_null = { Q_REFCOUNT_INITIALIZER(-1), 0, 0, true, false, 0 };
-
-QVectorData *QVectorData::malloc(int sizeofTypedData, int size, int sizeofT, QVectorData *init)
-{
- QVectorData* p = (QVectorData *)::malloc(sizeofTypedData + (size - 1) * sizeofT);
- Q_CHECK_PTR(p);
- ::memcpy(p, init, sizeofTypedData + (qMin(size, init->alloc) - 1) * sizeofT);
- return p;
-}
+const QVectorData QVectorData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, false, 0 };
QVectorData *QVectorData::allocate(int size, int alignment)
{
@@ -84,11 +76,9 @@ void QVectorData::free(QVectorData *x, int alignment)
::free(x);
}
-int QVectorData::grow(int sizeofTypedData, int size, int sizeofT, bool excessive)
+int QVectorData::grow(int sizeOfHeader, int size, int sizeOfT)
{
- if (excessive)
- return size + size / 2;
- return qAllocMore(size * sizeofT, sizeofTypedData - sizeofT) / sizeofT;
+ return qAllocMore(size * sizeOfT, sizeOfHeader) / sizeOfT;
}
/*!
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 4230e55ff5..c119ef43ae 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -65,37 +65,28 @@ QT_BEGIN_NAMESPACE
struct Q_CORE_EXPORT QVectorData
{
QtPrivate::RefCount ref;
- int alloc;
int size;
-#if defined(Q_PROCESSOR_SPARC) && defined(Q_CC_GNU) && defined(__LP64__) && defined(QT_BOOTSTRAPPED)
- // workaround for bug in gcc 3.4.2
- uint sharable;
- uint capacity;
- uint reserved;
-#else
- uint sharable : 1;
- uint capacity : 1;
- uint reserved : 30;
-#endif
+ uint alloc : 31;
+ uint capacityReserved : 1;
+
+ qptrdiff offset;
+
+ void* data() { return reinterpret_cast<char *>(this) + this->offset; }
static const QVectorData shared_null;
- // ### Qt 5: rename to 'allocate()'. The current name causes problems for
- // some debugges when the QVector is member of a class within an unnamed namespace.
- // ### Qt 5: can be removed completely. (Ralf)
- static QVectorData *malloc(int sizeofTypedData, int size, int sizeofT, QVectorData *init);
static QVectorData *allocate(int size, int alignment);
static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment);
static void free(QVectorData *data, int alignment);
- static int grow(int sizeofTypedData, int size, int sizeofT, bool excessive);
+ static int grow(int sizeOfHeader, int size, int sizeOfT);
};
template <typename T>
-struct QVectorTypedData : private QVectorData
-{ // private inheritance as we must not access QVectorData member thought QVectorTypedData
- // as this would break strict aliasing rules. (in the case of shared_null)
- T array[1];
+struct QVectorTypedData : QVectorData
+{
+ T* begin() { return reinterpret_cast<T *>(this->data()); }
+ T* end() { return begin() + this->size; }
- static inline void free(QVectorTypedData<T> *x, int alignment) { QVectorData::free(static_cast<QVectorData *>(x), alignment); }
+ static QVectorTypedData *sharedNull() { return static_cast<QVectorTypedData *>(const_cast<QVectorData *>(&QVectorData::shared_null)); }
};
class QRegion;
@@ -104,27 +95,30 @@ template <typename T>
class QVector
{
typedef QVectorTypedData<T> Data;
- union {
- QVectorData *d;
-#if defined(Q_CC_SUN) && (__SUNPRO_CC <= 0x550)
- QVectorTypedData<T> *p;
-#else
- Data *p;
-#endif
- };
+ Data *d;
public:
- // ### Qt 5: Consider making QVector non-shared to get at least one
- // "really fast" container. See tests/benchmarks/corelib/tools/qvector/
- inline QVector() : d(const_cast<QVectorData *>(&QVectorData::shared_null)) { }
+ inline QVector() : d(Data::sharedNull()) { }
explicit QVector(int size);
QVector(int size, const T &t);
- inline QVector(const QVector<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
- inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(p); }
+ inline QVector(const QVector<T> &v)
+ {
+ if (v.d->ref.ref()) {
+ d = v.d;
+ } else {
+ d = Data::sharedNull();
+ realloc(0, int(v.d->alloc));
+ qCopy(v.d->begin(), v.d->end(), d->begin());
+ d->size = v.d->size;
+ d->capacityReserved = v.d->capacityReserved;
+ }
+ }
+
+ inline ~QVector() { if (!d->ref.deref()) free(d); }
QVector<T> &operator=(const QVector<T> &v);
#ifdef Q_COMPILER_RVALUE_REFS
inline QVector<T> operator=(QVector<T> &&other)
- { qSwap(p, other.p); return *this; }
+ { qSwap(d, other.d); return *this; }
#endif
inline void swap(QVector<T> &other) { qSwap(d, other.d); }
#ifdef Q_COMPILER_INITIALIZER_LISTS
@@ -139,18 +133,27 @@ public:
void resize(int size);
- inline int capacity() const { return d->alloc; }
+ inline int capacity() const { return int(d->alloc); }
void reserve(int size);
- inline void squeeze() { realloc(d->size, d->size); d->capacity = 0; }
+ inline void squeeze() { realloc(d->size, d->size); d->capacityReserved = 0; }
+
+ inline void detach() { if (!isDetached()) detach_helper(); }
+ inline bool isDetached() const { return !d->ref.isShared(); }
+ inline void setSharable(bool sharable)
+ {
+ if (sharable == d->ref.isSharable())
+ return;
+ if (!sharable)
+ detach();
+ if (d != Data::sharedNull())
+ d->ref.setSharable(sharable);
+ }
- inline void detach() { if (d->ref != 1) detach_helper(); }
- inline bool isDetached() const { return d->ref == 1; }
- inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QVectorData::shared_null) d->sharable = sharable; }
inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
- inline T *data() { detach(); return p->array; }
- inline const T *data() const { return p->array; }
- inline const T *constData() const { return p->array; }
+ inline T *data() { detach(); return d->begin(); }
+ inline const T *data() const { return d->begin(); }
+ inline const T *constData() const { return d->begin(); }
void clear();
const T &at(int i) const;
@@ -243,12 +246,12 @@ public:
typedef T* iterator;
typedef const T* const_iterator;
#endif
- inline iterator begin() { detach(); return p->array; }
- inline const_iterator begin() const { return p->array; }
- inline const_iterator constBegin() const { return p->array; }
- inline iterator end() { detach(); return p->array + d->size; }
- inline const_iterator end() const { return p->array + d->size; }
- inline const_iterator constEnd() const { return p->array + d->size; }
+ inline iterator begin() { detach(); return d->begin(); }
+ inline const_iterator begin() const { return d->begin(); }
+ inline const_iterator constBegin() const { return d->begin(); }
+ inline iterator end() { detach(); return d->end(); }
+ inline const_iterator end() const { return d->end(); }
+ inline const_iterator constEnd() const { return d->end(); }
iterator insert(iterator before, int n, const T &x);
inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
iterator erase(iterator begin, iterator end);
@@ -313,46 +316,49 @@ private:
friend class QRegion; // Optimization for QRegion::rects()
void detach_helper();
- QVectorData *malloc(int alloc);
+ Data *malloc(int alloc);
void realloc(int size, int alloc);
void free(Data *d);
- int sizeOfTypedData() {
- // this is more or less the same as sizeof(Data), except that it doesn't
- // count the padding at the end
- return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this);
+
+ class AlignmentDummy { QVectorData header; T array[1]; };
+
+ static Q_DECL_CONSTEXPR int offsetOfTypedData()
+ {
+ // (non-POD)-safe offsetof(AlignmentDummy, array)
+ return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1);
}
- inline int alignOfTypedData() const
+ static Q_DECL_CONSTEXPR int alignOfTypedData()
{
#ifdef Q_ALIGNOF
- return qMax<int>(sizeof(void*), Q_ALIGNOF(Data));
+ return Q_ALIGNOF(AlignmentDummy);
#else
- return 0;
+ return sizeof(void *);
#endif
}
};
template <typename T>
void QVector<T>::detach_helper()
-{ realloc(d->size, d->alloc); }
+{ realloc(d->size, int(d->alloc)); }
template <typename T>
void QVector<T>::reserve(int asize)
-{ if (asize > d->alloc) realloc(d->size, asize); if (d->ref == 1) d->capacity = 1; }
+{ if (asize > int(d->alloc)) realloc(d->size, asize); if (isDetached()) d->capacityReserved = 1; }
template <typename T>
void QVector<T>::resize(int asize)
-{ realloc(asize, (asize > d->alloc || (!d->capacity && asize < d->size && asize < (d->alloc >> 1))) ?
- QVectorData::grow(sizeOfTypedData(), asize, sizeof(T), QTypeInfo<T>::isStatic)
- : d->alloc); }
+{ realloc(asize, (asize > int(d->alloc) || (!d->capacityReserved && asize < d->size && asize < int(d->alloc >> 1))) ?
+ QVectorData::grow(offsetOfTypedData(), asize, sizeof(T))
+ : int(d->alloc)); }
template <typename T>
inline void QVector<T>::clear()
{ *this = QVector<T>(); }
template <typename T>
inline const T &QVector<T>::at(int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
- return p->array[i]; }
+ return d->begin()[i]; }
template <typename T>
inline const T &QVector<T>::operator[](int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
- return p->array[i]; }
+ return d->begin()[i]; }
template <typename T>
inline T &QVector<T>::operator[](int i)
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
@@ -388,39 +394,37 @@ inline void QVector<T>::replace(int i, const T &t)
template <typename T>
QVector<T> &QVector<T>::operator=(const QVector<T> &v)
{
- QVectorData *o = v.d;
- o->ref.ref();
- if (!d->ref.deref())
- free(p);
- d = o;
- if (!d->sharable)
- detach_helper();
+ if (v.d != d) {
+ QVector<T> tmp(v);
+ tmp.swap(*this);
+ }
return *this;
}
template <typename T>
-inline QVectorData *QVector<T>::malloc(int aalloc)
+inline typename QVector<T>::Data *QVector<T>::malloc(int aalloc)
{
- QVectorData *vectordata = QVectorData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData());
+ QVectorData *vectordata = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(vectordata);
- return vectordata;
+ return static_cast<Data *>(vectordata);
}
template <typename T>
QVector<T>::QVector(int asize)
{
d = malloc(asize);
- d->ref = 1;
- d->alloc = d->size = asize;
- d->sharable = true;
- d->capacity = false;
+ d->ref.initializeOwned();
+ d->size = asize;
+ d->alloc = uint(d->size);
+ d->capacityReserved = false;
+ d->offset = offsetOfTypedData();
if (QTypeInfo<T>::isComplex) {
- T* b = p->array;
- T* i = p->array + d->size;
+ T* b = d->begin();
+ T* i = d->end();
while (i != b)
new (--i) T;
} else {
- qMemSet(p->array, 0, asize * sizeof(T));
+ qMemSet(d->begin(), 0, asize * sizeof(T));
}
}
@@ -428,12 +432,13 @@ template <typename T>
QVector<T>::QVector(int asize, const T &t)
{
d = malloc(asize);
- d->ref = 1;
- d->alloc = d->size = asize;
- d->sharable = true;
- d->capacity = false;
- T* i = p->array + d->size;
- while (i != p->array)
+ d->ref.initializeOwned();
+ d->size = asize;
+ d->alloc = uint(d->size);
+ d->capacityReserved = false;
+ d->offset = offsetOfTypedData();
+ T* i = d->end();
+ while (i != d->begin())
new (--i) T(t);
}
@@ -442,14 +447,22 @@ template <typename T>
QVector<T>::QVector(std::initializer_list<T> args)
{
d = malloc(int(args.size()));
- d->ref = 1;
- d->alloc = d->size = int(args.size());
- d->sharable = true;
- d->capacity = false;
- T* i = p->array + d->size;
- auto it = args.end();
- while (i != p->array)
- new (--i) T(*(--it));
+ d->ref.initializeOwned();
+ d->size = int(args.size());
+ d->alloc = uint(d->size);
+ d->capacityReserved = false;
+ d->offset = offsetOfTypedData();
+ if (QTypeInfo<T>::isComplex) {
+ T* b = d->begin();
+ T* i = d->end();
+ const T* s = args.end();
+ while (i != b)
+ new(--i) T(*--s);
+ } else {
+ // std::initializer_list<T>::iterator is guaranteed to be
+ // const T* ([support.initlist]/1), so can be memcpy'ed away from:
+ ::memcpy(d->begin(), args.begin(), args.size() * sizeof(T));
+ }
}
#endif
@@ -457,14 +470,12 @@ template <typename T>
void QVector<T>::free(Data *x)
{
if (QTypeInfo<T>::isComplex) {
- T* b = x->array;
- union { QVectorData *d; Data *p; } u;
- u.p = x;
- T* i = b + u.d->size;
+ T* b = x->begin();
+ T* i = b + x->size;
while (i-- != b)
i->~T();
}
- x->free(x, alignOfTypedData());
+ Data::free(x, alignOfTypedData());
}
template <typename T>
@@ -473,84 +484,82 @@ void QVector<T>::realloc(int asize, int aalloc)
Q_ASSERT(asize <= aalloc);
T *pOld;
T *pNew;
- union { QVectorData *d; Data *p; } x;
- x.d = d;
+ Data *x = d;
- if (QTypeInfo<T>::isComplex && asize < d->size && d->ref == 1 ) {
+ if (QTypeInfo<T>::isComplex && asize < d->size && isDetached()) {
// call the destructor on all objects that need to be
// destroyed when shrinking
- pOld = p->array + d->size;
- pNew = p->array + asize;
+ pOld = d->begin() + d->size;
+ pNew = d->begin() + asize;
while (asize < d->size) {
(--pOld)->~T();
d->size--;
}
}
- if (aalloc != d->alloc || d->ref != 1) {
+ if (aalloc != int(d->alloc) || !isDetached()) {
// (re)allocate memory
if (QTypeInfo<T>::isStatic) {
- x.d = malloc(aalloc);
- Q_CHECK_PTR(x.p);
- x.d->size = 0;
- } else if (d->ref != 1) {
- x.d = malloc(aalloc);
- Q_CHECK_PTR(x.p);
+ x = malloc(aalloc);
+ Q_CHECK_PTR(x);
+ x->size = 0;
+ } else if (!isDetached()) {
+ x = malloc(aalloc);
+ Q_CHECK_PTR(x);
if (QTypeInfo<T>::isComplex) {
- x.d->size = 0;
+ x->size = 0;
} else {
- ::memcpy(x.p, p, sizeOfTypedData() + (qMin(aalloc, d->alloc) - 1) * sizeof(T));
- x.d->size = d->size;
+ ::memcpy(x, d, offsetOfTypedData() + qMin(uint(aalloc), d->alloc) * sizeof(T));
+ x->size = d->size;
}
} else {
QT_TRY {
- QVectorData *mem = QVectorData::reallocate(d, sizeOfTypedData() + (aalloc - 1) * sizeof(T),
- sizeOfTypedData() + (d->alloc - 1) * sizeof(T), alignOfTypedData());
+ QVectorData *mem = QVectorData::reallocate(d, offsetOfTypedData() + aalloc * sizeof(T),
+ offsetOfTypedData() + d->alloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(mem);
- x.d = d = mem;
- x.d->size = d->size;
+ x = d = static_cast<Data *>(mem);
+ x->size = d->size;
} QT_CATCH (const std::bad_alloc &) {
- if (aalloc > d->alloc) // ignore the error in case we are just shrinking.
+ if (aalloc > int(d->alloc)) // ignore the error in case we are just shrinking.
QT_RETHROW;
}
}
- x.d->ref = 1;
- x.d->alloc = aalloc;
- x.d->sharable = true;
- x.d->capacity = d->capacity;
- x.d->reserved = 0;
+ x->ref.initializeOwned();
+ x->alloc = uint(aalloc);
+ x->capacityReserved = d->capacityReserved;
+ x->offset = offsetOfTypedData();
}
if (QTypeInfo<T>::isComplex) {
QT_TRY {
- pOld = p->array + x.d->size;
- pNew = x.p->array + x.d->size;
+ pOld = d->begin() + x->size;
+ pNew = x->begin() + x->size;
// copy objects from the old array into the new array
const int toMove = qMin(asize, d->size);
- while (x.d->size < toMove) {
+ while (x->size < toMove) {
new (pNew++) T(*pOld++);
- x.d->size++;
+ x->size++;
}
// construct all new objects when growing
- while (x.d->size < asize) {
+ while (x->size < asize) {
new (pNew++) T;
- x.d->size++;
+ x->size++;
}
} QT_CATCH (...) {
- free(x.p);
+ free(x);
QT_RETHROW;
}
- } else if (asize > x.d->size) {
+ } else if (asize > x->size) {
// initialize newly allocated memory to 0
- qMemSet(x.p->array + x.d->size, 0, (asize - x.d->size) * sizeof(T));
+ qMemSet(x->end(), 0, (asize - x->size) * sizeof(T));
}
- x.d->size = asize;
+ x->size = asize;
- if (d != x.d) {
+ if (d != x) {
if (!d->ref.deref())
- free(p);
- d = x.d;
+ free(d);
+ d = x;
}
}
@@ -560,31 +569,31 @@ Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
if (i < 0 || i >= d->size) {
return T();
}
- return p->array[i];
+ return d->begin()[i];
}
template<typename T>
Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
{
- return ((i < 0 || i >= d->size) ? defaultValue : p->array[i]);
+ return ((i < 0 || i >= d->size) ? defaultValue : d->begin()[i]);
}
template <typename T>
void QVector<T>::append(const T &t)
{
- if (d->ref != 1 || d->size + 1 > d->alloc) {
+ if (!isDetached() || d->size + 1 > int(d->alloc)) {
const T copy(t);
- realloc(d->size, (d->size + 1 > d->alloc) ?
- QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T), QTypeInfo<T>::isStatic)
- : d->alloc);
+ realloc(d->size, (d->size + 1 > int(d->alloc)) ?
+ QVectorData::grow(offsetOfTypedData(), d->size + 1, sizeof(T))
+ : int(d->alloc));
if (QTypeInfo<T>::isComplex)
- new (p->array + d->size) T(copy);
+ new (d->end()) T(copy);
else
- p->array[d->size] = copy;
+ *d->end() = copy;
} else {
if (QTypeInfo<T>::isComplex)
- new (p->array + d->size) T(t);
+ new (d->end()) T(t);
else
- p->array[d->size] = t;
+ *d->end() = t;
}
++d->size;
}
@@ -592,27 +601,26 @@ void QVector<T>::append(const T &t)
template <typename T>
typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
{
- int offset = int(before - p->array);
+ int offset = int(before - d->begin());
if (n != 0) {
const T copy(t);
- if (d->ref != 1 || d->size + n > d->alloc)
- realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + n, sizeof(T),
- QTypeInfo<T>::isStatic));
+ if (!isDetached() || d->size + n > int(d->alloc))
+ realloc(d->size, QVectorData::grow(offsetOfTypedData(), d->size + n, sizeof(T)));
if (QTypeInfo<T>::isStatic) {
- T *b = p->array + d->size;
- T *i = p->array + d->size + n;
+ T *b = d->end();
+ T *i = d->end() + n;
while (i != b)
new (--i) T;
- i = p->array + d->size;
+ i = d->end();
T *j = i + n;
- b = p->array + offset;
+ b = d->begin() + offset;
while (i != b)
*--j = *--i;
i = b+n;
while (i != b)
*--i = copy;
} else {
- T *b = p->array + offset;
+ T *b = d->begin() + offset;
T *i = b + n;
memmove(i, b, (d->size - offset) * sizeof(T));
while (i != b)
@@ -620,29 +628,29 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
}
d->size += n;
}
- return p->array + offset;
+ return d->begin() + offset;
}
template <typename T>
typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
{
- int f = int(abegin - p->array);
- int l = int(aend - p->array);
+ int f = int(abegin - d->begin());
+ int l = int(aend - d->begin());
int n = l - f;
detach();
if (QTypeInfo<T>::isComplex) {
- qCopy(p->array+l, p->array+d->size, p->array+f);
- T *i = p->array+d->size;
- T* b = p->array+d->size-n;
+ qCopy(d->begin()+l, d->end(), d->begin()+f);
+ T *i = d->end();
+ T* b = d->end()-n;
while (i != b) {
--i;
i->~T();
}
} else {
- memmove(p->array + f, p->array + l, (d->size-l)*sizeof(T));
+ memmove(d->begin() + f, d->begin() + l, (d->size-l)*sizeof(T));
}
d->size -= n;
- return p->array + f;
+ return d->begin() + f;
}
template <typename T>
@@ -652,9 +660,9 @@ bool QVector<T>::operator==(const QVector<T> &v) const
return false;
if (d == v.d)
return true;
- T* b = p->array;
+ T* b = d->begin();
T* i = b + d->size;
- T* j = v.p->array + d->size;
+ T* j = v.d->end();
while (i != b)
if (!(*--i == *--j))
return false;
@@ -667,8 +675,8 @@ QVector<T> &QVector<T>::fill(const T &from, int asize)
const T copy(from);
resize(asize < 0 ? d->size : asize);
if (d->size) {
- T *i = p->array + d->size;
- T *b = p->array;
+ T *i = d->end();
+ T *b = d->begin();
while (i != b)
*--i = copy;
}
@@ -681,9 +689,9 @@ QVector<T> &QVector<T>::operator+=(const QVector &l)
int newSize = d->size + l.d->size;
realloc(d->size, newSize);
- T *w = p->array + newSize;
- T *i = l.p->array + l.d->size;
- T *b = l.p->array;
+ T *w = d->begin() + newSize;
+ T *i = l.d->end();
+ T *b = l.d->begin();
while (i != b) {
if (QTypeInfo<T>::isComplex)
new (--w) T(*--i);
@@ -700,11 +708,11 @@ int QVector<T>::indexOf(const T &t, int from) const
if (from < 0)
from = qMax(from + d->size, 0);
if (from < d->size) {
- T* n = p->array + from - 1;
- T* e = p->array + d->size;
+ T* n = d->begin() + from - 1;
+ T* e = d->end();
while (++n != e)
if (*n == t)
- return n - p->array;
+ return n - d->begin();
}
return -1;
}
@@ -717,8 +725,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
else if (from >= d->size)
from = d->size-1;
if (from >= 0) {
- T* b = p->array;
- T* n = p->array + from + 1;
+ T* b = d->begin();
+ T* n = d->begin() + from + 1;
while (n != b) {
if (*--n == t)
return n - b;
@@ -730,8 +738,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
template <typename T>
bool QVector<T>::contains(const T &t) const
{
- T* b = p->array;
- T* i = p->array + d->size;
+ T* b = d->begin();
+ T* i = d->end();
while (i != b)
if (*--i == t)
return true;
@@ -742,8 +750,8 @@ template <typename T>
int QVector<T>::count(const T &t) const
{
int c = 0;
- T* b = p->array;
- T* i = p->array + d->size;
+ T* b = d->begin();
+ T* i = d->end();
while (i != b)
if (*--i == t)
++c;
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 250789a969..ac347404fd 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -2,6 +2,9 @@
HEADERS += \
tools/qalgorithms.h \
+ tools/qarraydata.h \
+ tools/qarraydataops.h \
+ tools/qarraydatapointer.h \
tools/qbitarray.h \
tools/qbytearray.h \
tools/qbytearraymatcher.h \
@@ -56,6 +59,7 @@ HEADERS += \
SOURCES += \
+ tools/qarraydata.cpp \
tools/qbitarray.cpp \
tools/qbytearray.cpp \
tools/qbytearraymatcher.cpp \