Make usage of internal QVariant space.
Each QVariant instance has internal storage which may be used for well-know basic types. This patch changes the behavior by delegating type dependent operation to QMetaType class which knows more types than QVariant itself. The patch significantly reduce amount of code in QVariant implementation. There are few side effects of this patch: - better performance: * for Core types when using Gui (QGuiVariant is able to construct Core types) * for small custom types (QVariant::Private::Data is used for all types that has size small enough) - comparing two QVariants can give different result for small custom types (binary comparison instead of pointer comparison) Change-Id: Ic17fa500d6a882110bfba896fd456c8e6c7a63a9 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
2b39be6dd5
commit
8fd64d22ac
@ -53,6 +53,7 @@
|
||||
#include "qurl.h"
|
||||
#include "qlocale.h"
|
||||
#include "private/qvariant_p.h"
|
||||
#include "qmetatype_p.h"
|
||||
|
||||
#ifndef QT_NO_GEOM_VARIANT
|
||||
#include "qsize.h"
|
||||
@ -72,299 +73,49 @@ QT_BEGIN_NAMESPACE
|
||||
# define FLT_DIG 6
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
struct TypeDefiniton {
|
||||
static const bool IsAvailable = true;
|
||||
};
|
||||
|
||||
// Ignore these types, as incomplete
|
||||
#ifdef QT_BOOTSTRAPPED
|
||||
template<> struct TypeDefiniton<QEasingCurve> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_GEOM_VARIANT
|
||||
template<> struct TypeDefiniton<QRect> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QRectF> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QSize> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QSizeF> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QLine> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QLineF> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QPoint> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QPointF> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
|
||||
struct CoreTypesFilter {
|
||||
template<typename T>
|
||||
struct Acceptor {
|
||||
static const bool IsAccepted = QTypeModuleInfo<T>::IsCore && TypeDefiniton<T>::IsAvailable;
|
||||
};
|
||||
};
|
||||
|
||||
static void construct(QVariant::Private *x, const void *copy)
|
||||
{
|
||||
x->is_shared = false;
|
||||
|
||||
switch (x->type) {
|
||||
case QVariant::String:
|
||||
v_construct<QString>(x, copy);
|
||||
break;
|
||||
case QVariant::Char:
|
||||
v_construct<QChar>(x, copy);
|
||||
break;
|
||||
case QVariant::StringList:
|
||||
v_construct<QStringList>(x, copy);
|
||||
break;
|
||||
case QVariant::Map:
|
||||
v_construct<QVariantMap>(x, copy);
|
||||
break;
|
||||
case QVariant::Hash:
|
||||
v_construct<QVariantHash>(x, copy);
|
||||
break;
|
||||
case QVariant::List:
|
||||
v_construct<QVariantList>(x, copy);
|
||||
break;
|
||||
case QVariant::Date:
|
||||
v_construct<QDate>(x, copy);
|
||||
break;
|
||||
case QVariant::Time:
|
||||
v_construct<QTime>(x, copy);
|
||||
break;
|
||||
case QVariant::DateTime:
|
||||
v_construct<QDateTime>(x, copy);
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
v_construct<QByteArray>(x, copy);
|
||||
break;
|
||||
case QVariant::BitArray:
|
||||
v_construct<QBitArray>(x, copy);
|
||||
break;
|
||||
#ifndef QT_NO_GEOM_VARIANT
|
||||
case QVariant::Size:
|
||||
v_construct<QSize>(x, copy);
|
||||
break;
|
||||
case QVariant::SizeF:
|
||||
v_construct<QSizeF>(x, copy);
|
||||
break;
|
||||
case QVariant::Rect:
|
||||
v_construct<QRect>(x, copy);
|
||||
break;
|
||||
case QVariant::LineF:
|
||||
v_construct<QLineF>(x, copy);
|
||||
break;
|
||||
case QVariant::Line:
|
||||
v_construct<QLine>(x, copy);
|
||||
break;
|
||||
case QVariant::RectF:
|
||||
v_construct<QRectF>(x, copy);
|
||||
break;
|
||||
case QVariant::Point:
|
||||
v_construct<QPoint>(x, copy);
|
||||
break;
|
||||
case QVariant::PointF:
|
||||
v_construct<QPointF>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::Url:
|
||||
v_construct<QUrl>(x, copy);
|
||||
break;
|
||||
case QVariant::Locale:
|
||||
v_construct<QLocale>(x, copy);
|
||||
break;
|
||||
#ifndef QT_NO_REGEXP
|
||||
case QVariant::RegExp:
|
||||
v_construct<QRegExp>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
case QVariant::EasingCurve:
|
||||
v_construct<QEasingCurve>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::Int:
|
||||
x->data.i = copy ? *static_cast<const int *>(copy) : 0;
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
x->data.u = copy ? *static_cast<const uint *>(copy) : 0u;
|
||||
break;
|
||||
case QVariant::Bool:
|
||||
x->data.b = copy ? *static_cast<const bool *>(copy) : false;
|
||||
break;
|
||||
case QVariant::Double:
|
||||
x->data.d = copy ? *static_cast<const double*>(copy) : 0.0;
|
||||
break;
|
||||
case QMetaType::Float:
|
||||
x->data.f = copy ? *static_cast<const float*>(copy) : 0.0f;
|
||||
break;
|
||||
case QMetaType::QObjectStar:
|
||||
x->data.o = copy ? *static_cast<QObject *const*>(copy) : 0;
|
||||
break;
|
||||
case QVariant::LongLong:
|
||||
x->data.ll = copy ? *static_cast<const qlonglong *>(copy) : Q_INT64_C(0);
|
||||
break;
|
||||
case QVariant::ULongLong:
|
||||
x->data.ull = copy ? *static_cast<const qulonglong *>(copy) : Q_UINT64_C(0);
|
||||
break;
|
||||
case QVariant::Invalid:
|
||||
case QVariant::UserType:
|
||||
break;
|
||||
default:
|
||||
void *ptr = QMetaType::create(x->type, copy);
|
||||
if (!ptr) {
|
||||
x->type = QVariant::Invalid;
|
||||
} else {
|
||||
x->is_shared = true;
|
||||
x->data.shared = new QVariant::PrivateShared(ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
x->is_null = !copy;
|
||||
QVariantConstructor<CoreTypesFilter> constructor(x, copy);
|
||||
QMetaTypeSwitcher::switcher<void>(constructor, x->type, 0);
|
||||
}
|
||||
|
||||
static void clear(QVariant::Private *d)
|
||||
{
|
||||
switch (d->type) {
|
||||
case QVariant::String:
|
||||
v_clear<QString>(d);
|
||||
break;
|
||||
case QVariant::Char:
|
||||
v_clear<QChar>(d);
|
||||
break;
|
||||
case QVariant::StringList:
|
||||
v_clear<QStringList>(d);
|
||||
break;
|
||||
case QVariant::Map:
|
||||
v_clear<QVariantMap>(d);
|
||||
break;
|
||||
case QVariant::Hash:
|
||||
v_clear<QVariantHash>(d);
|
||||
break;
|
||||
case QVariant::List:
|
||||
v_clear<QVariantList>(d);
|
||||
break;
|
||||
case QVariant::Date:
|
||||
v_clear<QDate>(d);
|
||||
break;
|
||||
case QVariant::Time:
|
||||
v_clear<QTime>(d);
|
||||
break;
|
||||
case QVariant::DateTime:
|
||||
v_clear<QDateTime>(d);
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
v_clear<QByteArray>(d);
|
||||
break;
|
||||
case QVariant::BitArray:
|
||||
v_clear<QBitArray>(d);
|
||||
break;
|
||||
#ifndef QT_NO_GEOM_VARIANT
|
||||
case QVariant::Point:
|
||||
v_clear<QPoint>(d);
|
||||
break;
|
||||
case QVariant::PointF:
|
||||
v_clear<QPointF>(d);
|
||||
break;
|
||||
case QVariant::Size:
|
||||
v_clear<QSize>(d);
|
||||
break;
|
||||
case QVariant::SizeF:
|
||||
v_clear<QSizeF>(d);
|
||||
break;
|
||||
case QVariant::Rect:
|
||||
v_clear<QRect>(d);
|
||||
break;
|
||||
case QVariant::LineF:
|
||||
v_clear<QLineF>(d);
|
||||
break;
|
||||
case QVariant::Line:
|
||||
v_clear<QLine>(d);
|
||||
break;
|
||||
case QVariant::RectF:
|
||||
v_clear<QRectF>(d);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::Url:
|
||||
v_clear<QUrl>(d);
|
||||
break;
|
||||
case QVariant::Locale:
|
||||
v_clear<QLocale>(d);
|
||||
break;
|
||||
#ifndef QT_NO_REGEXP
|
||||
case QVariant::RegExp:
|
||||
v_clear<QRegExp>(d);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
case QVariant::EasingCurve:
|
||||
v_clear<QEasingCurve>(d);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong:
|
||||
case QVariant::Double:
|
||||
case QMetaType::Float:
|
||||
case QMetaType::QObjectStar:
|
||||
break;
|
||||
case QVariant::Invalid:
|
||||
case QVariant::UserType:
|
||||
case QVariant::Int:
|
||||
case QVariant::UInt:
|
||||
case QVariant::Bool:
|
||||
break;
|
||||
default:
|
||||
QMetaType::destroy(d->type, d->data.shared->ptr);
|
||||
delete d->data.shared;
|
||||
break;
|
||||
}
|
||||
|
||||
d->type = QVariant::Invalid;
|
||||
d->is_null = true;
|
||||
d->is_shared = false;
|
||||
QVariantDestructor<CoreTypesFilter> cleaner(d);
|
||||
QMetaTypeSwitcher::switcher<void>(cleaner, d->type, 0);
|
||||
}
|
||||
|
||||
static bool isNull(const QVariant::Private *d)
|
||||
{
|
||||
switch(d->type) {
|
||||
case QVariant::String:
|
||||
return v_cast<QString>(d)->isNull();
|
||||
case QVariant::Char:
|
||||
return v_cast<QChar>(d)->isNull();
|
||||
case QVariant::Date:
|
||||
return v_cast<QDate>(d)->isNull();
|
||||
case QVariant::Time:
|
||||
return v_cast<QTime>(d)->isNull();
|
||||
case QVariant::DateTime:
|
||||
return v_cast<QDateTime>(d)->isNull();
|
||||
case QVariant::ByteArray:
|
||||
return v_cast<QByteArray>(d)->isNull();
|
||||
case QVariant::BitArray:
|
||||
return v_cast<QBitArray>(d)->isNull();
|
||||
#ifndef QT_NO_GEOM_VARIANT
|
||||
case QVariant::Size:
|
||||
return v_cast<QSize>(d)->isNull();
|
||||
case QVariant::SizeF:
|
||||
return v_cast<QSizeF>(d)->isNull();
|
||||
case QVariant::Rect:
|
||||
return v_cast<QRect>(d)->isNull();
|
||||
case QVariant::Line:
|
||||
return v_cast<QLine>(d)->isNull();
|
||||
case QVariant::LineF:
|
||||
return v_cast<QLineF>(d)->isNull();
|
||||
case QVariant::RectF:
|
||||
return v_cast<QRectF>(d)->isNull();
|
||||
case QVariant::Point:
|
||||
return v_cast<QPoint>(d)->isNull();
|
||||
case QVariant::PointF:
|
||||
return v_cast<QPointF>(d)->isNull();
|
||||
#endif
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
case QVariant::EasingCurve:
|
||||
#endif
|
||||
case QVariant::Url:
|
||||
case QVariant::Locale:
|
||||
case QVariant::RegExp:
|
||||
case QVariant::StringList:
|
||||
case QVariant::Map:
|
||||
case QVariant::Hash:
|
||||
case QVariant::List:
|
||||
case QVariant::Invalid:
|
||||
case QVariant::UserType:
|
||||
case QVariant::Int:
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong:
|
||||
case QVariant::Bool:
|
||||
case QVariant::Double:
|
||||
case QMetaType::Float:
|
||||
case QMetaType::QObjectStar:
|
||||
break;
|
||||
}
|
||||
return d->is_null;
|
||||
}
|
||||
|
||||
/*
|
||||
\internal
|
||||
\since 4.4
|
||||
|
||||
We cannot use v_cast() for QMetaType's numeric types because they're smaller than QVariant::Private::Data,
|
||||
which in turns makes v_cast() believe the value is stored in d->data.c. But
|
||||
it's not, since we're a QMetaType type.
|
||||
*/
|
||||
template<typename T>
|
||||
inline bool compareNumericMetaType(const QVariant::Private *const a, const QVariant::Private *const b)
|
||||
{
|
||||
return *static_cast<const T *>(a->data.shared->ptr) == *static_cast<const T *>(b->data.shared->ptr);
|
||||
QVariantIsNull<CoreTypesFilter> isNull(d);
|
||||
return QMetaTypeSwitcher::switcher<bool>(isNull, d->type, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -375,123 +126,8 @@ inline bool compareNumericMetaType(const QVariant::Private *const a, const QVari
|
||||
*/
|
||||
static bool compare(const QVariant::Private *a, const QVariant::Private *b)
|
||||
{
|
||||
switch(a->type) {
|
||||
case QVariant::List:
|
||||
return *v_cast<QVariantList>(a) == *v_cast<QVariantList>(b);
|
||||
case QVariant::Map: {
|
||||
const QVariantMap *m1 = v_cast<QVariantMap>(a);
|
||||
const QVariantMap *m2 = v_cast<QVariantMap>(b);
|
||||
if (m1->count() != m2->count())
|
||||
return false;
|
||||
QVariantMap::ConstIterator it = m1->constBegin();
|
||||
QVariantMap::ConstIterator it2 = m2->constBegin();
|
||||
while (it != m1->constEnd()) {
|
||||
if (*it != *it2 || it.key() != it2.key())
|
||||
return false;
|
||||
++it;
|
||||
++it2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case QVariant::Hash:
|
||||
return *v_cast<QVariantHash>(a) == *v_cast<QVariantHash>(b);
|
||||
case QVariant::String:
|
||||
return *v_cast<QString>(a) == *v_cast<QString>(b);
|
||||
case QVariant::Char:
|
||||
return *v_cast<QChar>(a) == *v_cast<QChar>(b);
|
||||
case QVariant::StringList:
|
||||
return *v_cast<QStringList>(a) == *v_cast<QStringList>(b);
|
||||
#ifndef QT_NO_GEOM_VARIANT
|
||||
case QVariant::Size:
|
||||
return *v_cast<QSize>(a) == *v_cast<QSize>(b);
|
||||
case QVariant::SizeF:
|
||||
return *v_cast<QSizeF>(a) == *v_cast<QSizeF>(b);
|
||||
case QVariant::Rect:
|
||||
return *v_cast<QRect>(a) == *v_cast<QRect>(b);
|
||||
case QVariant::Line:
|
||||
return *v_cast<QLine>(a) == *v_cast<QLine>(b);
|
||||
case QVariant::LineF:
|
||||
return *v_cast<QLineF>(a) == *v_cast<QLineF>(b);
|
||||
case QVariant::RectF:
|
||||
return *v_cast<QRectF>(a) == *v_cast<QRectF>(b);
|
||||
case QVariant::Point:
|
||||
return *v_cast<QPoint>(a) == *v_cast<QPoint>(b);
|
||||
case QVariant::PointF:
|
||||
return *v_cast<QPointF>(a) == *v_cast<QPointF>(b);
|
||||
#endif
|
||||
case QVariant::Url:
|
||||
return *v_cast<QUrl>(a) == *v_cast<QUrl>(b);
|
||||
case QVariant::Locale:
|
||||
return *v_cast<QLocale>(a) == *v_cast<QLocale>(b);
|
||||
#ifndef QT_NO_REGEXP
|
||||
case QVariant::RegExp:
|
||||
return *v_cast<QRegExp>(a) == *v_cast<QRegExp>(b);
|
||||
#endif
|
||||
case QVariant::Int:
|
||||
return a->data.i == b->data.i;
|
||||
case QVariant::UInt:
|
||||
return a->data.u == b->data.u;
|
||||
case QVariant::LongLong:
|
||||
return a->data.ll == b->data.ll;
|
||||
case QVariant::ULongLong:
|
||||
return a->data.ull == b->data.ull;
|
||||
case QVariant::Bool:
|
||||
return a->data.b == b->data.b;
|
||||
case QVariant::Double:
|
||||
return a->data.d == b->data.d;
|
||||
case QMetaType::Float:
|
||||
return a->data.f == b->data.f;
|
||||
case QMetaType::QObjectStar:
|
||||
return a->data.o == b->data.o;
|
||||
case QVariant::Date:
|
||||
return *v_cast<QDate>(a) == *v_cast<QDate>(b);
|
||||
case QVariant::Time:
|
||||
return *v_cast<QTime>(a) == *v_cast<QTime>(b);
|
||||
case QVariant::DateTime:
|
||||
return *v_cast<QDateTime>(a) == *v_cast<QDateTime>(b);
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
case QVariant::EasingCurve:
|
||||
return *v_cast<QEasingCurve>(a) == *v_cast<QEasingCurve>(b);
|
||||
#endif
|
||||
case QVariant::ByteArray:
|
||||
return *v_cast<QByteArray>(a) == *v_cast<QByteArray>(b);
|
||||
case QVariant::BitArray:
|
||||
return *v_cast<QBitArray>(a) == *v_cast<QBitArray>(b);
|
||||
case QVariant::Invalid:
|
||||
return true;
|
||||
case QMetaType::Long:
|
||||
return compareNumericMetaType<long>(a, b);
|
||||
case QMetaType::ULong:
|
||||
return compareNumericMetaType<ulong>(a, b);
|
||||
case QMetaType::Short:
|
||||
return compareNumericMetaType<short>(a, b);
|
||||
case QMetaType::UShort:
|
||||
return compareNumericMetaType<ushort>(a, b);
|
||||
case QMetaType::UChar:
|
||||
return compareNumericMetaType<uchar>(a, b);
|
||||
case QMetaType::Char:
|
||||
return compareNumericMetaType<char>(a, b);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!QMetaType::isRegistered(a->type))
|
||||
qFatal("QVariant::compare: type %d unknown to QVariant.", a->type);
|
||||
|
||||
const void *a_ptr = a->is_shared ? a->data.shared->ptr : &(a->data.ptr);
|
||||
const void *b_ptr = b->is_shared ? b->data.shared->ptr : &(b->data.ptr);
|
||||
|
||||
/* The reason we cannot place this test in a case branch above for the types
|
||||
* QMetaType::VoidStar, QMetaType::QObjectStar and so forth, is that it wouldn't include
|
||||
* user defined pointer types. */
|
||||
const char *const typeName = QMetaType::typeName(a->type);
|
||||
uint typeNameLen = qstrlen(typeName);
|
||||
if (typeNameLen > 0 && typeName[typeNameLen - 1] == '*')
|
||||
return *static_cast<void *const *>(a_ptr) == *static_cast<void *const *>(b_ptr);
|
||||
|
||||
if (a->is_null && b->is_null)
|
||||
return true;
|
||||
|
||||
return a_ptr == b_ptr;
|
||||
QVariantComparator<CoreTypesFilter> comparator(a, b);
|
||||
return QMetaTypeSwitcher::switcher<bool>(comparator, a->type, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -505,11 +141,11 @@ static qlonglong qMetaTypeNumber(const QVariant::Private *d)
|
||||
case QMetaType::LongLong:
|
||||
return d->data.ll;
|
||||
case QMetaType::Char:
|
||||
return qlonglong(*static_cast<signed char *>(d->data.shared->ptr));
|
||||
return qlonglong(d->data.c);
|
||||
case QMetaType::Short:
|
||||
return qlonglong(*static_cast<short *>(d->data.shared->ptr));
|
||||
return qlonglong(d->data.s);
|
||||
case QMetaType::Long:
|
||||
return qlonglong(*static_cast<long *>(d->data.shared->ptr));
|
||||
return qlonglong(d->data.l);
|
||||
case QMetaType::Float:
|
||||
return qRound64(d->data.f);
|
||||
case QVariant::Double:
|
||||
@ -527,11 +163,11 @@ static qulonglong qMetaTypeUNumber(const QVariant::Private *d)
|
||||
case QVariant::ULongLong:
|
||||
return d->data.ull;
|
||||
case QMetaType::UChar:
|
||||
return qulonglong(*static_cast<unsigned char *>(d->data.shared->ptr));
|
||||
return d->data.uc;
|
||||
case QMetaType::UShort:
|
||||
return qulonglong(*static_cast<ushort *>(d->data.shared->ptr));
|
||||
return d->data.us;
|
||||
case QMetaType::ULong:
|
||||
return qulonglong(*static_cast<ulong *>(d->data.shared->ptr));
|
||||
return d->data.ul;
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
return 0;
|
||||
@ -642,7 +278,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
|
||||
break;
|
||||
case QMetaType::Char:
|
||||
case QMetaType::UChar:
|
||||
*str = QChar::fromAscii(*static_cast<char *>(d->data.shared->ptr));
|
||||
*str = QChar::fromAscii(d->data.c);
|
||||
break;
|
||||
case QMetaType::Short:
|
||||
case QMetaType::Long:
|
||||
@ -835,7 +471,7 @@ static bool convert(const QVariant::Private *d, QVariant::Type t, void *result,
|
||||
break;
|
||||
case QMetaType::Char:
|
||||
case QMetaType::UChar:
|
||||
*ba = QByteArray(1, *static_cast<char *>(d->data.shared->ptr));
|
||||
*ba = QByteArray(1, d->data.c);
|
||||
break;
|
||||
case QVariant::Int:
|
||||
case QVariant::LongLong:
|
||||
@ -1396,7 +1032,7 @@ void QVariant::create(int type, const void *copy)
|
||||
|
||||
QVariant::~QVariant()
|
||||
{
|
||||
if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char && d.type < UserType))
|
||||
if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char))
|
||||
handler->clear(&d);
|
||||
}
|
||||
|
||||
@ -1412,7 +1048,7 @@ QVariant::QVariant(const QVariant &p)
|
||||
{
|
||||
if (d.is_shared) {
|
||||
d.data.shared->ref.ref();
|
||||
} else if (p.d.type > Char && p.d.type < QVariant::UserType) {
|
||||
} else if (p.d.type > Char) {
|
||||
handler->construct(&d, p.constData());
|
||||
d.is_null = p.d.is_null;
|
||||
}
|
||||
@ -1669,11 +1305,10 @@ QVariant::QVariant(int typeOrUserType, const void *copy, uint flags)
|
||||
if (flags) { //type is a pointer type
|
||||
d.type = typeOrUserType;
|
||||
d.data.ptr = *reinterpret_cast<void *const*>(copy);
|
||||
d.is_null = false;
|
||||
} else {
|
||||
create(typeOrUserType, copy);
|
||||
d.is_null = false;
|
||||
}
|
||||
d.is_null = false;
|
||||
}
|
||||
|
||||
QVariant::QVariant(int val)
|
||||
@ -1796,7 +1431,7 @@ QVariant& QVariant::operator=(const QVariant &variant)
|
||||
if (variant.d.is_shared) {
|
||||
variant.d.data.shared->ref.ref();
|
||||
d = variant.d;
|
||||
} else if (variant.d.type > Char && variant.d.type < UserType) {
|
||||
} else if (variant.d.type > Char) {
|
||||
d.type = variant.d.type;
|
||||
handler->construct(&d, variant.constData());
|
||||
d.is_null = variant.d.is_null;
|
||||
@ -1858,7 +1493,7 @@ const char *QVariant::typeName() const
|
||||
*/
|
||||
void QVariant::clear()
|
||||
{
|
||||
if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type < UserType && d.type > Char))
|
||||
if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char))
|
||||
handler->clear(&d);
|
||||
d.type = Invalid;
|
||||
d.is_null = true;
|
||||
|
@ -317,8 +317,13 @@ class Q_CORE_EXPORT QVariant
|
||||
union Data
|
||||
{
|
||||
char c;
|
||||
uchar uc;
|
||||
short s;
|
||||
ushort us;
|
||||
int i;
|
||||
uint u;
|
||||
long l;
|
||||
ulong ul;
|
||||
bool b;
|
||||
double d;
|
||||
float f;
|
||||
|
@ -59,6 +59,8 @@
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
|
||||
#include "qmetatypeswitcher_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef Q_CC_SUN // Sun CC picks the wrong overload, so introduce awful hack
|
||||
@ -146,8 +148,298 @@ inline void v_clear(QVariant::Private *d, T* = 0)
|
||||
|
||||
}
|
||||
|
||||
template<class Filter>
|
||||
class QVariantComparator {
|
||||
template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
|
||||
struct FilteredComparator {
|
||||
static bool compare(const QVariant::Private *a, const QVariant::Private *b)
|
||||
{
|
||||
return *v_cast<T>(a) == *v_cast<T>(b);
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct FilteredComparator<T, /* IsAcceptedType = */ false> {
|
||||
static bool compare(const QVariant::Private *m_a, const QVariant::Private *m_b)
|
||||
{
|
||||
if (!QMetaType::isRegistered(m_a->type))
|
||||
qFatal("QVariant::compare: type %d unknown to QVariant.", m_a->type);
|
||||
|
||||
const void *a_ptr = m_a->is_shared ? m_a->data.shared->ptr : &(m_a->data.ptr);
|
||||
const void *b_ptr = m_b->is_shared ? m_b->data.shared->ptr : &(m_b->data.ptr);
|
||||
|
||||
const char *const typeName = QMetaType::typeName(m_a->type);
|
||||
uint typeNameLen = qstrlen(typeName);
|
||||
if (typeNameLen > 0 && typeName[typeNameLen - 1] == '*')
|
||||
return *static_cast<void *const *>(a_ptr) == *static_cast<void *const *>(b_ptr);
|
||||
|
||||
if (m_a->is_null && m_b->is_null)
|
||||
return true;
|
||||
|
||||
return !memcmp(a_ptr, b_ptr, QMetaType::sizeOf(m_a->type));
|
||||
}
|
||||
};
|
||||
public:
|
||||
QVariantComparator(const QVariant::Private *a, const QVariant::Private *b)
|
||||
: m_a(a), m_b(b)
|
||||
{
|
||||
Q_ASSERT(a->type == b->type);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool delegate(const T*)
|
||||
{
|
||||
return FilteredComparator<T>::compare(m_a, m_b);
|
||||
}
|
||||
|
||||
bool delegate(const void*) { return true; }
|
||||
|
||||
protected:
|
||||
const QVariant::Private *m_a;
|
||||
const QVariant::Private *m_b;
|
||||
};
|
||||
|
||||
|
||||
Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
|
||||
|
||||
template<class Filter>
|
||||
class QVariantIsNull
|
||||
{
|
||||
/// \internal
|
||||
/// This class checks if a type T has method called isNull. Result is kept in the Value property
|
||||
/// TODO Can we somehow generalize it? A macro version?
|
||||
template<typename T, bool IsClass = QTypeInfo<T>::isComplex>
|
||||
class HasIsNullMethod
|
||||
{
|
||||
struct Yes { char unused[1]; };
|
||||
struct No { char unused[2]; };
|
||||
Q_STATIC_ASSERT(sizeof(Yes) != sizeof(No));
|
||||
|
||||
struct FallbackMixin { bool isNull() const; };
|
||||
struct Derived : public T, public FallbackMixin {};
|
||||
template<class C, C> struct TypeCheck {};
|
||||
|
||||
template<class C> static Yes test(...);
|
||||
template<class C> static No test(TypeCheck<bool (FallbackMixin::*)() const, &C::isNull> *);
|
||||
public:
|
||||
static const bool Value = (sizeof(test<Derived>(0)) == sizeof(Yes));
|
||||
};
|
||||
|
||||
// We need to exclude primitive types as they won't compile with HasIsNullMethod::Check classes
|
||||
// anyway it is not a problem as the types do not have isNull method.
|
||||
template<typename T>
|
||||
class HasIsNullMethod<T, /* IsClass = */ false> {
|
||||
public:
|
||||
static const bool Value = false;
|
||||
};
|
||||
|
||||
// TODO This part should go to autotests during HasIsNullMethod generalization.
|
||||
Q_STATIC_ASSERT(!HasIsNullMethod<bool>::Value);
|
||||
struct SelfTest1 { bool isNull() const; };
|
||||
Q_STATIC_ASSERT(HasIsNullMethod<SelfTest1>::Value);
|
||||
struct SelfTest2 {};
|
||||
Q_STATIC_ASSERT(!HasIsNullMethod<SelfTest2>::Value);
|
||||
struct SelfTest3 : public SelfTest1 {};
|
||||
Q_STATIC_ASSERT(HasIsNullMethod<SelfTest3>::Value);
|
||||
|
||||
template<typename T, bool HasIsNull = HasIsNullMethod<T>::Value>
|
||||
struct CallFilteredIsNull
|
||||
{
|
||||
static bool isNull(const QVariant::Private *d)
|
||||
{
|
||||
return v_cast<T>(d)->isNull();
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct CallFilteredIsNull<T, /* HasIsNull = */ false>
|
||||
{
|
||||
static bool isNull(const QVariant::Private *d)
|
||||
{
|
||||
return d->is_null;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
|
||||
struct CallIsNull
|
||||
{
|
||||
static bool isNull(const QVariant::Private *d)
|
||||
{
|
||||
return CallFilteredIsNull<T>::isNull(d);
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct CallIsNull<T, /* IsAcceptedType = */ false>
|
||||
{
|
||||
static bool isNull(const QVariant::Private *d)
|
||||
{
|
||||
return CallFilteredIsNull<T, false>::isNull(d);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
QVariantIsNull(const QVariant::Private *d)
|
||||
: m_d(d)
|
||||
{}
|
||||
template<typename T>
|
||||
bool delegate(const T*)
|
||||
{
|
||||
CallIsNull<T> null;
|
||||
return null.isNull(m_d);
|
||||
}
|
||||
// we need that as sizof(void) is undefined and it is needed in HasIsNullMethod
|
||||
bool delegate(const void *) { return m_d->is_null; }
|
||||
protected:
|
||||
const QVariant::Private *m_d;
|
||||
};
|
||||
|
||||
template<class Filter>
|
||||
class QVariantConstructor
|
||||
{
|
||||
template<typename T, bool IsSmall = (sizeof(T) <= sizeof(QVariant::Private::Data))>
|
||||
struct CallConstructor {};
|
||||
|
||||
template<typename T>
|
||||
struct CallConstructor<T, /* IsSmall = */ true>
|
||||
{
|
||||
CallConstructor(const QVariantConstructor &tc)
|
||||
{
|
||||
if (tc.m_copy)
|
||||
new (&tc.m_x->data.ptr) T(*static_cast<const T*>(tc.m_copy));
|
||||
else
|
||||
new (&tc.m_x->data.ptr) T();
|
||||
tc.m_x->is_shared = false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct CallConstructor<T, /* IsSmall = */ false>
|
||||
{
|
||||
CallConstructor(const QVariantConstructor &tc)
|
||||
{
|
||||
Q_STATIC_ASSERT(QTypeInfo<T>::isComplex);
|
||||
tc.m_x->data.shared = tc.m_copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T*>(tc.m_copy))
|
||||
: new QVariantPrivateSharedEx<T>;
|
||||
tc.m_x->is_shared = true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
|
||||
struct FilteredConstructor {
|
||||
FilteredConstructor(const QVariantConstructor &tc)
|
||||
{
|
||||
CallConstructor<T> tmp(tc);
|
||||
tc.m_x->is_null = !tc.m_copy;
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct FilteredConstructor<T, /* IsAcceptedType = */ false> {
|
||||
FilteredConstructor(const QVariantConstructor &tc)
|
||||
{
|
||||
// ignore types that lives outside of the current library
|
||||
tc.m_x->type = QVariant::Invalid;
|
||||
}
|
||||
};
|
||||
public:
|
||||
QVariantConstructor(QVariant::Private *x, const void *copy)
|
||||
: m_x(x)
|
||||
, m_copy(copy)
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
void delegate(const T*)
|
||||
{
|
||||
FilteredConstructor<T>(*this);
|
||||
}
|
||||
|
||||
void delegate(const QMetaTypeSwitcher::UnknownType*)
|
||||
{
|
||||
if (m_x->type == QVariant::UserType) {
|
||||
// TODO get rid of it
|
||||
// And yes! we can support historical magic, unkonwn/unconstructed user type isn't that
|
||||
// awesome? this QVariant::isValid will be true!
|
||||
m_x->is_null = !m_copy;
|
||||
m_x->is_shared = false;
|
||||
return;
|
||||
}
|
||||
// it is not a static known type, lets ask QMetaType if it can be constructed for us.
|
||||
const uint size = QMetaType::sizeOf(m_x->type);
|
||||
|
||||
if (size && size <= sizeof(QVariant::Private::Data)) {
|
||||
void *ptr = QMetaType::construct(m_x->type, &m_x->data.ptr, m_copy);
|
||||
if (!ptr) {
|
||||
m_x->type = QVariant::Invalid;
|
||||
}
|
||||
m_x->is_shared = false;
|
||||
} else {
|
||||
void *ptr = QMetaType::create(m_x->type, m_copy);
|
||||
if (!ptr) {
|
||||
m_x->type = QVariant::Invalid;
|
||||
} else {
|
||||
m_x->is_shared = true;
|
||||
m_x->data.shared = new QVariant::PrivateShared(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void delegate(const void*)
|
||||
{
|
||||
// QMetaType::Void == QVariant::Invalid, creating an invalid value creates invalid QVariant
|
||||
// TODO it might go away, check is needed
|
||||
m_x->is_shared = false;
|
||||
m_x->is_null = !m_copy;
|
||||
}
|
||||
private:
|
||||
QVariant::Private *m_x;
|
||||
const void *m_copy;
|
||||
};
|
||||
|
||||
template<class Filter>
|
||||
class QVariantDestructor
|
||||
{
|
||||
template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted>
|
||||
struct FilteredDestructor {
|
||||
FilteredDestructor(QVariant::Private *d)
|
||||
{
|
||||
v_clear<T>(d);
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct FilteredDestructor<T, /* IsAcceptedType = */ false> {
|
||||
FilteredDestructor(QVariant::Private *) {} // ignore non accessible types
|
||||
};
|
||||
|
||||
public:
|
||||
QVariantDestructor(QVariant::Private *d)
|
||||
: m_d(d)
|
||||
{}
|
||||
~QVariantDestructor()
|
||||
{
|
||||
m_d->type = QVariant::Invalid;
|
||||
m_d->is_null = true;
|
||||
m_d->is_shared = false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void delegate(const T*)
|
||||
{
|
||||
FilteredDestructor<T> cleaner(m_d);
|
||||
}
|
||||
|
||||
void delegate(const QMetaTypeSwitcher::UnknownType*)
|
||||
{
|
||||
// This is not a static type, so lets delegate everyting to QMetaType
|
||||
if (!m_d->is_shared) {
|
||||
QMetaType::destruct(m_d->type, &m_d->data.ptr);
|
||||
} else {
|
||||
QMetaType::destroy(m_d->type, m_d->data.shared->ptr);
|
||||
delete m_d->data.shared;
|
||||
}
|
||||
}
|
||||
// Ignore nonconstructible type
|
||||
void delegate(const void*) {}
|
||||
private:
|
||||
QVariant::Private *m_d;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QVARIANT_P_H
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "qvariant.h"
|
||||
|
||||
// Gui types
|
||||
#include "qbitmap.h"
|
||||
#include "qbrush.h"
|
||||
#include "qcolor.h"
|
||||
@ -64,7 +65,32 @@
|
||||
#include "qvector4d.h"
|
||||
#include "qquaternion.h"
|
||||
|
||||
// Core types
|
||||
#include "qvariant.h"
|
||||
#include "qbitarray.h"
|
||||
#include "qbytearray.h"
|
||||
#include "qdatastream.h"
|
||||
#include "qdebug.h"
|
||||
#include "qmap.h"
|
||||
#include "qdatetime.h"
|
||||
#include "qeasingcurve.h"
|
||||
#include "qlist.h"
|
||||
#include "qstring.h"
|
||||
#include "qstringlist.h"
|
||||
#include "qurl.h"
|
||||
#include "qlocale.h"
|
||||
|
||||
#ifndef QT_NO_GEOM_VARIANT
|
||||
#include "qsize.h"
|
||||
#include "qpoint.h"
|
||||
#include "qrect.h"
|
||||
#include "qline.h"
|
||||
#endif
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "private/qvariant_p.h"
|
||||
#include <private/qmetatype_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -72,340 +98,151 @@ Q_GUI_EXPORT const QVariant::Handler *qt_widgets_variant_handler = 0;
|
||||
|
||||
Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
|
||||
|
||||
template<typename T>
|
||||
struct TypeDefiniton {
|
||||
static const bool IsAvailable = true;
|
||||
};
|
||||
// Ignore these types, as incomplete
|
||||
#ifdef QT_NO_GEOM_VARIANT
|
||||
template<> struct TypeDefiniton<QRect> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QRectF> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QSize> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QSizeF> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QLine> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QLineF> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QPoint> { static const bool IsAvailable = false; };
|
||||
template<> struct TypeDefiniton<QPointF> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_SHORTCUT
|
||||
template<> struct TypeDefiniton<QKeySequence> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_CURSOR
|
||||
template<> struct TypeDefiniton<QCursor> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_MATRIX4X4
|
||||
template<> struct TypeDefiniton<QMatrix4x4> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_VECTOR2D
|
||||
template<> struct TypeDefiniton<QVector2D> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_VECTOR3D
|
||||
template<> struct TypeDefiniton<QVector3D> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_VECTOR4D
|
||||
template<> struct TypeDefiniton<QVector4D> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
#ifdef QT_NO_QUATERNION
|
||||
template<> struct TypeDefiniton<QQuaternion> { static const bool IsAvailable = false; };
|
||||
#endif
|
||||
|
||||
struct CoreAndGuiTypesFilter {
|
||||
template<typename T>
|
||||
struct Acceptor {
|
||||
static const bool IsAccepted = (QTypeModuleInfo<T>::IsCore || QTypeModuleInfo<T>::IsGui) && TypeDefiniton<T>::IsAvailable;
|
||||
};
|
||||
};
|
||||
|
||||
static void construct(QVariant::Private *x, const void *copy)
|
||||
{
|
||||
switch (x->type) {
|
||||
case QVariant::Bitmap:
|
||||
v_construct<QBitmap>(x, copy);
|
||||
break;
|
||||
case QVariant::Region:
|
||||
v_construct<QRegion>(x, copy);
|
||||
break;
|
||||
case QVariant::Polygon:
|
||||
v_construct<QPolygon>(x, copy);
|
||||
break;
|
||||
case QVariant::Font:
|
||||
v_construct<QFont>(x, copy);
|
||||
break;
|
||||
case QVariant::Pixmap:
|
||||
v_construct<QPixmap>(x, copy);
|
||||
break;
|
||||
case QVariant::Image:
|
||||
v_construct<QImage>(x, copy);
|
||||
break;
|
||||
case QVariant::Brush:
|
||||
v_construct<QBrush>(x, copy);
|
||||
break;
|
||||
case QVariant::Color:
|
||||
v_construct<QColor>(x, copy);
|
||||
break;
|
||||
case QVariant::Palette:
|
||||
v_construct<QPalette>(x, copy);
|
||||
break;
|
||||
case QVariant::Matrix:
|
||||
v_construct<QMatrix>(x, copy);
|
||||
break;
|
||||
case QVariant::Transform:
|
||||
v_construct<QTransform>(x, copy);
|
||||
break;
|
||||
case QVariant::TextFormat:
|
||||
v_construct<QTextFormat>(x, copy);
|
||||
break;
|
||||
case QVariant::TextLength:
|
||||
v_construct<QTextLength>(x, copy);
|
||||
break;
|
||||
#ifndef QT_NO_SHORTCUT
|
||||
case QVariant::KeySequence:
|
||||
v_construct<QKeySequence>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::Pen:
|
||||
v_construct<QPen>(x, copy);
|
||||
break;
|
||||
#ifndef QT_NO_CURSOR
|
||||
case QVariant::Cursor:
|
||||
v_construct<QCursor>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
case 62: {
|
||||
const int type = x->type;
|
||||
QVariantConstructor<CoreAndGuiTypesFilter> constructor(x, copy);
|
||||
QMetaTypeSwitcher::switcher<void>(constructor, type, 0);
|
||||
|
||||
// FIXME This is an ugly hack if QVariantConstructor fails to build a value it constructs an invalid type
|
||||
if (Q_UNLIKELY(x->type == QVariant::Invalid)) {
|
||||
if (type == 62) {
|
||||
// small 'trick' to let a QVariant(Qt::blue) create a variant
|
||||
// of type QColor
|
||||
// TODO Get rid of this hack.
|
||||
x->type = QVariant::Color;
|
||||
QColor color(*reinterpret_cast<const Qt::GlobalColor *>(copy));
|
||||
v_construct<QColor>(x, &color);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
#ifndef QT_NO_MATRIX4X4
|
||||
case QVariant::Matrix4x4:
|
||||
v_construct<QMatrix4x4>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR2D
|
||||
case QVariant::Vector2D:
|
||||
v_construct<QVector2D>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR3D
|
||||
case QVariant::Vector3D:
|
||||
v_construct<QVector3D>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR4D
|
||||
case QVariant::Vector4D:
|
||||
v_construct<QVector4D>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_QUATERNION
|
||||
case QVariant::Quaternion:
|
||||
v_construct<QQuaternion>(x, copy);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::SizePolicy:
|
||||
case QVariant::Icon:
|
||||
if (type == QVariant::Icon || type == QVariant::SizePolicy) {
|
||||
// TODO we need to clean up variant handlers, so they are replacament, not extension
|
||||
x->type = type;
|
||||
if (qt_widgets_variant_handler) {
|
||||
qt_widgets_variant_handler->construct(x, copy);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qcoreVariantHandler()->construct(x, copy);
|
||||
return;
|
||||
}
|
||||
x->is_null = !copy;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear(QVariant::Private *d)
|
||||
{
|
||||
switch (d->type) {
|
||||
case QVariant::Bitmap:
|
||||
v_clear<QBitmap>(d);
|
||||
break;
|
||||
case QVariant::Cursor:
|
||||
v_clear<QCursor>(d);
|
||||
break;
|
||||
case QVariant::Region:
|
||||
v_clear<QRegion>(d);
|
||||
break;
|
||||
case QVariant::Polygon:
|
||||
v_clear<QPolygon>(d);
|
||||
break;
|
||||
case QVariant::Font:
|
||||
v_clear<QFont>(d);
|
||||
break;
|
||||
case QVariant::Pixmap:
|
||||
v_clear<QPixmap>(d);
|
||||
break;
|
||||
case QVariant::Image:
|
||||
v_clear<QImage>(d);
|
||||
break;
|
||||
case QVariant::Brush:
|
||||
v_clear<QBrush>(d);
|
||||
break;
|
||||
case QVariant::Color:
|
||||
v_clear<QColor>(d);
|
||||
break;
|
||||
case QVariant::Palette:
|
||||
v_clear<QPalette>(d);
|
||||
break;
|
||||
case QVariant::Matrix:
|
||||
v_clear<QMatrix>(d);
|
||||
break;
|
||||
case QVariant::Transform:
|
||||
v_clear<QTransform>(d);
|
||||
break;
|
||||
case QVariant::TextFormat:
|
||||
v_clear<QTextFormat>(d);
|
||||
break;
|
||||
case QVariant::TextLength:
|
||||
v_clear<QTextLength>(d);
|
||||
break;
|
||||
#ifndef QT_NO_SHORTCUT
|
||||
case QVariant::KeySequence:
|
||||
v_clear<QKeySequence>(d);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::Pen:
|
||||
v_clear<QPen>(d);
|
||||
break;
|
||||
#ifndef QT_NO_MATRIX4X4
|
||||
case QVariant::Matrix4x4:
|
||||
v_clear<QMatrix4x4>(d);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR2D
|
||||
case QVariant::Vector2D:
|
||||
v_clear<QVector2D>(d);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR3D
|
||||
case QVariant::Vector3D:
|
||||
v_clear<QVector3D>(d);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR4D
|
||||
case QVariant::Vector4D:
|
||||
v_clear<QVector4D>(d);
|
||||
break;
|
||||
#endif
|
||||
#ifndef QT_NO_QUATERNION
|
||||
case QVariant::Quaternion:
|
||||
v_clear<QVector4D>(d);
|
||||
break;
|
||||
#endif
|
||||
case QVariant::SizePolicy:
|
||||
case QVariant::Icon:
|
||||
const int type = d->type;
|
||||
if (type == QVariant::Icon || type == QVariant::SizePolicy) {
|
||||
// TODO we need to clean up variant handlers, so they are replacament, not extension
|
||||
if (qt_widgets_variant_handler) {
|
||||
qt_widgets_variant_handler->clear(d);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qcoreVariantHandler()->clear(d);
|
||||
return;
|
||||
}
|
||||
|
||||
d->type = QVariant::Invalid;
|
||||
d->is_null = true;
|
||||
d->is_shared = false;
|
||||
QVariantDestructor<CoreAndGuiTypesFilter> destructor(d);
|
||||
QMetaTypeSwitcher::switcher<void>(destructor, type, 0);
|
||||
}
|
||||
|
||||
|
||||
// This class is a hack that customizes access to QPolygon
|
||||
template<class Filter>
|
||||
class QGuiVariantIsNull : public QVariantIsNull<Filter> {
|
||||
typedef QVariantIsNull<Filter> Base;
|
||||
public:
|
||||
QGuiVariantIsNull(const QVariant::Private *d)
|
||||
: QVariantIsNull<Filter>(d)
|
||||
{}
|
||||
template<typename T>
|
||||
bool delegate(const T *p) { return Base::delegate(p); }
|
||||
bool delegate(const QPolygon*) { return v_cast<QPolygon>(Base::m_d)->isEmpty(); }
|
||||
bool delegate(const void *p) { return Base::delegate(p); }
|
||||
};
|
||||
static bool isNull(const QVariant::Private *d)
|
||||
{
|
||||
switch(d->type) {
|
||||
case QVariant::Bitmap:
|
||||
return v_cast<QBitmap>(d)->isNull();
|
||||
case QVariant::Region:
|
||||
return v_cast<QRegion>(d)->isEmpty();
|
||||
case QVariant::Polygon:
|
||||
return v_cast<QPolygon>(d)->isEmpty();
|
||||
case QVariant::Pixmap:
|
||||
return v_cast<QPixmap>(d)->isNull();
|
||||
case QVariant::Image:
|
||||
return v_cast<QImage>(d)->isNull();
|
||||
case QVariant::Matrix:
|
||||
case QVariant::TextFormat:
|
||||
case QVariant::TextLength:
|
||||
case QVariant::Cursor:
|
||||
case QVariant::StringList:
|
||||
case QVariant::Font:
|
||||
case QVariant::Brush:
|
||||
case QVariant::Color:
|
||||
case QVariant::Palette:
|
||||
case QVariant::SizePolicy:
|
||||
#ifndef QT_NO_SHORTCUT
|
||||
case QVariant::KeySequence:
|
||||
#endif
|
||||
case QVariant::Pen:
|
||||
#ifndef QT_NO_MATRIX4X4
|
||||
case QVariant::Matrix4x4:
|
||||
#endif
|
||||
break;
|
||||
#ifndef QT_NO_VECTOR2D
|
||||
case QVariant::Vector2D:
|
||||
return v_cast<QVector2D>(d)->isNull();
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR3D
|
||||
case QVariant::Vector3D:
|
||||
return v_cast<QVector3D>(d)->isNull();
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR4D
|
||||
case QVariant::Vector4D:
|
||||
return v_cast<QVector4D>(d)->isNull();
|
||||
#endif
|
||||
#ifndef QT_NO_QUATERNION
|
||||
case QVariant::Quaternion:
|
||||
return v_cast<QQuaternion>(d)->isNull();
|
||||
#endif
|
||||
case QVariant::Icon:
|
||||
if (qt_widgets_variant_handler)
|
||||
return qt_widgets_variant_handler->isNull(d);
|
||||
break;
|
||||
default:
|
||||
return qcoreVariantHandler()->isNull(d);
|
||||
}
|
||||
return d->is_null;
|
||||
QGuiVariantIsNull<CoreAndGuiTypesFilter> isNull(d);
|
||||
return QMetaTypeSwitcher::switcher<bool>(isNull, d->type, 0);
|
||||
}
|
||||
|
||||
// This class is a hack that customizes access to QPixmap, QBitmap and QCursor
|
||||
template<class Filter>
|
||||
class QGuiVariantComparator : public QVariantComparator<Filter> {
|
||||
typedef QVariantComparator<Filter> Base;
|
||||
public:
|
||||
QGuiVariantComparator(const QVariant::Private *a, const QVariant::Private *b)
|
||||
: QVariantComparator<Filter>(a, b)
|
||||
{}
|
||||
template<typename T>
|
||||
bool delegate(const T *p)
|
||||
{
|
||||
if (Q_UNLIKELY(Base::m_a->type == QVariant::Icon || Base::m_a->type == QVariant::SizePolicy)) {
|
||||
// TODO we need to clean up variant handlers, so they are replacament, not extension
|
||||
if (Q_LIKELY(qt_widgets_variant_handler))
|
||||
return qt_widgets_variant_handler->compare(Base::m_a, Base::m_b);
|
||||
}
|
||||
return Base::delegate(p);
|
||||
}
|
||||
bool delegate(const QPixmap*)
|
||||
{
|
||||
return v_cast<QPixmap>(Base::m_a)->cacheKey() == v_cast<QPixmap>(Base::m_b)->cacheKey();
|
||||
}
|
||||
bool delegate(const QBitmap*)
|
||||
{
|
||||
return v_cast<QBitmap>(Base::m_a)->cacheKey() == v_cast<QBitmap>(Base::m_b)->cacheKey();
|
||||
}
|
||||
#ifndef QT_NO_CURSOR
|
||||
bool delegate(const QCursor*)
|
||||
{
|
||||
return v_cast<QCursor>(Base::m_a)->shape() == v_cast<QCursor>(Base::m_b)->shape();
|
||||
}
|
||||
#endif
|
||||
bool delegate(const void *p) { return Base::delegate(p); }
|
||||
};
|
||||
|
||||
static bool compare(const QVariant::Private *a, const QVariant::Private *b)
|
||||
{
|
||||
Q_ASSERT(a->type == b->type);
|
||||
switch(a->type) {
|
||||
case QVariant::Cursor:
|
||||
#ifndef QT_NO_CURSOR
|
||||
return v_cast<QCursor>(a)->shape() == v_cast<QCursor>(b)->shape();
|
||||
#endif
|
||||
case QVariant::Bitmap:
|
||||
return v_cast<QBitmap>(a)->cacheKey()
|
||||
== v_cast<QBitmap>(b)->cacheKey();
|
||||
case QVariant::Polygon:
|
||||
return *v_cast<QPolygon>(a) == *v_cast<QPolygon>(b);
|
||||
case QVariant::Region:
|
||||
return *v_cast<QRegion>(a) == *v_cast<QRegion>(b);
|
||||
case QVariant::Font:
|
||||
return *v_cast<QFont>(a) == *v_cast<QFont>(b);
|
||||
case QVariant::Pixmap:
|
||||
return v_cast<QPixmap>(a)->cacheKey() == v_cast<QPixmap>(b)->cacheKey();
|
||||
case QVariant::Image:
|
||||
return *v_cast<QImage>(a) == *v_cast<QImage>(b);
|
||||
case QVariant::Brush:
|
||||
return *v_cast<QBrush>(a) == *v_cast<QBrush>(b);
|
||||
case QVariant::Color:
|
||||
return *v_cast<QColor>(a) == *v_cast<QColor>(b);
|
||||
case QVariant::Palette:
|
||||
return *v_cast<QPalette>(a) == *v_cast<QPalette>(b);
|
||||
#ifndef QT_NO_ICON
|
||||
case QVariant::Icon:
|
||||
/* QIcon::operator==() cannot be reasonably implemented for QIcon,
|
||||
* so we always return false. */
|
||||
return false;
|
||||
#endif
|
||||
case QVariant::Matrix:
|
||||
return *v_cast<QMatrix>(a) == *v_cast<QMatrix>(b);
|
||||
case QVariant::Transform:
|
||||
return *v_cast<QTransform>(a) == *v_cast<QTransform>(b);
|
||||
case QVariant::TextFormat:
|
||||
return *v_cast<QTextFormat>(a) == *v_cast<QTextFormat>(b);
|
||||
case QVariant::TextLength:
|
||||
return *v_cast<QTextLength>(a) == *v_cast<QTextLength>(b);
|
||||
#ifndef QT_NO_SHORTCUT
|
||||
case QVariant::KeySequence:
|
||||
return *v_cast<QKeySequence>(a) == *v_cast<QKeySequence>(b);
|
||||
#endif
|
||||
case QVariant::Pen:
|
||||
return *v_cast<QPen>(a) == *v_cast<QPen>(b);
|
||||
#ifndef QT_NO_MATRIX4X4
|
||||
case QVariant::Matrix4x4:
|
||||
return *v_cast<QMatrix4x4>(a) == *v_cast<QMatrix4x4>(b);
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR2D
|
||||
case QVariant::Vector2D:
|
||||
return *v_cast<QVector2D>(a) == *v_cast<QVector2D>(b);
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR3D
|
||||
case QVariant::Vector3D:
|
||||
return *v_cast<QVector3D>(a) == *v_cast<QVector3D>(b);
|
||||
#endif
|
||||
#ifndef QT_NO_VECTOR4D
|
||||
case QVariant::Vector4D:
|
||||
return *v_cast<QVector4D>(a) == *v_cast<QVector4D>(b);
|
||||
#endif
|
||||
#ifndef QT_NO_QUATERNION
|
||||
case QVariant::Quaternion:
|
||||
return *v_cast<QQuaternion>(a) == *v_cast<QQuaternion>(b);
|
||||
#endif
|
||||
case QVariant::SizePolicy:
|
||||
if (qt_widgets_variant_handler)
|
||||
return qt_widgets_variant_handler->compare(a, b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return qcoreVariantHandler()->compare(a, b);
|
||||
QGuiVariantComparator<CoreAndGuiTypesFilter> comparator(a, b);
|
||||
return QMetaTypeSwitcher::switcher<bool>(comparator, a->type, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool convert(const QVariant::Private *d, QVariant::Type t,
|
||||
void *result, bool *ok)
|
||||
{
|
||||
|
@ -106,6 +106,10 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b)
|
||||
{
|
||||
Q_ASSERT(a->type == b->type);
|
||||
switch(a->type) {
|
||||
#ifndef QT_NO_ICON
|
||||
case QVariant::Icon:
|
||||
return false;
|
||||
#endif
|
||||
case QVariant::SizePolicy:
|
||||
return *v_cast<QSizePolicy>(a) == *v_cast<QSizePolicy>(b);
|
||||
default:
|
||||
|
@ -325,6 +325,10 @@ void tst_QVariant::isNull()
|
||||
QVariant var;
|
||||
QVERIFY( var.isNull() );
|
||||
|
||||
QString str1;
|
||||
QVariant var1( str1 );
|
||||
QVERIFY( var1.isNull() );
|
||||
|
||||
QVariant var2( QString::null );
|
||||
QVERIFY( var2.isNull() );
|
||||
|
||||
@ -2017,10 +2021,12 @@ void tst_QVariant::userType()
|
||||
|
||||
QVariant userVar3;
|
||||
qVariantSetValue(userVar3, data2);
|
||||
QVERIFY(userVar2 != userVar3);
|
||||
QVERIFY(userVar2 == userVar3);
|
||||
userVar3 = userVar2;
|
||||
QVERIFY(userVar2 == userVar3);
|
||||
}
|
||||
// At this point all QVariants got destroyed but we have 2 MyType instances.
|
||||
QCOMPARE(instanceCount, 2);
|
||||
{
|
||||
QVariant userVar;
|
||||
qVariantSetValue(userVar, &data);
|
||||
@ -2056,10 +2062,9 @@ void tst_QVariant::userType()
|
||||
QVariant myCarrier;
|
||||
qVariantSetValue(myCarrier, data);
|
||||
QCOMPARE(instanceCount, 3);
|
||||
|
||||
{
|
||||
QVariant second = myCarrier;
|
||||
QCOMPARE(instanceCount, 3);
|
||||
QCOMPARE(instanceCount, 4);
|
||||
second.detach();
|
||||
QCOMPARE(instanceCount, 4);
|
||||
}
|
||||
@ -2103,6 +2108,7 @@ void tst_QVariant::userType()
|
||||
QCOMPARE(qvariant_cast<int>(myCarrier), 42);
|
||||
}
|
||||
|
||||
// At this point all QVariants got destroyed and MyType objects too.
|
||||
QCOMPARE(instanceCount, 0);
|
||||
}
|
||||
|
||||
@ -2701,7 +2707,7 @@ void tst_QVariant::task172061_invalidDate() const
|
||||
|
||||
struct WontCompare
|
||||
{
|
||||
int x;
|
||||
int x,y,z,q,w,e,r,t;
|
||||
};
|
||||
Q_DECLARE_METATYPE(WontCompare);
|
||||
|
||||
@ -2952,7 +2958,12 @@ template<class T> void playWithVariant(const T &orig, bool isNull, const QString
|
||||
|
||||
{
|
||||
QVariant v2 = v;
|
||||
if (!(QTypeInfo<T>::isStatic && QTypeInfo<T>::isComplex)) {
|
||||
// Type is movable so standard comparison algorithm in QVariant should work
|
||||
// In a custom type QVariant is not aware of ==operator so it won't be called,
|
||||
// which may cause problems especially visible when using a not-movable type
|
||||
QCOMPARE(v2, v);
|
||||
}
|
||||
QVERIFY(v2.isValid());
|
||||
QCOMPARE(v2.isNull(), isNull);
|
||||
QCOMPARE(v2.toString(), toString);
|
||||
@ -2964,7 +2975,12 @@ template<class T> void playWithVariant(const T &orig, bool isNull, const QString
|
||||
v = QVariant();
|
||||
QCOMPARE(v3, v);
|
||||
v = v2;
|
||||
QCOMPARE(v, v2);
|
||||
if (!(QTypeInfo<T>::isStatic && QTypeInfo<T>::isComplex)) {
|
||||
// Type is movable so standard comparison algorithm in QVariant should work
|
||||
// In a custom type QVariant is not aware of ==operator so it won't be called,
|
||||
// which may cause problems especially visible when using a not-movable type
|
||||
QCOMPARE(v2, v);
|
||||
}
|
||||
QCOMPARE(qvariant_cast<T>(v2), qvariant_cast<T>(v));
|
||||
QCOMPARE(v2.toString(), toString);
|
||||
v3 = qVariantFromValue(orig);
|
||||
|
@ -80,8 +80,10 @@ void tst_Cmptest::compare_pointerfuncs()
|
||||
|
||||
Q_DECLARE_METATYPE(QVariant)
|
||||
|
||||
class PhonyClass
|
||||
{};
|
||||
struct PhonyClass
|
||||
{
|
||||
int i;
|
||||
};
|
||||
|
||||
void tst_Cmptest::compare_tostring_data()
|
||||
{
|
||||
@ -108,9 +110,11 @@ void tst_Cmptest::compare_tostring_data()
|
||||
<< QVariant(QVariant::Type(qRegisterMetaType<PhonyClass>("PhonyClass")))
|
||||
;
|
||||
|
||||
PhonyClass fake1 = {1};
|
||||
PhonyClass fake2 = {2};
|
||||
QTest::newRow("both non-null user type")
|
||||
<< QVariant(qRegisterMetaType<PhonyClass>("PhonyClass"), (const void*)0)
|
||||
<< QVariant(qRegisterMetaType<PhonyClass>("PhonyClass"), (const void*)0)
|
||||
<< QVariant(qRegisterMetaType<PhonyClass>("PhonyClass"), (const void*)&fake1)
|
||||
<< QVariant(qRegisterMetaType<PhonyClass>("PhonyClass"), (const void*)&fake2)
|
||||
;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user