summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.cpp
diff options
context:
space:
mode:
authorJędrzej Nowacki <jedrzej.nowacki@nokia.com>2011-10-12 17:32:26 +0200
committerQt by Nokia <qt-info@nokia.com>2011-11-09 10:11:34 +0100
commit8fd64d22ac7892b061a09c42c72aacf033b80876 (patch)
tree9c0d04049188ad5ff726419279ee88c3fdd0d1bf /src/corelib/kernel/qvariant.cpp
parent2b39be6dd5d111482e5df06ac6dea18ca338d9f0 (diff)
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>
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r--src/corelib/kernel/qvariant.cpp461
1 files changed, 48 insertions, 413 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;