From 9e92ecde74d33eddd39de88472964fb20feaaebf Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 10 Oct 2011 11:56:43 +0200 Subject: Provide API for "placement new" construction of meta-types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Kent Hansen --- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 139 +++++++++++++++++++++ .../gui/kernel/qguimetatype/tst_qguimetatype.cpp | 131 +++++++++++++++++++ 2 files changed, 270 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index cd01518e9e..8574c14b7c 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -76,6 +76,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(); void typedefs(); void isRegistered_data(); void isRegistered(); @@ -552,6 +558,139 @@ FOR_EACH_CORE_METATYPE(RETURN_CREATE_COPY_FUNCTION) TypeTestFunctionGetter::get(type)(); } +void tst_QMetaType::sizeOf_data() +{ + QTest::addColumn("type"); + QTest::addColumn("size"); +#define ADD_METATYPE_TEST_ROW(TYPE, ID) \ + QTest::newRow(QMetaType::typeName(QMetaType::ID)) << QMetaType::ID << int(sizeof(TYPE)); +FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW) +#undef ADD_METATYPE_TEST_ROW +} + +void tst_QMetaType::sizeOf() +{ + QFETCH(QMetaType::Type, type); + QFETCH(int, size); + QCOMPARE(QMetaType::sizeOf(type), size); +} + +void tst_QMetaType::construct_data() +{ + create_data(); +} + +#ifndef Q_ALIGNOF +template +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 +struct TypeAlignment +{ +#ifdef Q_ALIGNOF + enum { Value = Q_ALIGNOF(T) }; +#else + enum { Value = RoundToNextHighestPowerOfTwo::Value }; +#endif +}; + +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); + if (DefaultValueTraits::IsInitialized) { + Type *expected = DefaultValueFactory::create(); + QCOMPARE(*static_cast(actual), *expected); + delete expected; + } + QMetaType::destruct(ID, actual); + qFreeAligned(storage); + + QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0); + QMetaType::destruct(ID, 0); +} + +void tst_QMetaType::construct() +{ + struct TypeTestFunctionGetter + { + static TypeTestFunction get(int type) + { + switch (type) { +#define RETURN_CONSTRUCT_FUNCTION(TYPE, ID) \ + case QMetaType::ID: \ + return testConstructHelper; +FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION) +#undef RETURN_CONSTRUCT_FUNCTION + } + return 0; + } + }; + + QFETCH(QMetaType::Type, type); + TypeTestFunctionGetter::get(type)(); +} + +template +static void testConstructCopyHelper() +{ + typedef typename MetaEnumToType::Type Type; + Type *expected = TestValueFactory::create(); + 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); + + QVERIFY(QMetaType::construct(ID, 0, expected) == 0); + + delete expected; +} + +void tst_QMetaType::constructCopy_data() +{ + create_data(); +} + +void tst_QMetaType::constructCopy() +{ + struct TypeTestFunctionGetter + { + static TypeTestFunction get(int type) + { + switch (type) { +#define RETURN_CONSTRUCT_COPY_FUNCTION(TYPE, ID) \ + case QMetaType::ID: \ + return testConstructCopyHelper; +FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_COPY_FUNCTION) +#undef RETURN_CONSTRUCT_COPY_FUNCTION + } + return 0; + } + }; + + QFETCH(QMetaType::Type, type); + TypeTestFunctionGetter::get(type)(); +} + typedef QString CustomString; Q_DECLARE_METATYPE(CustomString) //this line is useless 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("type"); + QTest::addColumn("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 +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 +struct TypeAlignment +{ +#ifdef Q_ALIGNOF + enum { Value = Q_ALIGNOF(T) }; +#else + enum { Value = RoundToNextHighestPowerOfTwo::Value }; +#endif +}; + +void tst_QGuiMetaType::construct_data() +{ + create_data(); +} + +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); + Type *expected = DefaultValueFactory::create(); + QVERIFY2(TypeComparator::equal(*static_cast(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; +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 +static void testConstructCopyHelper() +{ + typedef typename MetaEnumToType::Type Type; + Type *expected = TestValueFactory::create(); + int size = QMetaType::sizeOf(ID); + void *storage = qMallocAligned(size, TypeAlignment::Value); + void *actual = QMetaType::construct(ID, storage, expected); + QCOMPARE(actual, storage); + QVERIFY2(TypeComparator::equal(*static_cast(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; +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" -- cgit v1.2.3