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 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 472 insertions(+), 3 deletions(-) (limited to 'src/corelib/kernel/qmetatype.cpp') 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() -- cgit v1.2.3