Improve connect: Use existing metatypes if possible

As there is now a chance that a QMetaMethod already contains the
metatypes for its arguments, we can just query it directly (and use the
fallback to name lookup logic that already exists there).
This also allows us to avoid creating a QList of names, and only
requires us to do a name lookup in case the connection actually fails.

Change-Id: Idda30bc4b538a94476ae6c533776c22340f0030d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Fabian Kosmale 2020-08-18 16:36:53 +02:00
parent 462b36c3de
commit 4d5a048d96
4 changed files with 65 additions and 15 deletions

View File

@ -207,6 +207,7 @@ public:
inline uint parameterTypeInfo(int index) const;
inline int parameterType(int index) const;
inline void getParameterTypes(int *types) const;
inline QByteArray parameterTypeName(int index) const;
inline QList<QByteArray> parameterTypes() const;
inline QList<QByteArray> parameterNames() const;
inline QByteArray tag() const;
@ -1780,6 +1781,12 @@ void QMetaMethodPrivate::getParameterTypes(int *types) const
}
}
QByteArray QMetaMethodPrivate::parameterTypeName(int index) const
{
int paramsIndex = parametersDataIndex();
return typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + index]);
}
QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
@ -1960,6 +1967,20 @@ QList<QByteArray> QMetaMethod::parameterTypes() const
return QMetaMethodPrivate::get(this)->parameterTypes();
}
/*!
\since 6.0
Returns the name of the type at position \a index
If there is no parameter at \a index, returns an empty QByteArray
\sa parameterNames()
*/
QByteArray QMetaMethod::parameterTypeName(int index) const
{
if (!mobj || index < 0 || index >= parameterCount())
return {};
return QMetaMethodPrivate::get(this)->parameterTypeName(index);
}
/*!
Returns a list of parameter names.

View File

@ -63,6 +63,7 @@ public:
QMetaType parameterMetaType(int index) const;
void getParameterTypes(int *types) const;
QList<QByteArray> parameterTypes() const;
QByteArray parameterTypeName(int index) const;
QList<QByteArray> parameterNames() const;
const char *tag() const;
enum Access { Private, Protected, Public };

View File

@ -95,28 +95,29 @@ QAbstractDynamicMetaObject::~QAbstractDynamicMetaObject()
{
}
static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
static int *queuedConnectionTypes(const QMetaMethod& method)
{
int *types = new int [typeNames.count() + 1];
Q_CHECK_PTR(types);
for (int i = 0; i < typeNames.count(); ++i) {
const QByteArray typeName = typeNames.at(i);
if (typeName.endsWith('*'))
types[i] = QMetaType::VoidStar;
const auto parameterCount = method.parameterCount();
int *typeIds = new int [parameterCount + 1];
Q_CHECK_PTR(typeIds);
for (int i = 0; i < parameterCount; ++i) {
const QMetaType metaType = method.parameterMetaType(i);
if (metaType.flags() & QMetaType::IsPointer)
typeIds[i] = QMetaType::VoidStar;
else
types[i] = QMetaType::fromName(typeName).id();
if (!types[i]) {
typeIds[i] = metaType.id();
if (!typeIds[i]) {
const QByteArray typeName = method.parameterTypeName(i);
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
delete [] types;
delete [] typeIds;
return nullptr;
}
}
types[typeNames.count()] = 0;
typeIds[parameterCount] = 0;
return types;
return typeIds;
}
static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc)
@ -2871,7 +2872,7 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho
int *types = nullptr;
if ((type == Qt::QueuedConnection)
&& !(types = queuedConnectionTypes(signal.parameterTypes())))
&& !(types = queuedConnectionTypes(signal)))
return QMetaObject::Connection(nullptr);
#ifndef QT_NO_DEBUG
@ -3615,7 +3616,7 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
const int *argumentTypes = c->argumentTypes.loadRelaxed();
if (!argumentTypes) {
QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
argumentTypes = queuedConnectionTypes(m.parameterTypes());
argumentTypes = queuedConnectionTypes(m);
if (!argumentTypes) // cannot queue arguments
argumentTypes = &DIRECT_CONNECTION_ONLY;
if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {

View File

@ -52,6 +52,8 @@ private slots:
void returnMetaType();
void parameterMetaType();
void parameterTypeName();
};
struct CustomType { };
@ -632,6 +634,12 @@ void tst_QMetaMethod::method()
QCOMPARE(QMetaType::fromName(method.typeName()), QMetaType::fromName(returnTypeName));
}
// check that parameterNames and parameterTypeName agree
const auto methodParmaterTypes = method.parameterTypes();
for (int i = 0; i< methodParmaterTypes.size(); ++i) {
QCOMPARE(methodParmaterTypes[i], method.parameterTypeName(i));
}
if (method.parameterTypes() != parameterTypeNames) {
// QMetaMethod should always produce semantically equivalent typenames
QList<QByteArray> actualTypeNames = method.parameterTypes();
@ -839,5 +847,24 @@ void tst_QMetaMethod::parameterMetaType()
}
void tst_QMetaMethod::parameterTypeName()
{
auto mo = MyTestClass::staticMetaObject;
const auto normalized = QMetaObject::normalizedSignature("doStuff(int, float, MyGadget)");
const int idx = mo.indexOfSlot(normalized);
QMetaMethod mm = mo.method(idx);
{
// check invalid indices
QVERIFY(mm.parameterTypeName(-1).isEmpty());
QVERIFY(mm.parameterTypeName(3).isEmpty());
}
{
QCOMPARE(mm.parameterTypeName(0), QByteArray("int"));
QCOMPARE(mm.parameterTypeName(1), QByteArray("float"));
QCOMPARE(mm.parameterTypeName(2), QByteArray("MyGadget"));
}
}
QTEST_MAIN(tst_QMetaMethod)
#include "tst_qmetamethod.moc"