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 --- src/corelib/kernel/qmetatype.cpp | 475 ++++++++++++++++++++- src/corelib/kernel/qmetatype.h | 41 +- src/gui/kernel/qguivariant.cpp | 38 +- src/widgets/kernel/qwidgetsvariant.cpp | 24 +- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 139 ++++++ .../gui/kernel/qguimetatype/tst_qguimetatype.cpp | 131 ++++++ 6 files changed, 827 insertions(+), 21 deletions(-) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 9a1beaf57b..1d22d42d0f 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -337,6 +337,9 @@ struct QMetaTypeGuiHelper QMetaType::SaveOperator saveOp; QMetaType::LoadOperator loadOp; #endif + QMetaType::Constructor constructor; + QMetaType::Destructor destructor; + int size; }; Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeGuiHelper = 0; Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeWidgetsHelper = 0; @@ -348,6 +351,7 @@ public: #ifndef QT_NO_DATASTREAM , saveOp(0), loadOp(0) #endif + , constructor(0), destructor(0), size(0) {} QByteArray typeName; @@ -358,6 +362,9 @@ public: QMetaType::LoadOperator loadOp; #endif int alias; + QMetaType::Constructor constructor; + QMetaType::Destructor destructor; + int size; }; Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE); @@ -460,12 +467,28 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length) /*! \internal - Registers a user type for marshalling, with \a typeName, a \a - destructor, and a \a constructor. Returns the type's handle, - or -1 if the type could not be registered. + This function is needed until existing code outside of qtbase + has been changed to call the new version of registerType(). */ int QMetaType::registerType(const char *typeName, Deleter deleter, Creator creator) +{ + return registerType(typeName, deleter, creator, 0, 0, 0); +} + +/*! \internal + \since 5.0 + + Registers a user type for marshalling, with \a typeName, a \a + deleter, a \a creator, a \a destructor, a \a constructor, and + a \a size. Returns the type's handle, or -1 if the type could + not be registered. + */ +int QMetaType::registerType(const char *typeName, Deleter deleter, + Creator creator, + Destructor destructor, + Constructor constructor, + int size) { QVector *ct = customTypes(); if (!ct || !typeName || !deleter || !creator) @@ -490,6 +513,9 @@ int QMetaType::registerType(const char *typeName, Deleter deleter, inf.creator = creator; inf.deleter = deleter; inf.alias = -1; + inf.constructor = constructor; + inf.destructor = destructor; + inf.size = size; idx = ct->size() + User; ct->append(inf); } @@ -1416,6 +1442,443 @@ void QMetaType::destroy(int type, void *data) } } +/*! + \since 5.0 + + Constructs a value of the given \a type in the existing memory + addressed by \a where, that is a copy of \a copy, and returns + \a where. If \a copy is zero, the value is default constructed. + + This is a low-level function for explicitly managing the memory + used to store the type. Consider calling create() if you don't + need this level of control (that is, use "new" rather than + "placement new"). + + You must ensure that \a where points to a location that can store + a value of type \a type, and that \a where is suitably aligned. + The type's size can be queried by calling sizeOf(). + + The rule of thumb for alignment is that a type is aligned to its + natural boundary, which is the smallest power of 2 that is bigger + than the type, unless that alignment is larger than the maximum + useful alignment for the platform. For practical purposes, + alignment larger than 2 * sizeof(void*) is only necessary for + special hardware instructions (e.g., aligned SSE loads and stores + on x86). + + \sa destruct(), sizeOf() +*/ +void *QMetaType::construct(int type, void *where, const void *copy) +{ + if (!where) + return 0; + switch (type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Long: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Int: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Short: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Char: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::ULong: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::UInt: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::LongLong: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::ULongLong: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::UShort: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::UChar: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Bool: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Float: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::Double: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QChar: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QVariantHash: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QVariantList: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QVariant: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#endif + case QMetaType::QByteArray: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QString: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QStringList: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#endif + case QMetaType::QDate: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QTime: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QDateTime: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#endif + case QMetaType::QLocale: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QRectF: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QSize: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QSizeF: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QLine: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QLineF: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QPoint: + return qMetaTypeConstructHelper(where, static_cast(copy)); + case QMetaType::QPointF: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#endif +#ifndef QT_BOOTSTRAPPED + case QMetaType::QEasingCurve: + return qMetaTypeConstructHelper(where, static_cast(copy)); +#endif + case QMetaType::Void: + return where; + default: + ; + } + + Constructor ctor = 0; + if (type >= FirstGuiType && type <= LastGuiType) { + Q_ASSERT(qMetaTypeGuiHelper); + if (!qMetaTypeGuiHelper) + return 0; + ctor = qMetaTypeGuiHelper[type - FirstGuiType].constructor; + } else if (type >= FirstWidgetsType && type <= LastWidgetsType) { + Q_ASSERT(qMetaTypeWidgetsHelper); + if (!qMetaTypeWidgetsHelper) + return 0; + ctor = qMetaTypeWidgetsHelper[type - FirstWidgetsType].constructor; + } else { + const QVector * const ct = customTypes(); + QReadLocker locker(customTypesLock()); + if (type < User || !ct || ct->count() <= type - User) + return 0; + ctor = ct->at(type - User).constructor; + if (!ctor) + return 0; + } + + return ctor(where, copy); +} + +/*! + \since 5.0 + + Destructs the value of the given \a type, located at \a where. + + Unlike destroy(), this function only invokes the type's + destructor, it doesn't invoke the delete operator. + + \sa construct() +*/ +void QMetaType::destruct(int type, void *where) +{ + if (!where) + return; + switch (type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + break; + case QMetaType::Long: + break; + case QMetaType::Int: + break; + case QMetaType::Short: + break; + case QMetaType::Char: + break; + case QMetaType::ULong: + break; + case QMetaType::LongLong: + break; + case QMetaType::ULongLong: + break; + case QMetaType::UInt: + break; + case QMetaType::UShort: + break; + case QMetaType::UChar: + break; + case QMetaType::Bool: + break; + case QMetaType::Float: + break; + case QMetaType::Double: + break; + case QMetaType::QChar: + static_cast< NS(QChar)* >(where)->NS(QChar)::~QChar(); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + static_cast< NS(QVariantMap)* >(where)->NS(QVariantMap)::~QVariantMap(); + break; + case QMetaType::QVariantHash: + static_cast< NS(QVariantHash)* >(where)->NS(QVariantHash)::~QVariantHash(); + break; + case QMetaType::QVariantList: + static_cast< NS(QVariantList)* >(where)->NS(QVariantList)::~QVariantList(); + break; + case QMetaType::QVariant: + static_cast< NS(QVariant)* >(where)->NS(QVariant)::~QVariant(); + break; +#endif + case QMetaType::QByteArray: + static_cast< NS(QByteArray)* >(where)->NS(QByteArray)::~QByteArray(); + break; + case QMetaType::QString: + static_cast< NS(QString)* >(where)->NS(QString)::~QString(); + break; + case QMetaType::QStringList: + static_cast< NS(QStringList)* >(where)->NS(QStringList)::~QStringList(); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + static_cast< NS(QBitArray)* >(where)->NS(QBitArray)::~QBitArray(); + break; +#endif + case QMetaType::QDate: + static_cast< NS(QDate)* >(where)->NS(QDate)::~QDate(); + break; + case QMetaType::QTime: + static_cast< NS(QTime)* >(where)->NS(QTime)::~QTime(); + break; + case QMetaType::QDateTime: + static_cast< NS(QDateTime)* >(where)->NS(QDateTime)::~QDateTime(); + break; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + static_cast< NS(QUrl)* >(where)->NS(QUrl)::~QUrl(); +#endif + break; + case QMetaType::QLocale: + static_cast< NS(QLocale)* >(where)->NS(QLocale)::~QLocale(); + break; +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + static_cast< NS(QRect)* >(where)->NS(QRect)::~QRect(); + break; + case QMetaType::QRectF: + static_cast< NS(QRectF)* >(where)->NS(QRectF)::~QRectF(); + break; + case QMetaType::QSize: + static_cast< NS(QSize)* >(where)->NS(QSize)::~QSize(); + break; + case QMetaType::QSizeF: + static_cast< NS(QSizeF)* >(where)->NS(QSizeF)::~QSizeF(); + break; + case QMetaType::QLine: + static_cast< NS(QLine)* >(where)->NS(QLine)::~QLine(); + break; + case QMetaType::QLineF: + static_cast< NS(QLineF)* >(where)->NS(QLineF)::~QLineF(); + break; + case QMetaType::QPoint: + static_cast< NS(QPoint)* >(where)->NS(QPoint)::~QPoint(); + break; + case QMetaType::QPointF: + static_cast< NS(QPointF)* >(where)->NS(QPointF)::~QPointF(); + break; +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + static_cast< NS(QRegExp)* >(where)->NS(QRegExp)::~QRegExp(); + break; +#endif +#ifndef QT_BOOTSTRAPPED + case QMetaType::QEasingCurve: + static_cast< NS(QEasingCurve)* >(where)->NS(QEasingCurve)::~QEasingCurve(); + break; +#endif + case QMetaType::Void: + break; + default: { + const QVector * const ct = customTypes(); + Destructor dtor = 0; + if (type >= FirstGuiType && type <= LastGuiType) { + Q_ASSERT(qMetaTypeGuiHelper); + if (!qMetaTypeGuiHelper) + return; + dtor = qMetaTypeGuiHelper[type - FirstGuiType].destructor; + } else if (type >= FirstWidgetsType && type <= LastWidgetsType) { + Q_ASSERT(qMetaTypeWidgetsHelper); + if (!qMetaTypeWidgetsHelper) + return; + dtor = qMetaTypeWidgetsHelper[type - FirstWidgetsType].destructor; + } else { + QReadLocker locker(customTypesLock()); + if (type < User || !ct || ct->count() <= type - User) + break; + dtor = ct->at(type - User).destructor; + if (!dtor) + break; + } + dtor(where); + break; } + } +} + +/*! + \since 5.0 + + Returns the size of the given \a type in bytes (i.e., sizeof(T), + where T is the actual type identified by the \a type argument). + + This function is typically used together with construct() + to perform low-level management of the memory used by a type. + + \sa construct() +*/ +int QMetaType::sizeOf(int type) +{ + switch (type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + return sizeof(void *); + case QMetaType::Long: + return sizeof(long); + case QMetaType::Int: + return sizeof(int); + case QMetaType::Short: + return sizeof(short); + case QMetaType::Char: + return sizeof(char); + case QMetaType::ULong: + return sizeof(ulong); + case QMetaType::UInt: + return sizeof(uint); + case QMetaType::LongLong: + return sizeof(qlonglong); + case QMetaType::ULongLong: + return sizeof(qulonglong); + case QMetaType::UShort: + return sizeof(ushort); + case QMetaType::UChar: + return sizeof(uchar); + case QMetaType::Bool: + return sizeof(bool); + case QMetaType::Float: + return sizeof(float); + case QMetaType::Double: + return sizeof(double); + case QMetaType::QChar: + return sizeof(NS(QChar)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + return sizeof(NS(QVariantMap)); + case QMetaType::QVariantHash: + return sizeof(NS(QVariantHash)); + case QMetaType::QVariantList: + return sizeof(NS(QVariantList)); + case QMetaType::QVariant: + return sizeof(NS(QVariant)); +#endif + case QMetaType::QByteArray: + return sizeof(NS(QByteArray)); + case QMetaType::QString: + return sizeof(NS(QString)); + case QMetaType::QStringList: + return sizeof(NS(QStringList)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + return sizeof(NS(QBitArray)); +#endif + case QMetaType::QDate: + return sizeof(NS(QDate)); + case QMetaType::QTime: + return sizeof(NS(QTime)); + case QMetaType::QDateTime: + return sizeof(NS(QDateTime)); +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + return sizeof(NS(QUrl)); +#endif + case QMetaType::QLocale: + return sizeof(NS(QLocale)); +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + return sizeof(NS(QRect)); + case QMetaType::QRectF: + return sizeof(NS(QRectF)); + case QMetaType::QSize: + return sizeof(NS(QSize)); + case QMetaType::QSizeF: + return sizeof(NS(QSizeF)); + case QMetaType::QLine: + return sizeof(NS(QLine)); + case QMetaType::QLineF: + return sizeof(NS(QLineF)); + case QMetaType::QPoint: + return sizeof(NS(QPoint)); + case QMetaType::QPointF: + return sizeof(NS(QPointF)); +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + return sizeof(NS(QRegExp)); +#endif +#ifndef QT_BOOTSTRAPPED + case QMetaType::QEasingCurve: + return sizeof(NS(QEasingCurve)); +#endif + case QMetaType::Void: + return 0; + default: + ; + } + + if (type >= FirstGuiType && type <= LastGuiType) { + Q_ASSERT(qMetaTypeGuiHelper); + if (!qMetaTypeGuiHelper) + return 0; + return qMetaTypeGuiHelper[type - FirstGuiType].size; + } else if (type >= FirstWidgetsType && type <= LastWidgetsType) { + Q_ASSERT(qMetaTypeWidgetsHelper); + if (!qMetaTypeWidgetsHelper) + return 0; + return qMetaTypeWidgetsHelper[type - FirstWidgetsType].size; + } + + const QVector * const ct = customTypes(); + QReadLocker locker(customTypesLock()); + if (type < User || !ct || ct->count() <= type - User) + return 0; + return ct->at(type - User).size; +} + /*! \fn int qRegisterMetaType(const char *typeName) \relates QMetaType @@ -1475,6 +1938,12 @@ void QMetaType::destroy(int type, void *data) /*! \typedef QMetaType::LoadOperator \internal */ +/*! \typedef QMetaType::Destructor + \internal +*/ +/*! \typedef QMetaType::Constructor + \internal +*/ /*! \fn int qRegisterMetaType() diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index e65c084ae0..660807c698 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -49,6 +49,8 @@ #include #endif +#include + #ifdef Bool #error qmetatype.h must be included before any header file that defines Bool #endif @@ -106,6 +108,9 @@ public: typedef void (*Deleter)(void *); typedef void *(*Creator)(const void *); + 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 *); @@ -116,16 +121,20 @@ public: #endif static int registerType(const char *typeName, Deleter deleter, Creator creator); + static int registerType(const char *typeName, Deleter deleter, + Creator creator, + Destructor destructor, + Constructor constructor, + int size); 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 bool isRegistered(int type); static void *create(int type, const void *copy = 0); -#ifdef QT_DEPRECATED - QT_DEPRECATED static void *construct(int type, const void *copy = 0) - { return create(type, copy); } -#endif static void destroy(int type, void *data); + static void *construct(int type, void *where, const void *copy); + static void destruct(int type, void *where); static void unregisterType(const char *typeName); #ifndef QT_NO_DATASTREAM @@ -148,6 +157,21 @@ void *qMetaTypeCreateHelper(const T *t) return new T(*static_cast(t)); } +template +void qMetaTypeDestructHelper(T *t) +{ + t->~T(); +} + +template +void *qMetaTypeConstructHelper(void *where, const T *t) +{ + if (!t) + return new (where) T; + else + return new (where) T(*static_cast(t)); +} + #ifndef QT_NO_DATASTREAM template void qMetaTypeSaveHelper(QDataStream &stream, const T *t) @@ -202,9 +226,16 @@ int qRegisterMetaType(const char *typeName CreatePtr cptr = qMetaTypeCreateHelper; typedef void(*DeletePtr)(T*); DeletePtr dptr = qMetaTypeDeleteHelper; + typedef void*(*ConstructPtr)(void *, const T*); + ConstructPtr ipcptr = qMetaTypeConstructHelper; + typedef void(*DestructPtr)(T*); + DestructPtr ipdptr = qMetaTypeDestructHelper; return QMetaType::registerType(typeName, reinterpret_cast(dptr), - reinterpret_cast(cptr)); + reinterpret_cast(cptr), + reinterpret_cast(ipdptr), + reinterpret_cast(ipcptr), + sizeof(T)); } #ifndef QT_NO_DATASTREAM diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index 982fc3ccd5..72f7e183e1 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -643,6 +643,9 @@ struct QMetaTypeGuiHelper QMetaType::SaveOperator saveOp; QMetaType::LoadOperator loadOp; #endif + QMetaType::Constructor constructor; + QMetaType::Destructor destructor; + int size; }; extern Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeGuiHelper; @@ -653,13 +656,21 @@ extern Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeGuiHelper; typedef void *(*QCreate##TYPE)(const TYPE *); \ static const QCreate##TYPE qCreate##TYPE = qMetaTypeCreateHelper; \ typedef void (*QDelete##TYPE)(TYPE *); \ - static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper; + static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper; \ + typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \ + static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper; \ + typedef void (*QDestruct##TYPE)(TYPE *); \ + static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper; #else # define Q_DECL_METATYPE_HELPER(TYPE) \ typedef void *(*QCreate##TYPE)(const TYPE *); \ static const QCreate##TYPE qCreate##TYPE = qMetaTypeCreateHelper; \ typedef void (*QDelete##TYPE)(TYPE *); \ static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper; \ + typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \ + static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper; \ + typedef void (*QDestruct##TYPE)(TYPE *); \ + static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper; \ typedef void (*QSave##TYPE)(QDataStream &, const TYPE *); \ static const QSave##TYPE qSave##TYPE = qMetaTypeSaveHelper; \ typedef void (*QLoad##TYPE)(QDataStream &, TYPE *); \ @@ -705,13 +716,20 @@ Q_DECL_METATYPE_HELPER(QQuaternion) #ifdef QT_NO_DATASTREAM # define Q_IMPL_METATYPE_HELPER(TYPE) \ { reinterpret_cast(qCreate##TYPE), \ - reinterpret_cast(qDelete##TYPE) } + reinterpret_cast(qDelete##TYPE), \ + reinterpret_cast(qConstruct##TYPE), \ + reinterpret_cast(qDestruct##TYPE), \ + sizeof(TYPE) \ + } #else # define Q_IMPL_METATYPE_HELPER(TYPE) \ { reinterpret_cast(qCreate##TYPE), \ reinterpret_cast(qDelete##TYPE), \ reinterpret_cast(qSave##TYPE), \ - reinterpret_cast(qLoad##TYPE) \ + reinterpret_cast(qLoad##TYPE), \ + reinterpret_cast(qConstruct##TYPE), \ + reinterpret_cast(qDestruct##TYPE), \ + sizeof(TYPE) \ } #endif @@ -726,12 +744,12 @@ static const QMetaTypeGuiHelper qVariantGuiHelper[] = { Q_IMPL_METATYPE_HELPER(QRegion), Q_IMPL_METATYPE_HELPER(QBitmap), #ifdef QT_NO_CURSOR - {0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, #else Q_IMPL_METATYPE_HELPER(QCursor), #endif #ifdef QT_NO_SHORTCUT - {0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, #else Q_IMPL_METATYPE_HELPER(QKeySequence), #endif @@ -743,27 +761,27 @@ static const QMetaTypeGuiHelper qVariantGuiHelper[] = { #ifndef QT_NO_MATRIX4X4 Q_IMPL_METATYPE_HELPER(QMatrix4x4), #else - {0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, #endif #ifndef QT_NO_VECTOR2D Q_IMPL_METATYPE_HELPER(QVector2D), #else - {0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, #endif #ifndef QT_NO_VECTOR3D Q_IMPL_METATYPE_HELPER(QVector3D), #else - {0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, #endif #ifndef QT_NO_VECTOR4D Q_IMPL_METATYPE_HELPER(QVector4D), #else - {0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0}, #endif #ifndef QT_NO_QUATERNION Q_IMPL_METATYPE_HELPER(QQuaternion) #else - {0, 0, 0, 0} + {0, 0, 0, 0, 0, 0, 0} #endif }; diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp index a349e161e3..1a21d91829 100644 --- a/src/widgets/kernel/qwidgetsvariant.cpp +++ b/src/widgets/kernel/qwidgetsvariant.cpp @@ -141,6 +141,9 @@ struct QMetaTypeGuiHelper QMetaType::SaveOperator saveOp; QMetaType::LoadOperator loadOp; #endif + QMetaType::Constructor constructor; + QMetaType::Destructor destructor; + int size; }; extern Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeWidgetsHelper; @@ -151,13 +154,21 @@ extern Q_CORE_EXPORT const QMetaTypeGuiHelper *qMetaTypeWidgetsHelper; typedef void *(*QCreate##TYPE)(const TYPE *); \ static const QCreate##TYPE qCreate##TYPE = qMetaTypeCreateHelper; \ typedef void (*QDelete##TYPE)(TYPE *); \ - static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper; + static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper; \ + typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \ + static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper; \ + typedef void (*QDestruct##TYPE)(TYPE *); \ + static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper; #else # define Q_DECL_METATYPE_HELPER(TYPE) \ typedef void *(*QCreate##TYPE)(const TYPE *); \ static const QCreate##TYPE qCreate##TYPE = qMetaTypeCreateHelper; \ typedef void (*QDelete##TYPE)(TYPE *); \ static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper; \ + typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \ + static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper; \ + typedef void (*QDestruct##TYPE)(TYPE *); \ + static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper; \ typedef void (*QSave##TYPE)(QDataStream &, const TYPE *); \ static const QSave##TYPE qSave##TYPE = qMetaTypeSaveHelper; \ typedef void (*QLoad##TYPE)(QDataStream &, TYPE *); \ @@ -172,13 +183,20 @@ Q_DECL_METATYPE_HELPER(QSizePolicy) #ifdef QT_NO_DATASTREAM # define Q_IMPL_METATYPE_HELPER(TYPE) \ { reinterpret_cast(qCreate##TYPE), \ - reinterpret_cast(qDelete##TYPE) } + reinterpret_cast(qDelete##TYPE), \ + reinterpret_cast(qConstruct##TYPE), \ + reinterpret_cast(qDestruct##TYPE), \ + sizeof(TYPE) \ + } #else # define Q_IMPL_METATYPE_HELPER(TYPE) \ { reinterpret_cast(qCreate##TYPE), \ reinterpret_cast(qDelete##TYPE), \ reinterpret_cast(qSave##TYPE), \ - reinterpret_cast(qLoad##TYPE) \ + reinterpret_cast(qLoad##TYPE), \ + reinterpret_cast(qConstruct##TYPE), \ + reinterpret_cast(qDestruct##TYPE), \ + sizeof(TYPE) \ } #endif 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