summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2011-10-10 11:56:43 +0200
committerQt by Nokia <qt-info@nokia.com>2011-10-19 10:25:28 +0200
commit9e92ecde74d33eddd39de88472964fb20feaaebf (patch)
treec127c382451255cf64d6259c33dc34c754e965b8
parentae30d71413595b3cb0550e047132ea07510d35a3 (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>
-rw-r--r--src/corelib/kernel/qmetatype.cpp475
-rw-r--r--src/corelib/kernel/qmetatype.h41
-rw-r--r--src/gui/kernel/qguivariant.cpp38
-rw-r--r--src/widgets/kernel/qwidgetsvariant.cpp24
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp139
-rw-r--r--tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp131
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,13 +467,29 @@ 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<QCustomTypeInfo> *ct = customTypes();
if (!ct || !typeName || !deleter || !creator)
return -1;
@@ -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);
}
@@ -1417,6 +1443,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<void*>(where, static_cast<void* const *>(copy));
+ case QMetaType::Long:
+ return qMetaTypeConstructHelper<long>(where, static_cast<const long *>(copy));
+ case QMetaType::Int:
+ return qMetaTypeConstructHelper<int>(where, static_cast<const int *>(copy));
+ case QMetaType::Short:
+ return qMetaTypeConstructHelper<short>(where, static_cast<const short *>(copy));
+ case QMetaType::Char:
+ return qMetaTypeConstructHelper<char>(where, static_cast<const char *>(copy));
+ case QMetaType::ULong:
+ return qMetaTypeConstructHelper<ulong>(where, static_cast<const ulong *>(copy));
+ case QMetaType::UInt:
+ return qMetaTypeConstructHelper<uint>(where, static_cast<const uint *>(copy));
+ case QMetaType::LongLong:
+ return qMetaTypeConstructHelper<qlonglong>(where, static_cast<const qlonglong *>(copy));
+ case QMetaType::ULongLong:
+ return qMetaTypeConstructHelper<qulonglong>(where, static_cast<const qulonglong *>(copy));
+ case QMetaType::UShort:
+ return qMetaTypeConstructHelper<ushort>(where, static_cast<const ushort *>(copy));
+ case QMetaType::UChar:
+ return qMetaTypeConstructHelper<uchar>(where, static_cast<const uchar *>(copy));
+ case QMetaType::Bool:
+ return qMetaTypeConstructHelper<bool>(where, static_cast<const bool *>(copy));
+ case QMetaType::Float:
+ return qMetaTypeConstructHelper<float>(where, static_cast<const float *>(copy));
+ case QMetaType::Double:
+ return qMetaTypeConstructHelper<double>(where, static_cast<const double *>(copy));
+ case QMetaType::QChar:
+ return qMetaTypeConstructHelper<NS(QChar)>(where, static_cast<const NS(QChar) *>(copy));
+#ifndef QT_BOOTSTRAPPED
+ case QMetaType::QVariantMap:
+ return qMetaTypeConstructHelper<NS(QVariantMap)>(where, static_cast<const NS(QVariantMap) *>(copy));
+ case QMetaType::QVariantHash:
+ return qMetaTypeConstructHelper<NS(QVariantHash)>(where, static_cast<const NS(QVariantHash) *>(copy));
+ case QMetaType::QVariantList:
+ return qMetaTypeConstructHelper<NS(QVariantList)>(where, static_cast<const NS(QVariantList) *>(copy));
+ case QMetaType::QVariant:
+ return qMetaTypeConstructHelper<NS(QVariant)>(where, static_cast<const NS(QVariant) *>(copy));
+#endif
+ case QMetaType::QByteArray:
+ return qMetaTypeConstructHelper<NS(QByteArray)>(where, static_cast<const NS(QByteArray) *>(copy));
+ case QMetaType::QString:
+ return qMetaTypeConstructHelper<NS(QString)>(where, static_cast<const NS(QString) *>(copy));
+ case QMetaType::QStringList:
+ return qMetaTypeConstructHelper<NS(QStringList)>(where, static_cast<const NS(QStringList) *>(copy));
+#ifndef QT_BOOTSTRAPPED
+ case QMetaType::QBitArray:
+ return qMetaTypeConstructHelper<NS(QBitArray)>(where, static_cast<const NS(QBitArray) *>(copy));
+#endif
+ case QMetaType::QDate:
+ return qMetaTypeConstructHelper<NS(QDate)>(where, static_cast<const NS(QDate) *>(copy));
+ case QMetaType::QTime:
+ return qMetaTypeConstructHelper<NS(QTime)>(where, static_cast<const NS(QTime) *>(copy));
+ case QMetaType::QDateTime:
+ return qMetaTypeConstructHelper<NS(QDateTime)>(where, static_cast<const NS(QDateTime) *>(copy));
+#ifndef QT_BOOTSTRAPPED
+ case QMetaType::QUrl:
+ return qMetaTypeConstructHelper<NS(QUrl)>(where, static_cast<const NS(QUrl) *>(copy));
+#endif
+ case QMetaType::QLocale:
+ return qMetaTypeConstructHelper<NS(QLocale)>(where, static_cast<const NS(QLocale) *>(copy));
+#ifndef QT_NO_GEOM_VARIANT
+ case QMetaType::QRect:
+ return qMetaTypeConstructHelper<NS(QRect)>(where, static_cast<const NS(QRect) *>(copy));
+ case QMetaType::QRectF:
+ return qMetaTypeConstructHelper<NS(QRectF)>(where, static_cast<const NS(QRectF) *>(copy));
+ case QMetaType::QSize:
+ return qMetaTypeConstructHelper<NS(QSize)>(where, static_cast<const NS(QSize) *>(copy));
+ case QMetaType::QSizeF:
+ return qMetaTypeConstructHelper<NS(QSizeF)>(where, static_cast<const NS(QSizeF) *>(copy));
+ case QMetaType::QLine:
+ return qMetaTypeConstructHelper<NS(QLine)>(where, static_cast<const NS(QLine) *>(copy));
+ case QMetaType::QLineF:
+ return qMetaTypeConstructHelper<NS(QLineF)>(where, static_cast<const NS(QLineF) *>(copy));
+ case QMetaType::QPoint:
+ return qMetaTypeConstructHelper<NS(QPoint)>(where, static_cast<const NS(QPoint) *>(copy));
+ case QMetaType::QPointF:
+ return qMetaTypeConstructHelper<NS(QPointF)>(where, static_cast<const NS(QPointF) *>(copy));
+#endif
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+ return qMetaTypeConstructHelper<NS(QRegExp)>(where, static_cast<const NS(QRegExp) *>(copy));
+#endif
+#ifndef QT_BOOTSTRAPPED
+ case QMetaType::QEasingCurve:
+ return qMetaTypeConstructHelper<NS(QEasingCurve)>(where, static_cast<const NS(QEasingCurve) *>(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<QCustomTypeInfo> * 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<QCustomTypeInfo> * 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<QCustomTypeInfo> * 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
\threadsafe
@@ -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 <QtCore/qdatastream.h>
#endif
+#include <new>
+
#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<const T*>(t));
}
+template <typename T>
+void qMetaTypeDestructHelper(T *t)
+{
+ t->~T();
+}
+
+template <typename T>
+void *qMetaTypeConstructHelper(void *where, const T *t)
+{
+ if (!t)
+ return new (where) T;
+ else
+ return new (where) T(*static_cast<const T*>(t));
+}
+
#ifndef QT_NO_DATASTREAM
template <typename T>
void qMetaTypeSaveHelper(QDataStream &stream, const T *t)
@@ -202,9 +226,16 @@ int qRegisterMetaType(const char *typeName
CreatePtr cptr = qMetaTypeCreateHelper<T>;
typedef void(*DeletePtr)(T*);
DeletePtr dptr = qMetaTypeDeleteHelper<T>;
+ typedef void*(*ConstructPtr)(void *, const T*);
+ ConstructPtr ipcptr = qMetaTypeConstructHelper<T>;
+ typedef void(*DestructPtr)(T*);
+ DestructPtr ipdptr = qMetaTypeDestructHelper<T>;
return QMetaType::registerType(typeName, reinterpret_cast<QMetaType::Deleter>(dptr),
- reinterpret_cast<QMetaType::Creator>(cptr));
+ reinterpret_cast<QMetaType::Creator>(cptr),
+ reinterpret_cast<QMetaType::Destructor>(ipdptr),
+ reinterpret_cast<QMetaType::Constructor>(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<TYPE>; \
typedef void (*QDelete##TYPE)(TYPE *); \
- static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper<TYPE>;
+ static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper<TYPE>; \
+ typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \
+ static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper<TYPE>; \
+ typedef void (*QDestruct##TYPE)(TYPE *); \
+ static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper<TYPE>;
#else
# define Q_DECL_METATYPE_HELPER(TYPE) \
typedef void *(*QCreate##TYPE)(const TYPE *); \
static const QCreate##TYPE qCreate##TYPE = qMetaTypeCreateHelper<TYPE>; \
typedef void (*QDelete##TYPE)(TYPE *); \
static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper<TYPE>; \
+ typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \
+ static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper<TYPE>; \
+ typedef void (*QDestruct##TYPE)(TYPE *); \
+ static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper<TYPE>; \
typedef void (*QSave##TYPE)(QDataStream &, const TYPE *); \
static const QSave##TYPE qSave##TYPE = qMetaTypeSaveHelper<TYPE>; \
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<QMetaType::Creator>(qCreate##TYPE), \
- reinterpret_cast<QMetaType::Deleter>(qDelete##TYPE) }
+ reinterpret_cast<QMetaType::Deleter>(qDelete##TYPE), \
+ reinterpret_cast<QMetaType::Constructor>(qConstruct##TYPE), \
+ reinterpret_cast<QMetaType::Destructor>(qDestruct##TYPE), \
+ sizeof(TYPE) \
+ }
#else
# define Q_IMPL_METATYPE_HELPER(TYPE) \
{ reinterpret_cast<QMetaType::Creator>(qCreate##TYPE), \
reinterpret_cast<QMetaType::Deleter>(qDelete##TYPE), \
reinterpret_cast<QMetaType::SaveOperator>(qSave##TYPE), \
- reinterpret_cast<QMetaType::LoadOperator>(qLoad##TYPE) \
+ reinterpret_cast<QMetaType::LoadOperator>(qLoad##TYPE), \
+ reinterpret_cast<QMetaType::Constructor>(qConstruct##TYPE), \
+ reinterpret_cast<QMetaType::Destructor>(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<TYPE>; \
typedef void (*QDelete##TYPE)(TYPE *); \
- static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper<TYPE>;
+ static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper<TYPE>; \
+ typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \
+ static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper<TYPE>; \
+ typedef void (*QDestruct##TYPE)(TYPE *); \
+ static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper<TYPE>;
#else
# define Q_DECL_METATYPE_HELPER(TYPE) \
typedef void *(*QCreate##TYPE)(const TYPE *); \
static const QCreate##TYPE qCreate##TYPE = qMetaTypeCreateHelper<TYPE>; \
typedef void (*QDelete##TYPE)(TYPE *); \
static const QDelete##TYPE qDelete##TYPE = qMetaTypeDeleteHelper<TYPE>; \
+ typedef void *(*QConstruct##TYPE)(void *, const TYPE *); \
+ static const QConstruct##TYPE qConstruct##TYPE = qMetaTypeConstructHelper<TYPE>; \
+ typedef void (*QDestruct##TYPE)(TYPE *); \
+ static const QDestruct##TYPE qDestruct##TYPE = qMetaTypeDestructHelper<TYPE>; \
typedef void (*QSave##TYPE)(QDataStream &, const TYPE *); \
static const QSave##TYPE qSave##TYPE = qMetaTypeSaveHelper<TYPE>; \
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<QMetaType::Creator>(qCreate##TYPE), \
- reinterpret_cast<QMetaType::Deleter>(qDelete##TYPE) }
+ reinterpret_cast<QMetaType::Deleter>(qDelete##TYPE), \
+ reinterpret_cast<QMetaType::Constructor>(qConstruct##TYPE), \
+ reinterpret_cast<QMetaType::Destructor>(qDestruct##TYPE), \
+ sizeof(TYPE) \
+ }
#else
# define Q_IMPL_METATYPE_HELPER(TYPE) \
{ reinterpret_cast<QMetaType::Creator>(qCreate##TYPE), \
reinterpret_cast<QMetaType::Deleter>(qDelete##TYPE), \
reinterpret_cast<QMetaType::SaveOperator>(qSave##TYPE), \
- reinterpret_cast<QMetaType::LoadOperator>(qLoad##TYPE) \
+ reinterpret_cast<QMetaType::LoadOperator>(qLoad##TYPE), \
+ reinterpret_cast<QMetaType::Constructor>(qConstruct##TYPE), \
+ reinterpret_cast<QMetaType::Destructor>(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<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_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<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
+};
+
+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);
+ if (DefaultValueTraits<ID>::IsInitialized) {
+ Type *expected = DefaultValueFactory<ID>::create();
+ QCOMPARE(*static_cast<Type *>(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<QMetaType::ID>;
+FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION)
+#undef RETURN_CONSTRUCT_FUNCTION
+ }
+ return 0;
+ }
+ };
+
+ QFETCH(QMetaType::Type, type);
+ TypeTestFunctionGetter::get(type)();
+}
+
+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);
+ QCOMPARE(*static_cast<Type *>(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<QMetaType::ID>;
+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<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"