diff options
author | Jędrzej Nowacki <jedrzej.nowacki@nokia.com> | 2011-12-13 12:07:47 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-12-22 13:20:40 +0100 |
commit | 56f154c747a6623fc8249265262160ac0adbe4cd (patch) | |
tree | 5b3a86073db010820b745d0ca8a9284997a71e7b | |
parent | d868c9945a188d6ad22e0b7d6d24ac7fca00ab4e (diff) |
Allow QMetaType to register information about movability
We need that information to perform some optimizations in QVariant.
Change-Id: Id9a1716e49e4cedd17cd09a32fea4ff003ef61f2
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 82 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 24 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype_p.h | 6 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 40 | ||||
-rw-r--r-- | tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp | 26 |
5 files changed, 173 insertions, 5 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index d5a22ef07d..02cf9ae49c 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -240,6 +240,16 @@ template<> struct TypeDefiniton<QRegExp> { static const bool IsAvailable = false */ /*! + \enum QMetaType::TypeFlags + + The enum describes attributes of a type supported by QMetaType. + + \value NeedsConstruction This type has non-trivial constructors. If the flag is not set instances can be safely initialized with memset to 0. + \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set calls to the destructor are not necessary before discarding objects. + \value MovableType An instance of a type having this attribute can be safely moved by memcpy. +*/ + +/*! \class QMetaType \brief The QMetaType class manages named types in the meta-object system. @@ -423,7 +433,7 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length) int QMetaType::registerType(const char *typeName, Deleter deleter, Creator creator) { - return registerType(typeName, deleter, creator, 0, 0, 0); + return registerType(typeName, deleter, creator, 0, 0, 0, TypeFlags()); } /*! \internal @@ -438,7 +448,7 @@ int QMetaType::registerType(const char *typeName, Deleter deleter, Creator creator, Destructor destructor, Constructor constructor, - int size) + int size, TypeFlags flags) { QVector<QCustomTypeInfo> *ct = customTypes(); if (!ct || !typeName || !deleter || !creator) @@ -470,6 +480,7 @@ int QMetaType::registerType(const char *typeName, Deleter deleter, inf.constructor = constructor; inf.destructor = destructor; inf.size = size; + inf.flags = flags; idx = ct->size() + User; ct->append(inf); } @@ -1633,6 +1644,73 @@ int QMetaType::sizeOf(int type) return QMetaTypeSwitcher::switcher<int>(sizeOf, type, 0); } +namespace { +class Flags +{ + template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted> + struct FlagsImpl + { + static quint32 Flags(const int) + { + return (!QTypeInfo<T>::isStatic * QMetaType::MovableType) + | (QTypeInfo<T>::isComplex * QMetaType::NeedsConstruction) + | (QTypeInfo<T>::isComplex * QMetaType::NeedsDestruction); + } + }; + template<typename T> + struct FlagsImpl<T, /* IsAcceptedType = */ false> + { + static quint32 Flags(const int type) + { + return Flags::undefinedTypeFlags(type); + } + }; +public: + Flags(const int type) + : m_type(type) + {} + template<typename T> + quint32 delegate(const T*) { return FlagsImpl<T>::Flags(m_type); } + quint32 delegate(const QMetaTypeSwitcher::UnknownType*) { return customTypeFlags(m_type); } +private: + const int m_type; + static quint32 customTypeFlags(const int type) + { + const QVector<QCustomTypeInfo> * const ct = customTypes(); + if (!ct) + return 0; + QReadLocker locker(customTypesLock()); + if (ct->count() <= type - QMetaType::User) + return 0; + return ct->at(type - QMetaType::User).flags; + } + static quint32 undefinedTypeFlags(const int type); +}; + +quint32 Flags::undefinedTypeFlags(const int type) +{ + if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType) + return qMetaTypeGuiHelper ? qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].flags : 0; + else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType) + return qMetaTypeWidgetsHelper ? qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].flags : 0; + return customTypeFlags(type); +} + +} // namespace + +/*! + \since 5.0 + + Returns flags of the given \a type. + + \sa TypeFlags() +*/ +QMetaType::TypeFlags QMetaType::typeFlags(int type) +{ + Flags flags(type); + return static_cast<QMetaType::TypeFlags>(QMetaTypeSwitcher::switcher<quint32>(flags, type, 0)); +} + /*! \fn int qRegisterMetaType(const char *typeName) \relates QMetaType diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 717e72c810..dd5b1f8ed5 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -202,6 +202,13 @@ public: User = 256 }; + enum TypeFlag { + NeedsConstruction = 0x1, + NeedsDestruction = 0x2, + MovableType = 0x4 + }; + Q_DECLARE_FLAGS(TypeFlags, TypeFlag) + typedef void (*Deleter)(void *); typedef void *(*Creator)(const void *); @@ -222,11 +229,13 @@ public: Creator creator, Destructor destructor, Constructor constructor, - int size); + int size, + QMetaType::TypeFlags flags); static int registerTypedef(const char *typeName, int aliasId); static int type(const char *typeName); static const char *typeName(int type); static int sizeOf(int type); + static TypeFlags typeFlags(int type); static bool isRegistered(int type); static void *create(int type, const void *copy = 0); #if QT_DEPRECATED_SINCE(5, 0) @@ -246,6 +255,8 @@ public: #undef QT_DEFINE_METATYPE_ID +Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags) + template <typename T> void qMetaTypeDeleteHelper(T *t) { @@ -334,11 +345,20 @@ int qRegisterMetaType(const char *typeName typedef void(*DestructPtr)(T*); DestructPtr ipdptr = qMetaTypeDestructHelper<T>; + QMetaType::TypeFlags flags; + if (!QTypeInfo<T>::isStatic) + flags |= QMetaType::MovableType; + if (QTypeInfo<T>::isComplex) { + flags |= QMetaType::NeedsConstruction; + flags |= QMetaType::NeedsDestruction; + } + return QMetaType::registerType(typeName, reinterpret_cast<QMetaType::Deleter>(dptr), reinterpret_cast<QMetaType::Creator>(cptr), reinterpret_cast<QMetaType::Destructor>(ipdptr), reinterpret_cast<QMetaType::Constructor>(ipcptr), - sizeof(T)); + sizeof(T), + flags); } #ifndef QT_NO_DATASTREAM diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index 448c6ded13..46c5697678 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -150,6 +150,7 @@ public: QMetaType::Constructor constructor; QMetaType::Destructor destructor; int size; + quint32 flags; // same as QMetaType::TypeFlags }; #ifndef QT_NO_DATASTREAM @@ -167,7 +168,10 @@ public: QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ /*constructor*/(reinterpret_cast<QMetaType::Constructor>(QMetaTypeInterface::Impl<Type>::constructor)), \ /*destructor*/(reinterpret_cast<QMetaType::Destructor>(QMetaTypeInterface::Impl<Type>::destructor)), \ - /*size*/(sizeof(Type)) \ + /*size*/(sizeof(Type)), \ + /*flags*/(!QTypeInfo<Type>::isStatic * QMetaType::MovableType) \ + | (QTypeInfo<Type>::isComplex * QMetaType::NeedsConstruction) \ + | (QTypeInfo<Type>::isComplex * QMetaType::NeedsDestruction) \ } QT_END_NAMESPACE diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index e0433ea4b0..12a57447cd 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -78,6 +78,8 @@ private slots: void createCopy(); void sizeOf_data(); void sizeOf(); + void flags_data(); + void flags(); void construct_data(); void construct(); void constructCopy_data(); @@ -129,6 +131,10 @@ protected: #ifdef Q_OS_LINUX pthread_yield(); #endif + if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) { + ++failureCount; + qWarning() << "Wrong typeInfo returned for" << tp; + } if (!QMetaType::isRegistered(tp)) { ++failureCount; qWarning() << name << "is not a registered metatype"; @@ -578,6 +584,40 @@ void tst_QMetaType::sizeOf() QCOMPARE(QMetaType::sizeOf(type), size); } +struct CustomMovable {}; +QT_BEGIN_NAMESPACE +Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE); +QT_END_NAMESPACE +Q_DECLARE_METATYPE(CustomMovable); + +void tst_QMetaType::flags_data() +{ + QTest::addColumn<int>("type"); + QTest::addColumn<bool>("isMovable"); + QTest::addColumn<bool>("isComplex"); + +#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \ + QTest::newRow(#RealType) << MetaTypeId << bool(!QTypeInfo<RealType>::isStatic) << bool(QTypeInfo<RealType>::isComplex); +QT_FOR_EACH_STATIC_CORE_CLASS(ADD_METATYPE_TEST_ROW) +QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW) +QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW) +#undef ADD_METATYPE_TEST_ROW + QTest::newRow("TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true; + QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << false << true; + QTest::newRow("CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true; +} + +void tst_QMetaType::flags() +{ + QFETCH(int, type); + QFETCH(bool, isMovable); + QFETCH(bool, isComplex); + + QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex); + QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex); + QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable); +} + void tst_QMetaType::construct_data() { create_data(); diff --git a/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp b/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp index 98314a9336..79eebbc828 100644 --- a/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp +++ b/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp @@ -56,6 +56,8 @@ private slots: void createCopy(); void sizeOf_data(); void sizeOf(); + void flags_data(); + void flags(); void construct_data(); void construct(); void constructCopy_data(); @@ -320,6 +322,30 @@ struct TypeAlignment #endif }; +void tst_QGuiMetaType::flags_data() +{ + QTest::addColumn<int>("type"); + QTest::addColumn<bool>("isMovable"); + QTest::addColumn<bool>("isComplex"); + +#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \ + QTest::newRow(#RealType) << MetaTypeId << bool(!QTypeInfo<RealType>::isStatic) << bool(QTypeInfo<RealType>::isComplex); +QT_FOR_EACH_STATIC_GUI_CLASS(ADD_METATYPE_TEST_ROW) +#undef ADD_METATYPE_TEST_ROW +} + +void tst_QGuiMetaType::flags() +{ + QFETCH(int, type); + QFETCH(bool, isMovable); + QFETCH(bool, isComplex); + + QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex); + QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex); + QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable); +} + + void tst_QGuiMetaType::construct_data() { create_data(); |