Merge remote-tracking branch 'origin/containers' into api_changes

Change-Id: Ib8427caca38a14c040850bf45346f3213ffd04b3
This commit is contained in:
João Abecasis 2012-03-08 14:58:00 +01:00
commit 08a993526e
77 changed files with 5851 additions and 1249 deletions

26
dist/changes-5.0.0 vendored
View File

@ -36,6 +36,13 @@ information about a particular change.
- QCoreApplication::translate() will no longer return the source text when - QCoreApplication::translate() will no longer return the source text when
the translation is empty. Use lrelease -removeidentical for optimization. the translation is empty. Use lrelease -removeidentical for optimization.
- QString and QByteArray constructors that take a size argument will now treat
negative sizes to indicate nul-terminated strings (a nul-terminated array of
QChar, in the case of QString). In Qt 4, negative sizes were ignored and
result in empty QString and QByteArray, respectively. The size argument to
those constructors now has a default value of -1, thus replacing the separate
constructors that did the same.
- Qt::escape() is deprecated (but can be enabled via - Qt::escape() is deprecated (but can be enabled via
QT_DISABLE_DEPRECATED_BEFORE), use QString::toHtmlEscaped() instead. QT_DISABLE_DEPRECATED_BEFORE), use QString::toHtmlEscaped() instead.
@ -51,6 +58,11 @@ information about a particular change.
* QMetaType::construct() has been renamed to QMetaType::create(). * QMetaType::construct() has been renamed to QMetaType::create().
* QMetaType::unregisterType() has been removed. * QMetaType::unregisterType() has been removed.
- QMetaMethod::signature() has been renamed to QMetaMethod::methodSignature(),
and the return type has been changed to QByteArray. This was done to be able
to generate the signature string on demand, rather than always storing it in
the meta-data.
- QTestLib: - QTestLib:
* The plain-text, xml and lightxml test output formats have been changed to * The plain-text, xml and lightxml test output formats have been changed to
show a test result for every row of test data in data-driven tests. In show a test result for every row of test data in data-driven tests. In
@ -533,6 +545,20 @@ Qt for Windows CE
QMetaType::User, which means that it points to the first registered custom QMetaType::User, which means that it points to the first registered custom
type, instead of a nonexistent type. type, instead of a nonexistent type.
- QMetaType
* Interpretation of QMetaType::Void was changed. Before, in some cases
it was returned as an invalid type id, but sometimes it was used as a valid
type (C++ "void"). In Qt5, new QMetaType::UnknownType was introduced to
distinguish between these two. QMetaType::UnknownType is an invalid type id
signaling that a type is unknown to QMetaType, and QMetaType::Void
is a valid type id of C++ void type. The difference will be visible for
example in call to QMetaType::typeName(), this function will return null for
QMetaType::UnknownType and a pointer to "void" string for
QMetaType::Void.
Please, notice that QMetaType::UnknownType has value 0, which previously was
reserved for QMetaType::Void.
- QMessageBox - QMessageBox

View File

@ -107,7 +107,7 @@ for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
const QMetaObject* metaObject = obj->metaObject(); const QMetaObject* metaObject = obj->metaObject();
QStringList methods; QStringList methods;
for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i) for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
methods << QString::fromLatin1(metaObject->method(i).signature()); methods << QString::fromLatin1(metaObject->method(i).methodSignature());
//! [methodCount] //! [methodCount]
//! [6] //! [6]

View File

@ -73,7 +73,7 @@ MyStruct s2 = var.value<MyStruct>();
//! [3] //! [3]
int id = QMetaType::type("MyClass"); int id = QMetaType::type("MyClass");
if (id != 0) { if (id != QMetaType::UnknownType) {
void *myClassPtr = QMetaType::create(id); void *myClassPtr = QMetaType::create(id);
... ...
QMetaType::destroy(id, myClassPtr); QMetaType::destroy(id, myClassPtr);

View File

@ -400,7 +400,7 @@ QString QJsonValue::toString() const
if (t != String) if (t != String)
return QString(); return QString();
stringData->ref.ref(); // the constructor below doesn't add a ref. stringData->ref.ref(); // the constructor below doesn't add a ref.
return QString(*(const QConstStringData<1> *)stringData); return QString(*(const QStaticStringData<1> *)stringData);
} }
/*! /*!

File diff suppressed because it is too large Load Diff

View File

@ -57,8 +57,13 @@ class Q_CORE_EXPORT QMetaMethod
public: public:
inline QMetaMethod() : mobj(0),handle(0) {} inline QMetaMethod() : mobj(0),handle(0) {}
const char *signature() const; QByteArray methodSignature() const;
QByteArray name() const;
const char *typeName() 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> parameterTypes() const;
QList<QByteArray> parameterNames() const; QList<QByteArray> parameterNames() const;
const char *tag() const; const char *tag() const;
@ -137,8 +142,16 @@ public:
inline bool isValid() const { return mobj != 0; } inline bool isValid() const { return mobj != 0; }
private: 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; const QMetaObject *mobj;
uint handle; uint handle;
friend class QMetaMethodPrivate;
friend struct QMetaObject; friend struct QMetaObject;
friend struct QMetaObjectPrivate; friend struct QMetaObjectPrivate;
friend class QObject; friend class QObject;

View File

@ -105,11 +105,64 @@ enum MetaObjectFlags {
RequiresVariantMetaObject = 0x02 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; class QMutex;
struct QMetaObjectPrivate struct QMetaObjectPrivate
{ {
enum { OutputRevision = 6 }; // Used by moc and qmetaobjectbuilder enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision; int revision;
int className; int className;
@ -122,6 +175,7 @@ struct QMetaObjectPrivate
int signalCount; //since revision 4 int signalCount; //since revision 4
// revision 5 introduces changes in normalized signatures, no new members // revision 5 introduces changes in normalized signatures, no new members
// revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself // revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself
// revision 7 is Qt 5
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject) static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); } { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
@ -134,6 +188,27 @@ struct QMetaObjectPrivate
bool normalizeStringData); bool normalizeStringData);
static int originalClone(const QMetaObject *obj, int local_method_index); 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); static QList<QByteArray> parameterTypeNamesFromSignature(const char *signature);
#ifndef QT_NO_QOBJECT #ifndef QT_NO_QOBJECT

View File

@ -78,26 +78,17 @@ QT_BEGIN_NAMESPACE
*/ */
// copied from moc's generator.cpp // copied from moc's generator.cpp
uint qvariant_nameToType(const char* name) bool isBuiltinType(const QByteArray &type)
{ {
if (!name) int id = QMetaType::type(type);
return 0; if (!id && !type.isEmpty() && type != "void")
return false;
uint tp = QMetaType::type(name); return (id < QMetaType::User);
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;
} }
// copied from qmetaobject.cpp
static inline const QMetaObjectPrivate *priv(const uint* data) static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
// end of copied lines from qmetaobject.cpp
class QMetaMethodBuilderPrivate class QMetaMethodBuilderPrivate
{ {
@ -136,6 +127,21 @@ public:
{ {
attributes = ((attributes & ~AccessMask) | (int)value); 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 class QMetaPropertyBuilderPrivate
@ -458,13 +464,13 @@ QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype)
{ {
QMetaMethodBuilder method; QMetaMethodBuilder method;
if (prototype.methodType() == QMetaMethod::Method) if (prototype.methodType() == QMetaMethod::Method)
method = addMethod(prototype.signature()); method = addMethod(prototype.methodSignature());
else if (prototype.methodType() == QMetaMethod::Signal) else if (prototype.methodType() == QMetaMethod::Signal)
method = addSignal(prototype.signature()); method = addSignal(prototype.methodSignature());
else if (prototype.methodType() == QMetaMethod::Slot) else if (prototype.methodType() == QMetaMethod::Slot)
method = addSlot(prototype.signature()); method = addSlot(prototype.methodSignature());
else if (prototype.methodType() == QMetaMethod::Constructor) else if (prototype.methodType() == QMetaMethod::Constructor)
method = addConstructor(prototype.signature()); method = addConstructor(prototype.methodSignature());
method.setReturnType(prototype.typeName()); method.setReturnType(prototype.typeName());
method.setParameterNames(prototype.parameterNames()); method.setParameterNames(prototype.parameterNames());
method.setTag(prototype.tag()); method.setTag(prototype.tag());
@ -535,7 +541,7 @@ QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signatur
QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype) QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype)
{ {
Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor); Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor);
QMetaMethodBuilder ctor = addConstructor(prototype.signature()); QMetaMethodBuilder ctor = addConstructor(prototype.methodSignature());
ctor.setReturnType(prototype.typeName()); ctor.setReturnType(prototype.typeName());
ctor.setParameterNames(prototype.parameterNames()); ctor.setParameterNames(prototype.parameterNames());
ctor.setTag(prototype.tag()); ctor.setTag(prototype.tag());
@ -588,7 +594,7 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& protot
if (prototype.hasNotifySignal()) { if (prototype.hasNotifySignal()) {
// Find an existing method for the notify signal, or add a new one. // Find an existing method for the notify signal, or add a new one.
QMetaMethod method = prototype.notifySignal(); QMetaMethod method = prototype.notifySignal();
int index = indexOfMethod(method.signature()); int index = indexOfMethod(method.methodSignature());
if (index == -1) if (index == -1)
index = addMethod(method).index(); index = addMethod(method).index();
d->properties[property._index].notifySignal = index; d->properties[property._index].notifySignal = index;
@ -1070,75 +1076,82 @@ int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name)
#define ALIGN(size,type) \ #define ALIGN(size,type) \
(size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1) (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: Entries::iterator it = m_entries.find(value);
typedef QHash<QByteArray, int> Entries; // string --> offset mapping if (it != m_entries.end())
typedef Entries::const_iterator const_iterator; return it.value();
Entries::const_iterator constBegin() const int pos = m_index;
{ return m_entries.constBegin(); } m_entries.insert(value, pos);
Entries::const_iterator constEnd() const ++m_index;
{ return m_entries.constEnd(); } return pos;
}
MetaStringTable() : m_offset(0) {} int QMetaStringTable::preferredAlignment()
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;
}
int arraySize() const { return m_offset; }
private:
Entries m_entries;
int m_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. #ifdef Q_ALIGNOF
if (!parameterNames.isEmpty()) { return Q_ALIGNOF(QByteArrayData);
QByteArray names; #else
bool first = true; return sizeof(void *);
foreach (const QByteArray &name, parameterNames) { #endif
if (first) }
first = false;
else
names += (char)',';
names += name;
}
return names;
}
// Count commas in the signature, excluding those inside template arguments. // Returns the size (in bytes) required for serializing this string table.
int index = signature.indexOf('('); int QMetaStringTable::blobSize() const
if (index < 0) {
return QByteArray(); int size = m_entries.size() * sizeof(QByteArrayData);
++index; Entries::const_iterator it;
if (index >= signature.size()) for (it = m_entries.constBegin(); it != m_entries.constEnd(); ++it)
return QByteArray(); size += it.key().size() + 1;
if (signature[index] == ')') return size;
return QByteArray(); }
int count = 1;
int brackets = 0; // Writes strings to string data struct.
while (index < signature.size() && signature[index] != ',') { // The struct consists of an array of QByteArrayData, followed by a char array
char ch = signature[index++]; // containing the actual strings. This format must match the one produced by
if (ch == '<') // moc (see generator.cpp).
++brackets; void QMetaStringTable::writeBlob(char *out)
else if (ch == '>') {
--brackets; Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (preferredAlignment()-1)));
else if (ch == ',' && brackets <= 0)
++count; 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 };
memcpy(out + i * sizeof(QByteArrayData), &data, sizeof(QByteArrayData));
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". // 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 Q_UNUSED(expectedSize); // Avoid warning in release mode
int size = 0; int size = 0;
int dataIndex; int dataIndex;
int paramsIndex;
int enumIndex; int enumIndex;
int index; int index;
bool hasRevisionedMethods = d->hasRevisionedMethods(); bool hasRevisionedMethods = d->hasRevisionedMethods();
@ -1181,8 +1195,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
break; 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) { 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->revision = QMetaObjectPrivate::OutputRevision;
pmeta->flags = d->flags; pmeta->flags = d->flags;
pmeta->className = 0; // Class name is always the first string. 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(); dataIndex += 5 * d->methods.size();
if (hasRevisionedMethods) if (hasRevisionedMethods)
dataIndex += d->methods.size(); dataIndex += d->methods.size();
paramsIndex = dataIndex;
dataIndex += methodParametersDataSize;
pmeta->propertyCount = d->properties.size(); pmeta->propertyCount = d->properties.size();
pmeta->propertyData = dataIndex; pmeta->propertyData = dataIndex;
@ -1218,6 +1239,8 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
dataIndex += 5 * d->methods.size(); dataIndex += 5 * d->methods.size();
if (hasRevisionedMethods) if (hasRevisionedMethods)
dataIndex += d->methods.size(); dataIndex += d->methods.size();
paramsIndex = dataIndex;
dataIndex += methodParametersDataSize;
dataIndex += 3 * d->properties.size(); dataIndex += 3 * d->properties.size();
if (hasNotifySignals) if (hasNotifySignals)
dataIndex += d->properties.size(); dataIndex += d->properties.size();
@ -1240,13 +1263,14 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
// Find the start of the data and string tables. // Find the start of the data and string tables.
int *data = reinterpret_cast<int *>(pmeta); int *data = reinterpret_cast<int *>(pmeta);
size += dataIndex * sizeof(int); size += dataIndex * sizeof(int);
ALIGN(size, void *);
char *str = reinterpret_cast<char *>(buf + size); char *str = reinterpret_cast<char *>(buf + size);
if (buf) { if (buf) {
if (relocatable) { 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); meta->d.data = reinterpret_cast<uint *>((quintptr)pmetaSize);
} else { } else {
meta->d.stringdata = str; meta->d.stringdata = reinterpret_cast<const QByteArrayData *>(str);
meta->d.data = reinterpret_cast<uint *>(data); 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. // Reset the current data position to just past the QMetaObjectPrivate.
dataIndex = MetaObjectPrivateFieldCount; dataIndex = MetaObjectPrivateFieldCount;
MetaStringTable strings; QMetaStringTable strings;
strings.enter(d->className); strings.enter(d->className);
// Output the class infos, // Output the class infos,
@ -1273,24 +1297,21 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->methodData); Q_ASSERT(!buf || dataIndex == pmeta->methodData);
for (index = 0; index < d->methods.size(); ++index) { for (index = 0; index < d->methods.size(); ++index) {
QMetaMethodBuilderPrivate *method = &(d->methods[index]); QMetaMethodBuilderPrivate *method = &(d->methods[index]);
int sig = strings.enter(method->signature); int name = strings.enter(method->name());
int params; int argc = method->parameterCount();
QByteArray names = buildParameterNames
(method->signature, method->parameterNames);
params = strings.enter(names);
int ret = strings.enter(method->returnType);
int tag = strings.enter(method->tag); int tag = strings.enter(method->tag);
int attrs = method->attributes; int attrs = method->attributes;
if (buf) { if (buf) {
data[dataIndex] = sig; data[dataIndex] = name;
data[dataIndex + 1] = params; data[dataIndex + 1] = argc;
data[dataIndex + 2] = ret; data[dataIndex + 2] = paramsIndex;
data[dataIndex + 3] = tag; data[dataIndex + 3] = tag;
data[dataIndex + 4] = attrs; data[dataIndex + 4] = attrs;
if (method->methodType() == QMetaMethod::Signal) if (method->methodType() == QMetaMethod::Signal)
pmeta->signalCount++; pmeta->signalCount++;
} }
dataIndex += 5; dataIndex += 5;
paramsIndex += 1 + argc * 2;
} }
if (hasRevisionedMethods) { if (hasRevisionedMethods) {
for (index = 0; index < d->methods.size(); ++index) { 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. // Output the properties in the class.
Q_ASSERT(!buf || dataIndex == pmeta->propertyData); Q_ASSERT(!buf || dataIndex == pmeta->propertyData);
for (index = 0; index < d->properties.size(); ++index) { for (index = 0; index < d->properties.size(); ++index) {
QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
int name = strings.enter(prop->name); 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; int flags = prop->flags;
if (!isVariantType(prop->type)) { if (!isBuiltinType(prop->type))
flags |= EnumOrFlag; flags |= EnumOrFlag;
} else {
flags |= qvariant_nameToType(prop->type) << 24;
}
if (buf) { if (buf) {
data[dataIndex] = name; data[dataIndex] = name;
data[dataIndex + 1] = type; data[dataIndex + 1] = typeInfo;
data[dataIndex + 2] = flags; data[dataIndex + 2] = flags;
} }
dataIndex += 3; dataIndex += 3;
@ -1372,34 +1429,25 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->constructorData); Q_ASSERT(!buf || dataIndex == pmeta->constructorData);
for (index = 0; index < d->constructors.size(); ++index) { for (index = 0; index < d->constructors.size(); ++index) {
QMetaMethodBuilderPrivate *method = &(d->constructors[index]); QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
int sig = strings.enter(method->signature); int name = strings.enter(method->name());
int params; int argc = method->parameterCount();
QByteArray names = buildParameterNames
(method->signature, method->parameterNames);
params = strings.enter(names);
int ret = strings.enter(method->returnType);
int tag = strings.enter(method->tag); int tag = strings.enter(method->tag);
int attrs = method->attributes; int attrs = method->attributes;
if (buf) { if (buf) {
data[dataIndex] = sig; data[dataIndex] = name;
data[dataIndex + 1] = params; data[dataIndex + 1] = argc;
data[dataIndex + 2] = ret; data[dataIndex + 2] = paramsIndex;
data[dataIndex + 3] = tag; data[dataIndex + 3] = tag;
data[dataIndex + 4] = attrs; data[dataIndex + 4] = attrs;
} }
dataIndex += 5; dataIndex += 5;
paramsIndex += 1 + argc * 2;
} }
size += strings.arraySize(); size += strings.blobSize();
if (buf) { if (buf)
// Write strings to string data array. strings.writeBlob(str);
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';
}
}
// Output the zero terminator in the data array. // Output the zero terminator in the data array.
if (buf) if (buf)
@ -1508,7 +1556,7 @@ void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output,
quintptr dataOffset = (quintptr)dataMo->d.data; quintptr dataOffset = (quintptr)dataMo->d.data;
output->d.superdata = superclass; 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.data = reinterpret_cast<const uint *>(buf + dataOffset);
output->d.extradata = 0; 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 is empty, then the method's return type is \c{void}. The \a value
will be normalized before it is added to the method. will be normalized before it is added to the method.
\sa returnType(), signature() \sa returnType(), parameterTypes(), signature()
*/ */
void QMetaMethodBuilder::setReturnType(const QByteArray& value) void QMetaMethodBuilder::setReturnType(const QByteArray& value)
{ {
@ -1905,6 +1953,20 @@ void QMetaMethodBuilder::setReturnType(const QByteArray& value)
d->returnType = QMetaObject::normalizedType(value); d->returnType = QMetaObject::normalizedType(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. Returns the list of parameter names for this method.

View File

@ -56,6 +56,7 @@
#include <QtCore/qobject.h> #include <QtCore/qobject.h>
#include <QtCore/qmetaobject.h> #include <QtCore/qmetaobject.h>
#include <QtCore/qdatastream.h> #include <QtCore/qdatastream.h>
#include <QtCore/qhash.h>
#include <QtCore/qmap.h> #include <QtCore/qmap.h>
@ -203,6 +204,7 @@ public:
QByteArray returnType() const; QByteArray returnType() const;
void setReturnType(const QByteArray& value); void setReturnType(const QByteArray& value);
QList<QByteArray> parameterTypes() const;
QList<QByteArray> parameterNames() const; QList<QByteArray> parameterNames() const;
void setParameterNames(const QList<QByteArray>& value); void setParameterNames(const QList<QByteArray>& value);
@ -318,6 +320,23 @@ private:
QMetaEnumBuilderPrivate *d_func() const; 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::AddMembers)
Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags)

View File

@ -242,6 +242,7 @@ template<> struct TypeDefinition<QRegExp> { static const bool IsAvailable = fals
\value QEasingCurve QEasingCurve \value QEasingCurve QEasingCurve
\value User Base value for user types \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 FirstGuiType
\omitvalue FirstWidgetsType \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_TYPE(QT_ADD_STATIC_METATYPE)
QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER) QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER)
QT_FOR_EACH_STATIC_HACKS_TYPE(QT_ADD_STATIC_METATYPE_HACKS_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; Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper = 0;
@ -348,10 +349,7 @@ Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveOp, void QMetaType::registerStreamOperators(const char *typeName, SaveOperator saveOp,
LoadOperator loadOp) LoadOperator loadOp)
{ {
int idx = type(typeName); registerStreamOperators(type(typeName), saveOp, loadOp);
if (!idx)
return;
registerStreamOperators(idx, saveOp, loadOp);
} }
/*! \internal /*! \internal
@ -434,7 +432,7 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length)
{ {
const QVector<QCustomTypeInfo> * const ct = customTypes(); const QVector<QCustomTypeInfo> * const ct = customTypes();
if (!ct) if (!ct)
return 0; return QMetaType::UnknownType;
for (int v = 0; v < ct->count(); ++v) { for (int v = 0; v < ct->count(); ++v) {
const QCustomTypeInfo &customInfo = ct->at(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 v + QMetaType::User;
} }
} }
return 0; return QMetaType::UnknownType;
} }
/*! \internal /*! \internal
@ -488,11 +486,11 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
int previousSize = 0; int previousSize = 0;
int previousFlags = 0; int previousFlags = 0;
if (!idx) { if (idx == UnknownType) {
QWriteLocker locker(customTypesLock()); QWriteLocker locker(customTypesLock());
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size()); normalizedTypeName.size());
if (!idx) { if (idx == UnknownType) {
QCustomTypeInfo inf; QCustomTypeInfo inf;
inf.typeName = normalizedTypeName; inf.typeName = normalizedTypeName;
inf.creator = creator; inf.creator = creator;
@ -558,12 +556,12 @@ int QMetaType::registerTypedef(const char* typeName, int aliasId)
int idx = qMetaTypeStaticType(normalizedTypeName.constData(), int idx = qMetaTypeStaticType(normalizedTypeName.constData(),
normalizedTypeName.size()); normalizedTypeName.size());
if (!idx) { if (idx == UnknownType) {
QWriteLocker locker(customTypesLock()); QWriteLocker locker(customTypesLock());
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size()); normalizedTypeName.size());
if (!idx) { if (idx == UnknownType) {
QCustomTypeInfo inf; QCustomTypeInfo inf;
inf.typeName = normalizedTypeName; inf.typeName = normalizedTypeName;
inf.alias = aliasId; inf.alias = aliasId;
@ -592,17 +590,20 @@ int QMetaType::registerTypedef(const char* typeName, int aliasId)
*/ */
bool QMetaType::isRegistered(int type) 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; return true;
} }
QReadLocker locker(customTypesLock()); QReadLocker locker(customTypesLock());
const QVector<QCustomTypeInfo> * const ct = customTypes(); const QVector<QCustomTypeInfo> * const ct = customTypes();
return ((type >= User) && (ct && ct->count() > type - User) && !ct->at(type - User).typeName.isEmpty()); 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. no such type.
\sa isRegistered(), typeName(), Type \sa isRegistered(), typeName(), Type
@ -611,17 +612,17 @@ int QMetaType::type(const char *typeName)
{ {
int length = qstrlen(typeName); int length = qstrlen(typeName);
if (!length) if (!length)
return 0; return UnknownType;
int type = qMetaTypeStaticType(typeName, length); int type = qMetaTypeStaticType(typeName, length);
if (!type) { if (type == UnknownType) {
QReadLocker locker(customTypesLock()); QReadLocker locker(customTypesLock());
type = qMetaTypeCustomType_unlocked(typeName, length); type = qMetaTypeCustomType_unlocked(typeName, length);
#ifndef QT_NO_QOBJECT #ifndef QT_NO_QOBJECT
if (!type) { if (type == UnknownType) {
const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName); const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName);
type = qMetaTypeStaticType(normalizedTypeName.constData(), type = qMetaTypeStaticType(normalizedTypeName.constData(),
normalizedTypeName.size()); normalizedTypeName.size());
if (!type) { if (type == UnknownType) {
type = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), type = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size()); normalizedTypeName.size());
} }
@ -652,6 +653,7 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
return false; return false;
switch(type) { switch(type) {
case QMetaType::UnknownType:
case QMetaType::Void: case QMetaType::Void:
case QMetaType::VoidStar: case QMetaType::VoidStar:
case QMetaType::QObjectStar: case QMetaType::QObjectStar:
@ -857,6 +859,7 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
return false; return false;
switch(type) { switch(type) {
case QMetaType::UnknownType:
case QMetaType::Void: case QMetaType::Void:
case QMetaType::VoidStar: case QMetaType::VoidStar:
case QMetaType::QObjectStar: case QMetaType::QObjectStar:
@ -1154,6 +1157,7 @@ void *QMetaType::create(int type, const void *copy)
case QMetaType::QModelIndex: case QMetaType::QModelIndex:
return new NS(QModelIndex)(*static_cast<const NS(QModelIndex)*>(copy)); return new NS(QModelIndex)(*static_cast<const NS(QModelIndex)*>(copy));
#endif #endif
case QMetaType::UnknownType:
case QMetaType::Void: case QMetaType::Void:
return 0; return 0;
default: default:
@ -1257,6 +1261,7 @@ void *QMetaType::create(int type, const void *copy)
case QMetaType::QModelIndex: case QMetaType::QModelIndex:
return new NS(QModelIndex); return new NS(QModelIndex);
#endif #endif
case QMetaType::UnknownType:
case QMetaType::Void: case QMetaType::Void:
return 0; return 0;
default: default:
@ -1318,6 +1323,7 @@ public:
template<typename T> template<typename T>
void delegate(const T *where) { DestroyerImpl<T>::Destroy(m_type, const_cast<T*>(where)); } void delegate(const T *where) { DestroyerImpl<T>::Destroy(m_type, const_cast<T*>(where)); }
void delegate(const void *) {} void delegate(const void *) {}
void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestroyer(m_type, (void*)where); } void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestroyer(m_type, (void*)where); }
private: private:
@ -1381,6 +1387,7 @@ public:
template<typename T> template<typename T>
void *delegate(const T *copy) { return ConstructorImpl<T>::Construct(m_type, m_where, copy); } void *delegate(const T *copy) { return ConstructorImpl<T>::Construct(m_type, m_where, copy); }
void *delegate(const void *) { return m_where; } 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); } void *delegate(const QMetaTypeSwitcher::NotBuiltinType *copy) { return customTypeConstructor(m_type, m_where, copy); }
private: private:
@ -1470,6 +1477,7 @@ public:
template<typename T> template<typename T>
void delegate(const T *where) { DestructorImpl<T>::Destruct(m_type, const_cast<T*>(where)); } void delegate(const T *where) { DestructorImpl<T>::Destruct(m_type, const_cast<T*>(where)); }
void delegate(const void *) {} void delegate(const void *) {}
void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestructor(m_type, (void*)where); } void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestructor(m_type, (void*)where); }
private: private:
@ -1539,6 +1547,7 @@ public:
template<typename T> template<typename T>
int delegate(const T*) { return SizeOfImpl<T>::Size(m_type); } 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); } int delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeSizeOf(m_type); }
private: private:
static int customTypeSizeOf(const int type) static int customTypeSizeOf(const int type)
@ -1609,13 +1618,14 @@ public:
template<typename T> template<typename T>
quint32 delegate(const T*) { return FlagsImpl<T>::Flags(m_type); } quint32 delegate(const T*) { return FlagsImpl<T>::Flags(m_type); }
quint32 delegate(const void*) { return 0; } quint32 delegate(const void*) { return 0; }
quint32 delegate(const QMetaTypeSwitcher::UnknownType*) { return 0; }
quint32 delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeFlags(m_type); } quint32 delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return customTypeFlags(m_type); }
private: private:
const int m_type; const int m_type;
static quint32 customTypeFlags(const int type) static quint32 customTypeFlags(const int type)
{ {
const QVector<QCustomTypeInfo> * const ct = customTypes(); const QVector<QCustomTypeInfo> * const ct = customTypes();
if (Q_UNLIKELY(!ct)) if (Q_UNLIKELY(!ct || type < QMetaType::User))
return 0; return 0;
QReadLocker locker(customTypesLock()); QReadLocker locker(customTypesLock());
if (Q_UNLIKELY(ct->count() <= type - QMetaType::User)) if (Q_UNLIKELY(ct->count() <= type - QMetaType::User))
@ -1796,6 +1806,7 @@ public:
template<typename T> template<typename T>
void delegate(const T*) { TypeInfoImpl<T>(m_type, info); } void delegate(const T*) { TypeInfoImpl<T>(m_type, info); }
void delegate(const void*) {} void delegate(const void*) {}
void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType*) { customTypeInfo(m_type); } void delegate(const QMetaTypeSwitcher::NotBuiltinType*) { customTypeInfo(m_type); }
private: private:
void customTypeInfo(const uint type) void customTypeInfo(const uint type)
@ -1816,7 +1827,7 @@ QMetaType QMetaType::typeInfo(const int type)
{ {
TypeInfo typeInfo(type); TypeInfo typeInfo(type);
QMetaTypeSwitcher::switcher<void>(typeInfo, type, 0); 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. , static_cast<const QMetaTypeInterface *>(0) // typeInfo::info is a temporary variable, we can't return address of it.
, typeInfo.info.creator , typeInfo.info.creator
, typeInfo.info.deleter , typeInfo.info.deleter
@ -1827,26 +1838,23 @@ QMetaType QMetaType::typeInfo(const int type)
, typeInfo.info.size , typeInfo.info.size
, typeInfo.info.flags , typeInfo.info.flags
, type) , type)
: QMetaType(-1); : QMetaType(UnknownType);
} }
QMetaType::QMetaType(const int typeId) QMetaType::QMetaType(const int typeId)
: m_typeId(typeId) : m_typeId(typeId)
{ {
if (Q_UNLIKELY(typeId == -1)) { if (Q_UNLIKELY(typeId == UnknownType)) {
// Constructs invalid QMetaType instance. // Constructs invalid QMetaType instance.
m_extensionFlags = 0xffffffff; m_extensionFlags = 0xffffffff;
Q_ASSERT(!isValid()); Q_ASSERT(!isValid());
} else { } else {
// TODO it can be better. // TODO it can be better.
*this = QMetaType::typeInfo(typeId); *this = QMetaType::typeInfo(typeId);
if (m_typeId > 0 && !m_creator) { if (m_typeId == UnknownType)
m_extensionFlags = 0xffffffff; m_extensionFlags = 0xffffffff;
m_typeId = -1; else if (m_typeId == QMetaType::Void)
}
if (m_typeId == QMetaType::Void) {
m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx; m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx;
}
} }
} }

View File

@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType) // F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ #define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
F(Void, 0, void) \ F(Void, 43, void) \
F(Bool, 1, bool) \ F(Bool, 1, bool) \
F(Int, 2, int) \ F(Int, 2, int) \
F(UInt, 3, uint) \ F(UInt, 3, uint) \
@ -192,8 +192,8 @@ public:
// these are merged with QVariant // these are merged with QVariant
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID) QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
FirstCoreType = Void, FirstCoreType = Bool,
LastCoreType = QModelIndex, LastCoreType = Void,
FirstGuiType = QFont, FirstGuiType = QFont,
LastGuiType = QPolygonF, LastGuiType = QPolygonF,
FirstWidgetsType = QIcon, FirstWidgetsType = QIcon,
@ -202,6 +202,7 @@ public:
QReal = sizeof(qreal) == sizeof(double) ? Double : Float, QReal = sizeof(qreal) == sizeof(double) ? Double : Float,
UnknownType = 0,
User = 256 User = 256
}; };
@ -677,7 +678,7 @@ inline QMetaType::~QMetaType()
inline bool QMetaType::isValid() const inline bool QMetaType::isValid() const
{ {
return m_typeId >= 0; return m_typeId != UnknownType;
} }
inline bool QMetaType::isRegistered() const inline bool QMetaType::isRegistered() const

View File

@ -59,7 +59,8 @@ QT_BEGIN_NAMESPACE
class QMetaTypeSwitcher { class QMetaTypeSwitcher {
public: 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> template<class ReturnType, class DelegateObject>
static ReturnType switcher(DelegateObject &logic, int type, const void *data); 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)) { switch (QMetaType::Type(type)) {
QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_SWICHER_CASE) QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_SWICHER_CASE)
case QMetaType::UnknownType:
return logic.delegate(static_cast<UnknownType const *>(data));
default: default:
if (type < QMetaType::User)
return logic.delegate(static_cast<UnknownType const *>(data));
return logic.delegate(static_cast<NotBuiltinType const *>(data)); return logic.delegate(static_cast<NotBuiltinType const *>(data));
} }
} }

View File

@ -105,6 +105,30 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
return types; 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]; static QBasicMutex _q_ObjectMutexPool[131];
/** \internal /** \internal
@ -2179,12 +2203,12 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
if (signal.attributes() & QMetaMethod::Compatibility) { if (signal.attributes() & QMetaMethod::Compatibility) {
if (!(method.attributes() & QMetaMethod::Compatibility)) if (!(method.attributes() & QMetaMethod::Compatibility))
qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)", qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)",
sender->className(), signal.signature()); sender->className(), signal.methodSignature().constData());
} else if ((method.attributes() & QMetaMethod::Compatibility) && } else if ((method.attributes() & QMetaMethod::Compatibility) &&
method.methodType() == QMetaMethod::Signal) { method.methodType() == QMetaMethod::Signal) {
qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)", qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
sender->className(), signal.signature(), sender->className(), signal.methodSignature().constData(),
receiver->className(), method.signature()); 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 QMetaObject *smeta = sender->metaObject();
const char *signal_arg = signal; const char *signal_arg = signal;
++signal; //skip code ++signal; //skip code
int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); QByteArray signalName;
if (signal_index < 0) { QArgumentTypeArray signalTypes;
// check for normalized signatures int signal_index;
tmp_signal_name = QMetaObject::normalizedSignature(signal - 1); if (QMetaObjectPrivate::get(smeta)->revision >= 7) {
signal = tmp_signal_name.constData() + 1; 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;
smeta = sender->metaObject(); 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); signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
} if (signal_index < 0) {
if (signal_index < 0) { // check for normalized signatures
// re-use tmp_signal_name and signal from above tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
signal = tmp_signal_name.constData() + 1;
smeta = sender->metaObject(); smeta = sender->metaObject();
signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true); 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);
}
}
} }
if (signal_index < 0) { if (signal_index < 0) {
err_method_notfound(sender, signal_arg, "connect"); 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; const char *method_arg = method;
++method; // skip code ++method; // skip code
QByteArray methodName;
QArgumentTypeArray methodTypes;
const QMetaObject *rmeta = receiver->metaObject(); const QMetaObject *rmeta = receiver->metaObject();
int method_index_relative = -1; int method_index_relative = -1;
switch (membcode) { if (QMetaObjectPrivate::get(rmeta)->revision >= 7) {
case QSLOT_CODE: switch (membcode) {
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false); case QSLOT_CODE:
break; method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
case QSIGNAL_CODE: &rmeta, methodName, methodTypes.size(), methodTypes.constData());
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); break;
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();
if (method_index_relative < 0) { methodTypes.clear();
// check for normalized methods methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
tmp_method_name = QMetaObject::normalizedSignature(method); // rmeta may have been modified above
method = tmp_method_name.constData(); rmeta = receiver->metaObject();
switch (membcode) {
// rmeta may have been modified above case QSLOT_CODE:
rmeta = receiver->metaObject(); 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) { switch (membcode) {
case QSLOT_CODE: case QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false); method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
if (method_index_relative < 0)
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
break; break;
case QSIGNAL_CODE: case QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
if (method_index_relative < 0)
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
break; 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) { if (method_index_relative < 0) {
@ -2355,7 +2434,18 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
return QMetaObject::Connection(0); 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" qWarning("QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s", "\n %s::%s --> %s::%s",
sender->metaObject()->className(), signal, sender->metaObject()->className(), signal,
@ -2365,8 +2455,11 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
int *types = 0; int *types = 0;
if ((type == Qt::QueuedConnection) 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); return QMetaObject::Connection(0);
}
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
if (warnCompat) { if (warnCompat) {
@ -2424,17 +2517,17 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho
|| method.methodType() == QMetaMethod::Constructor) { || method.methodType() == QMetaMethod::Constructor) {
qWarning("QObject::connect: Cannot connect %s::%s to %s::%s", qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
sender ? sender->metaObject()->className() : "(null)", sender ? sender->metaObject()->className() : "(null)",
signal.signature(), signal.methodSignature().constData(),
receiver ? receiver->metaObject()->className() : "(null)", receiver ? receiver->metaObject()->className() : "(null)",
method.signature() ); method.methodSignature().constData() );
return QMetaObject::Connection(0); return QMetaObject::Connection(0);
} }
// Reconstructing SIGNAL() macro result for signal.signature() string // Reconstructing SIGNAL() macro result for signal.methodSignature() string
QByteArray signalSignature; QByteArray signalSignature;
signalSignature.reserve(qstrlen(signal.signature())+1); signalSignature.reserve(signal.methodSignature().size()+1);
signalSignature.append((char)(QSIGNAL_CODE + '0')); signalSignature.append((char)(QSIGNAL_CODE + '0'));
signalSignature.append(signal.signature()); signalSignature.append(signal.methodSignature());
int signal_index; int signal_index;
int method_index; int method_index;
@ -2448,20 +2541,20 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho
const QMetaObject *rmeta = receiver->metaObject(); const QMetaObject *rmeta = receiver->metaObject();
if (signal_index == -1) { if (signal_index == -1) {
qWarning("QObject::connect: Can't find signal %s on instance of class %s", 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); return QMetaObject::Connection(0);
} }
if (method_index == -1) { if (method_index == -1) {
qWarning("QObject::connect: Can't find method %s on instance of class %s", 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); 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" qWarning("QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s", "\n %s::%s --> %s::%s",
smeta->className(), signal.signature(), smeta->className(), signal.methodSignature().constData(),
rmeta->className(), method.signature()); rmeta->className(), method.methodSignature().constData());
return QMetaObject::Connection(0); return QMetaObject::Connection(0);
} }
@ -2609,12 +2702,25 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
*/ */
bool res = false; bool res = false;
const QMetaObject *smeta = sender->metaObject(); 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 { do {
int signal_index = -1; int signal_index = -1;
if (signal) { if (signal) {
signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); if (QMetaObjectPrivate::get(smeta)->revision >= 7) {
if (signal_index < 0) signal_index = QMetaObjectPrivate::indexOfSignalRelative(
signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true); &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) if (signal_index < 0)
break; break;
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
@ -2629,7 +2735,13 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
} else { } else {
const QMetaObject *rmeta = receiver->metaObject(); const QMetaObject *rmeta = receiver->metaObject();
do { 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) if (method_index >= 0)
while (method_index < rmeta->methodOffset()) while (method_index < rmeta->methodOffset())
rmeta = rmeta->superClass(); rmeta = rmeta->superClass();
@ -2693,24 +2805,24 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
if(signal.methodType() != QMetaMethod::Signal) { if(signal.methodType() != QMetaMethod::Signal) {
qWarning("QObject::%s: Attempt to %s non-signal %s::%s", qWarning("QObject::%s: Attempt to %s non-signal %s::%s",
"disconnect","unbind", "disconnect","unbind",
sender->metaObject()->className(), signal.signature()); sender->metaObject()->className(), signal.methodSignature().constData());
return false; return false;
} }
} }
if (method.mobj) { if (method.mobj) {
if(method.methodType() == QMetaMethod::Constructor) { if(method.methodType() == QMetaMethod::Constructor) {
qWarning("QObject::disconect: cannot use constructor as argument %s::%s", qWarning("QObject::disconect: cannot use constructor as argument %s::%s",
receiver->metaObject()->className(), method.signature()); receiver->metaObject()->className(), method.methodSignature().constData());
return false; return false;
} }
} }
// Reconstructing SIGNAL() macro result for signal.signature() string // Reconstructing SIGNAL() macro result for signal.methodSignature() string
QByteArray signalSignature; QByteArray signalSignature;
if (signal.mobj) { if (signal.mobj) {
signalSignature.reserve(qstrlen(signal.signature())+1); signalSignature.reserve(signal.methodSignature().size()+1);
signalSignature.append((char)(QSIGNAL_CODE + '0')); signalSignature.append((char)(QSIGNAL_CODE + '0'));
signalSignature.append(signal.signature()); signalSignature.append(signal.methodSignature());
} }
int signal_index; 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. // is -1 then this signal is not a member of sender.
if (signal.mobj && signal_index == -1) { if (signal.mobj && signal_index == -1) {
qWarning("QObject::disconect: signal %s not found on class %s", qWarning("QObject::disconect: signal %s not found on class %s",
signal.signature(), sender->metaObject()->className()); signal.methodSignature().constData(), sender->metaObject()->className());
return false; return false;
} }
// If this condition is true then method is not a member of receeiver. // If this condition is true then method is not a member of receeiver.
if (receiver && method.mobj && method_index == -1) { if (receiver && method.mobj && method_index == -1) {
qWarning("QObject::disconect: method %s not found on class %s", qWarning("QObject::disconect: method %s not found on class %s",
method.signature(), receiver->metaObject()->className()); method.methodSignature().constData(), receiver->metaObject()->className());
return false; return false;
} }
@ -3045,7 +3157,8 @@ void QMetaObject::connectSlotsByName(QObject *o)
Q_ASSERT(mo); Q_ASSERT(mo);
const QObjectList list = o->findChildren<QObject *>(QString()); const QObjectList list = o->findChildren<QObject *>(QString());
for (int i = 0; i < mo->methodCount(); ++i) { 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); Q_ASSERT(slot);
if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_') if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
continue; continue;
@ -3065,7 +3178,7 @@ void QMetaObject::connectSlotsByName(QObject *o)
if (method.methodType() != QMetaMethod::Signal) if (method.methodType() != QMetaMethod::Signal)
continue; continue;
if (!qstrncmp(method.signature(), slot + len + 4, slotlen)) { if (!qstrncmp(method.methodSignature().constData(), slot + len + 4, slotlen)) {
int signalOffset, methodOffset; int signalOffset, methodOffset;
computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset); computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset);
sigIndex = k + - methodOffset + signalOffset; sigIndex = k + - methodOffset + signalOffset;
@ -3311,9 +3424,17 @@ int QObjectPrivate::signalIndex(const char *signalName) const
{ {
Q_Q(const QObject); Q_Q(const QObject);
const QMetaObject *base = q->metaObject(); const QMetaObject *base = q->metaObject();
int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false); int relative_index;
if (relative_index < 0) if (QMetaObjectPrivate::get(base)->revision >= 7) {
relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true); 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) if (relative_index < 0)
return relative_index; return relative_index;
relative_index = QMetaObjectPrivate::originalClone(base, relative_index); relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
@ -3536,7 +3657,7 @@ void QObject::dumpObjectInfo()
offset = methodOffset - signalOffset; offset = methodOffset - signalOffset;
} }
const QMetaMethod signal = metaObject()->method(signal_index + offset); const QMetaMethod signal = metaObject()->method(signal_index + offset);
qDebug(" signal: %s", signal.signature()); qDebug(" signal: %s", signal.methodSignature().constData());
// receivers // receivers
const QObjectPrivate::Connection *c = const QObjectPrivate::Connection *c =
@ -3552,7 +3673,7 @@ void QObject::dumpObjectInfo()
qDebug(" --> %s::%s %s", qDebug(" --> %s::%s %s",
receiverMetaObject->className(), receiverMetaObject->className(),
c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()), c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()),
method.signature()); method.methodSignature().constData());
c = c->nextConnectionList; c = c->nextConnectionList;
} }
} }
@ -3569,7 +3690,7 @@ void QObject::dumpObjectInfo()
qDebug(" <-- %s::%s %s", qDebug(" <-- %s::%s %s",
s->sender->metaObject()->className(), s->sender->metaObject()->className(),
s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()), s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
slot.signature()); slot.methodSignature().constData());
} }
} else { } else {
qDebug(" <None>"); qDebug(" <None>");
@ -4041,9 +4162,16 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
locker.unlock(); locker.unlock();
// reconstruct the signature to call connectNotify // reconstruct the signature to call connectNotify
const char *sig = senderMetaObject->d.stringdata + senderMetaObject->d.data[ QByteArray tmp_sig;
reinterpret_cast<const QMetaObjectPrivate*>(senderMetaObject->d.data)->methodData const char *sig;
+ 5 * (signal_index - signalOffset)]; 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); QVarLengthArray<char> signalSignature(qstrlen(sig) + 2);
signalSignature.data()[0] = char(QSIGNAL_CODE + '0'); signalSignature.data()[0] = char(QSIGNAL_CODE + '0');
strcpy(signalSignature.data() + 1 , sig); strcpy(signalSignature.data() + 1 , sig);

View File

@ -50,11 +50,12 @@ QT_BEGIN_NAMESPACE
class QByteArray; class QByteArray;
struct QByteArrayData;
class QString; class QString;
#ifndef Q_MOC_OUTPUT_REVISION #ifndef Q_MOC_OUTPUT_REVISION
#define Q_MOC_OUTPUT_REVISION 64 #define Q_MOC_OUTPUT_REVISION 65
#endif #endif
// The following macros are our "extensions" to C++ // The following macros are our "extensions" to C++
@ -326,6 +327,8 @@ struct Q_CORE_EXPORT QMetaObject
QMetaProperty userProperty() const; QMetaProperty userProperty() const;
static bool checkConnectArgs(const char *signal, const char *method); 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 normalizedSignature(const char *method);
static QByteArray normalizedType(const char *type); static QByteArray normalizedType(const char *type);
@ -439,7 +442,7 @@ struct Q_CORE_EXPORT QMetaObject
struct { // private data struct { // private data
const QMetaObject *superdata; const QMetaObject *superdata;
const char *stringdata; const QByteArrayData *stringdata;
const uint *data; const uint *data;
const void *extradata; const void *extradata;
} d; } d;
@ -480,9 +483,6 @@ struct QMetaObjectExtraData
StaticMetacallFunction static_metacall; StaticMetacallFunction static_metacall;
}; };
inline const char *QMetaObject::className() const
{ return d.stringdata; }
inline const QMetaObject *QMetaObject::superClass() const inline const QMetaObject *QMetaObject::superClass() const
{ return d.superdata; } { return d.superdata; }

View File

@ -1697,7 +1697,7 @@ void QVariant::load(QDataStream &s)
QByteArray name; QByteArray name;
s >> name; s >> name;
typeId = QMetaType::type(name.constData()); typeId = QMetaType::type(name.constData());
if (!typeId) { if (typeId == QMetaType::UnknownType) {
s.setStatus(QDataStream::ReadCorruptData); s.setStatus(QDataStream::ReadCorruptData);
return; return;
} }

View File

@ -126,7 +126,7 @@ class Q_CORE_EXPORT QVariant
{ {
public: public:
enum Type { enum Type {
Invalid = QMetaType::Void, Invalid = QMetaType::UnknownType,
Bool = QMetaType::Bool, Bool = QMetaType::Bool,
Int = QMetaType::Int, Int = QMetaType::Int,
UInt = QMetaType::UInt, UInt = QMetaType::UInt,

View File

@ -187,7 +187,11 @@ public:
return FilteredComparator<T>::compare(m_a, m_b); 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; } bool delegate(const QMetaTypeSwitcher::NotBuiltinType*) { return false; }
protected: protected:
const QVariant::Private *m_a; const QVariant::Private *m_a;
@ -281,7 +285,8 @@ public:
return CallIsNull<T>::isNull(m_d); return CallIsNull<T>::isNull(m_d);
} }
// we need that as sizof(void) is undefined and it is needed in HasIsNullMethod // 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; } bool delegate(const QMetaTypeSwitcher::NotBuiltinType *) { return m_d->is_null; }
protected: protected:
const QVariant::Private *m_d; const QVariant::Private *m_d;
@ -354,8 +359,18 @@ public:
void delegate(const void*) void delegate(const void*)
{ {
// QMetaType::Void == QVariant::Invalid, creating an invalid value creates invalid QVariant qWarning("Trying to create a QVariant instance of QMetaType::Void type, an invalid QVariant will be constructed instead");
// TODO it might go away, check is needed 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_shared = false;
m_x->is_null = !m_copy; 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); qWarning("Trying to destruct an instance of an invalid type, type id: %i", m_d->type);
} }
// Ignore nonconstructible type // Ignore nonconstructible type
void delegate(const void*) {} void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const void*) { Q_ASSERT(false); }
private: private:
QVariant::Private *m_d; 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); 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"; m_debugStream.nospace() << "QVariant::Invalid";
} }
void delegate(const void*) { Q_ASSERT(false); }
private: private:
QDebug m_debugStream; QDebug m_debugStream;
QVariant::Private *m_d; QVariant::Private *m_d;

View File

@ -1657,7 +1657,7 @@ void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalInd
#ifdef QSTATEMACHINE_DEBUG #ifdef QSTATEMACHINE_DEBUG
qDebug() << q_func() << ": sending signal event ( sender =" << sender qDebug() << q_func() << ": sending signal event ( sender =" << sender
<< ", signal =" << sender->metaObject()->method(signalIndex).signature() << ')'; << ", signal =" << sender->metaObject()->method(signalIndex).methodSignature().constData() << ')';
#endif #endif
postInternalEvent(new QStateMachine::SignalEvent(sender, signalIndex, vargs)); postInternalEvent(new QStateMachine::SignalEvent(sender, signalIndex, vargs));
processEvents(DirectProcessing); processEvents(DirectProcessing);
@ -2211,10 +2211,29 @@ void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation)
// Begin moc-generated code -- modify carefully (check "HAND EDIT" parts)! // 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[] = { static const uint qt_meta_data_QSignalEventGenerator[] = {
// content: // content:
6, // revision 7, // revision
0, // classname 0, // classname
0, 0, // classinfo 0, 0, // classinfo
1, 14, // methods 1, 14, // methods
@ -2224,16 +2243,15 @@ static const uint qt_meta_data_QSignalEventGenerator[] = {
0, // flags 0, // flags
0, // signalCount 0, // signalCount
// slots: signature, parameters, type, tag, flags // slots: name, argc, parameters, tag, flags
23, 22, 22, 22, 0x0a, 1, 0, 19, 2, 0x0a,
// slots: parameters
QMetaType::Void,
0 // eod 0 // eod
}; };
static const char qt_meta_stringdata_QSignalEventGenerator[] = {
"QSignalEventGenerator\0\0execute()\0"
};
void QSignalEventGenerator::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) void QSignalEventGenerator::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{ {
if (_c == QMetaObject::InvokeMetaMethod) { if (_c == QMetaObject::InvokeMetaMethod) {
@ -2252,7 +2270,7 @@ const QMetaObjectExtraData QSignalEventGenerator::staticMetaObjectExtraData = {
}; };
const QMetaObject QSignalEventGenerator::staticMetaObject = { const QMetaObject QSignalEventGenerator::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator, { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator.data,
qt_meta_data_QSignalEventGenerator, &staticMetaObjectExtraData } qt_meta_data_QSignalEventGenerator, &staticMetaObjectExtraData }
}; };
@ -2264,7 +2282,7 @@ const QMetaObject *QSignalEventGenerator::metaObject() const
void *QSignalEventGenerator::qt_metacast(const char *_clname) void *QSignalEventGenerator::qt_metacast(const char *_clname)
{ {
if (!_clname) return 0; 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 static_cast<void*>(const_cast< QSignalEventGenerator*>(this));
return QObject::qt_metacast(_clname); return QObject::qt_metacast(_clname);
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -57,7 +57,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#define IS_RAW_DATA(d) ((d)->offset != 0) #define IS_RAW_DATA(d) ((d)->offset != sizeof(QByteArrayData))
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -69,24 +69,25 @@ int qFindByteArray(
int qAllocMore(int alloc, int extra) int qAllocMore(int alloc, int extra)
{ {
if (alloc == 0 && extra == 0) Q_ASSERT(alloc >= 0 && extra >= 0);
return 0; Q_ASSERT(alloc < (1 << 30) - extra);
const int page = 1 << 12;
int nalloc; unsigned nalloc = alloc + extra;
alloc += extra;
if (alloc < 1<<6) { // Round up to next power of 2
nalloc = (1<<3) + ((alloc >>3) << 3);
} else { // Assuming container is growing, always overshoot
// don't do anything if the loop will overflow signed int. //--nalloc;
if (alloc >= INT_MAX/2)
return INT_MAX; nalloc |= nalloc >> 1;
nalloc = (alloc < page) ? 1 << 3 : page; nalloc |= nalloc >> 2;
while (nalloc < alloc) { nalloc |= nalloc >> 4;
if (nalloc <= 0) nalloc |= nalloc >> 8;
return INT_MAX; nalloc |= nalloc >> 16;
nalloc *= 2; ++nalloc;
}
} Q_ASSERT(nalloc > unsigned(alloc + extra));
return nalloc - extra; return nalloc - extra;
} }
@ -554,7 +555,7 @@ QByteArray qUncompress(const uchar* data, int nbytes)
} }
d.take(); // realloc was successful d.take(); // realloc was successful
d.reset(p); d.reset(p);
d->offset = 0; d->offset = sizeof(QByteArrayData);
int res = ::uncompress((uchar*)d->data(), &len, int res = ::uncompress((uchar*)d->data(), &len,
(uchar*)data+4, nbytes-4); (uchar*)data+4, nbytes-4);
@ -576,11 +577,11 @@ QByteArray qUncompress(const uchar* data, int nbytes)
d.take(); // realloc was successful d.take(); // realloc was successful
d.reset(p); d.reset(p);
} }
d->ref = 1; d->ref.initializeOwned();
d->size = len; d->size = len;
d->alloc = len; d->alloc = len;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QByteArrayData);
d->data()[len] = 0; d->data()[len] = 0;
return QByteArray(d.take(), 0, 0); return QByteArray(d.take(), 0, 0);
@ -614,10 +615,10 @@ static inline char qToLower(char c)
return c; return c;
} }
const QConstByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZER(-1), const QStaticByteArrayData<1> QByteArray::shared_null = { { Q_REFCOUNT_INITIALIZE_STATIC,
0, 0, 0, { 0 } }, { 0 } }; 0, 0, 0, sizeof(QByteArrayData) }, { 0 } };
const QConstByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1), const QStaticByteArrayData<1> QByteArray::shared_empty = { { Q_REFCOUNT_INITIALIZE_STATIC,
0, 0, 0, { 0 } }, { 0 } }; 0, 0, 0, sizeof(QByteArrayData) }, { 0 } };
/*! /*!
\class QByteArray \class QByteArray
@ -904,7 +905,7 @@ QByteArray &QByteArray::operator=(const char *str)
x = const_cast<Data *>(&shared_empty.ba); x = const_cast<Data *>(&shared_empty.ba);
} else { } else {
int len = qstrlen(str); 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); realloc(len);
x = d; x = d;
memcpy(x->data(), str, len + 1); // include null terminator memcpy(x->data(), str, len + 1); // include null terminator
@ -1289,38 +1290,16 @@ void QByteArray::chop(int n)
\sa isEmpty() \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 Constructs a byte array containing the first \a size bytes of
array \a data. array \a data.
If \a data is 0, a null byte array is constructed. 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. QByteArray makes a deep copy of the string data.
\sa fromRawData() \sa fromRawData()
@ -1330,18 +1309,22 @@ QByteArray::QByteArray(const char *data, int size)
{ {
if (!data) { if (!data) {
d = const_cast<Data *>(&shared_null.ba); d = const_cast<Data *>(&shared_null.ba);
} else if (size <= 0) {
d = const_cast<Data *>(&shared_empty.ba);
} else { } else {
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1)); if (size < 0)
Q_CHECK_PTR(d); size = strlen(data);
d->ref = 1; if (!size) {
d->size = size; d = const_cast<Data *>(&shared_empty.ba);
d->alloc = size; } else {
d->capacityReserved = false; d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
d->offset = 0; Q_CHECK_PTR(d);
memcpy(d->data(), data, size); d->ref.initializeOwned();
d->data()[size] = '\0'; 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 { } else {
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1)); d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
d->ref = 1; d->ref.initializeOwned();
d->size = size; d->size = size;
d->alloc = size; d->alloc = size;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QByteArrayData);
memset(d->data(), ch, size); memset(d->data(), ch, size);
d->data()[size] = '\0'; d->data()[size] = '\0';
} }
@ -1379,11 +1362,11 @@ QByteArray::QByteArray(int size, Qt::Initialization)
{ {
d = static_cast<Data *>(malloc(sizeof(Data) + size + 1)); d = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
d->ref = 1; d->ref.initializeOwned();
d->size = size; d->size = size;
d->alloc = size; d->alloc = size;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QByteArrayData);
d->data()[size] = '\0'; d->data()[size] = '\0';
} }
@ -1405,7 +1388,7 @@ void QByteArray::resize(int size)
if (size < 0) if (size < 0)
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; d->size = size;
return; return;
} }
@ -1426,15 +1409,15 @@ void QByteArray::resize(int size)
// //
Data *x = static_cast<Data *>(malloc(sizeof(Data) + size + 1)); Data *x = static_cast<Data *>(malloc(sizeof(Data) + size + 1));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
x->ref = 1; x->ref.initializeOwned();
x->size = size; x->size = size;
x->alloc = size; x->alloc = size;
x->capacityReserved = false; x->capacityReserved = false;
x->offset = 0; x->offset = sizeof(QByteArrayData);
x->data()[size] = '\0'; x->data()[size] = '\0';
d = x; d = x;
} else { } 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)) || (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
realloc(qAllocMore(size, sizeof(Data))); realloc(qAllocMore(size, sizeof(Data)));
if (int(d->alloc) >= size) { if (int(d->alloc) >= size) {
@ -1465,14 +1448,14 @@ QByteArray &QByteArray::fill(char ch, int size)
void QByteArray::realloc(int alloc) 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)); Data *x = static_cast<Data *>(malloc(sizeof(Data) + alloc + 1));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
x->ref = 1; x->ref.initializeOwned();
x->size = qMin(alloc, d->size); x->size = qMin(alloc, d->size);
x->alloc = alloc; x->alloc = alloc;
x->capacityReserved = d->capacityReserved; x->capacityReserved = d->capacityReserved;
x->offset = 0; x->offset = sizeof(QByteArrayData);
::memcpy(x->data(), d->data(), x->size); ::memcpy(x->data(), d->data(), x->size);
x->data()[x->size] = '\0'; x->data()[x->size] = '\0';
if (!d->ref.deref()) if (!d->ref.deref())
@ -1482,7 +1465,7 @@ void QByteArray::realloc(int alloc)
Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc + 1)); Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc + 1));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
x->alloc = alloc; x->alloc = alloc;
x->offset = 0; x->offset = sizeof(QByteArrayData);
d = x; d = x;
} }
} }
@ -1504,7 +1487,7 @@ void QByteArray::expand(int i)
QByteArray QByteArray::nulTerminated() const QByteArray QByteArray::nulTerminated() const
{ {
// is this fromRawData? // is this fromRawData?
if (!d->offset) if (!IS_RAW_DATA(d))
return *this; // no, then we're sure we're zero terminated return *this; // no, then we're sure we're zero terminated
QByteArray copy(*this); QByteArray copy(*this);
@ -1566,7 +1549,7 @@ QByteArray &QByteArray::prepend(const char *str)
QByteArray &QByteArray::prepend(const char *str, int len) QByteArray &QByteArray::prepend(const char *str, int len)
{ {
if (str) { 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))); realloc(qAllocMore(d->size + len, sizeof(Data)));
memmove(d->data()+len, d->data(), d->size); memmove(d->data()+len, d->data(), d->size);
memcpy(d->data(), str, len); memcpy(d->data(), str, len);
@ -1584,7 +1567,7 @@ QByteArray &QByteArray::prepend(const char *str, int len)
QByteArray &QByteArray::prepend(char ch) 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))); realloc(qAllocMore(d->size + 1, sizeof(Data)));
memmove(d->data()+1, d->data(), d->size); memmove(d->data()+1, d->data(), d->size);
d->data()[0] = ch; 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)) { if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
*this = ba; *this = ba;
} else if (ba.d != &shared_null.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))); realloc(qAllocMore(d->size + ba.d->size, sizeof(Data)));
memcpy(d->data() + d->size, ba.d->data(), ba.d->size); memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size; d->size += ba.d->size;
@ -1656,7 +1639,7 @@ QByteArray& QByteArray::append(const char *str)
{ {
if (str) { if (str) {
int len = qstrlen(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))); realloc(qAllocMore(d->size + len, sizeof(Data)));
memcpy(d->data() + d->size, str, len + 1); // include null terminator memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len; d->size += len;
@ -1681,7 +1664,7 @@ QByteArray &QByteArray::append(const char *str, int len)
if (len < 0) if (len < 0)
len = qstrlen(str); len = qstrlen(str);
if (str && len) { 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))); realloc(qAllocMore(d->size + len, sizeof(Data)));
memcpy(d->data() + d->size, str, len); // include null terminator memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len; d->size += len;
@ -1698,7 +1681,7 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch) 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))); realloc(qAllocMore(d->size + 1, sizeof(Data)));
d->data()[d->size++] = ch; d->data()[d->size++] = ch;
d->data()[d->size] = '\0'; d->data()[d->size] = '\0';
@ -3889,11 +3872,11 @@ QByteArray QByteArray::fromRawData(const char *data, int size)
} else { } else {
x = static_cast<Data *>(malloc(sizeof(Data) + 1)); x = static_cast<Data *>(malloc(sizeof(Data) + 1));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
x->ref = 1; x->ref.initializeOwned();
x->size = size; x->size = size;
x->alloc = 0; x->alloc = 0;
x->capacityReserved = false; x->capacityReserved = false;
x->offset = data - (x->d + sizeof(qptrdiff)); x->offset = data - reinterpret_cast<char *>(x);
} }
return QByteArray(x, 0, 0); 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) QByteArray &QByteArray::setRawData(const char *data, uint size)
{ {
if (d->ref != 1 || d->alloc) { if (d->ref.isShared() || d->alloc) {
*this = fromRawData(data, size); *this = fromRawData(data, size);
} else { } else {
if (data) { if (data) {
d->size = size; d->size = size;
d->offset = data - (d->d + sizeof(qptrdiff)); d->offset = data - reinterpret_cast<char *>(d);
} else { } else {
d->offset = 0; d->offset = sizeof(QByteArrayData);
d->size = 0; d->size = 0;
*d->data() = 0; *d->data() = 0;
} }

View File

@ -124,32 +124,31 @@ struct QByteArrayData
int size; int size;
uint alloc : 31; uint alloc : 31;
uint capacityReserved : 1; uint capacityReserved : 1;
union {
qptrdiff offset; // will always work as we add/subtract from a ushort ptr qptrdiff offset;
char d[sizeof(qptrdiff)];
}; inline char *data() { return reinterpret_cast<char *>(this) + offset; }
inline char *data() { return d + sizeof(qptrdiff) + offset; } inline const char *data() const { return reinterpret_cast<const char *>(this) + offset; }
inline const char *data() const { return d + sizeof(qptrdiff) + offset; }
}; };
template<int N> struct QConstByteArrayData template<int N> struct QStaticByteArrayData
{ {
const QByteArrayData ba; QByteArrayData ba;
const char data[N + 1]; 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) #if defined(Q_COMPILER_LAMBDA)
# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr<sizeof(str) - 1> { \ # define QByteArrayLiteral(str) ([]() -> QStaticByteArrayDataPtr<sizeof(str) - 1> { \
enum { Size = sizeof(str) - 1 }; \ enum { Size = sizeof(str) - 1 }; \
static const QConstByteArrayData<Size> qbytearray_literal = \ static const QStaticByteArrayData<Size> qbytearray_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QByteArrayData) }, str }; \
QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \ QStaticByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
return holder; }()) return holder; }())
#elif defined(Q_CC_GNU) #elif defined(Q_CC_GNU)
@ -160,9 +159,9 @@ template<int N> struct QConstByteArrayDataPtr
# define QByteArrayLiteral(str) \ # define QByteArrayLiteral(str) \
__extension__ ({ \ __extension__ ({ \
enum { Size = sizeof(str) - 1 }; \ enum { Size = sizeof(str) - 1 }; \
static const QConstByteArrayData<Size> qbytearray_literal = \ static const QStaticByteArrayData<Size> qbytearray_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QByteArrayData) }, str }; \
QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \ QStaticByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
holder; }) holder; })
#endif #endif
@ -180,8 +179,7 @@ private:
public: public:
inline QByteArray(); inline QByteArray();
QByteArray(const char *); QByteArray(const char *, int size = -1);
QByteArray(const char *, int size);
QByteArray(int size, char c); QByteArray(int size, char c);
QByteArray(int size, Qt::Initialization); QByteArray(int size, Qt::Initialization);
inline QByteArray(const QByteArray &); inline QByteArray(const QByteArray &);
@ -379,16 +377,16 @@ public:
bool isNull() const; bool isNull() const;
template <int n> template <int n>
inline QByteArray(const QConstByteArrayData<n> &dd) inline QByteArray(const QStaticByteArrayData<n> &dd)
: d(const_cast<QByteArrayData *>(&dd.ba)) {} : d(const_cast<QByteArrayData *>(&dd.ba)) {}
template <int N> 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)) {} : d(const_cast<QByteArrayData *>(&dd.ptr->ba)) {}
private: private:
operator QNoImplicitBoolCast() const; operator QNoImplicitBoolCast() const;
static const QConstByteArrayData<1> shared_null; static const QStaticByteArrayData<1> shared_null;
static const QConstByteArrayData<1> shared_empty; static const QStaticByteArrayData<1> shared_empty;
Data *d; Data *d;
QByteArray(Data *dd, int /*dummy*/, int /*dummy*/) : d(dd) {} QByteArray(Data *dd, int /*dummy*/, int /*dummy*/) : d(dd) {}
void realloc(int alloc); void realloc(int alloc);
@ -424,9 +422,9 @@ inline const char *QByteArray::data() const
inline const char *QByteArray::constData() const inline const char *QByteArray::constData() const
{ return d->data(); } { return d->data(); }
inline void QByteArray::detach() 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 inline bool QByteArray::isDetached() const
{ return d->ref == 1; } { return !d->ref.isShared(); }
inline QByteArray::QByteArray(const QByteArray &a) : d(a.d) inline QByteArray::QByteArray(const QByteArray &a) : d(a.d)
{ d->ref.ref(); } { d->ref.ref(); }
@ -435,7 +433,7 @@ inline int QByteArray::capacity() const
inline void QByteArray::reserve(int asize) inline void QByteArray::reserve(int asize)
{ {
if (d->ref != 1 || asize > int(d->alloc)) if (d->ref.isShared() || asize > int(d->alloc))
realloc(asize); realloc(asize);
if (!d->capacityReserved) { if (!d->capacityReserved) {
@ -446,11 +444,12 @@ inline void QByteArray::reserve(int asize)
inline void QByteArray::squeeze() 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); realloc(d->size);
if (d->capacityReserved) { 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; d->capacityReserved = false;
} }
} }

View File

@ -166,7 +166,7 @@ static int countBits(int hint)
const int MinNumBits = 4; const int MinNumBits = 4;
const QHashData QHashData::shared_null = { 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) void *QHashData::allocateNode(int nodeAlign)
@ -196,7 +196,7 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *),
d = new QHashData; d = new QHashData;
d->fakeNext = 0; d->fakeNext = 0;
d->buckets = 0; d->buckets = 0;
d->ref = 1; d->ref.initializeOwned();
d->size = size; d->size = size;
d->nodeSize = nodeSize; d->nodeSize = nodeSize;
d->userNumBits = userNumBits; d->userNumBits = userNumBits;

View File

@ -288,8 +288,8 @@ public:
void reserve(int size); void reserve(int size);
inline void squeeze() { reserve(1); } inline void squeeze() { reserve(1); }
inline void detach() { if (d->ref != 1) detach_helper(); } inline void detach() { if (d->ref.isShared()) detach_helper(); }
inline bool isDetached() const { return d->ref == 1; } 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 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; } inline bool isSharedWith(const QHash<Key, T> &other) const { return d == other.d; }

View File

@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE
const QLinkedListData QLinkedListData::shared_null = { const QLinkedListData QLinkedListData::shared_null = {
const_cast<QLinkedListData *>(&QLinkedListData::shared_null), const_cast<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 /*! \class QLinkedList

View File

@ -94,8 +94,8 @@ public:
inline int size() const { return d->size; } inline int size() const { return d->size; }
inline void detach() inline void detach()
{ if (d->ref != 1) detach_helper(); } { if (d->ref.isShared()) detach_helper(); }
inline bool isDetached() const { return d->ref == 1; } 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 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; } inline bool isSharedWith(const QLinkedList<T> &other) const { return d == other.d; }
@ -241,8 +241,6 @@ private:
template <typename T> template <typename T>
inline QLinkedList<T>::~QLinkedList() inline QLinkedList<T>::~QLinkedList()
{ {
if (!d)
return;
if (!d->ref.deref()) if (!d->ref.deref())
free(d); free(d);
} }
@ -252,7 +250,7 @@ void QLinkedList<T>::detach_helper()
{ {
union { QLinkedListData *d; Node *e; } x; union { QLinkedListData *d; Node *e; } x;
x.d = new QLinkedListData; x.d = new QLinkedListData;
x.d->ref = 1; x.d->ref.initializeOwned();
x.d->size = d->size; x.d->size = d->size;
x.d->sharable = true; x.d->sharable = true;
Node *original = e->n; Node *original = e->n;
@ -265,6 +263,7 @@ void QLinkedList<T>::detach_helper()
copy = copy->n; copy = copy->n;
} QT_CATCH(...) { } QT_CATCH(...) {
copy->n = x.e; copy->n = x.e;
Q_ASSERT(!x.d->ref.deref()); // Don't trigger assert in free
free(x.d); free(x.d);
QT_RETHROW; QT_RETHROW;
} }
@ -281,14 +280,13 @@ void QLinkedList<T>::free(QLinkedListData *x)
{ {
Node *y = reinterpret_cast<Node*>(x); Node *y = reinterpret_cast<Node*>(x);
Node *i = y->n; Node *i = y->n;
if (x->ref == 0) { Q_ASSERT(x->ref.atomic.load() == 0);
while(i != y) { while (i != y) {
Node *n = i; Node *n = i;
i = i->n; i = i->n;
delete n; delete n;
}
delete x;
} }
delete x;
} }
template <typename T> template <typename T>

View File

@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
the number of elements in the list. 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) 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 *))); Data* t = static_cast<Data *>(::malloc(DataHeaderSize + alloc * sizeof(void *)));
Q_CHECK_PTR(t); Q_CHECK_PTR(t);
t->ref = 1; t->ref.initializeOwned();
t->sharable = true;
t->alloc = alloc; t->alloc = alloc;
// The space reservation algorithm's optimization is biased towards appending: // The space reservation algorithm's optimization is biased towards appending:
// Something which looks like an append will put the data at the beginning, // 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 *))); Data* t = static_cast<Data *>(::malloc(DataHeaderSize + alloc * sizeof(void *)));
Q_CHECK_PTR(t); Q_CHECK_PTR(t);
t->ref = 1; t->ref.initializeOwned();
t->sharable = true;
t->alloc = alloc; t->alloc = alloc;
if (!alloc) { if (!alloc) {
t->begin = 0; t->begin = 0;
@ -146,7 +144,7 @@ QListData::Data *QListData::detach(int alloc)
void QListData::realloc(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 *))); Data *x = static_cast<Data *>(::realloc(d, DataHeaderSize + alloc * sizeof(void *)));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
@ -159,7 +157,7 @@ void QListData::realloc(int alloc)
// ensures that enough space is available to append n elements // ensures that enough space is available to append n elements
void **QListData::append(int n) void **QListData::append(int n)
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
int e = d->end; int e = d->end;
if (e + n > d->alloc) { if (e + n > d->alloc) {
int b = d->begin; int b = d->begin;
@ -190,7 +188,7 @@ void **QListData::append(const QListData& l)
void **QListData::prepend() void **QListData::prepend()
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
if (d->begin == 0) { if (d->begin == 0) {
if (d->end >= d->alloc / 3) if (d->end >= d->alloc / 3)
realloc(grow(d->alloc + 1)); realloc(grow(d->alloc + 1));
@ -208,7 +206,7 @@ void **QListData::prepend()
void **QListData::insert(int i) void **QListData::insert(int i)
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
if (i <= 0) if (i <= 0)
return prepend(); return prepend();
int size = d->end - d->begin; int size = d->end - d->begin;
@ -247,7 +245,7 @@ void **QListData::insert(int i)
void QListData::remove(int i) void QListData::remove(int i)
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
i += d->begin; i += d->begin;
if (i - d->begin < d->end - i) { if (i - d->begin < d->end - i) {
if (int offset = i - d->begin) if (int offset = i - d->begin)
@ -262,7 +260,7 @@ void QListData::remove(int i)
void QListData::remove(int i, int n) void QListData::remove(int i, int n)
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
i += d->begin; i += d->begin;
int middle = i + n/2; int middle = i + n/2;
if (middle - d->begin < d->end - middle) { 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) void QListData::move(int from, int to)
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
if (from == to) if (from == to)
return; return;
@ -318,7 +316,7 @@ void QListData::move(int from, int to)
void **QListData::erase(void **xi) void **QListData::erase(void **xi)
{ {
Q_ASSERT(d->ref == 1); Q_ASSERT(!d->ref.isShared());
int i = xi - (d->array + d->begin); int i = xi - (d->array + d->begin);
remove(i); remove(i);
return d->array + d->begin + i; return d->array + d->begin + i;

View File

@ -71,7 +71,6 @@ struct Q_CORE_EXPORT QListData {
struct Data { struct Data {
QtPrivate::RefCount ref; QtPrivate::RefCount ref;
int alloc, begin, end; int alloc, begin, end;
uint sharable : 1;
void *array[1]; void *array[1];
}; };
enum { DataHeaderSize = sizeof(Data) - sizeof(void *) }; enum { DataHeaderSize = sizeof(Data) - sizeof(void *) };
@ -114,7 +113,7 @@ class QList
public: public:
inline QList() : d(const_cast<QListData::Data *>(&QListData::shared_null)) { } 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();
QList<T> &operator=(const QList<T> &l); QList<T> &operator=(const QList<T> &l);
#ifdef Q_COMPILER_RVALUE_REFS #ifdef Q_COMPILER_RVALUE_REFS
@ -132,17 +131,25 @@ public:
inline int size() const { return p.size(); } 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() inline void detachShared()
{ {
// The "this->" qualification is needed for GCCE. // 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(); detach_helper();
} }
inline bool isDetached() const { return d->ref == 1; } inline bool isDetached() const { return !d->ref.isShared(); }
inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QListData::shared_null) d->sharable = sharable; } 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 isSharedWith(const QList<T> &other) const { return d == other.d; }
inline bool isEmpty() const { return p.isEmpty(); } 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) Q_INLINE_TEMPLATE QList<T> &QList<T>::operator=(const QList<T> &l)
{ {
if (d != l.d) { if (d != l.d) {
QListData::Data *o = l.d; QList<T> tmp(l);
o->ref.ref(); tmp.swap(*this);
if (!d->ref.deref())
dealloc(d);
d = o;
if (!d->sharable)
detach_helper();
} }
return *this; return *this;
} }
@ -478,7 +480,7 @@ template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc) Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc)
{ {
if (d->alloc < alloc) { if (d->alloc < alloc) {
if (d->ref != 1) if (d->ref.isShared())
detach_helper(alloc); detach_helper(alloc);
else else
p.realloc(alloc); p.realloc(alloc);
@ -488,7 +490,7 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc)
template <typename T> template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &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); Node *n = detach_helper_grow(INT_MAX, 1);
QT_TRY { QT_TRY {
node_construct(n, t); node_construct(n, t);
@ -522,7 +524,7 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
template <typename T> template <typename T>
inline void QList<T>::prepend(const T &t) inline void QList<T>::prepend(const T &t)
{ {
if (d->ref != 1) { if (d->ref.isShared()) {
Node *n = detach_helper_grow(0, 1); Node *n = detach_helper_grow(0, 1);
QT_TRY { QT_TRY {
node_construct(n, t); node_construct(n, t);
@ -556,7 +558,7 @@ inline void QList<T>::prepend(const T &t)
template <typename T> template <typename T>
inline void QList<T>::insert(int i, const T &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); Node *n = detach_helper_grow(i, 1);
QT_TRY { QT_TRY {
node_construct(n, t); node_construct(n, t);
@ -707,6 +709,28 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper()
detach_helper(d->alloc); detach_helper(d->alloc);
} }
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> template <typename T>
Q_OUTOFLINE_TEMPLATE QList<T>::~QList() Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
{ {
@ -802,7 +826,7 @@ Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l)
if (isEmpty()) { if (isEmpty()) {
*this = l; *this = l;
} else { } else {
Node *n = (d->ref != 1) Node *n = (d->ref.isShared())
? detach_helper_grow(INT_MAX, l.size()) ? detach_helper_grow(INT_MAX, l.size())
: reinterpret_cast<Node *>(p.append(l.p)); : reinterpret_cast<Node *>(p.append(l.p));
QT_TRY { QT_TRY {

View File

@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
const QMapData QMapData::shared_null = { const QMapData QMapData::shared_null = {
const_cast<QMapData *>(&shared_null), const_cast<QMapData *>(&shared_null),
{ const_cast<QMapData *>(&shared_null), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 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) QMapData *QMapData::createData(int alignment)
@ -63,7 +63,7 @@ QMapData *QMapData::createData(int alignment)
Node *e = reinterpret_cast<Node *>(d); Node *e = reinterpret_cast<Node *>(d);
e->backward = e; e->backward = e;
e->forward[0] = e; e->forward[0] = e;
d->ref = 1; d->ref.initializeOwned();
d->topLevel = 0; d->topLevel = 0;
d->size = 0; d->size = 0;
d->randomBits = 0; d->randomBits = 0;

View File

@ -179,7 +179,7 @@ public:
inline QMap() : d(const_cast<QMapData *>(&QMapData::shared_null)) { } inline QMap() : d(const_cast<QMapData *>(&QMapData::shared_null)) { }
inline QMap(const QMap<Key, T> &other) : d(other.d) inline QMap(const QMap<Key, T> &other) : d(other.d)
{ d->ref.ref(); if (!d->sharable) detach(); } { 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); QMap<Key, T> &operator=(const QMap<Key, T> &other);
#ifdef Q_COMPILER_RVALUE_REFS #ifdef Q_COMPILER_RVALUE_REFS
@ -199,8 +199,8 @@ public:
inline bool isEmpty() const { return d->size == 0; } inline bool isEmpty() const { return d->size == 0; }
inline void detach() { if (d->ref != 1) detach_helper(); } inline void detach() { if (d->ref.isShared()) detach_helper(); }
inline bool isDetached() const { return d->ref == 1; } 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 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 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; } inline void setInsertInOrder(bool ordered) { if (ordered) detach(); if (d != &QMapData::shared_null) d->insertInOrder = ordered; }

View File

@ -55,37 +55,61 @@ namespace QtPrivate
class RefCount class RefCount
{ {
public: public:
inline void ref() { inline bool ref() {
if (atomic.load() > 0) int count = atomic.load();
if (count == 0) // !isSharable
return false;
if (count != -1) // !isStatic
atomic.ref(); atomic.ref();
return true;
} }
inline bool deref() { inline bool deref() {
if (atomic.load() <= 0) int count = atomic.load();
if (count == 0) // !isSharable
return false;
if (count == -1) // isStatic
return true; return true;
return atomic.deref(); return atomic.deref();
} }
inline bool operator==(int value) const bool setSharable(bool sharable)
{ return atomic.load() == value; } {
inline bool operator!=(int value) const Q_ASSERT(!isShared());
{ return atomic.load() != value; } if (sharable)
inline bool operator!() const return atomic.testAndSetRelaxed(0, 1);
{ return !atomic.load(); } else
inline operator int() const return atomic.testAndSetRelaxed(1, 0);
{ return atomic.load(); } }
inline RefCount &operator=(int value)
{ atomic.store(value); return *this; } bool isStatic() const
inline RefCount &operator=(const RefCount &other) {
{ atomic.store(other.atomic.load()); return *this; } // 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; 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_NAMESPACE
QT_END_HEADER QT_END_HEADER

View File

@ -94,6 +94,8 @@
#define ULLONG_MAX quint64_C(18446744073709551615) #define ULLONG_MAX quint64_C(18446744073709551615)
#endif #endif
#define IS_RAW_DATA(d) ((d)->offset != sizeof(QStringData))
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#ifdef QT_USE_ICU #ifdef QT_USE_ICU
@ -793,8 +795,8 @@ const QString::Null QString::null = { };
\sa split() \sa split()
*/ */
const QConstStringData<1> QString::shared_null = { { 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 QConstStringData<1> QString::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; const QStaticStringData<1> QString::shared_empty = { { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, false, sizeof(QStringData) }, { 0 } };
int QString::grow(int size) int QString::grow(int size)
{ {
@ -1015,62 +1017,43 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
Constructs a string initialized with the first \a size characters Constructs a string initialized with the first \a size characters
of the QChar array \a unicode. 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 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. is and the Byte Order Mark is preserved if present.
\sa fromRawData()
*/ */
QString::QString(const QChar *unicode, int size) QString::QString(const QChar *unicode, int size)
{ {
if (!unicode) { if (!unicode) {
d = const_cast<Data *>(&shared_null.str); d = const_cast<Data *>(&shared_null.str);
} else if (size <= 0) {
d = const_cast<Data *>(&shared_empty.str);
} else { } else {
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar)); if (size < 0) {
Q_CHECK_PTR(d); size = 0;
d->ref = 1; while (unicode[size] != 0)
d->size = size; ++size;
d->alloc = (uint) size; }
d->capacityReserved = false; if (!size) {
d->offset = 0; d = const_cast<Data *>(&shared_empty.str);
memcpy(d->data(), unicode, size * sizeof(QChar)); } else {
d->data()[size] = '\0'; 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 Constructs a string of the given \a size with every character set
to \a ch. to \a ch.
@ -1084,11 +1067,11 @@ QString::QString(int size, QChar ch)
} else { } else {
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar)); d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
d->ref = 1; d->ref.initializeOwned();
d->size = size; d->size = size;
d->alloc = (uint) size; d->alloc = (uint) size;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QStringData);
d->data()[size] = '\0'; d->data()[size] = '\0';
ushort *i = d->data() + size; ushort *i = d->data() + size;
ushort *b = d->data(); ushort *b = d->data();
@ -1108,11 +1091,11 @@ QString::QString(int size, Qt::Initialization)
{ {
d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar)); d = (Data*) ::malloc(sizeof(Data)+(size+1)*sizeof(QChar));
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
d->ref = 1; d->ref.initializeOwned();
d->size = size; d->size = size;
d->alloc = (uint) size; d->alloc = (uint) size;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QStringData);
d->data()[size] = '\0'; d->data()[size] = '\0';
} }
@ -1130,11 +1113,11 @@ QString::QString(QChar ch)
{ {
d = (Data *) ::malloc(sizeof(Data) + 2*sizeof(QChar)); d = (Data *) ::malloc(sizeof(Data) + 2*sizeof(QChar));
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
d->ref = 1; d->ref.initializeOwned();
d->size = 1; d->size = 1;
d->alloc = 1; d->alloc = 1;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QStringData);
d->data()[0] = ch.unicode(); d->data()[0] = ch.unicode();
d->data()[1] = '\0'; d->data()[1] = '\0';
} }
@ -1232,7 +1215,7 @@ void QString::resize(int size)
if (size < 0) if (size < 0)
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; d->size = size;
return; return;
} }
@ -1243,7 +1226,7 @@ void QString::resize(int size)
QString::free(d); QString::free(d);
d = x; d = x;
} else { } 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)) (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
realloc(grow(size)); realloc(grow(size));
if (int(d->alloc) >= size) { if (int(d->alloc) >= size) {
@ -1306,14 +1289,14 @@ void QString::resize(int size)
// ### Qt 5: rename reallocData() to avoid confusion. 197625 // ### Qt 5: rename reallocData() to avoid confusion. 197625
void QString::realloc(int alloc) 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))); Data *x = static_cast<Data *>(::malloc(sizeof(Data) + (alloc+1) * sizeof(QChar)));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
x->ref = 1; x->ref.initializeOwned();
x->size = qMin(alloc, d->size); x->size = qMin(alloc, d->size);
x->alloc = (uint) alloc; x->alloc = (uint) alloc;
x->capacityReserved = d->capacityReserved; x->capacityReserved = d->capacityReserved;
x->offset =0; x->offset = sizeof(QStringData);
::memcpy(x->data(), d->data(), x->size * sizeof(QChar)); ::memcpy(x->data(), d->data(), x->size * sizeof(QChar));
x->data()[x->size] = 0; x->data()[x->size] = 0;
if (!d->ref.deref()) if (!d->ref.deref())
@ -1324,7 +1307,7 @@ void QString::realloc(int alloc)
Q_CHECK_PTR(p); Q_CHECK_PTR(p);
d = p; d = p;
d->alloc = alloc; 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) { if (d == &shared_null.str) {
operator=(str); operator=(str);
} else { } 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)); realloc(grow(d->size + str.d->size));
memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar));
d->size += str.d->size; d->size += str.d->size;
@ -1556,7 +1539,7 @@ QString &QString::append(const QLatin1String &str)
const uchar *s = (const uchar *)str.latin1(); const uchar *s = (const uchar *)str.latin1();
if (s) { if (s) {
int len = str.size(); 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)); realloc(grow(d->size + len));
ushort *i = d->data() + d->size; ushort *i = d->data() + d->size;
while ((*i++ = *s++)) while ((*i++ = *s++))
@ -1599,7 +1582,7 @@ QString &QString::append(const QLatin1String &str)
*/ */
QString &QString::append(QChar ch) 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)); realloc(grow(d->size + 1));
d->data()[d->size++] = ch.unicode(); d->data()[d->size++] = ch.unicode();
d->data()[d->size] = '\0'; d->data()[d->size] = '\0';
@ -3390,15 +3373,11 @@ QString QString::right(int n) const
QString QString::mid(int position, 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(); return QString();
if (n < 0) if (position < 0)
n = d->size - position;
if (position < 0) {
n += position;
position = 0; position = 0;
} if (n < 0 || n > d->size - position)
if (n + position > d->size)
n = d->size - position; n = d->size - position;
if (position == 0 && n == d->size) if (position == 0 && n == d->size)
return *this; return *this;
@ -3753,11 +3732,11 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size)
size = qstrlen(str); size = qstrlen(str);
d = static_cast<Data *>(::malloc(sizeof(Data) + (size+1) * sizeof(QChar))); d = static_cast<Data *>(::malloc(sizeof(Data) + (size+1) * sizeof(QChar)));
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
d->ref = 1; d->ref.initializeOwned();
d->size = size; d->size = size;
d->alloc = (uint) size; d->alloc = (uint) size;
d->capacityReserved = false; d->capacityReserved = false;
d->offset = 0; d->offset = sizeof(QStringData);
d->data()[size] = '\0'; d->data()[size] = '\0';
ushort *dst = d->data(); ushort *dst = d->data();
/* SIMD: /* SIMD:
@ -4765,7 +4744,7 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
const ushort *QString::utf16() const const ushort *QString::utf16() const
{ {
if (d->offset) if (IS_RAW_DATA(d))
const_cast<QString*>(this)->realloc(); // ensure '\\0'-termination for ::fromRawData strings const_cast<QString*>(this)->realloc(); // ensure '\\0'-termination for ::fromRawData strings
return d->data(); return d->data();
} }
@ -7067,11 +7046,11 @@ QString QString::fromRawData(const QChar *unicode, int size)
} else { } else {
x = static_cast<Data *>(::malloc(sizeof(Data) + sizeof(ushort))); x = static_cast<Data *>(::malloc(sizeof(Data) + sizeof(ushort)));
Q_CHECK_PTR(x); Q_CHECK_PTR(x);
x->ref = 1; x->ref.initializeOwned();
x->size = size; x->size = size;
x->alloc = 0; x->alloc = 0;
x->capacityReserved = false; 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); return QString(x, 0);
} }
@ -7092,14 +7071,14 @@ QString QString::fromRawData(const QChar *unicode, int size)
*/ */
QString &QString::setRawData(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); *this = fromRawData(unicode, size);
} else { } else {
if (unicode) { if (unicode) {
d->size = size; 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 { } else {
d->offset = 0; d->offset = sizeof(QStringData);
d->size = 0; d->size = 0;
} }
} }
@ -8059,15 +8038,11 @@ QStringRef QString::rightRef(int n) const
QStringRef QString::midRef(int position, 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(); return QStringRef();
if (n < 0) if (position < 0)
n = d->size - position;
if (position < 0) {
n += position;
position = 0; position = 0;
} if (n < 0 || n > d->size - position)
if (n + position > d->size)
n = d->size - position; n = d->size - position;
return QStringRef(this, position, n); return QStringRef(this, position, n);
} }

View File

@ -75,25 +75,24 @@ struct QStringData {
int size; int size;
uint alloc : 31; uint alloc : 31;
uint capacityReserved : 1; uint capacityReserved : 1;
union {
qptrdiff offset; // will always work as we add/subtract from a ushort ptr qptrdiff offset;
ushort d[sizeof(qptrdiff)/sizeof(ushort)];
}; inline ushort *data() { return reinterpret_cast<ushort *>(reinterpret_cast<char *>(this) + offset); }
inline ushort *data() { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; } inline const ushort *data() const { return reinterpret_cast<const ushort *>(reinterpret_cast<const char *>(this) + offset); }
inline const ushort *data() const { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; }
}; };
template<int N> struct QConstStringData; template<int N> struct QStaticStringData;
template<int N> struct QConstStringDataPtr template<int N> struct QStaticStringDataPtr
{ {
const QConstStringData<N> *ptr; const QStaticStringData<N> *ptr;
}; };
#if defined(Q_COMPILER_UNICODE_STRINGS) #if defined(Q_COMPILER_UNICODE_STRINGS)
template<int N> struct QConstStringData template<int N> struct QStaticStringData
{ {
const QStringData str; QStringData str;
const char16_t data[N + 1]; char16_t data[N + 1];
}; };
#define QT_UNICODE_LITERAL_II(str) u"" str #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__) && __SIZEOF_WCHAR_T__ == 2) \
|| (!defined(__SIZEOF_WCHAR_T__) && defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536)) || (!defined(__SIZEOF_WCHAR_T__) && defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536))
// wchar_t is 2 bytes // wchar_t is 2 bytes
template<int N> struct QConstStringData template<int N> struct QStaticStringData
{ {
const QStringData str; QStringData str;
const wchar_t data[N + 1]; wchar_t data[N + 1];
}; };
#if defined(Q_CC_MSVC) #if defined(Q_CC_MSVC)
@ -115,21 +114,21 @@ template<int N> struct QConstStringData
#endif #endif
#else #else
template<int N> struct QConstStringData template<int N> struct QStaticStringData
{ {
const QStringData str; QStringData str;
const ushort data[N + 1]; ushort data[N + 1];
}; };
#endif #endif
#if defined(QT_UNICODE_LITERAL_II) #if defined(QT_UNICODE_LITERAL_II)
# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str) # define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
# if defined(Q_COMPILER_LAMBDA) # 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 }; \ enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QConstStringData<Size> qstring_literal = \ static const QStaticStringData<Size> qstring_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QStringData) }, QT_UNICODE_LITERAL(str) }; \
QConstStringDataPtr<Size> holder = { &qstring_literal }; \ QStaticStringDataPtr<Size> holder = { &qstring_literal }; \
return holder; }()) return holder; }())
# elif defined(Q_CC_GNU) # elif defined(Q_CC_GNU)
@ -140,9 +139,9 @@ template<int N> struct QConstStringData
# define QStringLiteral(str) \ # define QStringLiteral(str) \
__extension__ ({ \ __extension__ ({ \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QConstStringData<Size> qstring_literal = \ static const QStaticStringData<Size> qstring_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ { { Q_REFCOUNT_INITIALIZE_STATIC, Size, 0, 0, sizeof(QStringData) }, QT_UNICODE_LITERAL(str) }; \
QConstStringDataPtr<Size> holder = { &qstring_literal }; \ QStaticStringDataPtr<Size> holder = { &qstring_literal }; \
holder; }) holder; })
# endif # endif
#endif #endif
@ -160,8 +159,7 @@ public:
typedef QStringData Data; typedef QStringData Data;
inline QString(); inline QString();
QString(const QChar *unicode, int size); // Qt5: don't cap size < 0 explicit QString(const QChar *unicode, int size = -1);
explicit QString(const QChar *unicode); // Qt5: merge with the above
QString(QChar c); QString(QChar c);
QString(int size, QChar c); QString(int size, QChar c);
inline QString(const QLatin1String &latin1); inline QString(const QLatin1String &latin1);
@ -340,7 +338,7 @@ public:
inline QString &prepend(const QLatin1String &s) { return insert(0, s); } inline QString &prepend(const QLatin1String &s) { return insert(0, s); }
inline QString &operator+=(QChar c) { 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)); realloc(grow(d->size + 1));
d->data()[d->size++] = c.unicode(); d->data()[d->size++] = c.unicode();
d->data()[d->size] = '\0'; d->data()[d->size] = '\0';
@ -592,9 +590,9 @@ public:
QString(int size, Qt::Initialization); QString(int size, Qt::Initialization);
template <int n> 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> 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: private:
#if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) #if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED)
@ -606,8 +604,8 @@ private:
QString &operator=(const QByteArray &a); QString &operator=(const QByteArray &a);
#endif #endif
static const QConstStringData<1> shared_null; static const QStaticStringData<1> shared_null;
static const QConstStringData<1> shared_empty; static const QStaticStringData<1> shared_empty;
Data *d; Data *d;
inline QString(Data *dd, int /*dummy*/) : d(dd) {} inline QString(Data *dd, int /*dummy*/) : d(dd) {}
@ -709,9 +707,9 @@ inline QChar *QString::data()
inline const QChar *QString::constData() const inline const QChar *QString::constData() const
{ return reinterpret_cast<const QChar*>(d->data()); } { return reinterpret_cast<const QChar*>(d->data()); }
inline void QString::detach() 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 inline bool QString::isDetached() const
{ return d->ref == 1; } { return !d->ref.isShared(); }
inline QString &QString::operator=(const QLatin1String &s) inline QString &QString::operator=(const QLatin1String &s)
{ {
*this = fromLatin1(s.latin1(), s.size()); *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) inline void QString::reserve(int asize)
{ {
if (d->ref != 1 || asize > int(d->alloc)) if (d->ref.isShared() || asize > int(d->alloc))
realloc(asize); realloc(asize);
if (!d->capacityReserved) { if (!d->capacityReserved) {
@ -885,11 +883,12 @@ inline void QString::reserve(int asize)
inline void QString::squeeze() inline void QString::squeeze()
{ {
if (d->ref > 1 || d->size < int(d->alloc)) if (d->ref.isShared() || d->size < int(d->alloc))
realloc(); realloc();
if (d->capacityReserved) { 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; d->capacityReserved = false;
} }
} }

View File

@ -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; typedef QString ConvertTo;
enum { ExactSize = true }; enum { ExactSize = true };
static int size(const type &) { return N; } 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; typedef QByteArray ConvertTo;
enum { ExactSize = false }; enum { ExactSize = false };
static int size(const type &) { return N; } static int size(const type &) { return N; }
@ -338,9 +338,8 @@ template <int N> struct QConcatenable<QConstByteArrayDataPtr<N> > : private QAbs
#endif #endif
static inline void appendTo(const type &ba, char *&out) static inline void appendTo(const type &ba, char *&out)
{ {
const char *a = ba.ptr->data; ::memcpy(out, ba.ptr->data, N);
while (*a) out += N;
*out++ = *a++;
} }
}; };

View File

@ -54,15 +54,7 @@ static inline int alignmentThreshold()
return 2 * sizeof(void*); return 2 * sizeof(void*);
} }
const QVectorData QVectorData::shared_null = { Q_REFCOUNT_INITIALIZER(-1), 0, 0, true, false, 0 }; const QVectorData QVectorData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 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;
}
QVectorData *QVectorData::allocate(int size, int alignment) QVectorData *QVectorData::allocate(int size, int alignment)
{ {
@ -84,11 +76,9 @@ void QVectorData::free(QVectorData *x, int alignment)
::free(x); ::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 qAllocMore(size * sizeOfT, sizeOfHeader) / sizeOfT;
return size + size / 2;
return qAllocMore(size * sizeofT, sizeofTypedData - sizeofT) / sizeofT;
} }
/*! /*!

View File

@ -65,37 +65,28 @@ QT_BEGIN_NAMESPACE
struct Q_CORE_EXPORT QVectorData struct Q_CORE_EXPORT QVectorData
{ {
QtPrivate::RefCount ref; QtPrivate::RefCount ref;
int alloc;
int size; int size;
#if defined(Q_PROCESSOR_SPARC) && defined(Q_CC_GNU) && defined(__LP64__) && defined(QT_BOOTSTRAPPED) uint alloc : 31;
// workaround for bug in gcc 3.4.2 uint capacityReserved : 1;
uint sharable;
uint capacity; qptrdiff offset;
uint reserved;
#else void* data() { return reinterpret_cast<char *>(this) + this->offset; }
uint sharable : 1;
uint capacity : 1;
uint reserved : 30;
#endif
static const QVectorData shared_null; 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 *allocate(int size, int alignment);
static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment); static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment);
static void free(QVectorData *data, 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> template <typename T>
struct QVectorTypedData : private QVectorData struct QVectorTypedData : 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* begin() { return reinterpret_cast<T *>(this->data()); }
T array[1]; 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; class QRegion;
@ -104,27 +95,30 @@ template <typename T>
class QVector class QVector
{ {
typedef QVectorTypedData<T> Data; typedef QVectorTypedData<T> Data;
union { Data *d;
QVectorData *d;
#if defined(Q_CC_SUN) && (__SUNPRO_CC <= 0x550)
QVectorTypedData<T> *p;
#else
Data *p;
#endif
};
public: public:
// ### Qt 5: Consider making QVector non-shared to get at least one inline QVector() : d(Data::sharedNull()) { }
// "really fast" container. See tests/benchmarks/corelib/tools/qvector/
inline QVector() : d(const_cast<QVectorData *>(&QVectorData::shared_null)) { }
explicit QVector(int size); explicit QVector(int size);
QVector(int size, const T &t); 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(const QVector<T> &v)
inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(p); } {
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); QVector<T> &operator=(const QVector<T> &v);
#ifdef Q_COMPILER_RVALUE_REFS #ifdef Q_COMPILER_RVALUE_REFS
inline QVector<T> operator=(QVector<T> &&other) inline QVector<T> operator=(QVector<T> &&other)
{ qSwap(p, other.p); return *this; } { qSwap(d, other.d); return *this; }
#endif #endif
inline void swap(QVector<T> &other) { qSwap(d, other.d); } inline void swap(QVector<T> &other) { qSwap(d, other.d); }
#ifdef Q_COMPILER_INITIALIZER_LISTS #ifdef Q_COMPILER_INITIALIZER_LISTS
@ -139,18 +133,27 @@ public:
void resize(int size); void resize(int size);
inline int capacity() const { return d->alloc; } inline int capacity() const { return int(d->alloc); }
void reserve(int size); 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 bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
inline T *data() { detach(); return p->array; } inline T *data() { detach(); return d->begin(); }
inline const T *data() const { return p->array; } inline const T *data() const { return d->begin(); }
inline const T *constData() const { return p->array; } inline const T *constData() const { return d->begin(); }
void clear(); void clear();
const T &at(int i) const; const T &at(int i) const;
@ -243,12 +246,12 @@ public:
typedef T* iterator; typedef T* iterator;
typedef const T* const_iterator; typedef const T* const_iterator;
#endif #endif
inline iterator begin() { detach(); return p->array; } inline iterator begin() { detach(); return d->begin(); }
inline const_iterator begin() const { return p->array; } inline const_iterator begin() const { return d->begin(); }
inline const_iterator constBegin() const { return p->array; } inline const_iterator constBegin() const { return d->begin(); }
inline iterator end() { detach(); return p->array + d->size; } inline iterator end() { detach(); return d->end(); }
inline const_iterator end() const { return p->array + d->size; } inline const_iterator end() const { return d->end(); }
inline const_iterator constEnd() const { return p->array + d->size; } inline const_iterator constEnd() const { return d->end(); }
iterator insert(iterator before, int n, const T &x); iterator insert(iterator before, int n, const T &x);
inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); } inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
iterator erase(iterator begin, iterator end); iterator erase(iterator begin, iterator end);
@ -313,46 +316,49 @@ private:
friend class QRegion; // Optimization for QRegion::rects() friend class QRegion; // Optimization for QRegion::rects()
void detach_helper(); void detach_helper();
QVectorData *malloc(int alloc); Data *malloc(int alloc);
void realloc(int size, int alloc); void realloc(int size, int alloc);
void free(Data *d); void free(Data *d);
int sizeOfTypedData() {
// this is more or less the same as sizeof(Data), except that it doesn't class AlignmentDummy { QVectorData header; T array[1]; };
// count the padding at the end
return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); 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 #ifdef Q_ALIGNOF
return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); return Q_ALIGNOF(AlignmentDummy);
#else #else
return 0; return sizeof(void *);
#endif #endif
} }
}; };
template <typename T> template <typename T>
void QVector<T>::detach_helper() void QVector<T>::detach_helper()
{ realloc(d->size, d->alloc); } { realloc(d->size, int(d->alloc)); }
template <typename T> template <typename T>
void QVector<T>::reserve(int asize) 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> template <typename T>
void QVector<T>::resize(int asize) void QVector<T>::resize(int asize)
{ realloc(asize, (asize > d->alloc || (!d->capacity && asize < d->size && asize < (d->alloc >> 1))) ? { realloc(asize, (asize > int(d->alloc) || (!d->capacityReserved && asize < d->size && asize < int(d->alloc >> 1))) ?
QVectorData::grow(sizeOfTypedData(), asize, sizeof(T), QTypeInfo<T>::isStatic) QVectorData::grow(offsetOfTypedData(), asize, sizeof(T))
: d->alloc); } : int(d->alloc)); }
template <typename T> template <typename T>
inline void QVector<T>::clear() inline void QVector<T>::clear()
{ *this = QVector<T>(); } { *this = QVector<T>(); }
template <typename T> template <typename T>
inline const T &QVector<T>::at(int i) const inline const T &QVector<T>::at(int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range"); { 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> template <typename T>
inline const T &QVector<T>::operator[](int i) const inline const T &QVector<T>::operator[](int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); { 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> template <typename T>
inline T &QVector<T>::operator[](int i) inline T &QVector<T>::operator[](int i)
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); { 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> template <typename T>
QVector<T> &QVector<T>::operator=(const QVector<T> &v) QVector<T> &QVector<T>::operator=(const QVector<T> &v)
{ {
QVectorData *o = v.d; if (v.d != d) {
o->ref.ref(); QVector<T> tmp(v);
if (!d->ref.deref()) tmp.swap(*this);
free(p); }
d = o;
if (!d->sharable)
detach_helper();
return *this; return *this;
} }
template <typename T> 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); Q_CHECK_PTR(vectordata);
return vectordata; return static_cast<Data *>(vectordata);
} }
template <typename T> template <typename T>
QVector<T>::QVector(int asize) QVector<T>::QVector(int asize)
{ {
d = malloc(asize); d = malloc(asize);
d->ref = 1; d->ref.initializeOwned();
d->alloc = d->size = asize; d->size = asize;
d->sharable = true; d->alloc = uint(d->size);
d->capacity = false; d->capacityReserved = false;
d->offset = offsetOfTypedData();
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
T* b = p->array; T* b = d->begin();
T* i = p->array + d->size; T* i = d->end();
while (i != b) while (i != b)
new (--i) T; new (--i) T;
} else { } 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) QVector<T>::QVector(int asize, const T &t)
{ {
d = malloc(asize); d = malloc(asize);
d->ref = 1; d->ref.initializeOwned();
d->alloc = d->size = asize; d->size = asize;
d->sharable = true; d->alloc = uint(d->size);
d->capacity = false; d->capacityReserved = false;
T* i = p->array + d->size; d->offset = offsetOfTypedData();
while (i != p->array) T* i = d->end();
while (i != d->begin())
new (--i) T(t); new (--i) T(t);
} }
@ -442,14 +447,22 @@ template <typename T>
QVector<T>::QVector(std::initializer_list<T> args) QVector<T>::QVector(std::initializer_list<T> args)
{ {
d = malloc(int(args.size())); d = malloc(int(args.size()));
d->ref = 1; d->ref.initializeOwned();
d->alloc = d->size = int(args.size()); d->size = int(args.size());
d->sharable = true; d->alloc = uint(d->size);
d->capacity = false; d->capacityReserved = false;
T* i = p->array + d->size; d->offset = offsetOfTypedData();
auto it = args.end(); if (QTypeInfo<T>::isComplex) {
while (i != p->array) T* b = d->begin();
new (--i) T(*(--it)); 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 #endif
@ -457,14 +470,12 @@ template <typename T>
void QVector<T>::free(Data *x) void QVector<T>::free(Data *x)
{ {
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
T* b = x->array; T* b = x->begin();
union { QVectorData *d; Data *p; } u; T* i = b + x->size;
u.p = x;
T* i = b + u.d->size;
while (i-- != b) while (i-- != b)
i->~T(); i->~T();
} }
x->free(x, alignOfTypedData()); Data::free(x, alignOfTypedData());
} }
template <typename T> template <typename T>
@ -473,84 +484,82 @@ void QVector<T>::realloc(int asize, int aalloc)
Q_ASSERT(asize <= aalloc); Q_ASSERT(asize <= aalloc);
T *pOld; T *pOld;
T *pNew; T *pNew;
union { QVectorData *d; Data *p; } x; Data *x = d;
x.d = 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 // call the destructor on all objects that need to be
// destroyed when shrinking // destroyed when shrinking
pOld = p->array + d->size; pOld = d->begin() + d->size;
pNew = p->array + asize; pNew = d->begin() + asize;
while (asize < d->size) { while (asize < d->size) {
(--pOld)->~T(); (--pOld)->~T();
d->size--; d->size--;
} }
} }
if (aalloc != d->alloc || d->ref != 1) { if (aalloc != int(d->alloc) || !isDetached()) {
// (re)allocate memory // (re)allocate memory
if (QTypeInfo<T>::isStatic) { if (QTypeInfo<T>::isStatic) {
x.d = malloc(aalloc); x = malloc(aalloc);
Q_CHECK_PTR(x.p); Q_CHECK_PTR(x);
x.d->size = 0; x->size = 0;
} else if (d->ref != 1) { } else if (!isDetached()) {
x.d = malloc(aalloc); x = malloc(aalloc);
Q_CHECK_PTR(x.p); Q_CHECK_PTR(x);
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
x.d->size = 0; x->size = 0;
} else { } else {
::memcpy(x.p, p, sizeOfTypedData() + (qMin(aalloc, d->alloc) - 1) * sizeof(T)); ::memcpy(x, d, offsetOfTypedData() + qMin(uint(aalloc), d->alloc) * sizeof(T));
x.d->size = d->size; x->size = d->size;
} }
} else { } else {
QT_TRY { QT_TRY {
QVectorData *mem = QVectorData::reallocate(d, sizeOfTypedData() + (aalloc - 1) * sizeof(T), QVectorData *mem = QVectorData::reallocate(d, offsetOfTypedData() + aalloc * sizeof(T),
sizeOfTypedData() + (d->alloc - 1) * sizeof(T), alignOfTypedData()); offsetOfTypedData() + d->alloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(mem); Q_CHECK_PTR(mem);
x.d = d = mem; x = d = static_cast<Data *>(mem);
x.d->size = d->size; x->size = d->size;
} QT_CATCH (const std::bad_alloc &) { } 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; QT_RETHROW;
} }
} }
x.d->ref = 1; x->ref.initializeOwned();
x.d->alloc = aalloc; x->alloc = uint(aalloc);
x.d->sharable = true; x->capacityReserved = d->capacityReserved;
x.d->capacity = d->capacity; x->offset = offsetOfTypedData();
x.d->reserved = 0;
} }
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
QT_TRY { QT_TRY {
pOld = p->array + x.d->size; pOld = d->begin() + x->size;
pNew = x.p->array + x.d->size; pNew = x->begin() + x->size;
// copy objects from the old array into the new array // copy objects from the old array into the new array
const int toMove = qMin(asize, d->size); const int toMove = qMin(asize, d->size);
while (x.d->size < toMove) { while (x->size < toMove) {
new (pNew++) T(*pOld++); new (pNew++) T(*pOld++);
x.d->size++; x->size++;
} }
// construct all new objects when growing // construct all new objects when growing
while (x.d->size < asize) { while (x->size < asize) {
new (pNew++) T; new (pNew++) T;
x.d->size++; x->size++;
} }
} QT_CATCH (...) { } QT_CATCH (...) {
free(x.p); free(x);
QT_RETHROW; QT_RETHROW;
} }
} else if (asize > x.d->size) { } else if (asize > x->size) {
// initialize newly allocated memory to 0 // 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()) if (!d->ref.deref())
free(p); free(d);
d = x.d; d = x;
} }
} }
@ -560,31 +569,31 @@ Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
if (i < 0 || i >= d->size) { if (i < 0 || i >= d->size) {
return T(); return T();
} }
return p->array[i]; return d->begin()[i];
} }
template<typename T> template<typename T>
Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const 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> template <typename T>
void QVector<T>::append(const T &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); const T copy(t);
realloc(d->size, (d->size + 1 > d->alloc) ? realloc(d->size, (d->size + 1 > int(d->alloc)) ?
QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T), QTypeInfo<T>::isStatic) QVectorData::grow(offsetOfTypedData(), d->size + 1, sizeof(T))
: d->alloc); : int(d->alloc));
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (p->array + d->size) T(copy); new (d->end()) T(copy);
else else
p->array[d->size] = copy; *d->end() = copy;
} else { } else {
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (p->array + d->size) T(t); new (d->end()) T(t);
else else
p->array[d->size] = t; *d->end() = t;
} }
++d->size; ++d->size;
} }
@ -592,27 +601,26 @@ void QVector<T>::append(const T &t)
template <typename T> template <typename T>
typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &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) { if (n != 0) {
const T copy(t); const T copy(t);
if (d->ref != 1 || d->size + n > d->alloc) if (!isDetached() || d->size + n > int(d->alloc))
realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + n, sizeof(T), realloc(d->size, QVectorData::grow(offsetOfTypedData(), d->size + n, sizeof(T)));
QTypeInfo<T>::isStatic));
if (QTypeInfo<T>::isStatic) { if (QTypeInfo<T>::isStatic) {
T *b = p->array + d->size; T *b = d->end();
T *i = p->array + d->size + n; T *i = d->end() + n;
while (i != b) while (i != b)
new (--i) T; new (--i) T;
i = p->array + d->size; i = d->end();
T *j = i + n; T *j = i + n;
b = p->array + offset; b = d->begin() + offset;
while (i != b) while (i != b)
*--j = *--i; *--j = *--i;
i = b+n; i = b+n;
while (i != b) while (i != b)
*--i = copy; *--i = copy;
} else { } else {
T *b = p->array + offset; T *b = d->begin() + offset;
T *i = b + n; T *i = b + n;
memmove(i, b, (d->size - offset) * sizeof(T)); memmove(i, b, (d->size - offset) * sizeof(T));
while (i != b) while (i != b)
@ -620,29 +628,29 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
} }
d->size += n; d->size += n;
} }
return p->array + offset; return d->begin() + offset;
} }
template <typename T> template <typename T>
typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
{ {
int f = int(abegin - p->array); int f = int(abegin - d->begin());
int l = int(aend - p->array); int l = int(aend - d->begin());
int n = l - f; int n = l - f;
detach(); detach();
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
qCopy(p->array+l, p->array+d->size, p->array+f); qCopy(d->begin()+l, d->end(), d->begin()+f);
T *i = p->array+d->size; T *i = d->end();
T* b = p->array+d->size-n; T* b = d->end()-n;
while (i != b) { while (i != b) {
--i; --i;
i->~T(); i->~T();
} }
} else { } 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; d->size -= n;
return p->array + f; return d->begin() + f;
} }
template <typename T> template <typename T>
@ -652,9 +660,9 @@ bool QVector<T>::operator==(const QVector<T> &v) const
return false; return false;
if (d == v.d) if (d == v.d)
return true; return true;
T* b = p->array; T* b = d->begin();
T* i = b + d->size; T* i = b + d->size;
T* j = v.p->array + d->size; T* j = v.d->end();
while (i != b) while (i != b)
if (!(*--i == *--j)) if (!(*--i == *--j))
return false; return false;
@ -667,8 +675,8 @@ QVector<T> &QVector<T>::fill(const T &from, int asize)
const T copy(from); const T copy(from);
resize(asize < 0 ? d->size : asize); resize(asize < 0 ? d->size : asize);
if (d->size) { if (d->size) {
T *i = p->array + d->size; T *i = d->end();
T *b = p->array; T *b = d->begin();
while (i != b) while (i != b)
*--i = copy; *--i = copy;
} }
@ -681,9 +689,9 @@ QVector<T> &QVector<T>::operator+=(const QVector &l)
int newSize = d->size + l.d->size; int newSize = d->size + l.d->size;
realloc(d->size, newSize); realloc(d->size, newSize);
T *w = p->array + newSize; T *w = d->begin() + newSize;
T *i = l.p->array + l.d->size; T *i = l.d->end();
T *b = l.p->array; T *b = l.d->begin();
while (i != b) { while (i != b) {
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (--w) T(*--i); new (--w) T(*--i);
@ -700,11 +708,11 @@ int QVector<T>::indexOf(const T &t, int from) const
if (from < 0) if (from < 0)
from = qMax(from + d->size, 0); from = qMax(from + d->size, 0);
if (from < d->size) { if (from < d->size) {
T* n = p->array + from - 1; T* n = d->begin() + from - 1;
T* e = p->array + d->size; T* e = d->end();
while (++n != e) while (++n != e)
if (*n == t) if (*n == t)
return n - p->array; return n - d->begin();
} }
return -1; return -1;
} }
@ -717,8 +725,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
else if (from >= d->size) else if (from >= d->size)
from = d->size-1; from = d->size-1;
if (from >= 0) { if (from >= 0) {
T* b = p->array; T* b = d->begin();
T* n = p->array + from + 1; T* n = d->begin() + from + 1;
while (n != b) { while (n != b) {
if (*--n == t) if (*--n == t)
return n - b; return n - b;
@ -730,8 +738,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
template <typename T> template <typename T>
bool QVector<T>::contains(const T &t) const bool QVector<T>::contains(const T &t) const
{ {
T* b = p->array; T* b = d->begin();
T* i = p->array + d->size; T* i = d->end();
while (i != b) while (i != b)
if (*--i == t) if (*--i == t)
return true; return true;
@ -742,8 +750,8 @@ template <typename T>
int QVector<T>::count(const T &t) const int QVector<T>::count(const T &t) const
{ {
int c = 0; int c = 0;
T* b = p->array; T* b = d->begin();
T* i = p->array + d->size; T* i = d->end();
while (i != b) while (i != b)
if (*--i == t) if (*--i == t)
++c; ++c;

View File

@ -2,6 +2,9 @@
HEADERS += \ HEADERS += \
tools/qalgorithms.h \ tools/qalgorithms.h \
tools/qarraydata.h \
tools/qarraydataops.h \
tools/qarraydatapointer.h \
tools/qbitarray.h \ tools/qbitarray.h \
tools/qbytearray.h \ tools/qbytearray.h \
tools/qbytearraymatcher.h \ tools/qbytearraymatcher.h \
@ -56,6 +59,7 @@ HEADERS += \
SOURCES += \ SOURCES += \
tools/qarraydata.cpp \
tools/qbitarray.cpp \ tools/qbitarray.cpp \
tools/qbytearray.cpp \ tools/qbytearray.cpp \
tools/qbytearraymatcher.cpp \ tools/qbytearraymatcher.cpp \

View File

@ -181,7 +181,7 @@ void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
continue; continue;
// try to connect/disconnect to a signal on the parent that has the same method signature // try to connect/disconnect to a signal on the parent that has the same method signature
QByteArray sig = QMetaObject::normalizedSignature(mm.signature()); QByteArray sig = QMetaObject::normalizedSignature(mm.methodSignature().constData());
if (them->indexOfSignal(sig) == -1) if (them->indexOfSignal(sig) == -1)
continue; continue;
sig.prepend(QSIGNAL_CODE + '0'); sig.prepend(QSIGNAL_CODE + '0');
@ -307,7 +307,7 @@ void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **
// invalid signal signature // invalid signal signature
// qDBusParametersForMethod has not yet complained about this one // qDBusParametersForMethod has not yet complained about this one
qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s", qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s",
senderMetaObject->className(), mm.signature()); senderMetaObject->className(), mm.methodSignature().constData());
return; return;
} }
@ -323,10 +323,38 @@ void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **
// modify carefully: this has been hand-edited! // modify carefully: this has been hand-edited!
// the relaySlot slot gets called with the void** array // the relaySlot slot gets called with the void** array
struct qt_meta_stringdata_QDBusAdaptorConnector_t {
QByteArrayData data[10];
char stringdata[96];
};
#define QT_MOC_LITERAL(idx, ofs, len) { \
Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \
offsetof(qt_meta_stringdata_QDBusAdaptorConnector_t, stringdata) + ofs \
- idx * sizeof(QByteArrayData) \
}
static const qt_meta_stringdata_QDBusAdaptorConnector_t qt_meta_stringdata_QDBusAdaptorConnector = {
{
QT_MOC_LITERAL(0, 0, 21),
QT_MOC_LITERAL(1, 22, 11),
QT_MOC_LITERAL(2, 34, 0),
QT_MOC_LITERAL(3, 35, 3),
QT_MOC_LITERAL(4, 39, 18),
QT_MOC_LITERAL(5, 58, 10),
QT_MOC_LITERAL(6, 69, 3),
QT_MOC_LITERAL(7, 73, 4),
QT_MOC_LITERAL(8, 78, 9),
QT_MOC_LITERAL(9, 88, 6)
},
"QDBusAdaptorConnector\0relaySignal\0\0"
"obj\0const QMetaObject*\0metaObject\0sid\0"
"args\0relaySlot\0polish\0"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_QDBusAdaptorConnector[] = { static const uint qt_meta_data_QDBusAdaptorConnector[] = {
// content: // content:
6, // revision 7, // revision
0, // classname 0, // classname
0, 0, // classinfo 0, 0, // classinfo
3, 14, // methods 3, 14, // methods
@ -336,22 +364,23 @@ static const uint qt_meta_data_QDBusAdaptorConnector[] = {
0, // flags 0, // flags
1, // signalCount 1, // signalCount
// signals: signature, parameters, type, tag, flags // signals: name, argc, parameters, tag, flags
47, 23, 22, 22, 0x05, 1, 4, 29, 2, 0x05,
// slots: signature, parameters, type, tag, flags // slots: name, argc, parameters, tag, flags
105, 22, 22, 22, 0x0a, 8, 0, 38, 2, 0x0a,
117, 22, 22, 22, 0x0a, 9, 0, 39, 2, 0x0a,
// signals: parameters
QMetaType::Void, QMetaType::QObjectStar, 0x80000000 | 4, QMetaType::Int, QMetaType::QVariantList, 3, 5, 6, 7,
// slots: parameters
QMetaType::Void,
QMetaType::Void,
0 // eod 0 // eod
}; };
static const char qt_meta_stringdata_QDBusAdaptorConnector[] = {
"QDBusAdaptorConnector\0\0obj,metaObject,sid,args\0"
"relaySignal(QObject*,const QMetaObject*,int,QVariantList)\0"
"relaySlot()\0polish()\0"
};
void QDBusAdaptorConnector::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) void QDBusAdaptorConnector::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{ {
if (_c == QMetaObject::InvokeMetaMethod) { if (_c == QMetaObject::InvokeMetaMethod) {
@ -371,7 +400,7 @@ const QMetaObjectExtraData QDBusAdaptorConnector::staticMetaObjectExtraData = {
}; };
const QMetaObject QDBusAdaptorConnector::staticMetaObject = { const QMetaObject QDBusAdaptorConnector::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector, { &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector.data,
qt_meta_data_QDBusAdaptorConnector, &staticMetaObjectExtraData } qt_meta_data_QDBusAdaptorConnector, &staticMetaObjectExtraData }
}; };
@ -383,7 +412,7 @@ const QMetaObject *QDBusAdaptorConnector::metaObject() const
void *QDBusAdaptorConnector::qt_metacast(const char *_clname) void *QDBusAdaptorConnector::qt_metacast(const char *_clname)
{ {
if (!_clname) return 0; if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_QDBusAdaptorConnector)) if (!strcmp(_clname, qt_meta_stringdata_QDBusAdaptorConnector.stringdata))
return static_cast<void*>(const_cast< QDBusAdaptorConnector*>(this)); return static_cast<void*>(const_cast< QDBusAdaptorConnector*>(this));
return QObject::qt_metacast(_clname); return QObject::qt_metacast(_clname);
} }

View File

@ -446,7 +446,7 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) { for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) {
QMetaMethod mm = mo->method(i); QMetaMethod mm = mo->method(i);
if (QByteArray(mm.signature()).startsWith(match)) { if (mm.methodSignature().startsWith(match)) {
// found a method with the same name as what we're looking for // found a method with the same name as what we're looking for
// hopefully, nobody is overloading asynchronous and synchronous methods with // hopefully, nobody is overloading asynchronous and synchronous methods with
// the same name // the same name

View File

@ -640,7 +640,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
continue; continue;
// check name: // check name:
QByteArray slotname = mm.signature(); QByteArray slotname = mm.methodSignature();
int paren = slotname.indexOf('('); int paren = slotname.indexOf('(');
if (paren != name.length() || !slotname.startsWith(name)) if (paren != name.length() || !slotname.startsWith(name))
continue; continue;
@ -686,7 +686,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
++i; ++i;
// make sure that the output parameters have signatures too // make sure that the output parameters have signatures too
if (returnType != 0 && QDBusMetaType::typeToSignature(returnType) == 0) if (returnType != QMetaType::UnknownType && returnType != QMetaType::Void && QDBusMetaType::typeToSignature(returnType) == 0)
continue; continue;
bool ok = true; bool ok = true;
@ -919,7 +919,7 @@ void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const Q
// output arguments // output arguments
QVariantList outputArgs; QVariantList outputArgs;
void *null = 0; void *null = 0;
if (metaTypes[0] != QMetaType::Void) { if (metaTypes[0] != QMetaType::Void && metaTypes[0] != QMetaType::UnknownType) {
QVariant arg(metaTypes[0], null); QVariant arg(metaTypes[0], null);
outputArgs.append( arg ); outputArgs.append( arg );
params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()); params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
@ -1188,7 +1188,7 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, in
QString interface = qDBusInterfaceFromMetaObject(mo); QString interface = qDBusInterfaceFromMetaObject(mo);
QMetaMethod mm = mo->method(signalId); QMetaMethod mm = mo->method(signalId);
QByteArray memberName = mm.signature(); QByteArray memberName = mm.methodSignature();
memberName.truncate(memberName.indexOf('(')); memberName.truncate(memberName.indexOf('('));
// check if it's scriptable // check if it's scriptable

View File

@ -280,7 +280,7 @@ int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
} else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) { } else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) {
// method call relay from Qt world to D-Bus world // method call relay from Qt world to D-Bus world
// get D-Bus equivalent signature // get D-Bus equivalent signature
QString methodName = QLatin1String(metaObject->dbusNameForMethod(id)); QString methodName = QString::fromLatin1(mm.name());
const int *inputTypes = metaObject->inputTypesForMethod(id); const int *inputTypes = metaObject->inputTypesForMethod(id);
int inputTypesCount = *inputTypes; int inputTypesCount = *inputTypes;

View File

@ -54,6 +54,7 @@
#include "qdbusabstractinterface_p.h" #include "qdbusabstractinterface_p.h"
#include <private/qmetaobject_p.h> #include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
#ifndef QT_NO_DBUS #ifndef QT_NO_DBUS
@ -69,8 +70,7 @@ public:
private: private:
struct Method { struct Method {
QByteArray parameters; QList<QByteArray> parameterNames;
QByteArray typeName;
QByteArray tag; QByteArray tag;
QByteArray name; QByteArray name;
QVarLengthArray<int, 4> inputTypes; QVarLengthArray<int, 4> inputTypes;
@ -103,10 +103,12 @@ private:
void parseMethods(); void parseMethods();
void parseSignals(); void parseSignals();
void parseProperties(); void parseProperties();
static int aggregateParameterCount(const QMap<QByteArray, Method> &map);
}; };
static const int intsPerProperty = 2; static const int intsPerProperty = 2;
static const int intsPerMethod = 3; static const int intsPerMethod = 2;
struct QDBusMetaObjectPrivate : public QMetaObjectPrivate struct QDBusMetaObjectPrivate : public QMetaObjectPrivate
{ {
@ -132,6 +134,30 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature,
const QDBusIntrospection::Annotations &annotations, const QDBusIntrospection::Annotations &annotations,
const char *direction, int id) const char *direction, int id)
{ {
struct QDBusRawTypeHandler {
static void destroy(void *)
{
qFatal("Cannot destroy placeholder type QDBusRawType");
}
static void *create(const void *)
{
qFatal("Cannot create placeholder type QDBusRawType");
return 0;
}
static void destruct(void *)
{
qFatal("Cannot destruct placeholder type QDBusRawType");
}
static void *construct(void *, const void *)
{
qFatal("Cannot construct placeholder type QDBusRawType");
return 0;
}
};
Type result; Type result;
result.id = QVariant::Invalid; result.id = QVariant::Invalid;
@ -157,8 +183,13 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature,
if (type == QVariant::Invalid || signature != QDBusMetaType::typeToSignature(type)) { if (type == QVariant::Invalid || signature != QDBusMetaType::typeToSignature(type)) {
// type is still unknown or doesn't match back to the signature that it // type is still unknown or doesn't match back to the signature that it
// was expected to, so synthesize a fake type // was expected to, so synthesize a fake type
type = QMetaType::VoidStar;
typeName = "QDBusRawType<0x" + signature.toHex() + ">*"; typeName = "QDBusRawType<0x" + signature.toHex() + ">*";
type = QMetaType::registerType(typeName, QDBusRawTypeHandler::destroy,
QDBusRawTypeHandler::create,
QDBusRawTypeHandler::destruct,
QDBusRawTypeHandler::construct,
sizeof(void *),
QMetaType::MovableType);
} }
result.name = typeName; result.name = typeName;
@ -215,8 +246,7 @@ void QDBusMetaObjectGenerator::parseMethods()
mm.inputTypes.append(type.id); mm.inputTypes.append(type.id);
mm.parameters.append(arg.name.toLatin1()); mm.parameterNames.append(arg.name.toLatin1());
mm.parameters.append(',');
prototype.append(type.name); prototype.append(type.name);
prototype.append(','); prototype.append(',');
@ -235,13 +265,9 @@ void QDBusMetaObjectGenerator::parseMethods()
mm.outputTypes.append(type.id); mm.outputTypes.append(type.id);
if (i == 0) { if (i != 0) {
// return value
mm.typeName = type.name;
} else {
// non-const ref parameter // non-const ref parameter
mm.parameters.append(arg.name.toLatin1()); mm.parameterNames.append(arg.name.toLatin1());
mm.parameters.append(',');
prototype.append(type.name); prototype.append(type.name);
prototype.append("&,"); prototype.append("&,");
@ -250,12 +276,10 @@ void QDBusMetaObjectGenerator::parseMethods()
if (!ok) continue; if (!ok) continue;
// convert the last commas: // convert the last commas:
if (!mm.parameters.isEmpty()) { if (!mm.parameterNames.isEmpty())
mm.parameters.truncate(mm.parameters.length() - 1);
prototype[prototype.length() - 1] = ')'; prototype[prototype.length() - 1] = ')';
} else { else
prototype.append(')'); prototype.append(')');
}
// check the async tag // check the async tag
if (m.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true")) if (m.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"))
@ -295,8 +319,7 @@ void QDBusMetaObjectGenerator::parseSignals()
mm.inputTypes.append(type.id); mm.inputTypes.append(type.id);
mm.parameters.append(arg.name.toLatin1()); mm.parameterNames.append(arg.name.toLatin1());
mm.parameters.append(',');
prototype.append(type.name); prototype.append(type.name);
prototype.append(','); prototype.append(',');
@ -304,12 +327,10 @@ void QDBusMetaObjectGenerator::parseSignals()
if (!ok) continue; if (!ok) continue;
// convert the last commas: // convert the last commas:
if (!mm.parameters.isEmpty()) { if (!mm.parameterNames.isEmpty())
mm.parameters.truncate(mm.parameters.length() - 1);
prototype[prototype.length() - 1] = ')'; prototype[prototype.length() - 1] = ')';
} else { else
prototype.append(')'); prototype.append(')');
}
// meta method flags // meta method flags
mm.flags = AccessProtected | MethodSignal | MethodScriptable; mm.flags = AccessProtected | MethodSignal | MethodScriptable;
@ -342,49 +363,27 @@ void QDBusMetaObjectGenerator::parseProperties()
if (p.access != QDBusIntrospection::Property::Read) if (p.access != QDBusIntrospection::Property::Read)
mp.flags |= Writable; mp.flags |= Writable;
if (mp.typeName == "QDBusVariant")
mp.flags |= QMetaType::QVariant << 24;
else if (mp.type < 0xff)
// encode the type in the flags
mp.flags |= mp.type << 24;
// add the property: // add the property:
properties.insert(name, mp); properties.insert(name, mp);
} }
} }
// Returns the sum of all parameters (including return type) for the given
// \a map of methods. This is needed for calculating the size of the methods'
// parameter type/name meta-data.
int QDBusMetaObjectGenerator::aggregateParameterCount(const QMap<QByteArray, Method> &map)
{
int sum = 0;
QMap<QByteArray, Method>::const_iterator it;
for (it = map.constBegin(); it != map.constEnd(); ++it) {
const Method &m = it.value();
sum += m.inputTypes.size() + qMax(1, m.outputTypes.size());
}
return sum;
}
void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
{ {
class MetaStringTable
{
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(); }
MetaStringTable() : m_offset(0) {}
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;
}
int arraySize() const { return m_offset; }
private:
Entries m_entries;
int m_offset;
};
// this code here is mostly copied from qaxbase.cpp // this code here is mostly copied from qaxbase.cpp
// with a few modifications to make it cleaner // with a few modifications to make it cleaner
@ -396,8 +395,14 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
QVarLengthArray<int> idata; QVarLengthArray<int> idata;
idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int)); idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int));
int methodParametersDataSize =
((aggregateParameterCount(signals_)
+ aggregateParameterCount(methods)) * 2) // types and parameter names
- signals_.count() // return "parameters" don't have names
- methods.count(); // ditto
QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data()); QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 6, "QtDBus meta-object generator should generate the same version as moc"); Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "QtDBus meta-object generator should generate the same version as moc");
header->revision = QMetaObjectPrivate::OutputRevision; header->revision = QMetaObjectPrivate::OutputRevision;
header->className = 0; header->className = 0;
header->classInfoCount = 0; header->classInfoCount = 0;
@ -405,7 +410,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
header->methodCount = signals_.count() + methods.count(); header->methodCount = signals_.count() + methods.count();
header->methodData = idata.size(); header->methodData = idata.size();
header->propertyCount = properties.count(); header->propertyCount = properties.count();
header->propertyData = header->methodData + header->methodCount * 5; header->propertyData = header->methodData + header->methodCount * 5 + methodParametersDataSize;
header->enumeratorCount = 0; header->enumeratorCount = 0;
header->enumeratorData = 0; header->enumeratorData = 0;
header->constructorCount = 0; header->constructorCount = 0;
@ -417,7 +422,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty; header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty;
int data_size = idata.size() + int data_size = idata.size() +
(header->methodCount * (5+intsPerMethod)) + (header->methodCount * (5+intsPerMethod)) + methodParametersDataSize +
(header->propertyCount * (3+intsPerProperty)); (header->propertyCount * (3+intsPerProperty));
foreach (const Method &mm, signals_) foreach (const Method &mm, signals_)
data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count(); data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count();
@ -425,10 +430,11 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count(); data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count();
idata.resize(data_size + 1); idata.resize(data_size + 1);
MetaStringTable strings; QMetaStringTable strings;
strings.enter(className.toLatin1()); strings.enter(className.toLatin1());
int offset = header->methodData; int offset = header->methodData;
int parametersOffset = offset + header->methodCount * 5;
int signatureOffset = header->methodDBusData; int signatureOffset = header->methodDBusData;
int typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod; int typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod;
idata[typeidOffset++] = 0; // eod idata[typeidOffset++] = 0; // eod
@ -439,16 +445,45 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
QMap<QByteArray, Method> &map = (x == 0) ? signals_ : methods; QMap<QByteArray, Method> &map = (x == 0) ? signals_ : methods;
for (QMap<QByteArray, Method>::ConstIterator it = map.constBegin(); for (QMap<QByteArray, Method>::ConstIterator it = map.constBegin();
it != map.constEnd(); ++it) { it != map.constEnd(); ++it) {
// form "prototype\0parameters\0typeName\0tag\0methodname\0"
const Method &mm = it.value(); const Method &mm = it.value();
idata[offset++] = strings.enter(it.key()); // prototype int argc = mm.inputTypes.size() + qMax(0, mm.outputTypes.size() - 1);
idata[offset++] = strings.enter(mm.parameters);
idata[offset++] = strings.enter(mm.typeName); idata[offset++] = strings.enter(mm.name);
idata[offset++] = argc;
idata[offset++] = parametersOffset;
idata[offset++] = strings.enter(mm.tag); idata[offset++] = strings.enter(mm.tag);
idata[offset++] = mm.flags; idata[offset++] = mm.flags;
idata[signatureOffset++] = strings.enter(mm.name); // Parameter types
for (int i = -1; i < argc; ++i) {
int type;
QByteArray typeName;
if (i < 0) { // Return type
if (!mm.outputTypes.isEmpty())
type = mm.outputTypes.first();
else
type = QMetaType::Void;
} else if (i < mm.inputTypes.size()) {
type = mm.inputTypes.at(i);
} else {
Q_ASSERT(mm.outputTypes.size() > 1);
type = mm.outputTypes.at(i - mm.inputTypes.size() + 1);
// Output parameters are references; type id not available
typeName = QMetaType::typeName(type);
typeName.append('&');
}
Q_ASSERT(type != QMetaType::UnknownType);
int typeInfo;
if (!typeName.isEmpty())
typeInfo = IsUnresolvedType | strings.enter(typeName);
else
typeInfo = type;
idata[parametersOffset++] = typeInfo;
}
// Parameter names
for (int i = 0; i < argc; ++i)
idata[parametersOffset++] = strings.enter(mm.parameterNames.at(i));
idata[signatureOffset++] = typeidOffset; idata[signatureOffset++] = typeidOffset;
idata[typeidOffset++] = mm.inputTypes.count(); idata[typeidOffset++] = mm.inputTypes.count();
@ -462,9 +497,12 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
} }
} }
Q_ASSERT(offset == header->propertyData); Q_ASSERT(offset == header->methodData + header->methodCount * 5);
Q_ASSERT(parametersOffset = header->propertyData);
Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod); Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod);
Q_ASSERT(typeidOffset == idata.size()); Q_ASSERT(typeidOffset == idata.size());
offset += methodParametersDataSize;
Q_ASSERT(offset == header->propertyData);
// add each property // add each property
signatureOffset = header->propertyDBusData; signatureOffset = header->propertyDBusData;
@ -472,9 +510,10 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
it != properties.constEnd(); ++it) { it != properties.constEnd(); ++it) {
const Property &mp = it.value(); const Property &mp = it.value();
// form is "name\0typeName\0signature\0" // form is name, typeinfo, flags
idata[offset++] = strings.enter(it.key()); // name idata[offset++] = strings.enter(it.key()); // name
idata[offset++] = strings.enter(mp.typeName); Q_ASSERT(mp.type != QMetaType::UnknownType);
idata[offset++] = mp.type;
idata[offset++] = mp.flags; idata[offset++] = mp.flags;
idata[signatureOffset++] = strings.enter(mp.signature); idata[signatureOffset++] = strings.enter(mp.signature);
@ -484,14 +523,8 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
Q_ASSERT(offset == header->propertyDBusData); Q_ASSERT(offset == header->propertyDBusData);
Q_ASSERT(signatureOffset == header->methodDBusData); Q_ASSERT(signatureOffset == header->methodDBusData);
char *string_data = new char[strings.arraySize()]; char *string_data = new char[strings.blobSize()];
{ strings.writeBlob(string_data);
MetaStringTable::const_iterator it;
for (it = strings.constBegin(); it != strings.constEnd(); ++it) {
memcpy(string_data + it.value(), it.key().constData(), it.key().size());
string_data[it.value() + it.key().size()] = '\0';
}
}
uint *uint_data = new uint[idata.size()]; uint *uint_data = new uint[idata.size()];
memcpy(uint_data, idata.data(), idata.size() * sizeof(int)); memcpy(uint_data, idata.data(), idata.size() * sizeof(int));
@ -499,7 +532,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
// put the metaobject together // put the metaobject together
obj->d.data = uint_data; obj->d.data = uint_data;
obj->d.extradata = 0; obj->d.extradata = 0;
obj->d.stringdata = string_data; obj->d.stringdata = reinterpret_cast<const QByteArrayData *>(string_data);
obj->d.superdata = &QDBusAbstractInterface::staticMetaObject; obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
} }
@ -613,22 +646,12 @@ static inline const QDBusMetaObjectPrivate *priv(const uint* data)
return reinterpret_cast<const QDBusMetaObjectPrivate *>(data); return reinterpret_cast<const QDBusMetaObjectPrivate *>(data);
} }
const char *QDBusMetaObject::dbusNameForMethod(int id) const
{
//id -= methodOffset();
if (id >= 0 && id < priv(d.data)->methodCount) {
int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
return d.stringdata + d.data[handle];
}
return 0;
}
const int *QDBusMetaObject::inputTypesForMethod(int id) const const int *QDBusMetaObject::inputTypesForMethod(int id) const
{ {
//id -= methodOffset(); //id -= methodOffset();
if (id >= 0 && id < priv(d.data)->methodCount) { if (id >= 0 && id < priv(d.data)->methodCount) {
int handle = priv(d.data)->methodDBusData + id*intsPerMethod; int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
return reinterpret_cast<const int*>(d.data + d.data[handle + 1]); return reinterpret_cast<const int*>(d.data + d.data[handle]);
} }
return 0; return 0;
} }
@ -638,7 +661,7 @@ const int *QDBusMetaObject::outputTypesForMethod(int id) const
//id -= methodOffset(); //id -= methodOffset();
if (id >= 0 && id < priv(d.data)->methodCount) { if (id >= 0 && id < priv(d.data)->methodCount) {
int handle = priv(d.data)->methodDBusData + id*intsPerMethod; int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
return reinterpret_cast<const int*>(d.data + d.data[handle + 2]); return reinterpret_cast<const int*>(d.data + d.data[handle + 1]);
} }
return 0; return 0;
} }

View File

@ -71,12 +71,11 @@ struct Q_DBUS_EXPORT QDBusMetaObject: public QMetaObject
QDBusError &error); QDBusError &error);
~QDBusMetaObject() ~QDBusMetaObject()
{ {
delete [] d.stringdata; delete [] reinterpret_cast<const char *>(d.stringdata);
delete [] d.data; delete [] d.data;
} }
// methods (slots & signals): // methods (slots & signals):
const char *dbusNameForMethod(int id) const;
const int *inputTypesForMethod(int id) const; const int *inputTypesForMethod(int id) const;
const int *outputTypesForMethod(int id) const; const int *outputTypesForMethod(int id) const;

View File

@ -311,7 +311,7 @@ bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
int QDBusMetaType::signatureToType(const char *signature) int QDBusMetaType::signatureToType(const char *signature)
{ {
if (!signature) if (!signature)
return QVariant::Invalid; return QMetaType::UnknownType;
QDBusMetaTypeId::init(); QDBusMetaTypeId::init();
switch (signature[0]) switch (signature[0])
@ -378,7 +378,7 @@ int QDBusMetaType::signatureToType(const char *signature)
} }
// fall through // fall through
default: default:
return QVariant::Invalid; return QMetaType::UnknownType;
} }
} }

View File

@ -141,7 +141,7 @@ int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
for ( ; it != end; ++it) { for ( ; it != end; ++it) {
const QByteArray &type = *it; const QByteArray &type = *it;
if (type.endsWith('*')) { if (type.endsWith('*')) {
//qWarning("Could not parse the method '%s'", mm.signature()); //qWarning("Could not parse the method '%s'", mm.methodSignature().constData());
// pointer? // pointer?
return -1; return -1;
} }
@ -152,7 +152,7 @@ int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
int id = QMetaType::type(basictype); int id = QMetaType::type(basictype);
if (id == 0) { if (id == 0) {
//qWarning("Could not parse the method '%s'", mm.signature()); //qWarning("Could not parse the method '%s'", mm.methodSignature().constData());
// invalid type in method parameter list // invalid type in method parameter list
return -1; return -1;
} else if (QDBusMetaType::typeToSignature(id) == 0) } else if (QDBusMetaType::typeToSignature(id) == 0)
@ -164,14 +164,14 @@ int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
} }
if (seenMessage) { // && !type.endsWith('&') if (seenMessage) { // && !type.endsWith('&')
//qWarning("Could not parse the method '%s'", mm.signature()); //qWarning("Could not parse the method '%s'", mm.methodSignature().constData());
// non-output parameters after message or after output params // non-output parameters after message or after output params
return -1; // not allowed return -1; // not allowed
} }
int id = QMetaType::type(type); int id = QMetaType::type(type);
if (id == 0) { if (id == QMetaType::UnknownType) {
//qWarning("Could not parse the method '%s'", mm.signature()); //qWarning("Could not parse the method '%s'", mm.methodSignature().constData());
// invalid type in method parameter list // invalid type in method parameter list
return -1; return -1;
} }

View File

@ -126,7 +126,7 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method
// now add methods: // now add methods:
for (int i = methodOffset; i < mo->methodCount(); ++i) { for (int i = methodOffset; i < mo->methodCount(); ++i) {
QMetaMethod mm = mo->method(i); QMetaMethod mm = mo->method(i);
QByteArray signature = mm.signature(); QByteArray signature = mm.methodSignature();
int paren = signature.indexOf('('); int paren = signature.indexOf('(');
bool isSignal; bool isSignal;

View File

@ -78,10 +78,10 @@ QList<QByteArray> QAccessibleObjectPrivate::actionList() const
continue; continue;
if (!qstrcmp(member.tag(), "QACCESSIBLE_SLOT")) { if (!qstrcmp(member.tag(), "QACCESSIBLE_SLOT")) {
if (member.signature() == defaultAction) if (member.methodSignature() == defaultAction)
actionList.prepend(defaultAction); actionList.prepend(defaultAction);
else else
actionList << member.signature(); actionList << member.methodSignature();
} }
} }

View File

@ -66,7 +66,7 @@ enum { IndentSpacesCount = 4 };
static QByteArray memberName(const QMetaMethod &member) static QByteArray memberName(const QMetaMethod &member)
{ {
QByteArray ba = member.signature(); QByteArray ba = member.methodSignature();
return ba.left(ba.indexOf('(')); return ba.left(ba.indexOf('('));
} }
@ -112,7 +112,8 @@ static void qSignalDumperCallback(QObject *caller, int method_index, void **argv
quintptr addr = quintptr(*reinterpret_cast<void **>(argv[i + 1])); quintptr addr = quintptr(*reinterpret_cast<void **>(argv[i + 1]));
str.append(QByteArray::number(addr, 16)); str.append(QByteArray::number(addr, 16));
} else if (typeId != QMetaType::Void) { } else if (typeId != QMetaType::UnknownType) {
Q_ASSERT(typeId != QMetaType::Void); // void parameter => metaobject is corrupt
str.append(arg) str.append(arg)
.append('(') .append('(')
.append(QVariant(typeId, argv[i + 1]).toString().toLocal8Bit()) .append(QVariant(typeId, argv[i + 1]).toString().toLocal8Bit())
@ -152,7 +153,7 @@ static void qSignalDumperCallbackSlot(QObject *caller, int method_index, void **
str += QByteArray::number(quintptr(caller), 16); str += QByteArray::number(quintptr(caller), 16);
str += ") "; str += ") ";
str += member.signature(); str += member.methodSignature();
qPrintMessage(str); qPrintMessage(str);
} }

View File

@ -122,9 +122,11 @@ private:
QList<QByteArray> params = member.parameterTypes(); QList<QByteArray> params = member.parameterTypes();
for (int i = 0; i < params.count(); ++i) { for (int i = 0; i < params.count(); ++i) {
int tp = QMetaType::type(params.at(i).constData()); int tp = QMetaType::type(params.at(i).constData());
if (tp == QMetaType::Void) if (tp == QMetaType::UnknownType) {
Q_ASSERT(tp != QMetaType::Void); // void parameter => metaobject is corrupt
qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.", qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
params.at(i).constData()); params.at(i).constData());
}
args << tp; args << tp;
} }
} }

View File

@ -1061,7 +1061,8 @@ static bool isValidSlot(const QMetaMethod &sl)
if (sl.access() != QMetaMethod::Private || !sl.parameterTypes().isEmpty() if (sl.access() != QMetaMethod::Private || !sl.parameterTypes().isEmpty()
|| qstrlen(sl.typeName()) || sl.methodType() != QMetaMethod::Slot) || qstrlen(sl.typeName()) || sl.methodType() != QMetaMethod::Slot)
return false; return false;
const char *sig = sl.signature(); QByteArray signature = sl.methodSignature();
const char *sig = signature.constData();
int len = qstrlen(sig); int len = qstrlen(sig);
if (len < 2) if (len < 2)
return false; return false;
@ -1084,7 +1085,7 @@ static void qPrintTestSlots(FILE *stream)
for (int i = 0; i < QTest::currentTestObject->metaObject()->methodCount(); ++i) { for (int i = 0; i < QTest::currentTestObject->metaObject()->methodCount(); ++i) {
QMetaMethod sl = QTest::currentTestObject->metaObject()->method(i); QMetaMethod sl = QTest::currentTestObject->metaObject()->method(i);
if (isValidSlot(sl)) if (isValidSlot(sl))
fprintf(stream, "%s\n", sl.signature()); fprintf(stream, "%s\n", sl.methodSignature().constData());
} }
} }
@ -1109,7 +1110,7 @@ static void qPrintDataTags(FILE *stream)
// Retrieve local tags: // Retrieve local tags:
QStringList localTags; QStringList localTags;
QTestTable table; QTestTable table;
char *slot = qstrdup(tf.signature()); char *slot = qstrdup(tf.methodSignature().constData());
slot[strlen(slot) - 2] = '\0'; slot[strlen(slot) - 2] = '\0';
QByteArray member; QByteArray member;
member.resize(qstrlen(slot) + qstrlen("_data()") + 1); member.resize(qstrlen(slot) + qstrlen("_data()") + 1);
@ -1781,7 +1782,7 @@ static void qInvokeTestMethods(QObject *testObject)
if (QTest::testFuncs) { if (QTest::testFuncs) {
for (int i = 0; i != QTest::testFuncCount; i++) { for (int i = 0; i != QTest::testFuncCount; i++) {
if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).signature(), if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).methodSignature().constData(),
QTest::testFuncs[i].data())) { QTest::testFuncs[i].data())) {
break; break;
} }
@ -1795,7 +1796,7 @@ static void qInvokeTestMethods(QObject *testObject)
for (int i = 0; i != methodCount; i++) { for (int i = 0; i != methodCount; i++) {
if (!isValidSlot(testMethods[i])) if (!isValidSlot(testMethods[i]))
continue; continue;
if (!qInvokeTestMethod(testMethods[i].signature())) if (!qInvokeTestMethod(testMethods[i].methodSignature().constData()))
break; break;
} }
delete[] testMethods; delete[] testMethods;

View File

@ -54,30 +54,37 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
uint qvariant_nameToType(const QByteArray &name) uint nameToBuiltinType(const QByteArray &name)
{ {
if (name.isEmpty()) if (name.isEmpty())
return 0; return 0;
uint tp = QMetaType::type(name.constData()); uint tp = QMetaType::type(name.constData());
return tp < QMetaType::User ? tp : 0; return tp < uint(QMetaType::User) ? tp : QMetaType::UnknownType;
} }
/* /*
Returns true if the type is a QVariant types. Returns true if the type is a built-in type.
*/ */
bool isVariantType(const QByteArray &type) bool isBuiltinType(const QByteArray &type)
{ {
return qvariant_nameToType(type) != 0; int id = QMetaType::type(type.constData());
if (id == QMetaType::UnknownType)
return false;
return (id < QMetaType::User);
} }
/*! static const char *metaTypeEnumValueString(int type)
Returns true if the type is qreal. {
*/ #define RETURN_METATYPENAME_STRING(MetaTypeName, MetaTypeId, RealType) \
static bool isQRealType(const QByteArray &type) case QMetaType::MetaTypeName: return #MetaTypeName;
{
return (type == "qreal"); switch (type) {
} QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
}
#undef RETURN_METATYPENAME_STRING
return 0;
}
Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile) Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile)
: out(outfile), cdef(classDef), metaTypes(metaTypes) : out(outfile), cdef(classDef), metaTypes(metaTypes)
@ -109,24 +116,28 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
return i - startPos; return i - startPos;
} }
int Generator::strreg(const QByteArray &s) void Generator::strreg(const QByteArray &s)
{ {
int idx = 0; if (!strings.contains(s))
for (int i = 0; i < strings.size(); ++i) { strings.append(s);
const QByteArray &str = strings.at(i); }
if (str == s)
return idx; int Generator::stridx(const QByteArray &s)
idx += str.length() + 1; {
for (int i = 0; i < str.length(); ++i) { int i = strings.indexOf(s);
if (str.at(i) == '\\') { Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
int cnt = lengthOfEscapeSequence(str, i) - 1; return i;
idx -= cnt; }
i += cnt;
} // Returns the sum of all parameters (including return type) for the given
} // \a list of methods. This is needed for calculating the size of the methods'
} // parameter type/name meta-data.
strings.append(s); static int aggregateParameterCount(const QList<FunctionDef> &list)
return idx; {
int sum = 0;
for (int i = 0; i < list.count(); ++i)
sum += list.at(i).arguments.count() + 1; // +1 for return type
return sum;
} }
void Generator::generateCode() void Generator::generateCode()
@ -135,10 +146,6 @@ void Generator::generateCode()
bool isQObject = (cdef->classname == "QObject"); bool isQObject = (cdef->classname == "QObject");
bool isConstructible = !cdef->constructorList.isEmpty(); bool isConstructible = !cdef->constructorList.isEmpty();
//
// build the data array
//
// filter out undeclared enumerators and sets // filter out undeclared enumerators and sets
{ {
QList<EnumDef> enumList; QList<EnumDef> enumList;
@ -156,95 +163,71 @@ void Generator::generateCode()
cdef->enumList = enumList; cdef->enumList = enumList;
} }
//
// Register all strings used in data section
//
strreg(cdef->qualified);
registerClassInfoStrings();
registerFunctionStrings(cdef->signalList);
registerFunctionStrings(cdef->slotList);
registerFunctionStrings(cdef->methodList);
registerFunctionStrings(cdef->constructorList);
registerPropertyStrings();
registerEnumStrings();
QByteArray qualifiedClassNameIdentifier = cdef->qualified; QByteArray qualifiedClassNameIdentifier = cdef->qualified;
qualifiedClassNameIdentifier.replace(':', '_'); qualifiedClassNameIdentifier.replace(':', '_');
int index = MetaObjectPrivateFieldCount;
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n");
fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision));
fprintf(out, " %4d, // classname\n", strreg(cdef->qualified));
fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
index += cdef->classInfoList.count() * 2;
int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
index += methodCount * 5;
if (cdef->revisionedMethods)
index += methodCount;
fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
index += cdef->propertyList.count() * 3;
if(cdef->notifyableProperties)
index += cdef->propertyList.count();
if (cdef->revisionedProperties)
index += cdef->propertyList.count();
fprintf(out, " %4d, %4d, // enums/sets\n", cdef->enumList.count(), cdef->enumList.count() ? index : 0);
int enumsIndex = index;
for (int i = 0; i < cdef->enumList.count(); ++i)
index += 4 + (cdef->enumList.at(i).values.count() * 2);
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
isConstructible ? index : 0);
fprintf(out, " %4d, // flags\n", 0);
fprintf(out, " %4d, // signalCount\n", cdef->signalList.count());
// //
// Build classinfo array // Build stringdata struct
// //
generateClassInfos(); fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, " QByteArrayData data[%d];\n", strings.size());
// {
// Build signals array first, otherwise the signal indices would be wrong int len = 0;
// for (int i = 0; i < strings.size(); ++i)
generateFunctions(cdef->signalList, "signal", MethodSignal); len += strings.at(i).length() + 1;
fprintf(out, " char stringdata[%d];\n", len + 1);
//
// Build slots array
//
generateFunctions(cdef->slotList, "slot", MethodSlot);
//
// Build method array
//
generateFunctions(cdef->methodList, "method", MethodMethod);
//
// Build method version arrays
//
if (cdef->revisionedMethods) {
generateFunctionRevisions(cdef->signalList, "signal");
generateFunctionRevisions(cdef->slotList, "slot");
generateFunctionRevisions(cdef->methodList, "method");
} }
fprintf(out, "};\n");
// // Macro that expands into a QByteArrayData. The offset member is
// Build property array // calculated from 1) the offset of the actual characters in the
// // stringdata.stringdata member, and 2) the stringdata.data index of the
generateProperties(); // QByteArrayData being defined. This calculation relies on the
// QByteArrayData::data() implementation returning simply "this + offset".
fprintf(out, "#define QT_MOC_LITERAL(idx, ofs, len) { \\\n"
" Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \\\n"
" offsetof(qt_meta_stringdata_%s_t, stringdata) + ofs \\\n"
" - idx * sizeof(QByteArrayData) \\\n"
" }\n",
qualifiedClassNameIdentifier.constData());
// fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
// Build enums array qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
// fprintf(out, " {\n");
generateEnums(enumsIndex); {
int idx = 0;
// for (int i = 0; i < strings.size(); ++i) {
// Build constructors array if (i)
// fprintf(out, ",\n");
if (isConstructible) const QByteArray &str = strings.at(i);
generateFunctions(cdef->constructorList, "constructor", MethodConstructor); fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length());
idx += str.length() + 1;
// for (int j = 0; j < str.length(); ++j) {
// Terminate data array if (str.at(j) == '\\') {
// int cnt = lengthOfEscapeSequence(str, j) - 1;
fprintf(out, "\n 0 // eod\n};\n\n"); idx -= cnt;
j += cnt;
}
}
}
fprintf(out, "\n },\n");
}
// //
// Build stringdata array // Build stringdata array
// //
fprintf(out, "static const char qt_meta_stringdata_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, " \""); fprintf(out, " \"");
int col = 0; int col = 0;
int len = 0; int len = 0;
@ -279,7 +262,113 @@ void Generator::generateCode()
fputs("\\0", out); fputs("\\0", out);
col += len + 2; col += len + 2;
} }
fprintf(out, "\"\n};\n\n");
// Terminate stringdata struct
fprintf(out, "\"\n};\n");
fprintf(out, "#undef QT_MOC_LITERAL\n\n");
//
// build the data array
//
int index = MetaObjectPrivateFieldCount;
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n");
fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision));
fprintf(out, " %4d, // classname\n", stridx(cdef->qualified));
fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
index += cdef->classInfoList.count() * 2;
int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
index += methodCount * 5;
if (cdef->revisionedMethods)
index += methodCount;
int paramsIndex = index;
int totalParameterCount = aggregateParameterCount(cdef->signalList)
+ aggregateParameterCount(cdef->slotList)
+ aggregateParameterCount(cdef->methodList)
+ aggregateParameterCount(cdef->constructorList);
index += totalParameterCount * 2 // types and parameter names
- methodCount // return "parameters" don't have names
- cdef->constructorList.count(); // "this" parameters don't have names
fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
index += cdef->propertyList.count() * 3;
if(cdef->notifyableProperties)
index += cdef->propertyList.count();
if (cdef->revisionedProperties)
index += cdef->propertyList.count();
fprintf(out, " %4d, %4d, // enums/sets\n", cdef->enumList.count(), cdef->enumList.count() ? index : 0);
int enumsIndex = index;
for (int i = 0; i < cdef->enumList.count(); ++i)
index += 4 + (cdef->enumList.at(i).values.count() * 2);
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
isConstructible ? index : 0);
fprintf(out, " %4d, // flags\n", 0);
fprintf(out, " %4d, // signalCount\n", cdef->signalList.count());
//
// Build classinfo array
//
generateClassInfos();
//
// Build signals array first, otherwise the signal indices would be wrong
//
generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex);
//
// Build slots array
//
generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex);
//
// Build method array
//
generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex);
//
// Build method version arrays
//
if (cdef->revisionedMethods) {
generateFunctionRevisions(cdef->signalList, "signal");
generateFunctionRevisions(cdef->slotList, "slot");
generateFunctionRevisions(cdef->methodList, "method");
}
//
// Build method parameters array
//
generateFunctionParameters(cdef->signalList, "signal");
generateFunctionParameters(cdef->slotList, "slot");
generateFunctionParameters(cdef->methodList, "method");
if (isConstructible)
generateFunctionParameters(cdef->constructorList, "constructor");
//
// Build property array
//
generateProperties();
//
// Build enums array
//
generateEnums(enumsIndex);
//
// Build constructors array
//
if (isConstructible)
generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex);
//
// Terminate data array
//
fprintf(out, "\n 0 // eod\n};\n\n");
// //
// Generate internal qt_static_metacall() function // Generate internal qt_static_metacall() function
@ -293,7 +382,7 @@ void Generator::generateCode()
QList<QByteArray> extraList; QList<QByteArray> extraList;
for (int i = 0; i < cdef->propertyList.count(); ++i) { for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i); const PropertyDef &p = cdef->propertyList.at(i);
if (!isVariantType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') && if (!isBuiltinType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') &&
!p.type.contains('<') && !p.type.contains('>')) { !p.type.contains('<') && !p.type.contains('>')) {
int s = p.type.lastIndexOf("::"); int s = p.type.lastIndexOf("::");
if (s > 0) { if (s > 0) {
@ -356,8 +445,9 @@ void Generator::generateCode()
fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData()); fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
else else
fprintf(out, " { 0, "); fprintf(out, " { 0, ");
fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ", fprintf(out, "qt_meta_stringdata_%s.data,\n"
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); " qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(),
qualifiedClassNameIdentifier.constData());
if (!hasExtraData) if (!hasExtraData)
fprintf(out, "0 }\n"); fprintf(out, "0 }\n");
else else
@ -379,7 +469,7 @@ void Generator::generateCode()
// //
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData()); fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
fprintf(out, " if (!_clname) return 0;\n"); fprintf(out, " if (!_clname) return 0;\n");
fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s))\n" fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata))\n"
" return static_cast<void*>(const_cast< %s*>(this));\n", " return static_cast<void*>(const_cast< %s*>(this));\n",
qualifiedClassNameIdentifier.constData(), cdef->classname.constData()); qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
@ -430,6 +520,15 @@ void Generator::generateCode()
} }
void Generator::registerClassInfoStrings()
{
for (int i = 0; i < cdef->classInfoList.size(); ++i) {
const ClassInfoDef &c = cdef->classInfoList.at(i);
strreg(c.name);
strreg(c.value);
}
}
void Generator::generateClassInfos() void Generator::generateClassInfos()
{ {
if (cdef->classInfoList.isEmpty()) if (cdef->classInfoList.isEmpty())
@ -439,32 +538,37 @@ void Generator::generateClassInfos()
for (int i = 0; i < cdef->classInfoList.size(); ++i) { for (int i = 0; i < cdef->classInfoList.size(); ++i) {
const ClassInfoDef &c = cdef->classInfoList.at(i); const ClassInfoDef &c = cdef->classInfoList.at(i);
fprintf(out, " %4d, %4d,\n", strreg(c.name), strreg(c.value)); fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value));
} }
} }
void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type) void Generator::registerFunctionStrings(const QList<FunctionDef>& list)
{ {
if (list.isEmpty())
return;
fprintf(out, "\n // %ss: signature, parameters, type, tag, flags\n", functype);
for (int i = 0; i < list.count(); ++i) { for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i); const FunctionDef &f = list.at(i);
QByteArray sig = f.name + '('; strreg(f.name);
QByteArray arguments; if (!isBuiltinType(f.normalizedType))
strreg(f.normalizedType);
strreg(f.tag);
for (int j = 0; j < f.arguments.count(); ++j) { for (int j = 0; j < f.arguments.count(); ++j) {
const ArgumentDef &a = f.arguments.at(j); const ArgumentDef &a = f.arguments.at(j);
if (j) { if (!isBuiltinType(a.normalizedType))
sig += ","; strreg(a.normalizedType);
arguments += ","; strreg(a.name);
}
sig += a.normalizedType;
arguments += a.name;
} }
sig += ')'; }
}
void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type, int &paramsIndex)
{
if (list.isEmpty())
return;
fprintf(out, "\n // %ss: name, argc, parameters, tag, flags\n", functype);
for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i);
unsigned char flags = type; unsigned char flags = type;
if (f.access == FunctionDef::Private) if (f.access == FunctionDef::Private)
@ -487,8 +591,12 @@ void Generator::generateFunctions(const QList<FunctionDef>& list, const char *fu
flags |= MethodScriptable; flags |= MethodScriptable;
if (f.revision > 0) if (f.revision > 0)
flags |= MethodRevisioned; flags |= MethodRevisioned;
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig),
strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags); int argc = f.arguments.count();
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n",
stridx(f.name), argc, paramsIndex, stridx(f.tag), flags);
paramsIndex += 1 + argc * 2;
} }
} }
@ -502,6 +610,54 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef>& list, const
} }
} }
void Generator::generateFunctionParameters(const QList<FunctionDef>& list, const char *functype)
{
if (list.isEmpty())
return;
fprintf(out, "\n // %ss: parameters\n", functype);
for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i);
fprintf(out, " ");
// Types
for (int j = -1; j < f.arguments.count(); ++j) {
if (j > -1)
fputc(' ', out);
const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType;
if (isBuiltinType(typeName)) {
int type = nameToBuiltinType(typeName);
const char *valueString = metaTypeEnumValueString(type);
if (valueString)
fprintf(out, "QMetaType::%s", valueString);
else
fprintf(out, "%4d", type);
} else {
Q_ASSERT(!typeName.isEmpty() || f.isConstructor);
fprintf(out, "0x%.8x | %d", IsUnresolvedType, stridx(typeName));
}
fputc(',', out);
}
// Parameter names
for (int j = 0; j < f.arguments.count(); ++j) {
const ArgumentDef &arg = f.arguments.at(j);
fprintf(out, " %4d,", stridx(arg.name));
}
fprintf(out, "\n");
}
}
void Generator::registerPropertyStrings()
{
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
strreg(p.name);
if (!isBuiltinType(p.type))
strreg(p.type);
}
}
void Generator::generateProperties() void Generator::generateProperties()
{ {
// //
@ -513,11 +669,8 @@ void Generator::generateProperties()
for (int i = 0; i < cdef->propertyList.count(); ++i) { for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i); const PropertyDef &p = cdef->propertyList.at(i);
uint flags = Invalid; uint flags = Invalid;
if (!isVariantType(p.type)) { if (!isBuiltinType(p.type))
flags |= EnumOrFlag; flags |= EnumOrFlag;
} else if (!isQRealType(p.type)) {
flags |= qvariant_nameToType(p.type) << 24;
}
if (!p.read.isEmpty()) if (!p.read.isEmpty())
flags |= Readable; flags |= Readable;
if (!p.write.isEmpty()) { if (!p.write.isEmpty()) {
@ -567,12 +720,20 @@ void Generator::generateProperties()
if (p.final) if (p.final)
flags |= Final; flags |= Final;
fprintf(out, " %4d, %4d, ", fprintf(out, " %4d, ", stridx(p.name));
strreg(p.name),
strreg(p.type)); if (isBuiltinType(p.type)) {
if (!(flags >> 24) && isQRealType(p.type)) int type = nameToBuiltinType(p.type);
fprintf(out, "(QMetaType::QReal << 24) | "); const char *valueString = metaTypeEnumValueString(type);
fprintf(out, "0x%.8x,\n", flags); if (valueString)
fprintf(out, "QMetaType::%s", valueString);
else
fprintf(out, "%4d", type);
} else {
fprintf(out, "0x%.8x | %d", IsUnresolvedType, stridx(p.type));
}
fprintf(out, ", 0x%.8x,\n", flags);
} }
if(cdef->notifyableProperties) { if(cdef->notifyableProperties) {
@ -596,6 +757,16 @@ void Generator::generateProperties()
} }
} }
void Generator::registerEnumStrings()
{
for (int i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
strreg(e.name);
for (int j = 0; j < e.values.count(); ++j)
strreg(e.values.at(j));
}
}
void Generator::generateEnums(int index) void Generator::generateEnums(int index)
{ {
if (cdef->enumDeclarations.isEmpty()) if (cdef->enumDeclarations.isEmpty())
@ -607,7 +778,7 @@ void Generator::generateEnums(int index)
for (i = 0; i < cdef->enumList.count(); ++i) { for (i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i); const EnumDef &e = cdef->enumList.at(i);
fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n", fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
strreg(e.name), stridx(e.name),
cdef->enumDeclarations.value(e.name) ? 1 : 0, cdef->enumDeclarations.value(e.name) ? 1 : 0,
e.values.count(), e.values.count(),
index); index);
@ -624,7 +795,7 @@ void Generator::generateEnums(int index)
code += "::" + e.name; code += "::" + e.name;
code += "::" + val; code += "::" + val;
fprintf(out, " %4d, uint(%s),\n", fprintf(out, " %4d, uint(%s),\n",
strreg(val), code.constData()); stridx(val), code.constData());
} }
} }
} }
@ -926,8 +1097,9 @@ void Generator::generateStaticMetacall()
fprintf(out, " switch (_id) {\n"); fprintf(out, " switch (_id) {\n");
for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) { for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
const FunctionDef &f = methodList.at(methodindex); const FunctionDef &f = methodList.at(methodindex);
Q_ASSERT(!f.normalizedType.isEmpty());
fprintf(out, " case %d: ", methodindex); fprintf(out, " case %d: ", methodindex);
if (f.normalizedType.size()) if (f.normalizedType != "void")
fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData()); fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
fprintf(out, "_t->"); fprintf(out, "_t->");
if (f.inPrivateClass.size()) if (f.inPrivateClass.size())
@ -942,7 +1114,7 @@ void Generator::generateStaticMetacall()
isUsed_a = true; isUsed_a = true;
} }
fprintf(out, ");"); fprintf(out, ");");
if (f.normalizedType.size()) { if (f.normalizedType != "void") {
fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ", fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
noRef(f.normalizedType).constData()); noRef(f.normalizedType).constData());
isUsed_a = true; isUsed_a = true;
@ -1021,7 +1193,8 @@ void Generator::generateSignal(FunctionDef *def,int index)
constQualifier = "const"; constQualifier = "const";
} }
if (def->arguments.isEmpty() && def->normalizedType.isEmpty()) { Q_ASSERT(!def->normalizedType.isEmpty());
if (def->arguments.isEmpty() && def->normalizedType == "void") {
fprintf(out, ")%s\n{\n" fprintf(out, ")%s\n{\n"
" QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n" " QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n"
"}\n", constQualifier, thisPtr.constData(), index); "}\n", constQualifier, thisPtr.constData(), index);
@ -1036,11 +1209,11 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData()); fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData());
} }
fprintf(out, ")%s\n{\n", constQualifier); fprintf(out, ")%s\n{\n", constQualifier);
if (def->type.name.size() && def->normalizedType.size()) if (def->type.name.size() && def->normalizedType != "void")
fprintf(out, " %s _t0 = %s();\n", noRef(def->normalizedType).constData(), noRef(def->normalizedType).constData()); fprintf(out, " %s _t0 = %s();\n", noRef(def->normalizedType).constData(), noRef(def->normalizedType).constData());
fprintf(out, " void *_a[] = { "); fprintf(out, " void *_a[] = { ");
if (def->normalizedType.isEmpty()) { if (def->normalizedType == "void") {
fprintf(out, "0"); fprintf(out, "0");
} else { } else {
if (def->returnTypeIsVolatile) if (def->returnTypeIsVolatile)
@ -1056,7 +1229,7 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i); fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
fprintf(out, " };\n"); fprintf(out, " };\n");
fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index); fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
if (def->normalizedType.size()) if (def->normalizedType != "void")
fprintf(out, " return _t0;\n"); fprintf(out, " return _t0;\n");
fprintf(out, "}\n"); fprintf(out, "}\n");
} }

View File

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

View File

@ -75,9 +75,7 @@ static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false)
} }
} }
*d = '\0'; *d = '\0';
QByteArray result; QByteArray result = normalizeTypeInternal(buf, d, fixScope);
if (strncmp("void", buf, d - buf) != 0)
result = normalizeTypeInternal(buf, d, fixScope);
if (buf != stackbuf) if (buf != stackbuf)
delete [] buf; delete [] buf;
return result; return result;
@ -822,8 +820,8 @@ void Moc::generate(FILE *out)
if (classList.size() && classList.first().classname == "Qt") if (classList.size() && classList.first().classname == "Qt")
fprintf(out, "#include <QtCore/qobject.h>\n"); fprintf(out, "#include <QtCore/qobject.h>\n");
if (mustIncludeQMetaTypeH) fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
fprintf(out, "#include <QtCore/qmetatype.h>\n"); fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
if (mustIncludeQPluginH) if (mustIncludeQPluginH)
fprintf(out, "#include <QtCore/qplugin.h>\n"); fprintf(out, "#include <QtCore/qplugin.h>\n");
@ -981,8 +979,6 @@ void Moc::createPropertyDef(PropertyDef &propDef)
type = "qlonglong"; type = "qlonglong";
else if (type == "ULongLong") else if (type == "ULongLong")
type = "qulonglong"; type = "qulonglong";
else if (type == "qreal")
mustIncludeQMetaTypeH = true;
propDef.type = type; propDef.type = type;

View File

@ -200,7 +200,7 @@ class Moc : public Parser
public: public:
Moc(Preprocessor &p) Moc(Preprocessor &p)
: preprocessor(p), noInclude(false), generatedCode(false), : preprocessor(p), noInclude(false), generatedCode(false),
mustIncludeQMetaTypeH(false), mustIncludeQPluginH(false) mustIncludeQPluginH(false)
{} {}
QByteArray filename; QByteArray filename;
@ -208,7 +208,6 @@ public:
Preprocessor &preprocessor; Preprocessor &preprocessor;
bool noInclude; bool noInclude;
bool generatedCode; bool generatedCode;
bool mustIncludeQMetaTypeH;
bool mustIncludeQPluginH; bool mustIncludeQPluginH;
QByteArray includePath; QByteArray includePath;
QList<QByteArray> includeFiles; QList<QByteArray> includeFiles;

View File

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

View File

@ -223,7 +223,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject()") QTest::newRow("MethodTestObject()")
<< QByteArray("MethodTestObject()") << QByteArray("MethodTestObject()")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>()) << (QList<int>())
<< (QList<QByteArray>()) << (QList<QByteArray>())
<< (QList<QByteArray>()) << (QList<QByteArray>())
@ -259,7 +259,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(int)") QTest::newRow("MethodTestObject(int)")
<< QByteArray("MethodTestObject(int)") << QByteArray("MethodTestObject(int)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>() << int(QMetaType::Int)) << (QList<int>() << int(QMetaType::Int))
<< (QList<QByteArray>() << QByteArray("int")) << (QList<QByteArray>() << QByteArray("int"))
<< (QList<QByteArray>() << QByteArray("constructorIntArg")) << (QList<QByteArray>() << QByteArray("constructorIntArg"))
@ -295,7 +295,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(qreal)") QTest::newRow("MethodTestObject(qreal)")
<< QByteArray("MethodTestObject(qreal)") << QByteArray("MethodTestObject(qreal)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>() << qMetaTypeId<qreal>()) << (QList<int>() << qMetaTypeId<qreal>())
<< (QList<QByteArray>() << QByteArray("qreal")) << (QList<QByteArray>() << QByteArray("qreal"))
<< (QList<QByteArray>() << QByteArray("constructorQRealArg")) << (QList<QByteArray>() << QByteArray("constructorQRealArg"))
@ -331,7 +331,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(QString)") QTest::newRow("MethodTestObject(QString)")
<< QByteArray("MethodTestObject(QString)") << QByteArray("MethodTestObject(QString)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>() << int(QMetaType::QString)) << (QList<int>() << int(QMetaType::QString))
<< (QList<QByteArray>() << QByteArray("QString")) << (QList<QByteArray>() << QByteArray("QString"))
<< (QList<QByteArray>() << QByteArray("constructorQStringArg")) << (QList<QByteArray>() << QByteArray("constructorQStringArg"))
@ -367,7 +367,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(CustomType)") QTest::newRow("MethodTestObject(CustomType)")
<< QByteArray("MethodTestObject(CustomType)") << QByteArray("MethodTestObject(CustomType)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>() << qMetaTypeId<CustomType>()) << (QList<int>() << qMetaTypeId<CustomType>())
<< (QList<QByteArray>() << QByteArray("CustomType")) << (QList<QByteArray>() << QByteArray("CustomType"))
<< (QList<QByteArray>() << QByteArray("constructorCustomTypeArg")) << (QList<QByteArray>() << QByteArray("constructorCustomTypeArg"))
@ -403,7 +403,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(CustomUnregisteredType)") QTest::newRow("MethodTestObject(CustomUnregisteredType)")
<< QByteArray("MethodTestObject(CustomUnregisteredType)") << QByteArray("MethodTestObject(CustomUnregisteredType)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>() << 0) << (QList<int>() << 0)
<< (QList<QByteArray>() << QByteArray("CustomUnregisteredType")) << (QList<QByteArray>() << QByteArray("CustomUnregisteredType"))
<< (QList<QByteArray>() << QByteArray("constructorCustomUnregisteredTypeArg")) << (QList<QByteArray>() << QByteArray("constructorCustomUnregisteredTypeArg"))
@ -536,7 +536,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") QTest::newRow("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)")
<< QByteArray("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)") << QByteArray("MethodTestObject(bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< parameterTypes << parameterTypeNames << parameterNames << parameterTypes << parameterTypeNames << parameterNames
<< QMetaMethod::Public << QMetaMethod::Public
<< QMetaMethod::Constructor; << QMetaMethod::Constructor;
@ -571,7 +571,7 @@ void tst_QMetaMethod::method_data()
QTest::newRow("MethodTestObject(bool,int)") QTest::newRow("MethodTestObject(bool,int)")
<< QByteArray("MethodTestObject(bool,int)") << QByteArray("MethodTestObject(bool,int)")
<< int(QMetaType::Void) << QByteArray("") << int(QMetaType::UnknownType) << QByteArray("")
<< (QList<int>() << int(QMetaType::Bool) << int(QMetaType::Int)) << (QList<int>() << int(QMetaType::Bool) << int(QMetaType::Int))
<< (QList<QByteArray>() << QByteArray("bool") << QByteArray("int")) << (QList<QByteArray>() << QByteArray("bool") << QByteArray("int"))
<< (QList<QByteArray>() << QByteArray("") << QByteArray("")) << (QList<QByteArray>() << QByteArray("") << QByteArray(""))
@ -603,15 +603,50 @@ void tst_QMetaMethod::method()
QCOMPARE(method.methodType(), methodType); QCOMPARE(method.methodType(), methodType);
QCOMPARE(method.access(), access); QCOMPARE(method.access(), access);
QCOMPARE(method.signature(), signature.constData()); QVERIFY(!method.methodSignature().isEmpty());
if (method.methodSignature() != signature) {
// QMetaMethod should always produce a semantically equivalent signature
int signatureIndex = (methodType == QMetaMethod::Constructor)
? mo->indexOfConstructor(method.methodSignature())
: mo->indexOfMethod(method.methodSignature());
QCOMPARE(signatureIndex, index);
}
QByteArray computedName = signature.left(signature.indexOf('('));
QCOMPARE(method.name(), computedName);
QCOMPARE(method.tag(), ""); QCOMPARE(method.tag(), "");
QCOMPARE(method.returnType(), returnType);
if (QByteArray(method.typeName()) != returnTypeName) {
// QMetaMethod should always produce a semantically equivalent typename
QCOMPARE(QMetaType::type(method.typeName()), QMetaType::type(returnTypeName));
}
QCOMPARE(method.typeName(), returnTypeName.constData()); if (method.parameterTypes() != parameterTypeNames) {
QCOMPARE(QMetaType::type(method.typeName()), returnType); // QMetaMethod should always produce semantically equivalent typenames
QList<QByteArray> actualTypeNames = method.parameterTypes();
QCOMPARE(method.parameterTypes(), parameterTypeNames); QCOMPARE(actualTypeNames.size(), parameterTypeNames.size());
for (int i = 0; i < parameterTypeNames.size(); ++i) {
QCOMPARE(QMetaType::type(actualTypeNames.at(i)),
QMetaType::type(parameterTypeNames.at(i)));
}
}
QCOMPARE(method.parameterNames(), parameterNames); QCOMPARE(method.parameterNames(), parameterNames);
QCOMPARE(method.parameterCount(), parameterTypes.size());
for (int i = 0; i < parameterTypes.size(); ++i)
QCOMPARE(method.parameterType(i), parameterTypes.at(i));
{
QVector<int> actualParameterTypes(parameterTypes.size());
method.getParameterTypes(actualParameterTypes.data());
for (int i = 0; i < parameterTypes.size(); ++i)
QCOMPARE(actualParameterTypes.at(i), parameterTypes.at(i));
}
// Bogus indexes
QCOMPARE(method.parameterType(-1), 0);
QCOMPARE(method.parameterType(parameterTypes.size()), 0);
} }
void tst_QMetaMethod::invalidMethod() void tst_QMetaMethod::invalidMethod()

View File

@ -978,25 +978,25 @@ void tst_QMetaObject::propertyNotify()
QVERIFY(prop.isValid()); QVERIFY(prop.isValid());
QVERIFY(prop.hasNotifySignal()); QVERIFY(prop.hasNotifySignal());
QMetaMethod signal = prop.notifySignal(); QMetaMethod signal = prop.notifySignal();
QCOMPARE(signal.signature(), "value6Changed()"); QCOMPARE(signal.methodSignature(), QByteArray("value6Changed()"));
prop = mo->property(mo->indexOfProperty("value7")); prop = mo->property(mo->indexOfProperty("value7"));
QVERIFY(prop.isValid()); QVERIFY(prop.isValid());
QVERIFY(prop.hasNotifySignal()); QVERIFY(prop.hasNotifySignal());
signal = prop.notifySignal(); signal = prop.notifySignal();
QCOMPARE(signal.signature(), "value7Changed(QString)"); QCOMPARE(signal.methodSignature(), QByteArray("value7Changed(QString)"));
prop = mo->property(mo->indexOfProperty("value8")); prop = mo->property(mo->indexOfProperty("value8"));
QVERIFY(prop.isValid()); QVERIFY(prop.isValid());
QVERIFY(!prop.hasNotifySignal()); QVERIFY(!prop.hasNotifySignal());
signal = prop.notifySignal(); signal = prop.notifySignal();
QCOMPARE(signal.signature(), (const char *)0); QCOMPARE(signal.methodSignature(), QByteArray());
prop = mo->property(mo->indexOfProperty("value")); prop = mo->property(mo->indexOfProperty("value"));
QVERIFY(prop.isValid()); QVERIFY(prop.isValid());
QVERIFY(!prop.hasNotifySignal()); QVERIFY(!prop.hasNotifySignal());
signal = prop.notifySignal(); signal = prop.notifySignal();
QCOMPARE(signal.signature(), (const char *)0); QCOMPARE(signal.methodSignature(), QByteArray());
} }
void tst_QMetaObject::propertyConstant() void tst_QMetaObject::propertyConstant()
@ -1114,7 +1114,7 @@ void tst_QMetaObject::indexOfMethod()
QFETCH(bool, isSignal); QFETCH(bool, isSignal);
int idx = object->metaObject()->indexOfMethod(name); int idx = object->metaObject()->indexOfMethod(name);
QVERIFY(idx >= 0); QVERIFY(idx >= 0);
QCOMPARE(object->metaObject()->method(idx).signature(), name.constData()); QCOMPARE(object->metaObject()->method(idx).methodSignature(), name);
QCOMPARE(object->metaObject()->indexOfSlot(name), isSignal ? -1 : idx); QCOMPARE(object->metaObject()->indexOfSlot(name), isSignal ? -1 : idx);
QCOMPARE(object->metaObject()->indexOfSignal(name), !isSignal ? -1 : idx); QCOMPARE(object->metaObject()->indexOfSignal(name), !isSignal ? -1 : idx);
} }

View File

@ -217,6 +217,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(nullMethod.signature(), QByteArray()); QCOMPARE(nullMethod.signature(), QByteArray());
QVERIFY(nullMethod.methodType() == QMetaMethod::Method); QVERIFY(nullMethod.methodType() == QMetaMethod::Method);
QVERIFY(nullMethod.returnType().isEmpty()); QVERIFY(nullMethod.returnType().isEmpty());
QVERIFY(nullMethod.parameterTypes().isEmpty());
QVERIFY(nullMethod.parameterNames().isEmpty()); QVERIFY(nullMethod.parameterNames().isEmpty());
QVERIFY(nullMethod.tag().isEmpty()); QVERIFY(nullMethod.tag().isEmpty());
QVERIFY(nullMethod.access() == QMetaMethod::Public); QVERIFY(nullMethod.access() == QMetaMethod::Public);
@ -229,6 +230,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Method); QVERIFY(method1.methodType() == QMetaMethod::Method);
QVERIFY(method1.returnType().isEmpty()); QVERIFY(method1.returnType().isEmpty());
QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QVERIFY(method1.parameterNames().isEmpty()); QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty()); QVERIFY(method1.tag().isEmpty());
QVERIFY(method1.access() == QMetaMethod::Public); QVERIFY(method1.access() == QMetaMethod::Public);
@ -242,6 +244,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method2.signature(), QByteArray("bar(QString)")); QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Method); QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("int")); QCOMPARE(method2.returnType(), QByteArray("int"));
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(method2.parameterNames().isEmpty()); QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty()); QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Public); QVERIFY(method2.access() == QMetaMethod::Public);
@ -267,6 +270,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Method); QVERIFY(method1.methodType() == QMetaMethod::Method);
QCOMPARE(method1.returnType(), QByteArray("int")); QCOMPARE(method1.returnType(), QByteArray("int"));
QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b"); QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(method1.tag(), QByteArray("tag")); QCOMPARE(method1.tag(), QByteArray("tag"));
QVERIFY(method1.access() == QMetaMethod::Private); QVERIFY(method1.access() == QMetaMethod::Private);
@ -276,6 +280,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method2.signature(), QByteArray("bar(QString)")); QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Method); QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("int")); QCOMPARE(method2.returnType(), QByteArray("int"));
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(method2.parameterNames().isEmpty()); QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty()); QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Public); QVERIFY(method2.access() == QMetaMethod::Public);
@ -296,6 +301,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Method); QVERIFY(method1.methodType() == QMetaMethod::Method);
QCOMPARE(method1.returnType(), QByteArray("int")); QCOMPARE(method1.returnType(), QByteArray("int"));
QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b"); QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(method1.tag(), QByteArray("tag")); QCOMPARE(method1.tag(), QByteArray("tag"));
QVERIFY(method1.access() == QMetaMethod::Private); QVERIFY(method1.access() == QMetaMethod::Private);
@ -305,6 +311,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method2.signature(), QByteArray("bar(QString)")); QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Method); QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("QString")); QCOMPARE(method2.returnType(), QByteArray("QString"));
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c"); QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(method2.tag(), QByteArray("Q_FOO")); QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
QVERIFY(method2.access() == QMetaMethod::Protected); QVERIFY(method2.access() == QMetaMethod::Protected);
@ -320,6 +327,7 @@ void tst_QMetaObjectBuilder::method()
QCOMPARE(method2.signature(), QByteArray("bar(QString)")); QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Method); QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("QString")); QCOMPARE(method2.returnType(), QByteArray("QString"));
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c"); QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(method2.tag(), QByteArray("Q_FOO")); QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
QVERIFY(method2.access() == QMetaMethod::Protected); QVERIFY(method2.access() == QMetaMethod::Protected);
@ -347,6 +355,7 @@ void tst_QMetaObjectBuilder::slot()
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Slot); QVERIFY(method1.methodType() == QMetaMethod::Slot);
QVERIFY(method1.returnType().isEmpty()); QVERIFY(method1.returnType().isEmpty());
QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QVERIFY(method1.parameterNames().isEmpty()); QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty()); QVERIFY(method1.tag().isEmpty());
QVERIFY(method1.access() == QMetaMethod::Public); QVERIFY(method1.access() == QMetaMethod::Public);
@ -359,6 +368,7 @@ void tst_QMetaObjectBuilder::slot()
QCOMPARE(method2.signature(), QByteArray("bar(QString)")); QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Slot); QVERIFY(method2.methodType() == QMetaMethod::Slot);
QVERIFY(method2.returnType().isEmpty()); QVERIFY(method2.returnType().isEmpty());
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(method2.parameterNames().isEmpty()); QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty()); QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Public); QVERIFY(method2.access() == QMetaMethod::Public);
@ -384,6 +394,7 @@ void tst_QMetaObjectBuilder::signal()
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Signal); QVERIFY(method1.methodType() == QMetaMethod::Signal);
QVERIFY(method1.returnType().isEmpty()); QVERIFY(method1.returnType().isEmpty());
QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QVERIFY(method1.parameterNames().isEmpty()); QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty()); QVERIFY(method1.tag().isEmpty());
QVERIFY(method1.access() == QMetaMethod::Protected); QVERIFY(method1.access() == QMetaMethod::Protected);
@ -396,6 +407,7 @@ void tst_QMetaObjectBuilder::signal()
QCOMPARE(method2.signature(), QByteArray("bar(QString)")); QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Signal); QVERIFY(method2.methodType() == QMetaMethod::Signal);
QVERIFY(method2.returnType().isEmpty()); QVERIFY(method2.returnType().isEmpty());
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(method2.parameterNames().isEmpty()); QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty()); QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Protected); QVERIFY(method2.access() == QMetaMethod::Protected);
@ -421,6 +433,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(ctor1.methodType() == QMetaMethod::Constructor); QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
QVERIFY(ctor1.returnType().isEmpty()); QVERIFY(ctor1.returnType().isEmpty());
QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QVERIFY(ctor1.parameterNames().isEmpty()); QVERIFY(ctor1.parameterNames().isEmpty());
QVERIFY(ctor1.tag().isEmpty()); QVERIFY(ctor1.tag().isEmpty());
QVERIFY(ctor1.access() == QMetaMethod::Public); QVERIFY(ctor1.access() == QMetaMethod::Public);
@ -433,6 +446,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QVERIFY(ctor2.returnType().isEmpty()); QVERIFY(ctor2.returnType().isEmpty());
QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(ctor2.parameterNames().isEmpty()); QVERIFY(ctor2.parameterNames().isEmpty());
QVERIFY(ctor2.tag().isEmpty()); QVERIFY(ctor2.tag().isEmpty());
QVERIFY(ctor2.access() == QMetaMethod::Public); QVERIFY(ctor2.access() == QMetaMethod::Public);
@ -458,6 +472,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(ctor1.methodType() == QMetaMethod::Constructor); QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor1.returnType(), QByteArray("int")); QCOMPARE(ctor1.returnType(), QByteArray("int"));
QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b"); QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(ctor1.tag(), QByteArray("tag")); QCOMPARE(ctor1.tag(), QByteArray("tag"));
QVERIFY(ctor1.access() == QMetaMethod::Private); QVERIFY(ctor1.access() == QMetaMethod::Private);
@ -466,6 +481,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QVERIFY(ctor2.returnType().isEmpty()); QVERIFY(ctor2.returnType().isEmpty());
QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(ctor2.parameterNames().isEmpty()); QVERIFY(ctor2.parameterNames().isEmpty());
QVERIFY(ctor2.tag().isEmpty()); QVERIFY(ctor2.tag().isEmpty());
QVERIFY(ctor2.access() == QMetaMethod::Public); QVERIFY(ctor2.access() == QMetaMethod::Public);
@ -484,6 +500,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(ctor1.methodType() == QMetaMethod::Constructor); QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor1.returnType(), QByteArray("int")); QCOMPARE(ctor1.returnType(), QByteArray("int"));
QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b"); QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(ctor1.tag(), QByteArray("tag")); QCOMPARE(ctor1.tag(), QByteArray("tag"));
QVERIFY(ctor1.access() == QMetaMethod::Private); QVERIFY(ctor1.access() == QMetaMethod::Private);
@ -492,6 +509,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor2.returnType(), QByteArray("QString")); QCOMPARE(ctor2.returnType(), QByteArray("QString"));
QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c"); QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(ctor2.tag(), QByteArray("Q_FOO")); QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
QVERIFY(ctor2.access() == QMetaMethod::Protected); QVERIFY(ctor2.access() == QMetaMethod::Protected);
@ -506,6 +524,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor2.returnType(), QByteArray("QString")); QCOMPARE(ctor2.returnType(), QByteArray("QString"));
QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c"); QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(ctor2.tag(), QByteArray("Q_FOO")); QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
QVERIFY(ctor2.access() == QMetaMethod::Protected); QVERIFY(ctor2.access() == QMetaMethod::Protected);
@ -525,6 +544,7 @@ void tst_QMetaObjectBuilder::constructor()
QCOMPARE(prototypeConstructor.signature(), QByteArray("SomethingOfEverything()")); QCOMPARE(prototypeConstructor.signature(), QByteArray("SomethingOfEverything()"));
QVERIFY(prototypeConstructor.methodType() == QMetaMethod::Constructor); QVERIFY(prototypeConstructor.methodType() == QMetaMethod::Constructor);
QCOMPARE(prototypeConstructor.returnType(), QByteArray()); QCOMPARE(prototypeConstructor.returnType(), QByteArray());
QVERIFY(prototypeConstructor.parameterTypes().isEmpty());
QVERIFY(prototypeConstructor.access() == QMetaMethod::Public); QVERIFY(prototypeConstructor.access() == QMetaMethod::Public);
QCOMPARE(prototypeConstructor.index(), 1); QCOMPARE(prototypeConstructor.index(), 1);
@ -1161,12 +1181,15 @@ bool tst_QMetaObjectBuilder::checkForSideEffects
static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2) static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2)
{ {
if (QByteArray(method1.signature()) != QByteArray(method2.signature())) if (method1.methodSignature() != method2.methodSignature())
return false; return false;
if (QByteArray(method1.typeName()) != QByteArray(method2.typeName())) if (QByteArray(method1.typeName()) != QByteArray(method2.typeName()))
return false; return false;
if (method1.parameterTypes() != method2.parameterTypes())
return false;
if (method1.parameterNames() != method2.parameterNames()) if (method1.parameterNames() != method2.parameterNames())
return false; return false;
@ -1466,7 +1489,7 @@ void TestObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id,
if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break; if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
default: { default: {
QMetaMethod ctor = _o->metaObject()->constructor(_id); QMetaMethod ctor = _o->metaObject()->constructor(_id);
qFatal("You forgot to add a case for CreateInstance %s", ctor.signature()); qFatal("You forgot to add a case for CreateInstance %s", ctor.methodSignature().constData());
} }
} }
} else if (_c == QMetaObject::InvokeMetaMethod) { } else if (_c == QMetaObject::InvokeMetaMethod) {
@ -1478,7 +1501,7 @@ void TestObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id,
case 2: *reinterpret_cast<QVariantList(*)>(_a[0]) = _t->listInvokableQRealQString(*reinterpret_cast<qreal(*)>(_a[1]), *reinterpret_cast<QString(*)>(_a[2])); break; case 2: *reinterpret_cast<QVariantList(*)>(_a[0]) = _t->listInvokableQRealQString(*reinterpret_cast<qreal(*)>(_a[1]), *reinterpret_cast<QString(*)>(_a[2])); break;
default: { default: {
QMetaMethod method = _o->metaObject()->method(_o->metaObject()->methodOffset() + _id); QMetaMethod method = _o->metaObject()->method(_o->metaObject()->methodOffset() + _id);
qFatal("You forgot to add a case for InvokeMetaMethod %s", method.signature()); qFatal("You forgot to add a case for InvokeMetaMethod %s", method.methodSignature().constData());
} }
} }
} else if (_c == QMetaObject::IndexOfMethod) { } else if (_c == QMetaObject::IndexOfMethod) {

View File

@ -332,6 +332,7 @@ void tst_QMetaType::typeName_data()
QT_FOR_EACH_STATIC_TYPE(TYPENAME_DATA) QT_FOR_EACH_STATIC_TYPE(TYPENAME_DATA)
QT_FOR_EACH_STATIC_ALIAS_TYPE(TYPENAME_DATA_ALIAS) QT_FOR_EACH_STATIC_ALIAS_TYPE(TYPENAME_DATA_ALIAS)
QTest::newRow("QMetaType::UnknownType") << QMetaType::UnknownType << static_cast<const char*>(0);
} }
void tst_QMetaType::typeName() void tst_QMetaType::typeName()
@ -642,6 +643,8 @@ void tst_QMetaType::sizeOf_data()
{ {
QTest::addColumn<QMetaType::Type>("type"); QTest::addColumn<QMetaType::Type>("type");
QTest::addColumn<int>("size"); QTest::addColumn<int>("size");
QTest::newRow("QMetaType::UnknownType") << QMetaType::UnknownType << 0;
#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \ #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
QTest::newRow(#RealType) << QMetaType::MetaTypeName << int(QTypeInfo<RealType>::sizeOf); QTest::newRow(#RealType) << QMetaType::MetaTypeName << int(QTypeInfo<RealType>::sizeOf);
FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW) FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
@ -1040,6 +1043,7 @@ void tst_QMetaType::isRegistered_data()
QTest::newRow("-1") << -1 << false; QTest::newRow("-1") << -1 << false;
QTest::newRow("-42") << -42 << false; QTest::newRow("-42") << -42 << false;
QTest::newRow("IsRegisteredDummyType + 1") << (dummyTypeId + 1) << false; QTest::newRow("IsRegisteredDummyType + 1") << (dummyTypeId + 1) << false;
QTest::newRow("QMetaType::UnknownType") << int(QMetaType::UnknownType) << false;
} }
void tst_QMetaType::isRegistered() void tst_QMetaType::isRegistered()

View File

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

View File

@ -1793,56 +1793,56 @@ void tst_QObject::metamethod()
QMetaMethod m; QMetaMethod m;
m = mobj->method(mobj->indexOfMethod("invoke1()")); m = mobj->method(mobj->indexOfMethod("invoke1()"));
QVERIFY(QByteArray(m.signature()) == "invoke1()"); QVERIFY(m.methodSignature() == "invoke1()");
QVERIFY(m.methodType() == QMetaMethod::Method); QVERIFY(m.methodType() == QMetaMethod::Method);
QVERIFY(m.access() == QMetaMethod::Public); QVERIFY(m.access() == QMetaMethod::Public);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("sinvoke1()")); m = mobj->method(mobj->indexOfMethod("sinvoke1()"));
QVERIFY(QByteArray(m.signature()) == "sinvoke1()"); QVERIFY(m.methodSignature() == "sinvoke1()");
QVERIFY(m.methodType() == QMetaMethod::Method); QVERIFY(m.methodType() == QMetaMethod::Method);
QVERIFY(m.access() == QMetaMethod::Public); QVERIFY(m.access() == QMetaMethod::Public);
QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("invoke2()")); m = mobj->method(mobj->indexOfMethod("invoke2()"));
QVERIFY(QByteArray(m.signature()) == "invoke2()"); QVERIFY(m.methodSignature() == "invoke2()");
QVERIFY(m.methodType() == QMetaMethod::Method); QVERIFY(m.methodType() == QMetaMethod::Method);
QVERIFY(m.access() == QMetaMethod::Protected); QVERIFY(m.access() == QMetaMethod::Protected);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility)); QVERIFY((m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("sinvoke2()")); m = mobj->method(mobj->indexOfMethod("sinvoke2()"));
QVERIFY(QByteArray(m.signature()) == "sinvoke2()"); QVERIFY(m.methodSignature() == "sinvoke2()");
QVERIFY(m.methodType() == QMetaMethod::Method); QVERIFY(m.methodType() == QMetaMethod::Method);
QVERIFY(m.access() == QMetaMethod::Protected); QVERIFY(m.access() == QMetaMethod::Protected);
QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility)); QVERIFY((m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("invoke3()")); m = mobj->method(mobj->indexOfMethod("invoke3()"));
QVERIFY(QByteArray(m.signature()) == "invoke3()"); QVERIFY(m.methodSignature() == "invoke3()");
QVERIFY(m.methodType() == QMetaMethod::Method); QVERIFY(m.methodType() == QMetaMethod::Method);
QVERIFY(m.access() == QMetaMethod::Private); QVERIFY(m.access() == QMetaMethod::Private);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("sinvoke3()")); m = mobj->method(mobj->indexOfMethod("sinvoke3()"));
QVERIFY(QByteArray(m.signature()) == "sinvoke3()"); QVERIFY(m.methodSignature() == "sinvoke3()");
QVERIFY(m.methodType() == QMetaMethod::Method); QVERIFY(m.methodType() == QMetaMethod::Method);
QVERIFY(m.access() == QMetaMethod::Private); QVERIFY(m.access() == QMetaMethod::Private);
QVERIFY((m.attributes() & QMetaMethod::Scriptable)); QVERIFY((m.attributes() & QMetaMethod::Scriptable));
QVERIFY(!(m.attributes() & QMetaMethod::Compatibility)); QVERIFY(!(m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("signal5()")); m = mobj->method(mobj->indexOfMethod("signal5()"));
QVERIFY(QByteArray(m.signature()) == "signal5()"); QVERIFY(m.methodSignature() == "signal5()");
QVERIFY(m.methodType() == QMetaMethod::Signal); QVERIFY(m.methodType() == QMetaMethod::Signal);
QVERIFY(m.access() == QMetaMethod::Protected); QVERIFY(m.access() == QMetaMethod::Protected);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility)); QVERIFY((m.attributes() & QMetaMethod::Compatibility));
m = mobj->method(mobj->indexOfMethod("aPublicSlot()")); m = mobj->method(mobj->indexOfMethod("aPublicSlot()"));
QVERIFY(QByteArray(m.signature()) == "aPublicSlot()"); QVERIFY(m.methodSignature() == "aPublicSlot()");
QVERIFY(m.methodType() == QMetaMethod::Slot); QVERIFY(m.methodType() == QMetaMethod::Slot);
QVERIFY(m.access() == QMetaMethod::Public); QVERIFY(m.access() == QMetaMethod::Public);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable)); QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));

View File

@ -3557,6 +3557,10 @@ void tst_QVariant::loadQVariantFromDataStream(QDataStream::Version version)
stream >> typeName >> loadedVariant; stream >> typeName >> loadedVariant;
const int id = QMetaType::type(typeName.toLatin1()); const int id = QMetaType::type(typeName.toLatin1());
if (id == QMetaType::Void) {
// Void type is not supported by QVariant
return;
}
QVariant constructedVariant(static_cast<QVariant::Type>(id)); QVariant constructedVariant(static_cast<QVariant::Type>(id));
QCOMPARE(constructedVariant.userType(), id); QCOMPARE(constructedVariant.userType(), id);
@ -3576,6 +3580,10 @@ void tst_QVariant::saveQVariantFromDataStream(QDataStream::Version version)
dataFileStream >> typeName; dataFileStream >> typeName;
QByteArray data = file.readAll(); QByteArray data = file.readAll();
const int id = QMetaType::type(typeName.toLatin1()); const int id = QMetaType::type(typeName.toLatin1());
if (id == QMetaType::Void) {
// Void type is not supported by QVariant
return;
}
QBuffer buffer; QBuffer buffer;
buffer.open(QIODevice::ReadWrite); buffer.open(QIODevice::ReadWrite);
@ -3636,7 +3644,9 @@ void tst_QVariant::debugStream_data()
const char *tagName = QMetaType::typeName(id); const char *tagName = QMetaType::typeName(id);
if (!tagName) if (!tagName)
continue; continue;
QTest::newRow(tagName) << QVariant(static_cast<QVariant::Type>(id)) << id; if (id != QMetaType::Void) {
QTest::newRow(tagName) << QVariant(static_cast<QVariant::Type>(id)) << id;
}
} }
QTest::newRow("QBitArray(111)") << QVariant(QBitArray(3, true)) << qMetaTypeId<QBitArray>(); QTest::newRow("QBitArray(111)") << QVariant(QBitArray(3, true)) << qMetaTypeId<QBitArray>();
QTest::newRow("CustomStreamableClass") << QVariant(qMetaTypeId<CustomStreamableClass>(), 0) << qMetaTypeId<CustomStreamableClass>(); QTest::newRow("CustomStreamableClass") << QVariant(qMetaTypeId<CustomStreamableClass>(), 0) << qMetaTypeId<CustomStreamableClass>();

View File

@ -0,0 +1,5 @@
TARGET = tst_qarraydata
SOURCES += tst_qarraydata.cpp
HEADERS += simplevector.h
QT = core testlib
CONFIG += testcase parallel_test

View File

@ -0,0 +1,341 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite 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 QARRAY_TEST_SIMPLE_VECTOR_H
#define QARRAY_TEST_SIMPLE_VECTOR_H
#include <QtCore/qarraydata.h>
#include <QtCore/qarraydatapointer.h>
#include <algorithm>
template <class T>
struct SimpleVector
{
private:
typedef QTypedArrayData<T> Data;
public:
typedef T value_type;
typedef typename Data::iterator iterator;
typedef typename Data::const_iterator const_iterator;
SimpleVector()
{
}
SimpleVector(size_t n, const T &t)
: d(Data::allocate(n))
{
if (n)
d->copyAppend(n, t);
}
SimpleVector(const T *begin, const T *end)
: d(Data::allocate(end - begin))
{
if (end - begin)
d->copyAppend(begin, end);
}
SimpleVector(QArrayDataPointerRef<T> ptr)
: d(ptr)
{
}
explicit SimpleVector(Data *ptr)
: d(ptr)
{
}
bool empty() const { return d->size == 0; }
bool isNull() const { return d.isNull(); }
bool isEmpty() const { return this->empty(); }
bool isStatic() const { return d->ref.isStatic(); }
bool isShared() const { return d->ref.isShared(); }
bool isSharedWith(const SimpleVector &other) const { return d == other.d; }
bool isSharable() const { return d->ref.isSharable(); }
void setSharable(bool sharable) { d.setSharable(sharable); }
size_t size() const { return d->size; }
size_t capacity() const { return d->alloc; }
iterator begin() { detach(); return d->begin(); }
iterator end() { detach(); return d->end(); }
const_iterator begin() const { return d->begin(); }
const_iterator end() const { return d->end(); }
const_iterator constBegin() const { return begin(); }
const_iterator constEnd() const { return end(); }
T &operator[](size_t i) { Q_ASSERT(i < size_t(d->size)); detach(); return begin()[i]; }
T &at(size_t i) { Q_ASSERT(i < size_t(d->size)); detach(); return begin()[i]; }
const T &operator[](size_t i) const { Q_ASSERT(i < size_t(d->size)); return begin()[i]; }
const T &at(size_t i) const { Q_ASSERT(i < size_t(d->size)); return begin()[i]; }
T &front()
{
Q_ASSERT(!isEmpty());
detach();
return *begin();
}
T &back()
{
Q_ASSERT(!isEmpty());
detach();
return *(end() - 1);
}
const T &front() const
{
Q_ASSERT(!isEmpty());
return *begin();
}
const T &back() const
{
Q_ASSERT(!isEmpty());
return *(end() - 1);
}
void reserve(size_t n)
{
if (n == 0)
return;
if (n <= capacity()) {
if (d->capacityReserved)
return;
if (!d->ref.isShared()) {
d->capacityReserved = 1;
return;
}
}
SimpleVector detached(Data::allocate(qMax(n, size()),
d->detachFlags() | Data::CapacityReserved));
if (size())
detached.d->copyAppend(constBegin(), constEnd());
detached.swap(*this);
}
void prepend(const_iterator first, const_iterator last)
{
if (!d->size) {
append(first, last);
return;
}
if (first == last)
return;
T *const begin = d->begin();
if (d->ref.isShared()
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
qMax(capacity(), size() + (last - first)),
d->detachFlags() | Data::Grow));
detached.d->copyAppend(first, last);
detached.d->copyAppend(begin, begin + d->size);
detached.swap(*this);
return;
}
d->insert(begin, first, last);
}
void append(const_iterator first, const_iterator last)
{
if (first == last)
return;
if (d->ref.isShared()
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
qMax(capacity(), size() + (last - first)),
d->detachFlags() | Data::Grow));
if (d->size) {
const T *const begin = constBegin();
detached.d->copyAppend(begin, begin + d->size);
}
detached.d->copyAppend(first, last);
detached.swap(*this);
return;
}
d->copyAppend(first, last);
}
void insert(int position, const_iterator first, const_iterator last)
{
if (position < 0)
position += d->size + 1;
if (position <= 0) {
prepend(first, last);
return;
}
if (size_t(position) >= size()) {
append(first, last);
return;
}
if (first == last)
return;
T *const begin = d->begin();
T *const where = begin + position;
const T *const end = begin + d->size;
if (d->ref.isShared()
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
qMax(capacity(), size() + (last - first)),
d->detachFlags() | Data::Grow));
if (position)
detached.d->copyAppend(begin, where);
detached.d->copyAppend(first, last);
detached.d->copyAppend(where, end);
detached.swap(*this);
return;
}
if ((first >= where && first < end)
|| (last > where && last <= end)) {
// Copy overlapping data first and only then shuffle it into place
T *start = d->begin() + position;
T *middle = d->end();
d->copyAppend(first, last);
std::rotate(start, middle, d->end());
return;
}
d->insert(where, first, last);
}
void swap(SimpleVector &other)
{
qSwap(d, other.d);
}
void clear()
{
d.clear();
}
void detach()
{
d.detach();
}
static SimpleVector fromRawData(const T *data, size_t size,
QArrayData::AllocationOptions options = Data::Default)
{
return SimpleVector(Data::fromRawData(data, size, options));
}
private:
QArrayDataPointer<T> d;
};
template <class T>
bool operator==(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
if (lhs.isSharedWith(rhs))
return true;
if (lhs.size() != rhs.size())
return false;
return std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template <class T>
bool operator!=(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return !(lhs == rhs);
}
template <class T>
bool operator<(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <class T>
bool operator>(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return rhs < lhs;
}
template <class T>
bool operator<=(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return !(rhs < lhs);
}
template <class T>
bool operator>=(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return !(lhs < rhs);
}
namespace std {
template <class T>
void swap(SimpleVector<T> &v1, SimpleVector<T> &v2)
{
v1.swap(v2);
}
}
#endif // include guard

File diff suppressed because it is too large Load Diff

View File

@ -1078,18 +1078,25 @@ void tst_QByteArray::toULongLong()
// global function defined in qbytearray.cpp // global function defined in qbytearray.cpp
void tst_QByteArray::qAllocMore() void tst_QByteArray::qAllocMore()
{ {
static const int t[] = { using QT_PREPEND_NAMESPACE(qAllocMore);
INT_MIN, INT_MIN + 1, -1234567, -66000, -1025,
-3, -1, 0, +1, +3, +1025, +66000, +1234567, INT_MAX - 1, INT_MAX,
INT_MAX/3
};
static const int N = sizeof(t)/sizeof(t[0]);
// make sure qAllocMore() doesn't loop infinitely on any input // Not very important, but please behave :-)
for (int i = 0; i < N; ++i) { QVERIFY(qAllocMore(0, 0) >= 0);
for (int j = 0; j < N; ++j) {
::qAllocMore(t[i], t[j]); for (int i = 1; i < 1 << 8; i <<= 1)
} QVERIFY(qAllocMore(i, 0) >= i);
for (int i = 1 << 8; i < 1 << 30; i <<= 1) {
const int alloc = qAllocMore(i, 0);
QVERIFY(alloc >= i);
QCOMPARE(qAllocMore(i - 8, 8), alloc - 8);
QCOMPARE(qAllocMore(i - 16, 16), alloc - 16);
QCOMPARE(qAllocMore(i - 24, 24), alloc - 24);
QCOMPARE(qAllocMore(i - 32, 32), alloc - 32);
QVERIFY(qAllocMore(i - 1, 0) >= i - 1);
QVERIFY(qAllocMore(i + 1, 0) >= i + 1);
} }
} }
@ -1587,8 +1594,8 @@ void tst_QByteArray::literals()
QVERIFY(str.length() == 4); QVERIFY(str.length() == 4);
QVERIFY(str == "abcd"); QVERIFY(str == "abcd");
QVERIFY(str.data_ptr()->ref == -1); QVERIFY(str.data_ptr()->ref.isStatic());
QVERIFY(str.data_ptr()->offset == 0); QVERIFY(str.data_ptr()->offset == sizeof(QByteArrayData));
const char *s = str.constData(); const char *s = str.constData();
QByteArray str2 = str; QByteArray str2 = str;

View File

@ -54,6 +54,9 @@ class tst_QList : public QObject
Q_OBJECT Q_OBJECT
private slots: private slots:
void init();
void cleanup();
void length() const; void length() const;
void lengthSignature() const; void lengthSignature() const;
void append() const; void append() const;
@ -90,8 +93,100 @@ private slots:
void initializeList() const; void initializeList() const;
void const_shared_null() const; void const_shared_null() const;
void setSharable1_data() const;
void setSharable1() const;
void setSharable2_data() const;
void setSharable2() const;
private:
int dummyForGuard;
}; };
struct Complex
{
Complex(int val)
: value(val)
, checkSum(this)
{
++liveCount;
}
Complex(Complex const &other)
: value(other.value)
, checkSum(this)
{
++liveCount;
}
Complex &operator=(Complex const &other)
{
check(); other.check();
value = other.value;
return *this;
}
~Complex()
{
--liveCount;
check();
}
operator int() const { return value; }
bool operator==(Complex const &other) const
{
check(); other.check();
return value == other.value;
}
bool check() const
{
if (this != checkSum) {
++errorCount;
return false;
}
return true;
}
struct Guard
{
Guard() : initialLiveCount(liveCount) {}
~Guard() { if (liveCount != initialLiveCount) ++errorCount; }
private:
Q_DISABLE_COPY(Guard);
int initialLiveCount;
};
static void resetErrors() { errorCount = 0; }
static int errors() { return errorCount; }
private:
static int errorCount;
static int liveCount;
int value;
void *checkSum;
};
int Complex::errorCount = 0;
int Complex::liveCount = 0;
void tst_QList::init()
{
Complex::resetErrors();
new (&dummyForGuard) Complex::Guard();
}
void tst_QList::cleanup()
{
QCOMPARE(Complex::errors(), 0);
reinterpret_cast<Complex::Guard *>(&dummyForGuard)->~Guard();
QCOMPARE(Complex::errors(), 0);
}
void tst_QList::length() const void tst_QList::length() const
{ {
/* Empty list. */ /* Empty list. */
@ -696,5 +791,82 @@ void tst_QList::const_shared_null() const
QVERIFY(!list2.isDetached()); QVERIFY(!list2.isDetached());
} }
Q_DECLARE_METATYPE(QList<int>);
Q_DECLARE_METATYPE(QList<Complex>);
template <class T>
void generateSetSharableData()
{
QTest::addColumn<QList<T> >("list");
QTest::addColumn<int>("size");
QTest::newRow("null") << QList<T>() << 0;
QTest::newRow("non-empty") << (QList<T>() << T(0) << T(1) << T(2) << T(3) << T(4)) << 5;
}
template <class T>
void runSetSharableTest()
{
QFETCH(QList<T>, list);
QFETCH(int, size);
QVERIFY(!list.isDetached()); // Shared with QTest
list.setSharable(true);
QCOMPARE(list.size(), size);
{
QList<T> copy(list);
QVERIFY(!copy.isDetached());
QVERIFY(copy.isSharedWith(list));
}
list.setSharable(false);
QVERIFY(list.isDetached() || list.isSharedWith(QList<T>()));
{
QList<T> copy(list);
QVERIFY(copy.isDetached() || copy.isSharedWith(QList<T>()));
QCOMPARE(copy.size(), size);
QCOMPARE(copy, list);
}
list.setSharable(true);
{
QList<T> copy(list);
QVERIFY(!copy.isDetached());
QVERIFY(copy.isSharedWith(list));
}
for (int i = 0; i < list.size(); ++i)
QCOMPARE(int(list[i]), i);
QCOMPARE(list.size(), size);
}
void tst_QList::setSharable1_data() const
{
generateSetSharableData<int>();
}
void tst_QList::setSharable2_data() const
{
generateSetSharableData<Complex>();
}
void tst_QList::setSharable1() const
{
runSetSharableTest<int>();
}
void tst_QList::setSharable2() const
{
runSetSharableTest<Complex>();
}
QTEST_APPLESS_MAIN(tst_QList) QTEST_APPLESS_MAIN(tst_QList)
#include "tst_qlist.moc" #include "tst_qlist.moc"

View File

@ -1421,16 +1421,51 @@ void tst_QString::mid()
QVERIFY(a.mid(9999).isNull()); QVERIFY(a.mid(9999).isNull());
QVERIFY(a.mid(9999,1).isNull()); QVERIFY(a.mid(9999,1).isNull());
QCOMPARE(a.mid(-1, 6), QString("ABCDEF"));
QCOMPARE(a.mid(-100, 6), QString("ABCDEF"));
QVERIFY(a.mid(INT_MAX).isNull());
QVERIFY(a.mid(INT_MAX, INT_MAX).isNull());
QCOMPARE(a.mid(-5, INT_MAX), a);
QCOMPARE(a.mid(-1, INT_MAX), a);
QCOMPARE(a.mid(0, INT_MAX), a);
QCOMPARE(a.mid(1, INT_MAX), QString("BCDEFGHIEfGEFG"));
QCOMPARE(a.mid(5, INT_MAX), QString("FGHIEfGEFG"));
QVERIFY(a.mid(20, INT_MAX).isNull());
QCOMPARE(a.mid(-1, -1), a);
QString n; QString n;
QVERIFY(n.mid(3,3).isNull()); QVERIFY(n.mid(3,3).isNull());
QVERIFY(n.mid(0,0).isNull()); QVERIFY(n.mid(0,0).isNull());
QVERIFY(n.mid(9999,0).isNull()); QVERIFY(n.mid(9999,0).isNull());
QVERIFY(n.mid(9999,1).isNull()); QVERIFY(n.mid(9999,1).isNull());
QVERIFY(n.mid(-1, 6).isNull());
QVERIFY(n.mid(-100, 6).isNull());
QVERIFY(n.mid(INT_MAX).isNull());
QVERIFY(n.mid(INT_MAX, INT_MAX).isNull());
QVERIFY(n.mid(-5, INT_MAX).isNull());
QVERIFY(n.mid(-1, INT_MAX).isNull());
QVERIFY(n.mid(0, INT_MAX).isNull());
QVERIFY(n.mid(1, INT_MAX).isNull());
QVERIFY(n.mid(5, INT_MAX).isNull());
QVERIFY(n.mid(20, INT_MAX).isNull());
QVERIFY(n.mid(-1, -1).isNull());
QString x = "Nine pineapples"; QString x = "Nine pineapples";
QCOMPARE(x.mid(5, 4), QString("pine")); QCOMPARE(x.mid(5, 4), QString("pine"));
QCOMPARE(x.mid(5), QString("pineapples")); QCOMPARE(x.mid(5), QString("pineapples"));
QCOMPARE(x.mid(-1, 6), QString("Nine p"));
QCOMPARE(x.mid(-100, 6), QString("Nine p"));
QVERIFY(x.mid(INT_MAX).isNull());
QVERIFY(x.mid(INT_MAX, INT_MAX).isNull());
QCOMPARE(x.mid(-5, INT_MAX), x);
QCOMPARE(x.mid(-1, INT_MAX), x);
QCOMPARE(x.mid(0, INT_MAX), x);
QCOMPARE(x.mid(1, INT_MAX), QString("ine pineapples"));
QCOMPARE(x.mid(5, INT_MAX), QString("pineapples"));
QVERIFY(x.mid(20, INT_MAX).isNull());
QCOMPARE(x.mid(-1, -1), x);
} }
void tst_QString::midRef() void tst_QString::midRef()
@ -1447,16 +1482,51 @@ void tst_QString::midRef()
QVERIFY(a.midRef(9999).toString().isEmpty()); QVERIFY(a.midRef(9999).toString().isEmpty());
QVERIFY(a.midRef(9999,1).toString().isEmpty()); QVERIFY(a.midRef(9999,1).toString().isEmpty());
QCOMPARE(a.midRef(-1, 6).toString(), QString("ABCDEF"));
QCOMPARE(a.midRef(-100, 6).toString(), QString("ABCDEF"));
QVERIFY(a.midRef(INT_MAX).isNull());
QVERIFY(a.midRef(INT_MAX, INT_MAX).isNull());
QCOMPARE(a.midRef(-5, INT_MAX).toString(), a);
QCOMPARE(a.midRef(-1, INT_MAX).toString(), a);
QCOMPARE(a.midRef(0, INT_MAX).toString(), a);
QCOMPARE(a.midRef(1, INT_MAX).toString(), QString("BCDEFGHIEfGEFG"));
QCOMPARE(a.midRef(5, INT_MAX).toString(), QString("FGHIEfGEFG"));
QVERIFY(a.midRef(20, INT_MAX).isNull());
QCOMPARE(a.midRef(-1, -1).toString(), a);
QString n; QString n;
QVERIFY(n.midRef(3,3).toString().isEmpty()); QVERIFY(n.midRef(3,3).toString().isEmpty());
QVERIFY(n.midRef(0,0).toString().isEmpty()); QVERIFY(n.midRef(0,0).toString().isEmpty());
QVERIFY(n.midRef(9999,0).toString().isEmpty()); QVERIFY(n.midRef(9999,0).toString().isEmpty());
QVERIFY(n.midRef(9999,1).toString().isEmpty()); QVERIFY(n.midRef(9999,1).toString().isEmpty());
QVERIFY(n.midRef(-1, 6).isNull());
QVERIFY(n.midRef(-100, 6).isNull());
QVERIFY(n.midRef(INT_MAX).isNull());
QVERIFY(n.midRef(INT_MAX, INT_MAX).isNull());
QVERIFY(n.midRef(-5, INT_MAX).isNull());
QVERIFY(n.midRef(-1, INT_MAX).isNull());
QVERIFY(n.midRef(0, INT_MAX).isNull());
QVERIFY(n.midRef(1, INT_MAX).isNull());
QVERIFY(n.midRef(5, INT_MAX).isNull());
QVERIFY(n.midRef(20, INT_MAX).isNull());
QVERIFY(n.midRef(-1, -1).isNull());
QString x = "Nine pineapples"; QString x = "Nine pineapples";
QCOMPARE(x.midRef(5, 4).toString(), QString("pine")); QCOMPARE(x.midRef(5, 4).toString(), QString("pine"));
QCOMPARE(x.midRef(5).toString(), QString("pineapples")); QCOMPARE(x.midRef(5).toString(), QString("pineapples"));
QCOMPARE(x.midRef(-1, 6).toString(), QString("Nine p"));
QCOMPARE(x.midRef(-100, 6).toString(), QString("Nine p"));
QVERIFY(x.midRef(INT_MAX).isNull());
QVERIFY(x.midRef(INT_MAX, INT_MAX).isNull());
QCOMPARE(x.midRef(-5, INT_MAX).toString(), x);
QCOMPARE(x.midRef(-1, INT_MAX).toString(), x);
QCOMPARE(x.midRef(0, INT_MAX).toString(), x);
QCOMPARE(x.midRef(1, INT_MAX).toString(), QString("ine pineapples"));
QCOMPARE(x.midRef(5, INT_MAX).toString(), QString("pineapples"));
QVERIFY(x.midRef(20, INT_MAX).isNull());
QCOMPARE(x.midRef(-1, -1).toString(), x);
} }
void tst_QString::stringRef() void tst_QString::stringRef()
@ -5056,8 +5126,8 @@ void tst_QString::literals()
QVERIFY(str.length() == 4); QVERIFY(str.length() == 4);
QVERIFY(str == QLatin1String("abcd")); QVERIFY(str == QLatin1String("abcd"));
QVERIFY(str.data_ptr()->ref == -1); QVERIFY(str.data_ptr()->ref.isStatic());
QVERIFY(str.data_ptr()->offset == 0); QVERIFY(str.data_ptr()->offset == sizeof(QStringData));
const QChar *s = str.constData(); const QChar *s = str.constData();
QString str2 = str; QString str2 = str;

View File

@ -85,6 +85,8 @@ private slots:
void initializeList(); void initializeList();
void const_shared_null(); void const_shared_null();
void setSharable_data();
void setSharable();
}; };
void tst_QVector::constructors() const void tst_QVector::constructors() const
@ -946,5 +948,97 @@ void tst_QVector::const_shared_null()
QVERIFY(!v2.isDetached()); QVERIFY(!v2.isDetached());
} }
Q_DECLARE_METATYPE(QVector<int>);
void tst_QVector::setSharable_data()
{
QTest::addColumn<QVector<int> >("vector");
QTest::addColumn<int>("size");
QTest::addColumn<int>("capacity");
QTest::addColumn<bool>("isCapacityReserved");
QVector<int> null;
QVector<int> empty(0, 5);
QVector<int> emptyReserved;
QVector<int> nonEmpty;
QVector<int> nonEmptyReserved;
emptyReserved.reserve(10);
nonEmptyReserved.reserve(15);
nonEmpty << 0 << 1 << 2 << 3 << 4;
nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6;
QVERIFY(emptyReserved.capacity() >= 10);
QVERIFY(nonEmptyReserved.capacity() >= 15);
QTest::newRow("null") << null << 0 << 0 << false;
QTest::newRow("empty") << empty << 0 << 0 << false;
QTest::newRow("empty, Reserved") << emptyReserved << 0 << 10 << true;
QTest::newRow("non-empty") << nonEmpty << 5 << 0 << false;
QTest::newRow("non-empty, Reserved") << nonEmptyReserved << 7 << 15 << true;
}
void tst_QVector::setSharable()
{
QFETCH(QVector<int>, vector);
QFETCH(int, size);
QFETCH(int, capacity);
QFETCH(bool, isCapacityReserved);
QVERIFY(!vector.isDetached()); // Shared with QTest
vector.setSharable(true);
QCOMPARE(vector.size(), size);
if (isCapacityReserved)
QVERIFY2(vector.capacity() >= capacity,
qPrintable(QString("Capacity is %1, expected at least %2.")
.arg(vector.capacity())
.arg(capacity)));
{
QVector<int> copy(vector);
QVERIFY(!copy.isDetached());
QVERIFY(copy.isSharedWith(vector));
}
vector.setSharable(false);
QVERIFY(vector.isDetached() || vector.isSharedWith(QVector<int>()));
{
QVector<int> copy(vector);
QVERIFY(copy.isDetached() || copy.isSharedWith(QVector<int>()));
QCOMPARE(copy.size(), size);
if (isCapacityReserved)
QVERIFY2(copy.capacity() >= capacity,
qPrintable(QString("Capacity is %1, expected at least %2.")
.arg(vector.capacity())
.arg(capacity)));
QCOMPARE(copy, vector);
}
vector.setSharable(true);
{
QVector<int> copy(vector);
QVERIFY(!copy.isDetached());
QVERIFY(copy.isSharedWith(vector));
}
for (int i = 0; i < vector.size(); ++i)
QCOMPARE(vector[i], i);
QCOMPARE(vector.size(), size);
if (isCapacityReserved)
QVERIFY2(vector.capacity() >= capacity,
qPrintable(QString("Capacity is %1, expected at least %2.")
.arg(vector.capacity())
.arg(capacity)));
}
QTEST_APPLESS_MAIN(tst_QVector) QTEST_APPLESS_MAIN(tst_QVector)
#include "tst_qvector.moc" #include "tst_qvector.moc"

View File

@ -1,6 +1,7 @@
TEMPLATE=subdirs TEMPLATE=subdirs
SUBDIRS=\ SUBDIRS=\
qalgorithms \ qalgorithms \
qarraydata \
qbitarray \ qbitarray \
qbytearray \ qbytearray \
qbytearraymatcher \ qbytearraymatcher \

View File

@ -397,16 +397,21 @@ void tst_QDBusMetaObject::types()
for (int i = metaobject->methodOffset(); i < metaobject->methodCount(); ++i) { for (int i = metaobject->methodOffset(); i < metaobject->methodCount(); ++i) {
QMetaMethod expected = metaobject->method(i); QMetaMethod expected = metaobject->method(i);
int methodIdx = result->indexOfMethod(expected.signature()); int methodIdx = result->indexOfMethod(expected.methodSignature().constData());
QVERIFY(methodIdx != -1); QVERIFY(methodIdx != -1);
QMetaMethod constructed = result->method(methodIdx); QMetaMethod constructed = result->method(methodIdx);
QCOMPARE(int(constructed.access()), int(expected.access())); QCOMPARE(int(constructed.access()), int(expected.access()));
QCOMPARE(int(constructed.methodType()), int(expected.methodType())); QCOMPARE(int(constructed.methodType()), int(expected.methodType()));
QCOMPARE(constructed.name(), expected.name());
QCOMPARE(constructed.parameterCount(), expected.parameterCount());
QCOMPARE(constructed.parameterNames(), expected.parameterNames()); QCOMPARE(constructed.parameterNames(), expected.parameterNames());
QCOMPARE(constructed.parameterTypes(), expected.parameterTypes()); QCOMPARE(constructed.parameterTypes(), expected.parameterTypes());
for (int j = 0; j < constructed.parameterCount(); ++j)
QCOMPARE(constructed.parameterType(j), expected.parameterType(j));
QCOMPARE(constructed.tag(), expected.tag()); QCOMPARE(constructed.tag(), expected.tag());
QCOMPARE(constructed.typeName(), expected.typeName()); QCOMPARE(constructed.typeName(), expected.typeName());
QCOMPARE(constructed.returnType(), expected.returnType());
} }
for (int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); ++i) { for (int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); ++i) {
@ -427,6 +432,8 @@ void tst_QDBusMetaObject::types()
QCOMPARE(constructed.isUser(), expected.isUser()); QCOMPARE(constructed.isUser(), expected.isUser());
QCOMPARE(constructed.isWritable(), expected.isWritable()); QCOMPARE(constructed.isWritable(), expected.isWritable());
QCOMPARE(constructed.typeName(), expected.typeName()); QCOMPARE(constructed.typeName(), expected.typeName());
QCOMPARE(constructed.type(), expected.type());
QCOMPARE(constructed.userType(), expected.userType());
} }
} }
@ -667,6 +674,204 @@ const char PropertyTest4_xml[] =
"<annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"Struct1\"/>" "<annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"Struct1\"/>"
"</property>"; "</property>";
class PropertyTest_b: public QObject
{
Q_OBJECT
Q_PROPERTY(bool property READ property WRITE setProperty)
public:
bool property() { return false; }
void setProperty(bool) { }
};
const char PropertyTest_b_xml[] =
"<property name=\"property\" type=\"b\" access=\"readwrite\"/>";
class PropertyTest_y: public QObject
{
Q_OBJECT
Q_PROPERTY(uchar property READ property WRITE setProperty)
public:
uchar property() { return 0; }
void setProperty(uchar) { }
};
const char PropertyTest_y_xml[] =
"<property name=\"property\" type=\"y\" access=\"readwrite\"/>";
class PropertyTest_n: public QObject
{
Q_OBJECT
Q_PROPERTY(short property READ property WRITE setProperty)
public:
short property() { return 0; }
void setProperty(short) { }
};
const char PropertyTest_n_xml[] =
"<property name=\"property\" type=\"n\" access=\"readwrite\"/>";
class PropertyTest_q: public QObject
{
Q_OBJECT
Q_PROPERTY(ushort property READ property WRITE setProperty)
public:
ushort property() { return 0; }
void setProperty(ushort) { }
};
const char PropertyTest_q_xml[] =
"<property name=\"property\" type=\"q\" access=\"readwrite\"/>";
class PropertyTest_u: public QObject
{
Q_OBJECT
Q_PROPERTY(uint property READ property WRITE setProperty)
public:
uint property() { return 0; }
void setProperty(uint) { }
};
const char PropertyTest_u_xml[] =
"<property name=\"property\" type=\"u\" access=\"readwrite\"/>";
class PropertyTest_x: public QObject
{
Q_OBJECT
Q_PROPERTY(qlonglong property READ property WRITE setProperty)
public:
qlonglong property() { return 0; }
void setProperty(qlonglong) { }
};
const char PropertyTest_x_xml[] =
"<property name=\"property\" type=\"x\" access=\"readwrite\"/>";
class PropertyTest_t: public QObject
{
Q_OBJECT
Q_PROPERTY(qulonglong property READ property WRITE setProperty)
public:
qulonglong property() { return 0; }
void setProperty(qulonglong) { }
};
const char PropertyTest_t_xml[] =
"<property name=\"property\" type=\"t\" access=\"readwrite\"/>";
class PropertyTest_d: public QObject
{
Q_OBJECT
Q_PROPERTY(double property READ property WRITE setProperty)
public:
double property() { return 0; }
void setProperty(double) { }
};
const char PropertyTest_d_xml[] =
"<property name=\"property\" type=\"d\" access=\"readwrite\"/>";
class PropertyTest_s: public QObject
{
Q_OBJECT
Q_PROPERTY(QString property READ property WRITE setProperty)
public:
QString property() { return QString(); }
void setProperty(QString) { }
};
const char PropertyTest_s_xml[] =
"<property name=\"property\" type=\"s\" access=\"readwrite\"/>";
class PropertyTest_v: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusVariant property READ property WRITE setProperty)
public:
QDBusVariant property() { return QDBusVariant(); }
void setProperty(QDBusVariant) { }
};
const char PropertyTest_v_xml[] =
"<property name=\"property\" type=\"v\" access=\"readwrite\"/>";
class PropertyTest_o: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusObjectPath property READ property WRITE setProperty)
public:
QDBusObjectPath property() { return QDBusObjectPath(); }
void setProperty(QDBusObjectPath) { }
};
const char PropertyTest_o_xml[] =
"<property name=\"property\" type=\"o\" access=\"readwrite\"/>";
class PropertyTest_g: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusSignature property READ property WRITE setProperty)
public:
QDBusSignature property() { return QDBusSignature(); }
void setProperty(QDBusSignature) { }
};
const char PropertyTest_g_xml[] =
"<property name=\"property\" type=\"g\" access=\"readwrite\"/>";
class PropertyTest_h: public QObject
{
Q_OBJECT
Q_PROPERTY(QDBusUnixFileDescriptor property READ property WRITE setProperty)
public:
QDBusUnixFileDescriptor property() { return QDBusUnixFileDescriptor(); }
void setProperty(QDBusUnixFileDescriptor) { }
};
const char PropertyTest_h_xml[] =
"<property name=\"property\" type=\"h\" access=\"readwrite\"/>";
class PropertyTest_ay: public QObject
{
Q_OBJECT
Q_PROPERTY(QByteArray property READ property WRITE setProperty)
public:
QByteArray property() { return QByteArray(); }
void setProperty(QByteArray) { }
};
const char PropertyTest_ay_xml[] =
"<property name=\"property\" type=\"ay\" access=\"readwrite\"/>";
class PropertyTest_as: public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList property READ property WRITE setProperty)
public:
QStringList property() { return QStringList(); }
void setProperty(QStringList) { }
};
const char PropertyTest_as_xml[] =
"<property name=\"property\" type=\"as\" access=\"readwrite\"/>";
class PropertyTest_av: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList property READ property WRITE setProperty)
public:
QVariantList property() { return QVariantList(); }
void setProperty(QVariantList) { }
};
const char PropertyTest_av_xml[] =
"<property name=\"property\" type=\"av\" access=\"readwrite\"/>";
class PropertyTest_ao: public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QDBusObjectPath> property READ property WRITE setProperty)
public:
QList<QDBusObjectPath> property() { return QList<QDBusObjectPath>(); }
void setProperty(QList<QDBusObjectPath>) { }
};
const char PropertyTest_ao_xml[] =
"<property name=\"property\" type=\"ao\" access=\"readwrite\"/>";
class PropertyTest_ag: public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QDBusSignature> property READ property WRITE setProperty)
public:
QList<QDBusSignature> property() { return QList<QDBusSignature>(); }
void setProperty(QList<QDBusSignature>) { }
};
const char PropertyTest_ag_xml[] =
"<property name=\"property\" type=\"ag\" access=\"readwrite\"/>";
void tst_QDBusMetaObject::properties_data() void tst_QDBusMetaObject::properties_data()
{ {
QTest::addColumn<const QMetaObject *>("metaobject"); QTest::addColumn<const QMetaObject *>("metaobject");
@ -676,6 +881,25 @@ void tst_QDBusMetaObject::properties_data()
QTest::newRow("readwrite") << &PropertyTest2::staticMetaObject << QString(PropertyTest2_xml); QTest::newRow("readwrite") << &PropertyTest2::staticMetaObject << QString(PropertyTest2_xml);
QTest::newRow("write") << &PropertyTest3::staticMetaObject << QString(PropertyTest3_xml); QTest::newRow("write") << &PropertyTest3::staticMetaObject << QString(PropertyTest3_xml);
QTest::newRow("customtype") << &PropertyTest4::staticMetaObject << QString(PropertyTest4_xml); QTest::newRow("customtype") << &PropertyTest4::staticMetaObject << QString(PropertyTest4_xml);
QTest::newRow("bool") << &PropertyTest_b::staticMetaObject << QString(PropertyTest_b_xml);
QTest::newRow("byte") << &PropertyTest_y::staticMetaObject << QString(PropertyTest_y_xml);
QTest::newRow("short") << &PropertyTest_n::staticMetaObject << QString(PropertyTest_n_xml);
QTest::newRow("ushort") << &PropertyTest_q::staticMetaObject << QString(PropertyTest_q_xml);
QTest::newRow("uint") << &PropertyTest_u::staticMetaObject << QString(PropertyTest_u_xml);
QTest::newRow("qlonglong") << &PropertyTest_x::staticMetaObject << QString(PropertyTest_x_xml);
QTest::newRow("qulonglong") << &PropertyTest_t::staticMetaObject << QString(PropertyTest_t_xml);
QTest::newRow("double") << &PropertyTest_d::staticMetaObject << QString(PropertyTest_d_xml);
QTest::newRow("QString") << &PropertyTest_s::staticMetaObject << QString(PropertyTest_s_xml);
QTest::newRow("QDBusVariant") << &PropertyTest_v::staticMetaObject << QString(PropertyTest_v_xml);
QTest::newRow("QDBusObjectPath") << &PropertyTest_o::staticMetaObject << QString(PropertyTest_o_xml);
QTest::newRow("QDBusSignature") << &PropertyTest_g::staticMetaObject << QString(PropertyTest_g_xml);
QTest::newRow("QDBusUnixFileDescriptor") << &PropertyTest_h::staticMetaObject << QString(PropertyTest_h_xml);
QTest::newRow("QByteArray") << &PropertyTest_ay::staticMetaObject << QString(PropertyTest_ay_xml);
QTest::newRow("QStringList") << &PropertyTest_as::staticMetaObject << QString(PropertyTest_as_xml);
QTest::newRow("QVariantList") << &PropertyTest_av::staticMetaObject << QString(PropertyTest_av_xml);
QTest::newRow("QList<QDBusObjectPath>") << &PropertyTest_ao::staticMetaObject << QString(PropertyTest_ao_xml);
QTest::newRow("QList<QDBusSignature>") << &PropertyTest_ag::staticMetaObject << QString(PropertyTest_ag_xml);
} }
void tst_QDBusMetaObject::properties() void tst_QDBusMetaObject::properties()

View File

@ -748,7 +748,7 @@ void tst_Moc::classinfoWithEscapes()
QCOMPARE(mobj->methodCount() - mobj->methodOffset(), 1); QCOMPARE(mobj->methodCount() - mobj->methodOffset(), 1);
QMetaMethod mm = mobj->method(mobj->methodOffset()); QMetaMethod mm = mobj->method(mobj->methodOffset());
QCOMPARE(mm.signature(), "slotWithAReallyLongName(int)"); QCOMPARE(mm.methodSignature(), QByteArray("slotWithAReallyLongName(int)"));
} }
void tst_Moc::trNoopInClassInfo() void tst_Moc::trNoopInClassInfo()
@ -1093,14 +1093,14 @@ void tst_Moc::invokable()
{ {
const QMetaObject &mobj = InvokableBeforeReturnType::staticMetaObject; const QMetaObject &mobj = InvokableBeforeReturnType::staticMetaObject;
QCOMPARE(mobj.methodCount(), 6); QCOMPARE(mobj.methodCount(), 6);
QVERIFY(mobj.method(5).signature() == QByteArray("foo()")); QVERIFY(mobj.method(5).methodSignature() == QByteArray("foo()"));
} }
{ {
const QMetaObject &mobj = InvokableBeforeInline::staticMetaObject; const QMetaObject &mobj = InvokableBeforeInline::staticMetaObject;
QCOMPARE(mobj.methodCount(), 7); QCOMPARE(mobj.methodCount(), 7);
QVERIFY(mobj.method(5).signature() == QByteArray("foo()")); QVERIFY(mobj.method(5).methodSignature() == QByteArray("foo()"));
QVERIFY(mobj.method(6).signature() == QByteArray("bar()")); QVERIFY(mobj.method(6).methodSignature() == QByteArray("bar()"));
} }
} }
@ -1109,22 +1109,22 @@ void tst_Moc::singleFunctionKeywordSignalAndSlot()
{ {
const QMetaObject &mobj = SingleFunctionKeywordBeforeReturnType::staticMetaObject; const QMetaObject &mobj = SingleFunctionKeywordBeforeReturnType::staticMetaObject;
QCOMPARE(mobj.methodCount(), 7); QCOMPARE(mobj.methodCount(), 7);
QVERIFY(mobj.method(5).signature() == QByteArray("mySignal()")); QVERIFY(mobj.method(5).methodSignature() == QByteArray("mySignal()"));
QVERIFY(mobj.method(6).signature() == QByteArray("mySlot()")); QVERIFY(mobj.method(6).methodSignature() == QByteArray("mySlot()"));
} }
{ {
const QMetaObject &mobj = SingleFunctionKeywordBeforeInline::staticMetaObject; const QMetaObject &mobj = SingleFunctionKeywordBeforeInline::staticMetaObject;
QCOMPARE(mobj.methodCount(), 7); QCOMPARE(mobj.methodCount(), 7);
QVERIFY(mobj.method(5).signature() == QByteArray("mySignal()")); QVERIFY(mobj.method(5).methodSignature() == QByteArray("mySignal()"));
QVERIFY(mobj.method(6).signature() == QByteArray("mySlot()")); QVERIFY(mobj.method(6).methodSignature() == QByteArray("mySlot()"));
} }
{ {
const QMetaObject &mobj = SingleFunctionKeywordAfterInline::staticMetaObject; const QMetaObject &mobj = SingleFunctionKeywordAfterInline::staticMetaObject;
QCOMPARE(mobj.methodCount(), 7); QCOMPARE(mobj.methodCount(), 7);
QVERIFY(mobj.method(5).signature() == QByteArray("mySignal()")); QVERIFY(mobj.method(5).methodSignature() == QByteArray("mySignal()"));
QVERIFY(mobj.method(6).signature() == QByteArray("mySlot()")); QVERIFY(mobj.method(6).methodSignature() == QByteArray("mySlot()"));
} }
} }
@ -1231,7 +1231,7 @@ void tst_Moc::constructors()
QMetaMethod mm = mo->constructor(0); QMetaMethod mm = mo->constructor(0);
QCOMPARE(mm.access(), QMetaMethod::Public); QCOMPARE(mm.access(), QMetaMethod::Public);
QCOMPARE(mm.methodType(), QMetaMethod::Constructor); QCOMPARE(mm.methodType(), QMetaMethod::Constructor);
QCOMPARE(mm.signature(), "CtorTestClass(QObject*)"); QCOMPARE(mm.methodSignature(), QByteArray("CtorTestClass(QObject*)"));
QCOMPARE(mm.typeName(), ""); QCOMPARE(mm.typeName(), "");
QList<QByteArray> paramNames = mm.parameterNames(); QList<QByteArray> paramNames = mm.parameterNames();
QCOMPARE(paramNames.size(), 1); QCOMPARE(paramNames.size(), 1);
@ -1244,7 +1244,7 @@ void tst_Moc::constructors()
QMetaMethod mm = mo->constructor(1); QMetaMethod mm = mo->constructor(1);
QCOMPARE(mm.access(), QMetaMethod::Public); QCOMPARE(mm.access(), QMetaMethod::Public);
QCOMPARE(mm.methodType(), QMetaMethod::Constructor); QCOMPARE(mm.methodType(), QMetaMethod::Constructor);
QCOMPARE(mm.signature(), "CtorTestClass()"); QCOMPARE(mm.methodSignature(), QByteArray("CtorTestClass()"));
QCOMPARE(mm.typeName(), ""); QCOMPARE(mm.typeName(), "");
QCOMPARE(mm.parameterNames().size(), 0); QCOMPARE(mm.parameterNames().size(), 0);
QCOMPARE(mm.parameterTypes().size(), 0); QCOMPARE(mm.parameterTypes().size(), 0);
@ -1253,7 +1253,7 @@ void tst_Moc::constructors()
QMetaMethod mm = mo->constructor(2); QMetaMethod mm = mo->constructor(2);
QCOMPARE(mm.access(), QMetaMethod::Public); QCOMPARE(mm.access(), QMetaMethod::Public);
QCOMPARE(mm.methodType(), QMetaMethod::Constructor); QCOMPARE(mm.methodType(), QMetaMethod::Constructor);
QCOMPARE(mm.signature(), "CtorTestClass(QString)"); QCOMPARE(mm.methodSignature(), QByteArray("CtorTestClass(QString)"));
QCOMPARE(mm.typeName(), ""); QCOMPARE(mm.typeName(), "");
QList<QByteArray> paramNames = mm.parameterNames(); QList<QByteArray> paramNames = mm.parameterNames();
QCOMPARE(paramNames.size(), 1); QCOMPARE(paramNames.size(), 1);

View File

@ -1275,7 +1275,7 @@ static int numberOfConnectedSignals(MySubWindow *subWindow)
QMetaMethod method = subWindow->metaObject()->method(i); QMetaMethod method = subWindow->metaObject()->method(i);
if (method.methodType() == QMetaMethod::Signal) { if (method.methodType() == QMetaMethod::Signal) {
QString signature(QLatin1String("2")); QString signature(QLatin1String("2"));
signature += QLatin1String(method.signature()); signature += QLatin1String(method.methodSignature().constData());
numConnectedSignals += subWindow->receivers(signature.toLatin1()); numConnectedSignals += subWindow->receivers(signature.toLatin1());
} }
} }

View File

@ -174,7 +174,7 @@ void tst_qmetaobject::indexOfMethod_data()
const QMetaObject *mo = &QTreeView::staticMetaObject; const QMetaObject *mo = &QTreeView::staticMetaObject;
for (int i = 0; i < mo->methodCount(); ++i) { for (int i = 0; i < mo->methodCount(); ++i) {
QMetaMethod method = mo->method(i); QMetaMethod method = mo->method(i);
QByteArray sig = method.signature(); QByteArray sig = method.methodSignature();
QTest::newRow(sig) << sig; QTest::newRow(sig) << sig;
} }
} }
@ -197,7 +197,7 @@ void tst_qmetaobject::indexOfSignal_data()
QMetaMethod method = mo->method(i); QMetaMethod method = mo->method(i);
if (method.methodType() != QMetaMethod::Signal) if (method.methodType() != QMetaMethod::Signal)
continue; continue;
QByteArray sig = method.signature(); QByteArray sig = method.methodSignature();
QTest::newRow(sig) << sig; QTest::newRow(sig) << sig;
} }
} }
@ -220,7 +220,7 @@ void tst_qmetaobject::indexOfSlot_data()
QMetaMethod method = mo->method(i); QMetaMethod method = mo->method(i);
if (method.methodType() != QMetaMethod::Slot) if (method.methodType() != QMetaMethod::Slot)
continue; continue;
QByteArray sig = method.signature(); QByteArray sig = method.methodSignature();
QTest::newRow(sig) << sig; QTest::newRow(sig) << sig;
} }
} }

View File

@ -66,24 +66,18 @@ QT_BEGIN_NAMESPACE
template <typename T> template <typename T>
class QRawVector class QRawVector
{ {
struct Data : QVectorData { T array[1]; }; typedef QVectorTypedData<T> Data;
T *m_begin; T *m_begin;
int m_size; int m_size;
int m_alloc; int m_alloc;
public: public:
//static Data dummy; static Data *toBase(T *begin)
//int headerOffset() { return (char*)&dummy.array - (char*)&dummy; } { return (Data*)((char*)begin - offsetOfTypedData()); }
inline int headerOffset() const { static T *fromBase(void *d)
// gcc complains about: return offsetof(Data, array); and also { return (T*)((char*)d + offsetOfTypedData()); }
// does not like '0' in the expression below.
return (char *)&(((Data *)(1))->array) - (char *)1;
}
inline Data *toBase(T *begin) const
{ return (Data*)((char*)begin - headerOffset()); }
inline T *fromBase(void *d) const
{ return (T*)((char*)d + headerOffset()); }
inline QRawVector() inline QRawVector()
{ m_begin = fromBase(0); m_alloc = m_size = 0; realloc(m_size, m_alloc, true); } { m_begin = fromBase(0); m_alloc = m_size = 0; realloc(m_size, m_alloc, true); }
explicit QRawVector(int size); explicit QRawVector(int size);
@ -270,17 +264,20 @@ private:
T *allocate(int alloc); T *allocate(int alloc);
void realloc(int size, int alloc, bool ref); void realloc(int size, int alloc, bool ref);
void free(T *begin, int size); void free(T *begin, int size);
int sizeOfTypedData() {
// this is more or less the same as sizeof(Data), except that it doesn't class AlignmentDummy { QVectorData header; T array[1]; };
// count the padding at the end
return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); static Q_DECL_CONSTEXPR int offsetOfTypedData()
{
// (non-POD)-safe offsetof(AlignmentDummy, array)
return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1);
} }
static inline int alignOfTypedData() static Q_DECL_CONSTEXPR int alignOfTypedData()
{ {
#ifdef Q_ALIGNOF #ifdef Q_ALIGNOF
return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); return Q_ALIGNOF(AlignmentDummy);
#else #else
return 0; return sizeof(void *);
#endif #endif
} }
@ -288,11 +285,11 @@ public:
QVector<T> mutateToVector() QVector<T> mutateToVector()
{ {
Data *d = toBase(m_begin); Data *d = toBase(m_begin);
d->ref = 1; d->ref.initializeOwned();
d->alloc = m_alloc; d->alloc = m_alloc;
d->size = m_size; d->size = m_size;
d->sharable = 0; d->capacityReserved = 0;
d->capacity = 0; d->offset = offsetOfTypedData();
QVector<T> v; QVector<T> v;
*reinterpret_cast<QVectorData **>(&v) = d; *reinterpret_cast<QVectorData **>(&v) = d;
@ -309,7 +306,7 @@ void QRawVector<T>::reserve(int asize)
template <typename T> template <typename T>
void QRawVector<T>::resize(int asize) void QRawVector<T>::resize(int asize)
{ realloc(asize, (asize > m_alloc || (asize < m_size && asize < (m_alloc >> 1))) { realloc(asize, (asize > m_alloc || (asize < m_size && asize < (m_alloc >> 1)))
? QVectorData::grow(sizeOfTypedData(), asize, sizeof(T), QTypeInfo<T>::isStatic) ? QVectorData::grow(offsetOfTypedData(), asize, sizeof(T))
: m_alloc, false); } : m_alloc, false); }
template <typename T> template <typename T>
inline void QRawVector<T>::clear() inline void QRawVector<T>::clear()
@ -370,7 +367,7 @@ QRawVector<T> &QRawVector<T>::operator=(const QRawVector<T> &v)
template <typename T> template <typename T>
inline T *QRawVector<T>::allocate(int aalloc) inline T *QRawVector<T>::allocate(int aalloc)
{ {
QVectorData *d = QVectorData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); QVectorData *d = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
return fromBase(d); return fromBase(d);
} }
@ -446,10 +443,9 @@ void QRawVector<T>::realloc(int asize, int aalloc, bool ref)
changed = true; changed = true;
} else { } else {
QT_TRY { QT_TRY {
QVectorData *mem = QVectorData::reallocate( QVectorData *mem = QVectorData::reallocate(toBase(m_begin),
toBase(m_begin), sizeOfTypedData() + (aalloc - 1) * sizeof(T), offsetOfTypedData() + aalloc * sizeof(T),
sizeOfTypedData() offsetOfTypedData() + xalloc * sizeof(T), alignOfTypedData());
+ (xalloc - 1) * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(mem); Q_CHECK_PTR(mem);
xbegin = fromBase(mem); xbegin = fromBase(mem);
xsize = m_size; xsize = m_size;
@ -511,8 +507,7 @@ void QRawVector<T>::append(const T &t)
{ {
if (m_size + 1 > m_alloc) { if (m_size + 1 > m_alloc) {
const T copy(t); const T copy(t);
realloc(m_size, QVectorData::grow(sizeOfTypedData(), m_size + 1, sizeof(T), realloc(m_size, QVectorData::grow(offsetOfTypedData(), m_size + 1, sizeof(T)), false);
QTypeInfo<T>::isStatic), false);
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (m_begin + m_size) T(copy); new (m_begin + m_size) T(copy);
else else
@ -533,8 +528,7 @@ typename QRawVector<T>::iterator QRawVector<T>::insert(iterator before, size_typ
if (n != 0) { if (n != 0) {
const T copy(t); const T copy(t);
if (m_size + n > m_alloc) if (m_size + n > m_alloc)
realloc(m_size, QVectorData::grow(sizeOfTypedData(), m_size + n, sizeof(T), realloc(m_size, QVectorData::grow(offsetOfTypedData(), m_size + n, sizeof(T)), false);
QTypeInfo<T>::isStatic), false);
if (QTypeInfo<T>::isStatic) { if (QTypeInfo<T>::isStatic) {
T *b = m_begin + m_size; T *b = m_begin + m_size;
T *i = m_begin + m_size + n; T *i = m_begin + m_size + n;