diff options
author | Kent Hansen <kent.hansen@nokia.com> | 2011-10-10 11:56:43 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-10-19 10:25:28 +0200 |
commit | 9e92ecde74d33eddd39de88472964fb20feaaebf (patch) | |
tree | c127c382451255cf64d6259c33dc34c754e965b8 /tests/auto/gui/kernel | |
parent | ae30d71413595b3cb0550e047132ea07510d35a3 (diff) |
Provide API for "placement new" construction of meta-types
By making it possible to specify the place in memory where a
type should be constructed, any meta-type can be allocated on
the stack, for example. In the QML/JS QObject binding, this
makes it possible to call slots and access properties from
JavaScript without having to perform any mallocs (e.g. due to
QVariant creation) in the C++ <--> JS value conversion, in
the best case.
In addition to QMetaType::construct() and QMetaType::destruct(),
this change introduces QMetaType::typeSize(), which returns the
size of a type in bytes. This can be used to prepare a suitable
buffer for constructing a type using construct().
Benchmarks indicate that in-place construction is 2-5x faster
than normal construction for core and GUI types on linux-g++.
Note that there is already a QMetaType::construct() function
in Qt 4, which has been renamed to QMetaType::create() in Qt 5.
In order to avoid existing usages of construct() in user code
to call the Qt 5 construct() (when they really meant to call
create()), the third argument ("copy") of construct() is made
mandatory. Hence, calls to QMetaType::construct() written for
Qt 4 will cause a compile error when compiled with Qt 5, and
the user must adapt his code.
Task-number: QTBUG-12574
Change-Id: I836f06f6ee1c1c3edbd199a03424c78c942bdd3e
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'tests/auto/gui/kernel')
-rw-r--r-- | tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp b/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp index 4b5aa347a8..98314a9336 100644 --- a/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp +++ b/tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp @@ -54,6 +54,12 @@ private slots: void create(); void createCopy_data(); void createCopy(); + void sizeOf_data(); + void sizeOf(); + void construct_data(); + void construct(); + void constructCopy_data(); + void constructCopy(); }; #define FOR_EACH_GUI_METATYPE(F) \ @@ -271,5 +277,130 @@ FOR_EACH_GUI_METATYPE(RETURN_CREATE_COPY_FUNCTION) TypeTestFunctionGetter::get(type)(); } +void tst_QGuiMetaType::sizeOf_data() +{ + QTest::addColumn<QMetaType::Type>("type"); + QTest::addColumn<int>("size"); +#define ADD_METATYPE_TEST_ROW(TYPE, ID) \ + QTest::newRow(QMetaType::typeName(QMetaType::ID)) << QMetaType::ID << int(sizeof(TYPE)); +FOR_EACH_GUI_METATYPE(ADD_METATYPE_TEST_ROW) +#undef ADD_METATYPE_TEST_ROW +} + +void tst_QGuiMetaType::sizeOf() +{ + QFETCH(QMetaType::Type, type); + QFETCH(int, size); + QCOMPARE(QMetaType::sizeOf(type), size); +} + +#ifndef Q_ALIGNOF +template<uint N> +struct RoundToNextHighestPowerOfTwo +{ +private: + enum { V1 = N-1 }; + enum { V2 = V1 | (V1 >> 1) }; + enum { V3 = V2 | (V2 >> 2) }; + enum { V4 = V3 | (V3 >> 4) }; + enum { V5 = V4 | (V4 >> 8) }; + enum { V6 = V5 | (V5 >> 16) }; +public: + enum { Value = V6 + 1 }; +}; +#endif + +template<class T> +struct TypeAlignment +{ +#ifdef Q_ALIGNOF + enum { Value = Q_ALIGNOF(T) }; +#else + enum { Value = RoundToNextHighestPowerOfTwo<sizeof(T)>::Value }; +#endif +}; + +void tst_QGuiMetaType::construct_data() +{ + create_data(); +} + +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); + Type *expected = DefaultValueFactory<ID>::create(); + QVERIFY2(TypeComparator<ID>::equal(*static_cast<Type *>(actual), *expected), QMetaType::typeName(ID)); + delete expected; + QMetaType::destruct(ID, actual); + qFreeAligned(storage); +} + +void tst_QGuiMetaType::construct() +{ + struct TypeTestFunctionGetter + { + static TypeTestFunction get(int type) + { + switch (type) { +#define RETURN_CONSTRUCT_FUNCTION(TYPE, ID) \ + case QMetaType::ID: \ + return testConstructHelper<QMetaType::ID>; +FOR_EACH_GUI_METATYPE(RETURN_CONSTRUCT_FUNCTION) +#undef RETURN_CONSTRUCT_FUNCTION + } + return 0; + } + }; + + QFETCH(QMetaType::Type, type); + TypeTestFunctionGetter::get(type)(); +} + +void tst_QGuiMetaType::constructCopy_data() +{ + create_data(); +} + +template <int ID> +static void testConstructCopyHelper() +{ + typedef typename MetaEnumToType<ID>::Type Type; + Type *expected = TestValueFactory<ID>::create(); + int size = QMetaType::sizeOf(ID); + void *storage = qMallocAligned(size, TypeAlignment<Type>::Value); + void *actual = QMetaType::construct(ID, storage, expected); + QCOMPARE(actual, storage); + QVERIFY2(TypeComparator<ID>::equal(*static_cast<Type*>(actual), *expected), QMetaType::typeName(ID)); + QMetaType::destruct(ID, actual); + qFreeAligned(storage); + delete expected; +} + +void tst_QGuiMetaType::constructCopy() +{ + struct TypeTestFunctionGetter + { + static TypeTestFunction get(int type) + { + switch (type) { +#define RETURN_CONSTRUCT_COPY_FUNCTION(TYPE, ID) \ + case QMetaType::ID: \ + return testConstructCopyHelper<QMetaType::ID>; +FOR_EACH_GUI_METATYPE(RETURN_CONSTRUCT_COPY_FUNCTION) +#undef RETURN_CONSTRUCT_COPY_FUNCTION + } + return 0; + } + }; + + QFETCH(QMetaType::Type, type); + TypeTestFunctionGetter::get(type)(); +} + QTEST_MAIN(tst_QGuiMetaType) #include "tst_qguimetatype.moc" |