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>
This commit is contained in:
Kent Hansen 2011-10-10 11:56:43 +02:00 committed by Qt by Nokia
parent ae30d71413
commit 9e92ecde74
6 changed files with 827 additions and 21 deletions

View File

@ -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<QCustomTypeInfo> *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<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
@ -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()

View File

@ -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

View File

@ -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
};

View File

@ -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

View File

@ -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

View File

@ -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"