From 214e031d56714ba69ef929f1e763e243b393e460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Tue, 20 Dec 2011 17:11:46 +0100 Subject: Implement new static less API for QMetaType. Currently QMetaType API contains almost only static methods. This works nice until someone needs more information or needs to do more operations on a type. In this case every function call has to do type dispatch. This API allows to avoid redundant type dispatching, by caching a type information in a QMetaType instance. It gives significant performance boost especially for custom types (up to 9x). Change-Id: I223d066268402e072e41ca1d0a3e7bc160655d7f Reviewed-by: Stephen Kelly Reviewed-by: Bradley T. Hughes --- src/corelib/kernel/qmetatype.cpp | 170 +++++++++++++++++++++ src/corelib/kernel/qmetatype.h | 145 +++++++++++++++++- src/corelib/kernel/qmetatype_p.h | 43 ++++-- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 156 ++++++++++++++++--- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 54 ++++++- 5 files changed, 534 insertions(+), 34 deletions(-) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index d965c48255..a1baf28f10 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1753,4 +1753,174 @@ QMetaType::TypeFlags QMetaType::typeFlags(int type) \sa Q_DECLARE_METATYPE(), QMetaType::type() */ +namespace { +class TypeInfo { + template::IsAccepted> + struct TypeInfoImpl + { + TypeInfoImpl(const uint /* type */, QMetaTypeInterface &info) + { + QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(T); + info = tmp; + } + }; + + template + struct TypeInfoImpl + { + TypeInfoImpl(const uint type, QMetaTypeInterface &info) + { + if (QTypeModuleInfo::IsGui) { + if (Q_LIKELY(qMetaTypeGuiHelper)) + info = qMetaTypeGuiHelper[type - QMetaType::FirstGuiType]; + return; + } + if (QTypeModuleInfo::IsWidget) { + if (Q_LIKELY(qMetaTypeWidgetsHelper)) + info = qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType]; + return; + } + } + }; +public: + QMetaTypeInterface info; + TypeInfo(const uint type) + : m_type(type) + { + QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_EMPTY(); + info = tmp; + } + template + void delegate(const T*) { TypeInfoImpl(m_type, info); } + void delegate(const void*) {} + void delegate(const QMetaTypeSwitcher::UnknownType*) { customTypeInfo(m_type); } +private: + void customTypeInfo(const uint type) + { + const QVector * const ct = customTypes(); + if (Q_UNLIKELY(!ct)) + return; + QReadLocker locker(customTypesLock()); + if (Q_LIKELY(uint(ct->count()) > type - QMetaType::User)) + info = ct->at(type - QMetaType::User); + } + + const uint m_type; +}; +} // namespace + +QMetaType QMetaType::typeInfo(const int type) +{ + TypeInfo typeInfo(type); + QMetaTypeSwitcher::switcher(typeInfo, type, 0); + return typeInfo.info.creator || !type ? QMetaType(QMetaType::NoExtensionFlags + , static_cast(0) // typeInfo::info is a temporary variable, we can't return address of it. + , typeInfo.info.creator + , typeInfo.info.deleter + , typeInfo.info.saveOp + , typeInfo.info.loadOp + , typeInfo.info.constructor + , typeInfo.info.destructor + , typeInfo.info.size + , typeInfo.info.flags + , type) + : QMetaType(-1); +} + +QMetaType::QMetaType(const int typeId) + : m_typeId(typeId) +{ + if (Q_UNLIKELY(typeId == -1)) { + // Constructs invalid QMetaType instance. + m_extensionFlags = 0xffffffff; + Q_ASSERT(!isValid()); + } else { + // TODO it can be better. + *this = QMetaType::typeInfo(typeId); + if (m_typeId > 0 && !m_creator) { + m_extensionFlags = 0xffffffff; + m_typeId = -1; + } + if (m_typeId == QMetaType::Void) { + m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx; + } + } +} + +QMetaType::QMetaType(const QMetaType &other) + : m_creator(other.m_creator) + , m_deleter(other.m_deleter) + , m_saveOp(other.m_saveOp) + , m_loadOp(other.m_loadOp) + , m_constructor(other.m_constructor) + , m_destructor(other.m_destructor) + , m_extension(other.m_extension) // space reserved for future use + , m_size(other.m_size) + , m_typeFlags(other.m_typeFlags) + , m_extensionFlags(other.m_extensionFlags) + , m_typeId(other.m_typeId) +{} + +QMetaType &QMetaType::operator =(const QMetaType &other) +{ + m_creator = other.m_creator; + m_deleter = other.m_deleter; + m_saveOp = other.m_saveOp; + m_loadOp = other.m_loadOp; + m_constructor = other.m_constructor; + m_destructor = other.m_destructor; + m_size = other.m_size; + m_typeFlags = other.m_typeFlags; + m_extensionFlags = other.m_extensionFlags; + m_extension = other.m_extension; // space reserved for future use + m_typeId = other.m_typeId; + return *this; +} + +void QMetaType::ctor(const QMetaTypeInterface *info) +{ + // Special case for Void type, the type is valid but not constructible. + // In future we may consider to remove this assert and extend this function to initialize + // differently m_extensionFlags for different types. Currently it is not needed. + Q_ASSERT(m_typeId == QMetaType::Void); + Q_UNUSED(info); + m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx; +} + +void QMetaType::dtor() +{} + +void *QMetaType::createExtended(const void *copy) const +{ + Q_UNUSED(copy); + return 0; +} + +void QMetaType::destroyExtended(void *data) const +{ + Q_UNUSED(data); +} + +void *QMetaType::constructExtended(void *where, const void *copy) const +{ + Q_UNUSED(where); + Q_UNUSED(copy); + return 0; +} + +void QMetaType::destructExtended(void *data) const +{ + Q_UNUSED(data); +} + +uint QMetaType::sizeExtended() const +{ + return 0; +} + +QMetaType::TypeFlags QMetaType::flagsExtended() const +{ + return 0; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index ff3f9341e4..0b6a62e5c8 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -177,8 +177,16 @@ QT_BEGIN_NAMESPACE TypeName = Id, class QDataStream; +class QMetaTypeInterface; class Q_CORE_EXPORT QMetaType { + enum ExtensionFlag { NoExtensionFlags, + CreateEx = 0x1, DestroyEx = 0x2, + ConstructEx = 0x4, DestructEx = 0x8, + NameEx = 0x10, SizeEx = 0x20, + CtorEx = 0x40, DtorEx = 0x80, + FlagsEx = 0x100 + }; public: enum Type { // these are merged with QVariant @@ -218,9 +226,9 @@ public: typedef void (*Destructor)(void *); typedef void *(*Constructor)(void *, const void *); -#ifndef QT_NO_DATASTREAM typedef void (*SaveOperator)(QDataStream &, const void *); typedef void (*LoadOperator)(QDataStream &, void *); +#ifndef QT_NO_DATASTREAM static void registerStreamOperators(const char *typeName, SaveOperator saveOp, LoadOperator loadOp); static void registerStreamOperators(int type, SaveOperator saveOp, @@ -253,6 +261,56 @@ public: static bool save(QDataStream &stream, int type, const void *data); static bool load(QDataStream &stream, int type, void *data); #endif + + QMetaType(const int type); + inline ~QMetaType(); + + inline bool isValid() const; + inline bool isRegistered() const; + inline int sizeOf() const; + inline TypeFlags flags() const; + + inline void *create(const void *copy = 0) const; + inline void destroy(void *data) const; + inline void *construct(void *where, const void *copy = 0) const; + inline void destruct(void *data) const; +private: + static QMetaType typeInfo(const int type); + inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, + Creator creator, + Deleter deleter, + SaveOperator saveOp, + LoadOperator loadOp, + Constructor constructor, + Destructor destructor, + uint sizeOf, + uint typeFlags, + int typeId); + QMetaType(const QMetaType &other); + QMetaType &operator =(const QMetaType &); + inline bool isExtended(const ExtensionFlag flag) const { return m_extensionFlags & flag; } + + // Methods used for future binary compatibile extensions + void ctor(const QMetaTypeInterface *info); + void dtor(); + uint sizeExtended() const; + QMetaType::TypeFlags flagsExtended() const; + void *createExtended(const void *copy = 0) const; + void destroyExtended(void *data) const; + void *constructExtended(void *where, const void *copy = 0) const; + void destructExtended(void *data) const; + + Creator m_creator; + Deleter m_deleter; + SaveOperator m_saveOp; + LoadOperator m_loadOp; + Constructor m_constructor; + Destructor m_destructor; + void *m_extension; // space reserved for future use + uint m_size; + uint m_typeFlags; + uint m_extensionFlags; + int m_typeId; }; #undef QT_DEFINE_METATYPE_ID @@ -555,6 +613,91 @@ Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSet) Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSharedPointer) Q_DECLARE_METATYPE_TEMPLATE_1ARG(QLinkedList) +inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info, + Creator creator, + Deleter deleter, + SaveOperator saveOp, + LoadOperator loadOp, + Constructor constructor, + Destructor destructor, + uint size, + uint typeFlags, + int typeId) + : m_creator(creator) + , m_deleter(deleter) + , m_saveOp(saveOp) + , m_loadOp(loadOp) + , m_constructor(constructor) + , m_destructor(destructor) + , m_size(size) + , m_typeFlags(typeFlags) + , m_extensionFlags(extensionFlags) + , m_typeId(typeId) +{ + if (Q_UNLIKELY(isExtended(CtorEx) || typeId == QMetaType::Void)) + ctor(info); +} + +inline QMetaType::~QMetaType() +{ + if (Q_UNLIKELY(isExtended(DtorEx))) + dtor(); +} + +inline bool QMetaType::isValid() const +{ + return m_typeId >= 0; +} + +inline bool QMetaType::isRegistered() const +{ + return isValid(); +} + +inline void *QMetaType::create(const void *copy) const +{ + if (Q_UNLIKELY(isExtended(CreateEx))) + return createExtended(copy); + return m_creator(copy); +} + +inline void QMetaType::destroy(void *data) const +{ + if (Q_UNLIKELY(isExtended(DestroyEx))) + return destroyExtended(data); + m_deleter(data); +} + +inline void *QMetaType::construct(void *where, const void *copy) const +{ + if (Q_UNLIKELY(isExtended(ConstructEx))) + return constructExtended(where, copy); + return m_constructor(where, copy); +} + +inline void QMetaType::destruct(void *data) const +{ + if (Q_UNLIKELY(isExtended(DestructEx))) + return destructExtended(data); + if (Q_UNLIKELY(!data)) + return; + m_destructor(data); +} + +inline int QMetaType::sizeOf() const +{ + if (Q_UNLIKELY(isExtended(SizeEx))) + return sizeExtended(); + return m_size; +} + +inline QMetaType::TypeFlags QMetaType::flags() const +{ + if (Q_UNLIKELY(isExtended(FlagsEx))) + return flagsExtended(); + return QMetaType::TypeFlags(m_typeFlags); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index b1edc350a1..e48c5d3033 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -132,10 +132,8 @@ public: } static void deleter(T *t) { delete t; } - #ifndef QT_NO_DATASTREAM static void saver(QDataStream &stream, const T *t) { stream << *t; } static void loader(QDataStream &stream, T *t) { stream >> *t; } - #endif // QT_NO_DATASTREAM static void destructor(T *t) { Q_UNUSED(t) // Silence MSVC that warns for POD types. @@ -151,10 +149,8 @@ public: QMetaType::Creator creator; QMetaType::Deleter deleter; -#ifndef QT_NO_DATASTREAM QMetaType::SaveOperator saveOp; QMetaType::LoadOperator loadOp; -#endif QMetaType::Constructor constructor; QMetaType::Destructor destructor; int size; @@ -165,10 +161,8 @@ template<> struct QMetaTypeInterface::Impl { static void *creator(const void *) { return 0; } static void deleter(void *) {} -#ifndef QT_NO_DATASTREAM static void saver(QDataStream &, const void *) {} static void loader(QDataStream &, void *) {} -#endif // QT_NO_DATASTREAM static void destructor(void *){} static void *constructor(void *, const void *) { return 0; } }; @@ -177,15 +171,22 @@ struct QMetaTypeInterface::Impl { # define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ /*saveOp*/(reinterpret_cast(QMetaTypeInterface::Impl::saver)), \ /*loadOp*/(reinterpret_cast(QMetaTypeInterface::Impl::loader)), +# define QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) \ + /*saveOp*/ 0, \ + /*loadOp*/ 0, #else -# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) +# define QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) \ + /*saveOp*/ 0, \ + /*loadOp*/ 0, +# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ + QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) #endif -#define QT_METATYPE_INTERFACE_INIT(Type) \ +#define QT_METATYPE_INTERFACE_INIT_IMPL(Type, DATASTREAM_DELEGATE) \ { \ /*creator*/(reinterpret_cast(QMetaTypeInterface::Impl::creator)), \ /*deleter*/(reinterpret_cast(QMetaTypeInterface::Impl::deleter)), \ - QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \ + DATASTREAM_DELEGATE(Type) \ /*constructor*/(reinterpret_cast(QMetaTypeInterface::Impl::constructor)), \ /*destructor*/(reinterpret_cast(QMetaTypeInterface::Impl::destructor)), \ /*size*/(QTypeInfo::sizeOf), \ @@ -194,6 +195,30 @@ struct QMetaTypeInterface::Impl { | (QTypeInfo::isComplex * QMetaType::NeedsDestruction) \ } + +/* These QT_METATYPE_INTERFACE_INIT* macros are used to initialize QMetaTypeInterface instance. + + - QT_METATYPE_INTERFACE_INIT(Type) -> It takes Type argument and creates all necessary wrapper functions for the Type, + it detects if QT_NO_DATASTREAM was defined. Probably it is the macro that you want to use. + + - QT_METATYPE_INTERFACE_INIT_EMPTY() -> It initializes an empty QMetaTypeInterface instance. + + - QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) -> Temporary workaround for missing auto-detection of data stream + operators. It creates same instance as QT_METATYPE_INTERFACE_INIT(Type) but with null stream operators callbacks. + */ +#define QT_METATYPE_INTERFACE_INIT(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL) +#define QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL) +#define QT_METATYPE_INTERFACE_INIT_EMPTY() \ +{ \ + /*creator*/ 0, \ + /*deleter*/ 0, \ + QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL() \ + /*constructor*/ 0, \ + /*destructor*/ 0, \ + /*size*/ 0, \ + /*flags*/ 0 \ +} + QT_END_NAMESPACE #endif // QMETATYPE_P_H diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index f90e7f463f..72913d10f2 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -78,8 +78,12 @@ private slots: void createCopy(); void sizeOf_data(); void sizeOf(); + void sizeOfStaticLess_data(); + void sizeOfStaticLess(); void flags_data(); void flags(); + void flagsStaticLess_data(); + void flagsStaticLess(); void construct_data(); void construct(); void constructCopy_data(); @@ -88,6 +92,8 @@ private slots: void registerType(); void isRegistered_data(); void isRegistered(); + void isRegisteredStaticLess_data(); + void isRegisteredStaticLess(); void registerStreamBuiltin(); void automaticTemplateRegistration(); }; @@ -125,6 +131,9 @@ class MetaTypeTorturer: public QThread protected: void run() { + Bar space[1]; + space[0].~Bar(); + for (int i = 0; i < 1000; ++i) { const QByteArray name = QString("Bar%1_%2").arg(i).arg((size_t)QThread::currentThreadId()).toLatin1(); const char *nm = name.constData(); @@ -132,6 +141,15 @@ protected: #ifdef Q_OS_LINUX pthread_yield(); #endif + QMetaType info(tp); + if (!info.isValid()) { + ++failureCount; + qWarning() << "Wrong typeInfo returned for" << tp; + } + if (!info.isRegistered()) { + ++failureCount; + qWarning() << name << "is not a registered metatype"; + } if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) { ++failureCount; qWarning() << "Wrong typeInfo returned for" << tp; @@ -148,9 +166,22 @@ protected: ++failureCount; qWarning() << "Wrong typeName returned for" << tp; } - void *buf = QMetaType::create(tp, 0); - void *buf2 = QMetaType::create(tp, buf); - if (!buf) { + void *buf1 = QMetaType::create(tp, 0); + void *buf2 = QMetaType::create(tp, buf1); + void *buf3 = info.create(tp, 0); + void *buf4 = info.create(tp, buf1); + + QMetaType::construct(tp, space, 0); + QMetaType::destruct(tp, space); + QMetaType::construct(tp, space, buf1); + QMetaType::destruct(tp, space); + + info.construct(space, 0); + info.destruct(space); + info.construct(space, buf1); + info.destruct(space); + + if (!buf1) { ++failureCount; qWarning() << "Null buffer returned by QMetaType::create(tp, 0)"; } @@ -158,9 +189,20 @@ protected: ++failureCount; qWarning() << "Null buffer returned by QMetaType::create(tp, buf)"; } - QMetaType::destroy(tp, buf); + if (!buf3) { + ++failureCount; + qWarning() << "Null buffer returned by info.create(tp, 0)"; + } + if (!buf4) { + ++failureCount; + qWarning() << "Null buffer returned by infocreate(tp, buf)"; + } + QMetaType::destroy(tp, buf1); QMetaType::destroy(tp, buf2); + info.destroy(buf3); + info.destroy(buf4); } + new (space) Bar; } public: MetaTypeTorturer() : failureCount(0) { } @@ -480,13 +522,17 @@ template static void testCreateHelper() { typedef typename MetaEnumToType::Type Type; - void *actual = QMetaType::create(ID); + QMetaType info(ID); + void *actual1 = QMetaType::create(ID); + void *actual2 = info.create(); if (DefaultValueTraits::IsInitialized) { Type *expected = DefaultValueFactory::create(); - QCOMPARE(*static_cast(actual), *expected); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); delete expected; } - QMetaType::destroy(ID, actual); + QMetaType::destroy(ID, actual1); + info.destroy(actual2); } template<> @@ -529,9 +575,13 @@ static void testCreateCopyHelper() { typedef typename MetaEnumToType::Type Type; Type *expected = TestValueFactory::create(); - void *actual = QMetaType::create(ID, expected); - QCOMPARE(*static_cast(actual), *expected); - QMetaType::destroy(ID, actual); + QMetaType info(ID); + void *actual1 = QMetaType::create(ID, expected); + void *actual2 = info.create(expected); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); + QMetaType::destroy(ID, actual1); + info.destroy(actual2); delete expected; } @@ -588,6 +638,18 @@ void tst_QMetaType::sizeOf() QCOMPARE(QMetaType::sizeOf(type), size); } +void tst_QMetaType::sizeOfStaticLess_data() +{ + sizeOf_data(); +} + +void tst_QMetaType::sizeOfStaticLess() +{ + QFETCH(QMetaType::Type, type); + QFETCH(int, size); + QCOMPARE(QMetaType(type).sizeOf(), size); +} + struct CustomMovable {}; QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE); @@ -653,6 +715,23 @@ void tst_QMetaType::flags() QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject); } +void tst_QMetaType::flagsStaticLess_data() +{ + flags_data(); +} + +void tst_QMetaType::flagsStaticLess() +{ + QFETCH(int, type); + QFETCH(bool, isMovable); + QFETCH(bool, isComplex); + + int flags = QMetaType(type).flags(); + QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex); + QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex); + QCOMPARE(bool(flags & QMetaType::MovableType), isMovable); +} + void tst_QMetaType::construct_data() { create_data(); @@ -688,20 +767,30 @@ template static void testConstructHelper() { typedef typename MetaEnumToType::Type Type; - int size = QMetaType::sizeOf(ID); - void *storage = qMallocAligned(size, TypeAlignment::Value); - void *actual = QMetaType::construct(ID, storage, /*copy=*/0); - QCOMPARE(actual, storage); + QMetaType info(ID); + int size = info.sizeOf(); + void *storage1 = qMallocAligned(size, TypeAlignment::Value); + void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0); + void *storage2 = qMallocAligned(size, TypeAlignment::Value); + void *actual2 = info.construct(storage2, /*copy=*/0); + QCOMPARE(actual1, storage1); + QCOMPARE(actual2, storage2); if (DefaultValueTraits::IsInitialized) { Type *expected = DefaultValueFactory::create(); - QCOMPARE(*static_cast(actual), *expected); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); delete expected; } - QMetaType::destruct(ID, actual); - qFreeAligned(storage); + QMetaType::destruct(ID, actual1); + qFreeAligned(storage1); + info.destruct(actual2); + qFreeAligned(storage2); QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0); QMetaType::destruct(ID, 0); + + QVERIFY(info.construct(0, /*copy=*/0) == 0); + info.destruct(0); } template<> @@ -748,15 +837,24 @@ static void testConstructCopyHelper() { typedef typename MetaEnumToType::Type Type; Type *expected = TestValueFactory::create(); + QMetaType info(ID); int size = QMetaType::sizeOf(ID); - void *storage = qMallocAligned(size, TypeAlignment::Value); - void *actual = QMetaType::construct(ID, storage, expected); - QCOMPARE(actual, storage); - QCOMPARE(*static_cast(actual), *expected); - QMetaType::destruct(ID, actual); - qFreeAligned(storage); + QCOMPARE(info.sizeOf(), size); + void *storage1 = qMallocAligned(size, TypeAlignment::Value); + void *actual1 = QMetaType::construct(ID, storage1, expected); + void *storage2 = qMallocAligned(size, TypeAlignment::Value); + void *actual2 = info.construct(storage2, expected); + QCOMPARE(actual1, storage1); + QCOMPARE(actual2, storage2); + QCOMPARE(*static_cast(actual1), *expected); + QCOMPARE(*static_cast(actual2), *expected); + QMetaType::destruct(ID, actual1); + qFreeAligned(storage1); + info.destruct(actual2); + qFreeAligned(storage2); QVERIFY(QMetaType::construct(ID, 0, expected) == 0); + QVERIFY(info.construct(0, expected) == 0); delete expected; } @@ -895,6 +993,18 @@ void tst_QMetaType::isRegistered() QCOMPARE(QMetaType::isRegistered(typeId), registered); } +void tst_QMetaType::isRegisteredStaticLess_data() +{ + isRegistered_data(); +} + +void tst_QMetaType::isRegisteredStaticLess() +{ + QFETCH(int, typeId); + QFETCH(bool, registered); + QCOMPARE(QMetaType(typeId).isRegistered(), registered); +} + void tst_QMetaType::registerStreamBuiltin() { //should not crash; diff --git a/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp index 1c5dc9227f..a3cdd38e56 100644 --- a/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -72,6 +72,8 @@ private slots: void constructCoreType_data(); void constructCoreType(); + void constructCoreTypeStaticLess_data(); + void constructCoreTypeStaticLess(); void constructCoreTypeCopy_data(); void constructCoreTypeCopy(); @@ -79,6 +81,8 @@ private slots: void constructInPlace(); void constructInPlaceCopy_data(); void constructInPlaceCopy(); + void constructInPlaceCopyStaticLess_data(); + void constructInPlaceCopyStaticLess(); }; tst_QMetaType::tst_QMetaType() @@ -89,6 +93,12 @@ tst_QMetaType::~tst_QMetaType() { } +struct BigClass +{ + double n,i,e,r,o,b; +}; +Q_DECLARE_METATYPE(BigClass); + void tst_QMetaType::typeBuiltin_data() { QTest::addColumn("typeName"); @@ -260,6 +270,23 @@ void tst_QMetaType::constructCoreType() } } +void tst_QMetaType::constructCoreTypeStaticLess_data() +{ + constructCoreType_data(); +} + +void tst_QMetaType::constructCoreTypeStaticLess() +{ + QFETCH(int, typeId); + QBENCHMARK { + QMetaType type(typeId); + for (int i = 0; i < 100000; ++i) { + void *data = type.create((void *)0); + type.destroy(data); + } + } +} + void tst_QMetaType::constructCoreTypeCopy_data() { constructCoreType_data(); @@ -285,6 +312,7 @@ void tst_QMetaType::constructCoreTypeCopy() void tst_QMetaType::constructInPlace_data() { constructCoreType_data(); + QTest::newRow("custom") << qMetaTypeId(); } void tst_QMetaType::constructInPlace() @@ -305,7 +333,7 @@ void tst_QMetaType::constructInPlace() void tst_QMetaType::constructInPlaceCopy_data() { - constructCoreType_data(); + constructInPlace_data(); } void tst_QMetaType::constructInPlaceCopy() @@ -326,5 +354,29 @@ void tst_QMetaType::constructInPlaceCopy() qFreeAligned(storage); } +void tst_QMetaType::constructInPlaceCopyStaticLess_data() +{ + constructInPlaceCopy_data(); +} + +void tst_QMetaType::constructInPlaceCopyStaticLess() +{ + QFETCH(int, typeId); + int size = QMetaType::sizeOf(typeId); + void *storage = qMallocAligned(size, 2 * sizeof(qlonglong)); + void *other = QMetaType::create(typeId); + QCOMPARE(QMetaType::construct(typeId, storage, other), storage); + QMetaType::destruct(typeId, storage); + QBENCHMARK { + QMetaType type(typeId); + for (int i = 0; i < 100000; ++i) { + type.construct(storage, other); + type.destruct(storage); + } + } + QMetaType::destroy(typeId, other); + qFreeAligned(storage); +} + QTEST_MAIN(tst_QMetaType) #include "tst_qmetatype.moc" -- cgit v1.2.3