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>
|
||||
inline T qobject_cast(QObject *object)
|
||||
{
|
||||
static_assert(std::is_pointer_v<T>,
|
||||
"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));
|
||||
return QtPrivate::qobject_cast_helper<T>(object);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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>>,
|
||||
"qobject_cast cannot cast away constness (use const_cast)");
|
||||
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));
|
||||
return QtPrivate::qobject_cast_helper<T>(object);
|
||||
}
|
||||
|
||||
|
||||
template <class T> constexpr const char * qobject_interface_iid() = delete;
|
||||
template <class T> inline 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 **));
|
||||
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
|
||||
|
@ -92,6 +92,7 @@ private slots:
|
||||
void dumpObjectTree();
|
||||
void connectToSender();
|
||||
void qobjectConstCast();
|
||||
void qobjectCastFinal();
|
||||
void uniqConnection();
|
||||
void uniqConnectionPtr();
|
||||
void interfaceIid();
|
||||
@ -2429,6 +2430,13 @@ public:
|
||||
int rtti() const override { return 43; }
|
||||
};
|
||||
|
||||
class FinalObject final: public FooObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
int rtti() const override { return 44; }
|
||||
};
|
||||
|
||||
void tst_QObject::declareInterface()
|
||||
{
|
||||
FooObject obj;
|
||||
@ -3691,9 +3699,29 @@ void tst_QObject::qobjectConstCast()
|
||||
const QObject *cptr = &obj;
|
||||
|
||||
QVERIFY(qobject_cast<FooObject *>(ptr));
|
||||
QVERIFY(qobject_cast<const FooObject *>(ptr));
|
||||
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()
|
||||
{
|
||||
SenderObject s;
|
||||
|
Loading…
x
Reference in New Issue
Block a user