Implement new static less API for QMetaType.
Currently QMetaType API contains almost only static methods. This works nice until someone needs more information or needs to do more operations on a type. In this case every function call has to do type dispatch. This API allows to avoid redundant type dispatching, by caching a type information in a QMetaType instance. It gives significant performance boost especially for custom types (up to 9x). Change-Id: I223d066268402e072e41ca1d0a3e7bc160655d7f Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com> Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
parent
b9eb3715f5
commit
214e031d56
@ -1753,4 +1753,174 @@ QMetaType::TypeFlags QMetaType::typeFlags(int type)
|
||||
\sa Q_DECLARE_METATYPE(), QMetaType::type()
|
||||
*/
|
||||
|
||||
namespace {
|
||||
class TypeInfo {
|
||||
template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>
|
||||
struct TypeInfoImpl
|
||||
{
|
||||
TypeInfoImpl(const uint /* type */, QMetaTypeInterface &info)
|
||||
{
|
||||
QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(T);
|
||||
info = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct TypeInfoImpl<T, /* IsAcceptedType = */ false>
|
||||
{
|
||||
TypeInfoImpl(const uint type, QMetaTypeInterface &info)
|
||||
{
|
||||
if (QTypeModuleInfo<T>::IsGui) {
|
||||
if (Q_LIKELY(qMetaTypeGuiHelper))
|
||||
info = qMetaTypeGuiHelper[type - QMetaType::FirstGuiType];
|
||||
return;
|
||||
}
|
||||
if (QTypeModuleInfo<T>::IsWidget) {
|
||||
if (Q_LIKELY(qMetaTypeWidgetsHelper))
|
||||
info = qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType];
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
public:
|
||||
QMetaTypeInterface info;
|
||||
TypeInfo(const uint type)
|
||||
: m_type(type)
|
||||
{
|
||||
QMetaTypeInterface tmp = QT_METATYPE_INTERFACE_INIT_EMPTY();
|
||||
info = tmp;
|
||||
}
|
||||
template<typename T>
|
||||
void delegate(const T*) { TypeInfoImpl<T>(m_type, info); }
|
||||
void delegate(const void*) {}
|
||||
void delegate(const QMetaTypeSwitcher::UnknownType*) { customTypeInfo(m_type); }
|
||||
private:
|
||||
void customTypeInfo(const uint type)
|
||||
{
|
||||
const QVector<QCustomTypeInfo> * const ct = customTypes();
|
||||
if (Q_UNLIKELY(!ct))
|
||||
return;
|
||||
QReadLocker locker(customTypesLock());
|
||||
if (Q_LIKELY(uint(ct->count()) > type - QMetaType::User))
|
||||
info = ct->at(type - QMetaType::User);
|
||||
}
|
||||
|
||||
const uint m_type;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
QMetaType QMetaType::typeInfo(const int type)
|
||||
{
|
||||
TypeInfo typeInfo(type);
|
||||
QMetaTypeSwitcher::switcher<void>(typeInfo, type, 0);
|
||||
return typeInfo.info.creator || !type ? QMetaType(QMetaType::NoExtensionFlags
|
||||
, static_cast<const QMetaTypeInterface *>(0) // typeInfo::info is a temporary variable, we can't return address of it.
|
||||
, typeInfo.info.creator
|
||||
, typeInfo.info.deleter
|
||||
, typeInfo.info.saveOp
|
||||
, typeInfo.info.loadOp
|
||||
, typeInfo.info.constructor
|
||||
, typeInfo.info.destructor
|
||||
, typeInfo.info.size
|
||||
, typeInfo.info.flags
|
||||
, type)
|
||||
: QMetaType(-1);
|
||||
}
|
||||
|
||||
QMetaType::QMetaType(const int typeId)
|
||||
: m_typeId(typeId)
|
||||
{
|
||||
if (Q_UNLIKELY(typeId == -1)) {
|
||||
// Constructs invalid QMetaType instance.
|
||||
m_extensionFlags = 0xffffffff;
|
||||
Q_ASSERT(!isValid());
|
||||
} else {
|
||||
// TODO it can be better.
|
||||
*this = QMetaType::typeInfo(typeId);
|
||||
if (m_typeId > 0 && !m_creator) {
|
||||
m_extensionFlags = 0xffffffff;
|
||||
m_typeId = -1;
|
||||
}
|
||||
if (m_typeId == QMetaType::Void) {
|
||||
m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMetaType::QMetaType(const QMetaType &other)
|
||||
: m_creator(other.m_creator)
|
||||
, m_deleter(other.m_deleter)
|
||||
, m_saveOp(other.m_saveOp)
|
||||
, m_loadOp(other.m_loadOp)
|
||||
, m_constructor(other.m_constructor)
|
||||
, m_destructor(other.m_destructor)
|
||||
, m_extension(other.m_extension) // space reserved for future use
|
||||
, m_size(other.m_size)
|
||||
, m_typeFlags(other.m_typeFlags)
|
||||
, m_extensionFlags(other.m_extensionFlags)
|
||||
, m_typeId(other.m_typeId)
|
||||
{}
|
||||
|
||||
QMetaType &QMetaType::operator =(const QMetaType &other)
|
||||
{
|
||||
m_creator = other.m_creator;
|
||||
m_deleter = other.m_deleter;
|
||||
m_saveOp = other.m_saveOp;
|
||||
m_loadOp = other.m_loadOp;
|
||||
m_constructor = other.m_constructor;
|
||||
m_destructor = other.m_destructor;
|
||||
m_size = other.m_size;
|
||||
m_typeFlags = other.m_typeFlags;
|
||||
m_extensionFlags = other.m_extensionFlags;
|
||||
m_extension = other.m_extension; // space reserved for future use
|
||||
m_typeId = other.m_typeId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void QMetaType::ctor(const QMetaTypeInterface *info)
|
||||
{
|
||||
// Special case for Void type, the type is valid but not constructible.
|
||||
// In future we may consider to remove this assert and extend this function to initialize
|
||||
// differently m_extensionFlags for different types. Currently it is not needed.
|
||||
Q_ASSERT(m_typeId == QMetaType::Void);
|
||||
Q_UNUSED(info);
|
||||
m_extensionFlags = CreateEx | DestroyEx | ConstructEx | DestructEx;
|
||||
}
|
||||
|
||||
void QMetaType::dtor()
|
||||
{}
|
||||
|
||||
void *QMetaType::createExtended(const void *copy) const
|
||||
{
|
||||
Q_UNUSED(copy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QMetaType::destroyExtended(void *data) const
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
}
|
||||
|
||||
void *QMetaType::constructExtended(void *where, const void *copy) const
|
||||
{
|
||||
Q_UNUSED(where);
|
||||
Q_UNUSED(copy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QMetaType::destructExtended(void *data) const
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
}
|
||||
|
||||
uint QMetaType::sizeExtended() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMetaType::TypeFlags QMetaType::flagsExtended() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -177,8 +177,16 @@ QT_BEGIN_NAMESPACE
|
||||
TypeName = Id,
|
||||
|
||||
class QDataStream;
|
||||
class QMetaTypeInterface;
|
||||
|
||||
class Q_CORE_EXPORT QMetaType {
|
||||
enum ExtensionFlag { NoExtensionFlags,
|
||||
CreateEx = 0x1, DestroyEx = 0x2,
|
||||
ConstructEx = 0x4, DestructEx = 0x8,
|
||||
NameEx = 0x10, SizeEx = 0x20,
|
||||
CtorEx = 0x40, DtorEx = 0x80,
|
||||
FlagsEx = 0x100
|
||||
};
|
||||
public:
|
||||
enum Type {
|
||||
// these are merged with QVariant
|
||||
@ -218,9 +226,9 @@ public:
|
||||
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 *);
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
static void registerStreamOperators(const char *typeName, SaveOperator saveOp,
|
||||
LoadOperator loadOp);
|
||||
static void registerStreamOperators(int type, SaveOperator saveOp,
|
||||
@ -253,6 +261,56 @@ public:
|
||||
static bool save(QDataStream &stream, int type, const void *data);
|
||||
static bool load(QDataStream &stream, int type, void *data);
|
||||
#endif
|
||||
|
||||
QMetaType(const int type);
|
||||
inline ~QMetaType();
|
||||
|
||||
inline bool isValid() const;
|
||||
inline bool isRegistered() const;
|
||||
inline int sizeOf() const;
|
||||
inline TypeFlags flags() const;
|
||||
|
||||
inline void *create(const void *copy = 0) const;
|
||||
inline void destroy(void *data) const;
|
||||
inline void *construct(void *where, const void *copy = 0) const;
|
||||
inline void destruct(void *data) const;
|
||||
private:
|
||||
static QMetaType typeInfo(const int type);
|
||||
inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
|
||||
Creator creator,
|
||||
Deleter deleter,
|
||||
SaveOperator saveOp,
|
||||
LoadOperator loadOp,
|
||||
Constructor constructor,
|
||||
Destructor destructor,
|
||||
uint sizeOf,
|
||||
uint typeFlags,
|
||||
int typeId);
|
||||
QMetaType(const QMetaType &other);
|
||||
QMetaType &operator =(const QMetaType &);
|
||||
inline bool isExtended(const ExtensionFlag flag) const { return m_extensionFlags & flag; }
|
||||
|
||||
// Methods used for future binary compatibile extensions
|
||||
void ctor(const QMetaTypeInterface *info);
|
||||
void dtor();
|
||||
uint sizeExtended() const;
|
||||
QMetaType::TypeFlags flagsExtended() const;
|
||||
void *createExtended(const void *copy = 0) const;
|
||||
void destroyExtended(void *data) const;
|
||||
void *constructExtended(void *where, const void *copy = 0) const;
|
||||
void destructExtended(void *data) const;
|
||||
|
||||
Creator m_creator;
|
||||
Deleter m_deleter;
|
||||
SaveOperator m_saveOp;
|
||||
LoadOperator m_loadOp;
|
||||
Constructor m_constructor;
|
||||
Destructor m_destructor;
|
||||
void *m_extension; // space reserved for future use
|
||||
uint m_size;
|
||||
uint m_typeFlags;
|
||||
uint m_extensionFlags;
|
||||
int m_typeId;
|
||||
};
|
||||
|
||||
#undef QT_DEFINE_METATYPE_ID
|
||||
@ -555,6 +613,91 @@ Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSet)
|
||||
Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSharedPointer)
|
||||
Q_DECLARE_METATYPE_TEMPLATE_1ARG(QLinkedList)
|
||||
|
||||
inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
|
||||
Creator creator,
|
||||
Deleter deleter,
|
||||
SaveOperator saveOp,
|
||||
LoadOperator loadOp,
|
||||
Constructor constructor,
|
||||
Destructor destructor,
|
||||
uint size,
|
||||
uint typeFlags,
|
||||
int typeId)
|
||||
: m_creator(creator)
|
||||
, m_deleter(deleter)
|
||||
, m_saveOp(saveOp)
|
||||
, m_loadOp(loadOp)
|
||||
, m_constructor(constructor)
|
||||
, m_destructor(destructor)
|
||||
, m_size(size)
|
||||
, m_typeFlags(typeFlags)
|
||||
, m_extensionFlags(extensionFlags)
|
||||
, m_typeId(typeId)
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(CtorEx) || typeId == QMetaType::Void))
|
||||
ctor(info);
|
||||
}
|
||||
|
||||
inline QMetaType::~QMetaType()
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(DtorEx)))
|
||||
dtor();
|
||||
}
|
||||
|
||||
inline bool QMetaType::isValid() const
|
||||
{
|
||||
return m_typeId >= 0;
|
||||
}
|
||||
|
||||
inline bool QMetaType::isRegistered() const
|
||||
{
|
||||
return isValid();
|
||||
}
|
||||
|
||||
inline void *QMetaType::create(const void *copy) const
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(CreateEx)))
|
||||
return createExtended(copy);
|
||||
return m_creator(copy);
|
||||
}
|
||||
|
||||
inline void QMetaType::destroy(void *data) const
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(DestroyEx)))
|
||||
return destroyExtended(data);
|
||||
m_deleter(data);
|
||||
}
|
||||
|
||||
inline void *QMetaType::construct(void *where, const void *copy) const
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(ConstructEx)))
|
||||
return constructExtended(where, copy);
|
||||
return m_constructor(where, copy);
|
||||
}
|
||||
|
||||
inline void QMetaType::destruct(void *data) const
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(DestructEx)))
|
||||
return destructExtended(data);
|
||||
if (Q_UNLIKELY(!data))
|
||||
return;
|
||||
m_destructor(data);
|
||||
}
|
||||
|
||||
inline int QMetaType::sizeOf() const
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(SizeEx)))
|
||||
return sizeExtended();
|
||||
return m_size;
|
||||
}
|
||||
|
||||
inline QMetaType::TypeFlags QMetaType::flags() const
|
||||
{
|
||||
if (Q_UNLIKELY(isExtended(FlagsEx)))
|
||||
return flagsExtended();
|
||||
return QMetaType::TypeFlags(m_typeFlags);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
||||
|
@ -132,10 +132,8 @@ public:
|
||||
}
|
||||
|
||||
static void deleter(T *t) { delete t; }
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
static void saver(QDataStream &stream, const T *t) { stream << *t; }
|
||||
static void loader(QDataStream &stream, T *t) { stream >> *t; }
|
||||
#endif // QT_NO_DATASTREAM
|
||||
static void destructor(T *t)
|
||||
{
|
||||
Q_UNUSED(t) // Silence MSVC that warns for POD types.
|
||||
@ -151,10 +149,8 @@ public:
|
||||
|
||||
QMetaType::Creator creator;
|
||||
QMetaType::Deleter deleter;
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
QMetaType::SaveOperator saveOp;
|
||||
QMetaType::LoadOperator loadOp;
|
||||
#endif
|
||||
QMetaType::Constructor constructor;
|
||||
QMetaType::Destructor destructor;
|
||||
int size;
|
||||
@ -165,10 +161,8 @@ template<>
|
||||
struct QMetaTypeInterface::Impl<void> {
|
||||
static void *creator(const void *) { return 0; }
|
||||
static void deleter(void *) {}
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
static void saver(QDataStream &, const void *) {}
|
||||
static void loader(QDataStream &, void *) {}
|
||||
#endif // QT_NO_DATASTREAM
|
||||
static void destructor(void *){}
|
||||
static void *constructor(void *, const void *) { return 0; }
|
||||
};
|
||||
@ -177,15 +171,22 @@ struct QMetaTypeInterface::Impl<void> {
|
||||
# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \
|
||||
/*saveOp*/(reinterpret_cast<QMetaType::SaveOperator>(QMetaTypeInterface::Impl<Type>::saver)), \
|
||||
/*loadOp*/(reinterpret_cast<QMetaType::LoadOperator>(QMetaTypeInterface::Impl<Type>::loader)),
|
||||
# define QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) \
|
||||
/*saveOp*/ 0, \
|
||||
/*loadOp*/ 0,
|
||||
#else
|
||||
# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type)
|
||||
# define QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type) \
|
||||
/*saveOp*/ 0, \
|
||||
/*loadOp*/ 0,
|
||||
# define QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \
|
||||
QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(Type)
|
||||
#endif
|
||||
|
||||
#define QT_METATYPE_INTERFACE_INIT(Type) \
|
||||
#define QT_METATYPE_INTERFACE_INIT_IMPL(Type, DATASTREAM_DELEGATE) \
|
||||
{ \
|
||||
/*creator*/(reinterpret_cast<QMetaType::Creator>(QMetaTypeInterface::Impl<Type>::creator)), \
|
||||
/*deleter*/(reinterpret_cast<QMetaType::Deleter>(QMetaTypeInterface::Impl<Type>::deleter)), \
|
||||
QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \
|
||||
DATASTREAM_DELEGATE(Type) \
|
||||
/*constructor*/(reinterpret_cast<QMetaType::Constructor>(QMetaTypeInterface::Impl<Type>::constructor)), \
|
||||
/*destructor*/(reinterpret_cast<QMetaType::Destructor>(QMetaTypeInterface::Impl<Type>::destructor)), \
|
||||
/*size*/(QTypeInfo<Type>::sizeOf), \
|
||||
@ -194,6 +195,30 @@ struct QMetaTypeInterface::Impl<void> {
|
||||
| (QTypeInfo<Type>::isComplex * QMetaType::NeedsDestruction) \
|
||||
}
|
||||
|
||||
|
||||
/* These QT_METATYPE_INTERFACE_INIT* macros are used to initialize QMetaTypeInterface instance.
|
||||
|
||||
- QT_METATYPE_INTERFACE_INIT(Type) -> It takes Type argument and creates all necessary wrapper functions for the Type,
|
||||
it detects if QT_NO_DATASTREAM was defined. Probably it is the macro that you want to use.
|
||||
|
||||
- QT_METATYPE_INTERFACE_INIT_EMPTY() -> It initializes an empty QMetaTypeInterface instance.
|
||||
|
||||
- QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) -> Temporary workaround for missing auto-detection of data stream
|
||||
operators. It creates same instance as QT_METATYPE_INTERFACE_INIT(Type) but with null stream operators callbacks.
|
||||
*/
|
||||
#define QT_METATYPE_INTERFACE_INIT(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL)
|
||||
#define QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL)
|
||||
#define QT_METATYPE_INTERFACE_INIT_EMPTY() \
|
||||
{ \
|
||||
/*creator*/ 0, \
|
||||
/*deleter*/ 0, \
|
||||
QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL() \
|
||||
/*constructor*/ 0, \
|
||||
/*destructor*/ 0, \
|
||||
/*size*/ 0, \
|
||||
/*flags*/ 0 \
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMETATYPE_P_H
|
||||
|
@ -78,8 +78,12 @@ private slots:
|
||||
void createCopy();
|
||||
void sizeOf_data();
|
||||
void sizeOf();
|
||||
void sizeOfStaticLess_data();
|
||||
void sizeOfStaticLess();
|
||||
void flags_data();
|
||||
void flags();
|
||||
void flagsStaticLess_data();
|
||||
void flagsStaticLess();
|
||||
void construct_data();
|
||||
void construct();
|
||||
void constructCopy_data();
|
||||
@ -88,6 +92,8 @@ private slots:
|
||||
void registerType();
|
||||
void isRegistered_data();
|
||||
void isRegistered();
|
||||
void isRegisteredStaticLess_data();
|
||||
void isRegisteredStaticLess();
|
||||
void registerStreamBuiltin();
|
||||
void automaticTemplateRegistration();
|
||||
};
|
||||
@ -125,6 +131,9 @@ class MetaTypeTorturer: public QThread
|
||||
protected:
|
||||
void run()
|
||||
{
|
||||
Bar space[1];
|
||||
space[0].~Bar();
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
const QByteArray name = QString("Bar%1_%2").arg(i).arg((size_t)QThread::currentThreadId()).toLatin1();
|
||||
const char *nm = name.constData();
|
||||
@ -132,6 +141,15 @@ protected:
|
||||
#ifdef Q_OS_LINUX
|
||||
pthread_yield();
|
||||
#endif
|
||||
QMetaType info(tp);
|
||||
if (!info.isValid()) {
|
||||
++failureCount;
|
||||
qWarning() << "Wrong typeInfo returned for" << tp;
|
||||
}
|
||||
if (!info.isRegistered()) {
|
||||
++failureCount;
|
||||
qWarning() << name << "is not a registered metatype";
|
||||
}
|
||||
if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) {
|
||||
++failureCount;
|
||||
qWarning() << "Wrong typeInfo returned for" << tp;
|
||||
@ -148,9 +166,22 @@ protected:
|
||||
++failureCount;
|
||||
qWarning() << "Wrong typeName returned for" << tp;
|
||||
}
|
||||
void *buf = QMetaType::create(tp, 0);
|
||||
void *buf2 = QMetaType::create(tp, buf);
|
||||
if (!buf) {
|
||||
void *buf1 = QMetaType::create(tp, 0);
|
||||
void *buf2 = QMetaType::create(tp, buf1);
|
||||
void *buf3 = info.create(tp, 0);
|
||||
void *buf4 = info.create(tp, buf1);
|
||||
|
||||
QMetaType::construct(tp, space, 0);
|
||||
QMetaType::destruct(tp, space);
|
||||
QMetaType::construct(tp, space, buf1);
|
||||
QMetaType::destruct(tp, space);
|
||||
|
||||
info.construct(space, 0);
|
||||
info.destruct(space);
|
||||
info.construct(space, buf1);
|
||||
info.destruct(space);
|
||||
|
||||
if (!buf1) {
|
||||
++failureCount;
|
||||
qWarning() << "Null buffer returned by QMetaType::create(tp, 0)";
|
||||
}
|
||||
@ -158,9 +189,20 @@ protected:
|
||||
++failureCount;
|
||||
qWarning() << "Null buffer returned by QMetaType::create(tp, buf)";
|
||||
}
|
||||
QMetaType::destroy(tp, buf);
|
||||
if (!buf3) {
|
||||
++failureCount;
|
||||
qWarning() << "Null buffer returned by info.create(tp, 0)";
|
||||
}
|
||||
if (!buf4) {
|
||||
++failureCount;
|
||||
qWarning() << "Null buffer returned by infocreate(tp, buf)";
|
||||
}
|
||||
QMetaType::destroy(tp, buf1);
|
||||
QMetaType::destroy(tp, buf2);
|
||||
info.destroy(buf3);
|
||||
info.destroy(buf4);
|
||||
}
|
||||
new (space) Bar;
|
||||
}
|
||||
public:
|
||||
MetaTypeTorturer() : failureCount(0) { }
|
||||
@ -480,13 +522,17 @@ template<int ID>
|
||||
static void testCreateHelper()
|
||||
{
|
||||
typedef typename MetaEnumToType<ID>::Type Type;
|
||||
void *actual = QMetaType::create(ID);
|
||||
QMetaType info(ID);
|
||||
void *actual1 = QMetaType::create(ID);
|
||||
void *actual2 = info.create();
|
||||
if (DefaultValueTraits<ID>::IsInitialized) {
|
||||
Type *expected = DefaultValueFactory<ID>::create();
|
||||
QCOMPARE(*static_cast<Type *>(actual), *expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual1), *expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual2), *expected);
|
||||
delete expected;
|
||||
}
|
||||
QMetaType::destroy(ID, actual);
|
||||
QMetaType::destroy(ID, actual1);
|
||||
info.destroy(actual2);
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -529,9 +575,13 @@ static void testCreateCopyHelper()
|
||||
{
|
||||
typedef typename MetaEnumToType<ID>::Type Type;
|
||||
Type *expected = TestValueFactory<ID>::create();
|
||||
void *actual = QMetaType::create(ID, expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual), *expected);
|
||||
QMetaType::destroy(ID, actual);
|
||||
QMetaType info(ID);
|
||||
void *actual1 = QMetaType::create(ID, expected);
|
||||
void *actual2 = info.create(expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual1), *expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual2), *expected);
|
||||
QMetaType::destroy(ID, actual1);
|
||||
info.destroy(actual2);
|
||||
delete expected;
|
||||
}
|
||||
|
||||
@ -588,6 +638,18 @@ void tst_QMetaType::sizeOf()
|
||||
QCOMPARE(QMetaType::sizeOf(type), size);
|
||||
}
|
||||
|
||||
void tst_QMetaType::sizeOfStaticLess_data()
|
||||
{
|
||||
sizeOf_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::sizeOfStaticLess()
|
||||
{
|
||||
QFETCH(QMetaType::Type, type);
|
||||
QFETCH(int, size);
|
||||
QCOMPARE(QMetaType(type).sizeOf(), size);
|
||||
}
|
||||
|
||||
struct CustomMovable {};
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
|
||||
@ -653,6 +715,23 @@ void tst_QMetaType::flags()
|
||||
QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject);
|
||||
}
|
||||
|
||||
void tst_QMetaType::flagsStaticLess_data()
|
||||
{
|
||||
flags_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::flagsStaticLess()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
QFETCH(bool, isMovable);
|
||||
QFETCH(bool, isComplex);
|
||||
|
||||
int flags = QMetaType(type).flags();
|
||||
QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex);
|
||||
QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex);
|
||||
QCOMPARE(bool(flags & QMetaType::MovableType), isMovable);
|
||||
}
|
||||
|
||||
void tst_QMetaType::construct_data()
|
||||
{
|
||||
create_data();
|
||||
@ -688,20 +767,30 @@ 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);
|
||||
QMetaType info(ID);
|
||||
int size = info.sizeOf();
|
||||
void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
||||
void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
|
||||
void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
||||
void *actual2 = info.construct(storage2, /*copy=*/0);
|
||||
QCOMPARE(actual1, storage1);
|
||||
QCOMPARE(actual2, storage2);
|
||||
if (DefaultValueTraits<ID>::IsInitialized) {
|
||||
Type *expected = DefaultValueFactory<ID>::create();
|
||||
QCOMPARE(*static_cast<Type *>(actual), *expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual1), *expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual2), *expected);
|
||||
delete expected;
|
||||
}
|
||||
QMetaType::destruct(ID, actual);
|
||||
qFreeAligned(storage);
|
||||
QMetaType::destruct(ID, actual1);
|
||||
qFreeAligned(storage1);
|
||||
info.destruct(actual2);
|
||||
qFreeAligned(storage2);
|
||||
|
||||
QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0);
|
||||
QMetaType::destruct(ID, 0);
|
||||
|
||||
QVERIFY(info.construct(0, /*copy=*/0) == 0);
|
||||
info.destruct(0);
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -748,15 +837,24 @@ static void testConstructCopyHelper()
|
||||
{
|
||||
typedef typename MetaEnumToType<ID>::Type Type;
|
||||
Type *expected = TestValueFactory<ID>::create();
|
||||
QMetaType info(ID);
|
||||
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);
|
||||
QCOMPARE(info.sizeOf(), size);
|
||||
void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
||||
void *actual1 = QMetaType::construct(ID, storage1, expected);
|
||||
void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
|
||||
void *actual2 = info.construct(storage2, expected);
|
||||
QCOMPARE(actual1, storage1);
|
||||
QCOMPARE(actual2, storage2);
|
||||
QCOMPARE(*static_cast<Type *>(actual1), *expected);
|
||||
QCOMPARE(*static_cast<Type *>(actual2), *expected);
|
||||
QMetaType::destruct(ID, actual1);
|
||||
qFreeAligned(storage1);
|
||||
info.destruct(actual2);
|
||||
qFreeAligned(storage2);
|
||||
|
||||
QVERIFY(QMetaType::construct(ID, 0, expected) == 0);
|
||||
QVERIFY(info.construct(0, expected) == 0);
|
||||
|
||||
delete expected;
|
||||
}
|
||||
@ -895,6 +993,18 @@ void tst_QMetaType::isRegistered()
|
||||
QCOMPARE(QMetaType::isRegistered(typeId), registered);
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredStaticLess_data()
|
||||
{
|
||||
isRegistered_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredStaticLess()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
QFETCH(bool, registered);
|
||||
QCOMPARE(QMetaType(typeId).isRegistered(), registered);
|
||||
}
|
||||
|
||||
void tst_QMetaType::registerStreamBuiltin()
|
||||
{
|
||||
//should not crash;
|
||||
|
@ -72,6 +72,8 @@ private slots:
|
||||
|
||||
void constructCoreType_data();
|
||||
void constructCoreType();
|
||||
void constructCoreTypeStaticLess_data();
|
||||
void constructCoreTypeStaticLess();
|
||||
void constructCoreTypeCopy_data();
|
||||
void constructCoreTypeCopy();
|
||||
|
||||
@ -79,6 +81,8 @@ private slots:
|
||||
void constructInPlace();
|
||||
void constructInPlaceCopy_data();
|
||||
void constructInPlaceCopy();
|
||||
void constructInPlaceCopyStaticLess_data();
|
||||
void constructInPlaceCopyStaticLess();
|
||||
};
|
||||
|
||||
tst_QMetaType::tst_QMetaType()
|
||||
@ -89,6 +93,12 @@ tst_QMetaType::~tst_QMetaType()
|
||||
{
|
||||
}
|
||||
|
||||
struct BigClass
|
||||
{
|
||||
double n,i,e,r,o,b;
|
||||
};
|
||||
Q_DECLARE_METATYPE(BigClass);
|
||||
|
||||
void tst_QMetaType::typeBuiltin_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("typeName");
|
||||
@ -260,6 +270,23 @@ void tst_QMetaType::constructCoreType()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructCoreTypeStaticLess_data()
|
||||
{
|
||||
constructCoreType_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructCoreTypeStaticLess()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
QBENCHMARK {
|
||||
QMetaType type(typeId);
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
void *data = type.create((void *)0);
|
||||
type.destroy(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructCoreTypeCopy_data()
|
||||
{
|
||||
constructCoreType_data();
|
||||
@ -285,6 +312,7 @@ void tst_QMetaType::constructCoreTypeCopy()
|
||||
void tst_QMetaType::constructInPlace_data()
|
||||
{
|
||||
constructCoreType_data();
|
||||
QTest::newRow("custom") << qMetaTypeId<BigClass>();
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlace()
|
||||
@ -305,7 +333,7 @@ void tst_QMetaType::constructInPlace()
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopy_data()
|
||||
{
|
||||
constructCoreType_data();
|
||||
constructInPlace_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopy()
|
||||
@ -326,5 +354,29 @@ void tst_QMetaType::constructInPlaceCopy()
|
||||
qFreeAligned(storage);
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopyStaticLess_data()
|
||||
{
|
||||
constructInPlaceCopy_data();
|
||||
}
|
||||
|
||||
void tst_QMetaType::constructInPlaceCopyStaticLess()
|
||||
{
|
||||
QFETCH(int, typeId);
|
||||
int size = QMetaType::sizeOf(typeId);
|
||||
void *storage = qMallocAligned(size, 2 * sizeof(qlonglong));
|
||||
void *other = QMetaType::create(typeId);
|
||||
QCOMPARE(QMetaType::construct(typeId, storage, other), storage);
|
||||
QMetaType::destruct(typeId, storage);
|
||||
QBENCHMARK {
|
||||
QMetaType type(typeId);
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
type.construct(storage, other);
|
||||
type.destruct(storage);
|
||||
}
|
||||
}
|
||||
QMetaType::destroy(typeId, other);
|
||||
qFreeAligned(storage);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMetaType)
|
||||
#include "tst_qmetatype.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user