summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qvariant.cpp461
-rw-r--r--src/corelib/kernel/qvariant.h5
-rw-r--r--src/corelib/kernel/qvariant_p.h292
-rw-r--r--src/gui/kernel/qguivariant.cpp447
-rw-r--r--src/widgets/kernel/qwidgetsvariant.cpp4
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp28
-rw-r--r--tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp12
7 files changed, 521 insertions, 728 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 470be1c0b0..894ebcbb80 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -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
-static void construct(QVariant::Private *x, const void *copy)
-{
- x->is_shared = false;
+template<typename T>
+struct TypeDefiniton {
+ static const bool IsAvailable = true;
+};
- 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;
+// Ignore these types, as incomplete
+#ifdef QT_BOOTSTRAPPED
+template<> struct TypeDefiniton<QEasingCurve> { static const bool IsAvailable = false; };
#endif
-#ifndef QT_BOOTSTRAPPED
- case QVariant::EasingCurve:
- v_construct<QEasingCurve>(x, copy);
- break;
+#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
- 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;
-}
-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;
- }
+struct CoreTypesFilter {
+ template<typename T>
+ struct Acceptor {
+ static const bool IsAccepted = QTypeModuleInfo<T>::IsCore && TypeDefiniton<T>::IsAvailable;
+ };
+};
- d->type = QVariant::Invalid;
- d->is_null = true;
- d->is_shared = false;
+static void construct(QVariant::Private *x, const void *copy)
+{
+ QVariantConstructor<CoreTypesFilter> constructor(x, copy);
+ QMetaTypeSwitcher::switcher<void>(constructor, x->type, 0);
}
-static bool isNull(const QVariant::Private *d)
+static void clear(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;
+ QVariantDestructor<CoreTypesFilter> cleaner(d);
+ QMetaTypeSwitcher::switcher<void>(cleaner, d->type, 0);
}
-/*
- \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)
+static bool isNull(const QVariant::Private *d)
{
- 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;
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index fbf5a84d3e..ee1a2add54 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -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;
diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h
index 98a7bcbf57..aa03bb298a 100644
--- a/src/corelib/kernel/qvariant_p.h
+++ b/src/corelib/kernel/qvariant_p.h
@@ -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
diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp
index 72f7e183e1..2bb7524ab9 100644
--- a/src/gui/kernel/qguivariant.cpp
+++ b/src/gui/kernel/qguivariant.cpp
@@ -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,339 +98,150 @@ Q_GUI_EXPORT const QVariant::Handler *qt_widgets_variant_handler = 0;
Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
-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;
+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
- case QVariant::Pen:
- v_construct<QPen>(x, copy);
- break;
-#ifndef QT_NO_CURSOR
- case QVariant::Cursor:
- v_construct<QCursor>(x, copy);
- break;
+#ifdef QT_NO_SHORTCUT
+template<> struct TypeDefiniton<QKeySequence> { static const bool IsAvailable = false; };
#endif
- case 62: {
- // small 'trick' to let a QVariant(Qt::blue) create a variant
- // of type QColor
- x->type = QVariant::Color;
- QColor color(*reinterpret_cast<const Qt::GlobalColor *>(copy));
- v_construct<QColor>(x, &color);
- break;
- }
-#ifndef QT_NO_MATRIX4X4
- case QVariant::Matrix4x4:
- v_construct<QMatrix4x4>(x, copy);
- break;
+#ifdef QT_NO_CURSOR
+template<> struct TypeDefiniton<QCursor> { static const bool IsAvailable = false; };
#endif
-#ifndef QT_NO_VECTOR2D
- case QVariant::Vector2D:
- v_construct<QVector2D>(x, copy);
- break;
+#ifdef QT_NO_MATRIX4X4
+template<> struct TypeDefiniton<QMatrix4x4> { static const bool IsAvailable = false; };
#endif
-#ifndef QT_NO_VECTOR3D
- case QVariant::Vector3D:
- v_construct<QVector3D>(x, copy);
- break;
+#ifdef QT_NO_VECTOR2D
+template<> struct TypeDefiniton<QVector2D> { static const bool IsAvailable = false; };
#endif
-#ifndef QT_NO_VECTOR4D
- case QVariant::Vector4D:
- v_construct<QVector4D>(x, copy);
- break;
+#ifdef QT_NO_VECTOR3D
+template<> struct TypeDefiniton<QVector3D> { static const bool IsAvailable = false; };
#endif
-#ifndef QT_NO_QUATERNION
- case QVariant::Quaternion:
- v_construct<QQuaternion>(x, copy);
- break;
+#ifdef QT_NO_VECTOR4D
+template<> struct TypeDefiniton<QVector4D> { static const bool IsAvailable = false; };
#endif
- case QVariant::SizePolicy:
- case QVariant::Icon:
- if (qt_widgets_variant_handler) {
- qt_widgets_variant_handler->construct(x, copy);
+#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)
+{
+ 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);
return;
}
- break;
- default:
- qcoreVariantHandler()->construct(x, copy);
- return;
+ 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);
+ }
+ }
}
- 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);
}
-static bool compare(const QVariant::Private *a, const QVariant::Private *b)
-{
- Q_ASSERT(a->type == b->type);
- switch(a->type) {
- case QVariant::Cursor:
+// 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
- 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;
+ bool delegate(const QCursor*)
+ {
+ return v_cast<QCursor>(Base::m_a)->shape() == v_cast<QCursor>(Base::m_b)->shape();
}
- return qcoreVariantHandler()->compare(a, b);
-}
-
+#endif
+ bool delegate(const void *p) { return Base::delegate(p); }
+};
+static bool compare(const QVariant::Private *a, const QVariant::Private *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)
diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp
index 1a21d91829..dcffa0e87e 100644
--- a/src/widgets/kernel/qwidgetsvariant.cpp
+++ b/src/widgets/kernel/qwidgetsvariant.cpp
@@ -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:
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index c4fed9088f..21bdfa7791 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -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;
- QCOMPARE(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);
diff --git a/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp b/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp
index 4d38aa1646..70396a75b3 100644
--- a/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp
+++ b/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp
@@ -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)
;
}