qobject_cast: optimize when the target is marked final
If it is, then we can perform a direct meta object pointer comparison. Comparing meta objects is, after all, what QMetaObject::inherits() and QMetaObject::cast()) are doing: const QMetaObject *m = this; do { if (metaObject == m) return true; } while ((m = m->d.superdata)); But if we know the class is final, we know an object can either be exactly of the type we want or not be so at all. Change-Id: If6333547d215c1d84d1cfffdfd82c04e75251608 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
parent
01ad117b32
commit
8a029843a3
@ -420,28 +420,17 @@ bool QObject::setProperty(const char *name, QVariant &&value)
|
|||||||
template <class T>
|
template <class T>
|
||||||
inline T qobject_cast(QObject *object)
|
inline T qobject_cast(QObject *object)
|
||||||
{
|
{
|
||||||
static_assert(std::is_pointer_v<T>,
|
return QtPrivate::qobject_cast_helper<T>(object);
|
||||||
"qobject_cast requires to cast towards a pointer type");
|
|
||||||
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
|
|
||||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
|
|
||||||
"qobject_cast requires the type to have a Q_OBJECT macro");
|
|
||||||
return static_cast<T>(ObjType::staticMetaObject.cast(object));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline T qobject_cast(const QObject *object)
|
inline T qobject_cast(const QObject *object)
|
||||||
{
|
{
|
||||||
static_assert(std::is_pointer_v<T>,
|
|
||||||
"qobject_cast requires to cast towards a pointer type");
|
|
||||||
static_assert(std::is_const_v<std::remove_pointer_t<T>>,
|
static_assert(std::is_const_v<std::remove_pointer_t<T>>,
|
||||||
"qobject_cast cannot cast away constness (use const_cast)");
|
"qobject_cast cannot cast away constness (use const_cast)");
|
||||||
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
|
return QtPrivate::qobject_cast_helper<T>(object);
|
||||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
|
|
||||||
"qobject_cast requires the type to have a Q_OBJECT macro");
|
|
||||||
return static_cast<T>(ObjType::staticMetaObject.cast(object));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class T> constexpr const char * qobject_interface_iid() = delete;
|
template <class T> constexpr const char * qobject_interface_iid() = delete;
|
||||||
template <class T> inline T *
|
template <class T> inline T *
|
||||||
qobject_iid_cast(QObject *object, const char *IId = qobject_interface_iid<T *>())
|
qobject_iid_cast(QObject *object, const char *IId = qobject_interface_iid<T *>())
|
||||||
|
@ -737,6 +737,24 @@ namespace QtPrivate {
|
|||||||
static int test(int (Object::*)(QMetaObject::Call, int, void **));
|
static int test(int (Object::*)(QMetaObject::Call, int, void **));
|
||||||
enum { Value = sizeof(test(&Object::qt_metacall)) == sizeof(int) };
|
enum { Value = sizeof(test(&Object::qt_metacall)) == sizeof(int) };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class TgtType, class SrcType>
|
||||||
|
inline TgtType qobject_cast_helper(SrcType *object)
|
||||||
|
{
|
||||||
|
using ObjType = std::remove_cv_t<std::remove_pointer_t<TgtType>> ;
|
||||||
|
static_assert(std::is_pointer_v<TgtType>,
|
||||||
|
"qobject_cast requires to cast towards a pointer type");
|
||||||
|
static_assert(HasQ_OBJECT_Macro<ObjType>::Value,
|
||||||
|
"qobject_cast requires the type to have a Q_OBJECT macro");
|
||||||
|
|
||||||
|
if constexpr (std::is_final_v<ObjType>) {
|
||||||
|
if (object && object->metaObject() == &ObjType::staticMetaObject)
|
||||||
|
return static_cast<TgtType>(object);
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return static_cast<TgtType>(ObjType::staticMetaObject.cast(object));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -92,6 +92,7 @@ private slots:
|
|||||||
void dumpObjectTree();
|
void dumpObjectTree();
|
||||||
void connectToSender();
|
void connectToSender();
|
||||||
void qobjectConstCast();
|
void qobjectConstCast();
|
||||||
|
void qobjectCastFinal();
|
||||||
void uniqConnection();
|
void uniqConnection();
|
||||||
void uniqConnectionPtr();
|
void uniqConnectionPtr();
|
||||||
void interfaceIid();
|
void interfaceIid();
|
||||||
@ -2429,6 +2430,13 @@ public:
|
|||||||
int rtti() const override { return 43; }
|
int rtti() const override { return 43; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FinalObject final: public FooObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
int rtti() const override { return 44; }
|
||||||
|
};
|
||||||
|
|
||||||
void tst_QObject::declareInterface()
|
void tst_QObject::declareInterface()
|
||||||
{
|
{
|
||||||
FooObject obj;
|
FooObject obj;
|
||||||
@ -3691,9 +3699,29 @@ void tst_QObject::qobjectConstCast()
|
|||||||
const QObject *cptr = &obj;
|
const QObject *cptr = &obj;
|
||||||
|
|
||||||
QVERIFY(qobject_cast<FooObject *>(ptr));
|
QVERIFY(qobject_cast<FooObject *>(ptr));
|
||||||
|
QVERIFY(qobject_cast<const FooObject *>(ptr));
|
||||||
QVERIFY(qobject_cast<const FooObject *>(cptr));
|
QVERIFY(qobject_cast<const FooObject *>(cptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QObject::qobjectCastFinal()
|
||||||
|
{
|
||||||
|
FooObject foo;
|
||||||
|
QObject *ptr = &foo;
|
||||||
|
const QObject *cptr = &foo;
|
||||||
|
|
||||||
|
QCOMPARE(qobject_cast<FinalObject *>(ptr), nullptr);
|
||||||
|
QCOMPARE(qobject_cast<const FinalObject *>(ptr), nullptr);
|
||||||
|
QCOMPARE(qobject_cast<const FinalObject *>(cptr), nullptr);
|
||||||
|
|
||||||
|
FinalObject final;
|
||||||
|
ptr = &final;
|
||||||
|
cptr = &final;
|
||||||
|
|
||||||
|
QCOMPARE(qobject_cast<FinalObject *>(ptr), &final);
|
||||||
|
QCOMPARE(qobject_cast<const FinalObject *>(ptr), &final);
|
||||||
|
QCOMPARE(qobject_cast<const FinalObject *>(cptr), &final);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QObject::uniqConnection()
|
void tst_QObject::uniqConnection()
|
||||||
{
|
{
|
||||||
SenderObject s;
|
SenderObject s;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user