summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJędrzej Nowacki <jedrzej.nowacki@nokia.com>2011-12-20 17:11:46 +0100
committerQt by Nokia <qt-info@nokia.com>2012-02-16 02:00:15 +0100
commit214e031d56714ba69ef929f1e763e243b393e460 (patch)
tree4732bd79e015eecb85e66ba3a3facc58d5fba9ae
parentb9eb3715f55378802a1a0ae2f61d799ab84ee49a (diff)
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 <stephen.kelly@kdab.com> Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
-rw-r--r--src/corelib/kernel/qmetatype.cpp170
-rw-r--r--src/corelib/kernel/qmetatype.h145
-rw-r--r--src/corelib/kernel/qmetatype_p.h43
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp156
-rw-r--r--tests/benchmarks/corelib/kernel/qmetatype/tst_qmetatype.cpp54
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<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>
+ struct TypeInfoImpl
+ {
+ TypeInfoImpl(const uint /* type */, QMetaTypeInterface &info)
+ {
+ QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(T);
+ info = tmp;
+ }
+ };
+
+ template<typename T>
+ struct TypeInfoImpl<T, /* IsAcceptedType = */ false>
+ {
+ TypeInfoImpl(const uint type, QMetaTypeInterface &info)
+ {
+ if (QTypeModuleInfo<T>::IsGui) {
+ if (Q_LIKELY(qMetaTypeGuiHelper))
+ info = qMetaTypeGuiHelper[type - QMetaType::FirstGuiType];
+ return;
+ }
+ if (QTypeModuleInfo<T>::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<typename T>
+ void delegate(const T*) { TypeInfoImpl<T>(m_type, info); }
+ void delegate(const void*) {}
+ void delegate(const QMetaTypeSwitcher::UnknownType*) { customTypeInfo(m_type); }
+private:
+ void customTypeInfo(const uint type)
+ {
+ const QVector<QCustomTypeInfo> * 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<void>(typeInfo, type, 0);
+ return typeInfo.info.creator || !type ? QMetaType(QMetaType::NoExtensionFlags
+ , static_cast<const QMetaTypeInterface *>(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<void> {
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<void> {
# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \
/*saveOp*/(reinterpret_cast<QMetaType::SaveOperator>(QMetaTypeInterface::Impl<Type>::saver)), \
/*loadOp*/(reinterpret_cast<QMetaType::LoadOperator>(QMetaTypeInterface::Impl<Type>::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<QMetaType::Creator>(QMetaTypeInterface::Impl<Type>::creator)), \
/*deleter*/(reinterpret_cast<QMetaType::Deleter>(QMetaTypeInterface::Impl<Type>::deleter)), \
- QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \
+ DATASTREAM_DELEGATE(Type) \
/*constructor*/(reinterpret_cast<QMetaType::Constructor>(QMetaTypeInterface::Impl<Type>::constructor)), \
/*destructor*/(reinterpret_cast<QMetaType::Destructor>(QMetaTypeInterface::Impl<Type>::destructor)), \
/*size*/(QTypeInfo<Type>::sizeOf), \
@@ -194,6 +195,30 @@ struct QMetaTypeInterface::Impl<void> {
| (QTypeInfo<Type>::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<int ID>
static void testCreateHelper()
{
typedef typename MetaEnumToType<ID>::Type Type;
- void *actual = QMetaType::create(ID);
+ QMetaType info(ID);
+ void *actual1 = QMetaType::create(ID);
+ void *actual2 = info.create();
if (DefaultValueTraits<ID>::IsInitialized) {
Type *expected = DefaultValueFactory<ID>::create();
- QCOMPARE(*static_cast<Type *>(actual), *expected);
+ QCOMPARE(*static_cast<Type *>(actual1), *expected);
+ QCOMPARE(*static_cast<Type *>(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<ID>::Type Type;
Type *expected = TestValueFactory<ID>::create();
- void *actual = QMetaType::create(ID, expected);
- QCOMPARE(*static_cast<Type *>(actual), *expected);
- QMetaType::destroy(ID, actual);
+ QMetaType info(ID);
+ void *actual1 = QMetaType::create(ID, expected);
+ void *actual2 = info.create(expected);
+ QCOMPARE(*static_cast<Type *>(actual1), *expected);
+ QCOMPARE(*static_cast<Type *>(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<int ID>
static void testConstructHelper()
{
typedef typename MetaEnumToType<ID>::Type Type;
- int size = QMetaType::sizeOf(ID);
- void *storage = qMallocAligned(size, TypeAlignment<Type>::Value);
- void *actual = QMetaType::construct(ID, storage, /*copy=*/0);
- QCOMPARE(actual, storage);
+ QMetaType info(ID);
+ int size = info.sizeOf();
+ void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
+ void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
+ void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
+ void *actual2 = info.construct(storage2, /*copy=*/0);
+ QCOMPARE(actual1, storage1);
+ QCOMPARE(actual2, storage2);
if (DefaultValueTraits<ID>::IsInitialized) {
Type *expected = DefaultValueFactory<ID>::create();
- QCOMPARE(*static_cast<Type *>(actual), *expected);
+ QCOMPARE(*static_cast<Type *>(actual1), *expected);
+ QCOMPARE(*static_cast<Type *>(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<ID>::Type Type;
Type *expected = TestValueFactory<ID>::create();
+ QMetaType info(ID);
int size = QMetaType::sizeOf(ID);
- void *storage = qMallocAligned(size, TypeAlignment<Type>::Value);
- void *actual = QMetaType::construct(ID, storage, expected);
- QCOMPARE(actual, storage);
- QCOMPARE(*static_cast<Type *>(actual), *expected);
- QMetaType::destruct(ID, actual);
- qFreeAligned(storage);
+ QCOMPARE(info.sizeOf(), size);
+ void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
+ void *actual1 = QMetaType::construct(ID, storage1, expected);
+ void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
+ void *actual2 = info.construct(storage2, expected);
+ QCOMPARE(actual1, storage1);
+ QCOMPARE(actual2, storage2);
+ QCOMPARE(*static_cast<Type *>(actual1), *expected);
+ QCOMPARE(*static_cast<Type *>(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<QByteArray>("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<BigClass>();
}
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"