Refactor QVariant handlers.
authorJędrzej Nowacki <jedrzej.nowacki@nokia.com>
Tue, 29 Nov 2011 14:42:33 +0000 (15:42 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 4 Jan 2012 13:25:25 +0000 (14:25 +0100)
QVariant implementation is based on delegation to a handler. The handler
has rather simple construction, it is a set of function that implements
a switch statement over known types and redirects calls to a right
method of an encapsulated types instance. Unfortunately after qt
modularization project, it is not easy to use types directly from
different modules, as they can be undefined or completely unaccessible.
Which means that each module has to implement own handler to cooperate
correctly with QVariant. We can suspect that list of modules known to
QVariant will grow and it is not limited to GUI, Widgets and Core,
therefore it would be nice to have an unified, from performance and
source code point of view, way of working with handlers.

This patch is an attempt to cleanup handlers. Keynotes:
- Each handler is working only on types defined in the same module
- Core handler implements handling of primitive types too
- Custom types have an own handler
- Each handler is independent which means that dispatch between handlers
  is done on QVariant level
- Handlers might be registered / unregistered using same interface

Change-Id: Ib096df65e2c4ce464bc7a684aade5af7d1264c24
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
src/corelib/kernel/qmetatype_p.h
src/corelib/kernel/qvariant.cpp
src/corelib/kernel/qvariant.h
src/corelib/kernel/qvariant_p.h
src/gui/kernel/qguivariant.cpp
src/widgets/kernel/qwidgetsvariant.cpp
tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp

index 46c5697..391f37c 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-enum { /* TYPEMODULEINFO flags */
-    Q_CORE_TYPE = 1,
-    Q_GUI_TYPE = 2,
-    Q_WIDGET_TYPE = 3
-};
+namespace QModulesPrivate {
+enum Names { Core, Gui, Widgets, Unknown, ModulesCount /* ModulesCount has to be at the end */ };
+
+static inline int moduleForType(const int typeId)
+{
+    if (typeId <= QMetaType::LastCoreType)
+        return Core;
+    if (typeId <= QMetaType::LastGuiType)
+        return Gui;
+    if (typeId <= QMetaType::LastWidgetsType)
+        return Widgets;
+    if (typeId <= QMetaType::LastCoreExtType)
+        return Core;
+    return Unknown;
+}
+}
 
 template <typename T>
 class QTypeModuleInfo
@@ -73,7 +84,6 @@ public:
         IsGui = false,
         IsUnknown = !IsCore
     };
-    static inline int module() { return IsCore ? Q_CORE_TYPE : 0; }
 };
 
 #define QT_ASSIGN_TYPE_TO_MODULE(TYPE, MODULE) \
@@ -82,9 +92,9 @@ class QTypeModuleInfo<TYPE > \
 { \
 public: \
     enum Module { \
-        IsCore = (((MODULE) == (Q_CORE_TYPE))), \
-        IsWidget = (((MODULE) == (Q_WIDGET_TYPE))), \
-        IsGui = (((MODULE) == (Q_GUI_TYPE))), \
+        IsCore = (((MODULE) == (QModulesPrivate::Core))), \
+        IsWidget = (((MODULE) == (QModulesPrivate::Widgets))), \
+        IsGui = (((MODULE) == (QModulesPrivate::Gui))), \
         IsUnknown = !(IsCore || IsWidget || IsGui) \
     }; \
     static inline int module() { return MODULE; } \
@@ -96,11 +106,11 @@ public: \
 
 
 #define QT_DECLARE_CORE_MODULE_TYPES_ITER(TypeName, TypeId, Name) \
-    QT_ASSIGN_TYPE_TO_MODULE(Name, Q_CORE_TYPE);
+    QT_ASSIGN_TYPE_TO_MODULE(Name, QModulesPrivate::Core);
 #define QT_DECLARE_GUI_MODULE_TYPES_ITER(TypeName, TypeId, Name) \
-    QT_ASSIGN_TYPE_TO_MODULE(Name, Q_GUI_TYPE);
+    QT_ASSIGN_TYPE_TO_MODULE(Name, QModulesPrivate::Gui);
 #define QT_DECLARE_WIDGETS_MODULE_TYPES_ITER(TypeName, TypeId, Name) \
-    QT_ASSIGN_TYPE_TO_MODULE(Name, Q_WIDGET_TYPE);
+    QT_ASSIGN_TYPE_TO_MODULE(Name, QModulesPrivate::Widgets);
 
 QT_FOR_EACH_STATIC_CORE_CLASS(QT_DECLARE_CORE_MODULE_TYPES_ITER)
 QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_DECLARE_CORE_MODULE_TYPES_ITER)
index 2971739..f898cc4 100644 (file)
@@ -74,6 +74,25 @@ QT_BEGIN_NAMESPACE
 #endif
 
 namespace {
+class HandlersManager
+{
+    static const QVariant::Handler *Handlers[QModulesPrivate::ModulesCount];
+public:
+    const QVariant::Handler *operator[] (const int typeId) const
+    {
+        return Handlers[QModulesPrivate::moduleForType(typeId)];
+    }
+
+    void registerHandler(const QModulesPrivate::Names name, const QVariant::Handler *handler)
+    {
+        Handlers[name] = handler;
+    }
+
+    inline void unregisterHandler(const QModulesPrivate::Names name);
+};
+}  // namespace
+
+namespace {
 template<typename T>
 struct TypeDefiniton {
     static const bool IsAvailable = true;
@@ -100,7 +119,9 @@ struct CoreTypesFilter {
         static const bool IsAccepted = QTypeModuleInfo<T>::IsCore && TypeDefiniton<T>::IsAvailable;
     };
 };
-} // namspace
+} // annonymous used to hide TypeDefiniton
+
+namespace { // annonymous used to hide QVariant handlers
 
 static void construct(QVariant::Private *x, const void *copy)
 {
@@ -813,13 +834,142 @@ const QVariant::Handler qt_kernel_variant_handler = {
 #endif
 };
 
+static void dummyConstruct(QVariant::Private *, const void *) { Q_ASSERT_X(false, "QVariant", "Trying to construct an unknown type"); }
+static void dummyClear(QVariant::Private *) { Q_ASSERT_X(false, "QVariant", "Trying to clear an unknown type"); }
+static bool dummyIsNull(const QVariant::Private *d) { Q_ASSERT_X(false, "QVariant::isNull", "Trying to call isNull on an unknown type"); return d->is_null; }
+static bool dummyCompare(const QVariant::Private *, const QVariant::Private *) { Q_ASSERT_X(false, "QVariant", "Trying to compare an unknown types"); return false; }
+static bool dummyConvert(const QVariant::Private *, QVariant::Type , void *, bool *) { Q_ASSERT_X(false, "QVariant", "Trying to convert an unknown type"); return false; }
+#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
+static void dummyStreamDebug(QDebug, const QVariant &) { Q_ASSERT_X(false, "QVariant", "Trying to convert an unknown type"); }
+#endif
+const QVariant::Handler qt_dummy_variant_handler = {
+    dummyConstruct,
+    dummyClear,
+    dummyIsNull,
+#ifndef QT_NO_DATASTREAM
+    0,
+    0,
+#endif
+    dummyCompare,
+    dummyConvert,
+    0,
+#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
+    dummyStreamDebug
+#else
+    0
+#endif
+};
+
+static void customConstruct(QVariant::Private *d, const void *copy)
+{
+    const uint size = QMetaType::sizeOf(d->type);
+    if (!size) {
+        d->type = QVariant::Invalid;
+        return;
+    }
+
+    // this logic should match with QVariantIntegrator::CanUseInternalSpace
+    if (size <= sizeof(QVariant::Private::Data)
+            && (QMetaType::typeFlags(d->type) & QMetaType::MovableType)) {
+        QMetaType::construct(d->type, &d->data.ptr, copy);
+        d->is_shared = false;
+    } else {
+        void *ptr = QMetaType::create(d->type, copy);
+        d->is_shared = true;
+        d->data.shared = new QVariant::PrivateShared(ptr);
+    }
+}
+
+static void customClear(QVariant::Private *d)
+{
+    if (!d->is_shared) {
+        QMetaType::destruct(d->type, &d->data.ptr);
+    } else {
+        QMetaType::destroy(d->type, d->data.shared->ptr);
+        delete d->data.shared;
+    }
+}
+
+static bool customIsNull(const QVariant::Private *d)
+{
+    return d->is_null;
+}
+
+static bool customCompare(const QVariant::Private *a, const QVariant::Private *b)
+{
+    const char *const typeName = QMetaType::typeName(a->type);
+    if (Q_UNLIKELY(!typeName) && Q_LIKELY(!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);
+
+    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 !memcmp(a_ptr, b_ptr, QMetaType::sizeOf(a->type));
+}
+
+static bool customConvert(const QVariant::Private *, QVariant::Type, void *, bool *ok)
+{
+    if (ok)
+        *ok = false;
+    return false;
+}
+
+#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
+static void customStreamDebug(QDebug, const QVariant &) {}
+#endif
+
+const QVariant::Handler qt_custom_variant_handler = {
+    customConstruct,
+    customClear,
+    customIsNull,
+#ifndef QT_NO_DATASTREAM
+    0,
+    0,
+#endif
+    customCompare,
+    customConvert,
+    0,
+#if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
+    customStreamDebug
+#else
+    0
+#endif
+};
+
+} // annonymous used to hide QVariant handlers
+
+static HandlersManager handlerManager;
+Q_STATIC_ASSERT_X(!QModulesPrivate::Core, "Initialization assumes that ModulesNames::Core is 0");
+const QVariant::Handler *HandlersManager::Handlers[QModulesPrivate::ModulesCount]
+                                        = { &qt_kernel_variant_handler, &qt_dummy_variant_handler,
+                                            &qt_dummy_variant_handler, &qt_custom_variant_handler };
+
 Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler()
 {
     return &qt_kernel_variant_handler;
 }
 
+inline void HandlersManager::unregisterHandler(const QModulesPrivate::Names name)
+{
+    Handlers[name] = &qt_dummy_variant_handler;
+}
 
-const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
+Q_CORE_EXPORT void QVariantPrivate::registerHandler(const int /* Modules::Names */name, const QVariant::Handler *handler)
+{
+    handlerManager.registerHandler(static_cast<QModulesPrivate::Names>(name), handler);
+}
+
+Q_CORE_EXPORT void QVariantPrivate::unregisterHandler(const int /* Modules::Names */ name)
+{
+    handlerManager.unregisterHandler(static_cast<QModulesPrivate::Names>(name));
+}
 
 /*!
     \class QVariant
@@ -1018,7 +1168,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler;
 void QVariant::create(int type, const void *copy)
 {
     d.type = type;
-    handler->construct(&d, copy);
+    handlerManager[type]->construct(&d, copy);
 }
 
 /*!
@@ -1035,7 +1185,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))
-        handler->clear(&d);
+        handlerManager[d.type]->clear(&d);
 }
 
 /*!
@@ -1051,7 +1201,7 @@ QVariant::QVariant(const QVariant &p)
     if (d.is_shared) {
         d.data.shared->ref.ref();
     } else if (p.d.type > Char) {
-        handler->construct(&d, p.constData());
+        handlerManager[d.type]->construct(&d, p.constData());
         d.is_null = p.d.is_null;
     }
 }
@@ -1435,7 +1585,7 @@ QVariant& QVariant::operator=(const QVariant &variant)
         d = variant.d;
     } else if (variant.d.type > Char) {
         d.type = variant.d.type;
-        handler->construct(&d, variant.constData());
+        handlerManager[d.type]->construct(&d, variant.constData());
         d.is_null = variant.d.is_null;
     } else {
         d = variant.d;
@@ -1465,9 +1615,9 @@ void QVariant::detach()
 
     Private dd;
     dd.type = d.type;
-    handler->construct(&dd, constData());
+    handlerManager[d.type]->construct(&dd, constData());
     if (!d.data.shared->ref.deref())
-        handler->clear(&d);
+        handlerManager[d.type]->clear(&d);
     d.data.shared = dd.data.shared;
 }
 
@@ -1496,7 +1646,7 @@ const char *QVariant::typeName() const
 void QVariant::clear()
 {
     if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared && d.type > Char))
-        handler->clear(&d);
+        handlerManager[d.type]->clear(&d);
     d.type = Invalid;
     d.is_null = true;
     d.is_shared = false;
@@ -1732,14 +1882,13 @@ QDataStream& operator<<(QDataStream &s, const QVariant::Type p)
 */
 
 template <typename T>
-inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t,
-                          const QVariant::Handler *handler, T * = 0)
+inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t, const HandlersManager &handler)
 {
     if (d.type == t)
         return *v_cast<T>(&d);
 
     T ret;
-    handler->convert(&d, t, &ret, 0);
+    handler[d.type]->convert(&d, t, &ret, 0);
     return ret;
 }
 
@@ -1754,7 +1903,7 @@ inline T qVariantToHelper(const QVariant::Private &d, QVariant::Type t,
 */
 QStringList QVariant::toStringList() const
 {
-    return qVariantToHelper<QStringList>(d, StringList, handler);
+    return qVariantToHelper<QStringList>(d, StringList, handlerManager);
 }
 
 /*!
@@ -1767,7 +1916,7 @@ QStringList QVariant::toStringList() const
 */
 QString QVariant::toString() const
 {
-    return qVariantToHelper<QString>(d, String, handler);
+    return qVariantToHelper<QString>(d, String, handlerManager);
 }
 
 /*!
@@ -1778,7 +1927,7 @@ QString QVariant::toString() const
 */
 QVariantMap QVariant::toMap() const
 {
-    return qVariantToHelper<QVariantMap>(d, Map, handler);
+    return qVariantToHelper<QVariantMap>(d, Map, handlerManager);
 }
 
 /*!
@@ -1789,7 +1938,7 @@ QVariantMap QVariant::toMap() const
 */
 QVariantHash QVariant::toHash() const
 {
-    return qVariantToHelper<QVariantHash>(d, Hash, handler);
+    return qVariantToHelper<QVariantHash>(d, Hash, handlerManager);
 }
 
 /*!
@@ -1805,7 +1954,7 @@ QVariantHash QVariant::toHash() const
 */
 QDate QVariant::toDate() const
 {
-    return qVariantToHelper<QDate>(d, Date, handler);
+    return qVariantToHelper<QDate>(d, Date, handlerManager);
 }
 
 /*!
@@ -1821,7 +1970,7 @@ QDate QVariant::toDate() const
 */
 QTime QVariant::toTime() const
 {
-    return qVariantToHelper<QTime>(d, Time, handler);
+    return qVariantToHelper<QTime>(d, Time, handlerManager);
 }
 
 /*!
@@ -1838,7 +1987,7 @@ QTime QVariant::toTime() const
 */
 QDateTime QVariant::toDateTime() const
 {
-    return qVariantToHelper<QDateTime>(d, DateTime, handler);
+    return qVariantToHelper<QDateTime>(d, DateTime, handlerManager);
 }
 
 /*!
@@ -1853,7 +2002,7 @@ QDateTime QVariant::toDateTime() const
 #ifndef QT_BOOTSTRAPPED
 QEasingCurve QVariant::toEasingCurve() const
 {
-    return qVariantToHelper<QEasingCurve>(d, EasingCurve, handler);
+    return qVariantToHelper<QEasingCurve>(d, EasingCurve, handlerManager);
 }
 #endif
 
@@ -1868,7 +2017,7 @@ QEasingCurve QVariant::toEasingCurve() const
 */
 QByteArray QVariant::toByteArray() const
 {
-    return qVariantToHelper<QByteArray>(d, ByteArray, handler);
+    return qVariantToHelper<QByteArray>(d, ByteArray, handlerManager);
 }
 
 #ifndef QT_NO_GEOM_VARIANT
@@ -1882,7 +2031,7 @@ QByteArray QVariant::toByteArray() const
 */
 QPoint QVariant::toPoint() const
 {
-    return qVariantToHelper<QPoint>(d, Point, handler);
+    return qVariantToHelper<QPoint>(d, Point, handlerManager);
 }
 
 /*!
@@ -1895,7 +2044,7 @@ QPoint QVariant::toPoint() const
 */
 QRect QVariant::toRect() const
 {
-    return qVariantToHelper<QRect>(d, Rect, handler);
+    return qVariantToHelper<QRect>(d, Rect, handlerManager);
 }
 
 /*!
@@ -1908,7 +2057,7 @@ QRect QVariant::toRect() const
 */
 QSize QVariant::toSize() const
 {
-    return qVariantToHelper<QSize>(d, Size, handler);
+    return qVariantToHelper<QSize>(d, Size, handlerManager);
 }
 
 /*!
@@ -1921,7 +2070,7 @@ QSize QVariant::toSize() const
 */
 QSizeF QVariant::toSizeF() const
 {
-    return qVariantToHelper<QSizeF>(d, SizeF, handler);
+    return qVariantToHelper<QSizeF>(d, SizeF, handlerManager);
 }
 
 /*!
@@ -1934,7 +2083,7 @@ QSizeF QVariant::toSizeF() const
 */
 QRectF QVariant::toRectF() const
 {
-    return qVariantToHelper<QRectF>(d, RectF, handler);
+    return qVariantToHelper<QRectF>(d, RectF, handlerManager);
 }
 
 /*!
@@ -1947,7 +2096,7 @@ QRectF QVariant::toRectF() const
 */
 QLineF QVariant::toLineF() const
 {
-    return qVariantToHelper<QLineF>(d, LineF, handler);
+    return qVariantToHelper<QLineF>(d, LineF, handlerManager);
 }
 
 /*!
@@ -1960,7 +2109,7 @@ QLineF QVariant::toLineF() const
 */
 QLine QVariant::toLine() const
 {
-    return qVariantToHelper<QLine>(d, Line, handler);
+    return qVariantToHelper<QLine>(d, Line, handlerManager);
 }
 
 /*!
@@ -1973,7 +2122,7 @@ QLine QVariant::toLine() const
 */
 QPointF QVariant::toPointF() const
 {
-    return qVariantToHelper<QPointF>(d, PointF, handler);
+    return qVariantToHelper<QPointF>(d, PointF, handlerManager);
 }
 
 #endif // QT_NO_GEOM_VARIANT
@@ -1988,7 +2137,7 @@ QPointF QVariant::toPointF() const
 */
 QUrl QVariant::toUrl() const
 {
-    return qVariantToHelper<QUrl>(d, Url, handler);
+    return qVariantToHelper<QUrl>(d, Url, handlerManager);
 }
 
 /*!
@@ -2001,7 +2150,7 @@ QUrl QVariant::toUrl() const
 */
 QLocale QVariant::toLocale() const
 {
-    return qVariantToHelper<QLocale>(d, Locale, handler);
+    return qVariantToHelper<QLocale>(d, Locale, handlerManager);
 }
 
 /*!
@@ -2016,7 +2165,7 @@ QLocale QVariant::toLocale() const
 #ifndef QT_NO_REGEXP
 QRegExp QVariant::toRegExp() const
 {
-    return qVariantToHelper<QRegExp>(d, RegExp, handler);
+    return qVariantToHelper<QRegExp>(d, RegExp, handlerManager);
 }
 #endif
 
@@ -2030,7 +2179,7 @@ QRegExp QVariant::toRegExp() const
 */
 QChar QVariant::toChar() const
 {
-    return qVariantToHelper<QChar>(d, Char, handler);
+    return qVariantToHelper<QChar>(d, Char, handlerManager);
 }
 
 /*!
@@ -2041,12 +2190,12 @@ QChar QVariant::toChar() const
 */
 QBitArray QVariant::toBitArray() const
 {
-    return qVariantToHelper<QBitArray>(d, BitArray, handler);
+    return qVariantToHelper<QBitArray>(d, BitArray, handlerManager);
 }
 
 template <typename T>
 inline T qNumVariantToHelper(const QVariant::Private &d,
-                             const QVariant::Handler *handler, bool *ok, const T& val)
+                             const HandlersManager &handler, bool *ok, const T& val)
 {
     uint t = qMetaTypeId<T>();
     if (ok)
@@ -2054,8 +2203,8 @@ inline T qNumVariantToHelper(const QVariant::Private &d,
     if (d.type == t)
         return val;
 
-    T ret;
-    if (!handler->convert(&d, QVariant::Type(t), &ret, ok) && ok)
+    T ret = 0;
+    if (!handler[d.type]->convert(&d, QVariant::Type(t), &ret, ok) && ok)
         *ok = false;
     return ret;
 }
@@ -2077,7 +2226,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d,
 */
 int QVariant::toInt(bool *ok) const
 {
-    return qNumVariantToHelper<int>(d, handler, ok, d.data.i);
+    return qNumVariantToHelper<int>(d, handlerManager, ok, d.data.i);
 }
 
 /*!
@@ -2097,7 +2246,7 @@ int QVariant::toInt(bool *ok) const
 */
 uint QVariant::toUInt(bool *ok) const
 {
-    return qNumVariantToHelper<uint>(d, handler, ok, d.data.u);
+    return qNumVariantToHelper<uint>(d, handlerManager, ok, d.data.u);
 }
 
 /*!
@@ -2112,7 +2261,7 @@ uint QVariant::toUInt(bool *ok) const
 */
 qlonglong QVariant::toLongLong(bool *ok) const
 {
-    return qNumVariantToHelper<qlonglong>(d, handler, ok, d.data.ll);
+    return qNumVariantToHelper<qlonglong>(d, handlerManager, ok, d.data.ll);
 }
 
 /*!
@@ -2128,7 +2277,7 @@ qlonglong QVariant::toLongLong(bool *ok) const
 */
 qulonglong QVariant::toULongLong(bool *ok) const
 {
-    return qNumVariantToHelper<qulonglong>(d, handler, ok, d.data.ull);
+    return qNumVariantToHelper<qulonglong>(d, handlerManager, ok, d.data.ull);
 }
 
 /*!
@@ -2148,7 +2297,7 @@ bool QVariant::toBool() const
         return d.data.b;
 
     bool res = false;
-    handler->convert(&d, Bool, &res, 0);
+    handlerManager[d.type]->convert(&d, Bool, &res, 0);
 
     return res;
 }
@@ -2165,7 +2314,7 @@ bool QVariant::toBool() const
 */
 double QVariant::toDouble(bool *ok) const
 {
-    return qNumVariantToHelper<double>(d, handler, ok, d.data.d);
+    return qNumVariantToHelper<double>(d, handlerManager, ok, d.data.d);
 }
 
 /*!
@@ -2182,7 +2331,7 @@ double QVariant::toDouble(bool *ok) const
 */
 float QVariant::toFloat(bool *ok) const
 {
-    return qNumVariantToHelper<float>(d, handler, ok, d.data.f);
+    return qNumVariantToHelper<float>(d, handlerManager, ok, d.data.f);
 }
 
 /*!
@@ -2199,7 +2348,7 @@ float QVariant::toFloat(bool *ok) const
 */
 qreal QVariant::toReal(bool *ok) const
 {
-    return qNumVariantToHelper<qreal>(d, handler, ok, d.data.real);
+    return qNumVariantToHelper<qreal>(d, handlerManager, ok, d.data.real);
 }
 
 /*!
@@ -2210,7 +2359,7 @@ qreal QVariant::toReal(bool *ok) const
 */
 QVariantList QVariant::toList() const
 {
-    return qVariantToHelper<QVariantList>(d, List, handler);
+    return qVariantToHelper<QVariantList>(d, List, handlerManager);
 }
 
 
@@ -2418,13 +2567,25 @@ bool QVariant::convert(Type t)
         return false;
 
     bool isOk = true;
-    if (!handler->convert(&oldValue.d, t, data(), &isOk))
+    if (!handlerManager[d.type]->convert(&oldValue.d, t, data(), &isOk))
         isOk = false;
     d.is_null = !isOk;
     return isOk;
 }
 
 /*!
+  \fn convert(const int type, void *ptr) const
+  \internal
+  Created for qvariant_cast() usage
+*/
+bool QVariant::convert(const int type, void *ptr) const
+{
+    Q_ASSERT(type < int(QMetaType::User));
+    return handlerManager[type]->convert(&d, QVariant::Type(type), ptr, 0);
+}
+
+
+/*!
     \fn bool operator==(const QVariant &v1, const QVariant &v2)
 
     \relates QVariant
@@ -2490,7 +2651,7 @@ bool QVariant::cmp(const QVariant &v) const
         if (!v2.canConvert(Type(d.type)) || !v2.convert(Type(d.type)))
             return false;
     }
-    return handler->compare(&d, &v2.d);
+    return handlerManager[d.type]->compare(&d, &v2.d);
 }
 
 /*! \internal
@@ -2520,7 +2681,7 @@ void* QVariant::data()
 */
 bool QVariant::isNull() const
 {
-    return handler->isNull(&d);
+    return handlerManager[d.type]->isNull(&d);
 }
 
 #ifndef QT_NO_DEBUG_STREAM
@@ -2528,7 +2689,7 @@ QDebug operator<<(QDebug dbg, const QVariant &v)
 {
 #ifndef Q_BROKEN_DEBUG_STREAM
     dbg.nospace() << "QVariant(" << v.typeName() << ", ";
-    QVariant::handler->debugStream(dbg, v);
+    handlerManager[v.d.type]->debugStream(dbg, v);
     dbg.nospace() << ')';
     return dbg.space();
 #else
index 02458a0..9b477e5 100644 (file)
@@ -370,19 +370,21 @@ class Q_CORE_EXPORT QVariant
     { return !cmp(v); }
 
 protected:
-    friend inline bool qvariant_cast_helper(const QVariant &, QVariant::Type, void *);
-    friend void qRegisterGuiVariant();
-    friend void qUnregisterGuiVariant();
     friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &);
 #ifndef QT_NO_DEBUG_STREAM
     friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &);
 #endif
     Private d;
-
-    static const Handler *handler;
-
+#ifndef Q_NO_TEMPLATE_FRIENDS
+    template<typename T>
+    friend inline T qvariant_cast(const QVariant &);
+private:
+#else
+public:
+#endif
     void create(int type, const void *copy);
     bool cmp(const QVariant &other) const;
+    bool convert(const int t, void *ptr) const;
 
 private:
     // force compile error, prevent QVariant(bool) to be called
@@ -396,9 +398,6 @@ public:
     inline DataPtr &data_ptr() { return d; }
 };
 
-inline bool qvariant_cast_helper(const QVariant &v, QVariant::Type tp, void *ptr)
-{ return QVariant::handler->convert(&v.d, tp, ptr, 0); }
-
 template <typename T>
 inline QVariant qVariantFromValue(const T &t)
 {
@@ -488,7 +487,7 @@ template<typename T> inline T qvariant_cast(const QVariant &v)
         return *reinterpret_cast<const T *>(v.constData());
     if (vid < int(QMetaType::User)) {
         T t;
-        if (qvariant_cast_helper(v, QVariant::Type(vid), &t))
+        if (v.convert(vid, &t))
             return t;
     }
     return T();
index a90164f..0436e9f 100644 (file)
@@ -58,8 +58,6 @@
 
 #include <QtCore/qglobal.h>
 #include <QtCore/qvariant.h>
-#include <QtCore/private/qmetatype_p.h>
-
 #include "qmetatypeswitcher_p.h"
 
 QT_BEGIN_NAMESPACE
@@ -172,24 +170,7 @@ class QVariantComparator {
     };
     template<typename T>
     struct FilteredComparator<T, /* IsAcceptedType = */ false> {
-        static bool compare(const QVariant::Private *m_a, const QVariant::Private *m_b)
-        {
-            const char *const typeName = QMetaType::typeName(m_a->type);
-            if (Q_UNLIKELY(!typeName) && Q_LIKELY(!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);
-
-            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));
-        }
+        static bool compare(const QVariant::Private *, const QVariant::Private *) { return false; }
     };
 public:
     QVariantComparator(const QVariant::Private *a, const QVariant::Private *b)
@@ -372,22 +353,8 @@ public:
             m_x->is_shared = false;
             return;
         }
-        const uint size = QMetaType::sizeOf(m_x->type);
-        if (!size) {
-            m_x->type = QVariant::Invalid;
-            return;
-        }
-
-        // this logic should match with QVariantIntegrator::CanUseInternalSpace
-        if (size <= sizeof(QVariant::Private::Data)
-                && (QMetaType::typeFlags(m_x->type) & QMetaType::MovableType)) {
-            QMetaType::construct(m_x->type, &m_x->data.ptr, m_copy);
-            m_x->is_shared = false;
-        } else {
-            void *ptr = QMetaType::create(m_x->type, m_copy);
-            m_x->is_shared = true;
-            m_x->data.shared = new QVariant::PrivateShared(ptr);
-        }
+        qWarning("Trying to construct an instance of an invalid type, type id: %i", m_x->type);
+        m_x->type = QVariant::Invalid;
     }
 
     void delegate(const void*)
@@ -436,13 +403,9 @@ public:
 
     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;
-        }
+        if (m_d->type == QVariant::UserType)
+            return;
+        qWarning("Trying to destruct an instance of an invalid type, type id: %i", m_d->type);
     }
     // Ignore nonconstructible type
     void delegate(const void*) {}
@@ -450,6 +413,11 @@ private:
     QVariant::Private *m_d;
 };
 
+namespace QVariantPrivate {
+Q_CORE_EXPORT void registerHandler(const int /* Modules::Names */ name, const QVariant::Handler *handler);
+Q_CORE_EXPORT void unregisterHandler(const int /* Modules::Names */ name);
+}
+
 QT_END_NAMESPACE
 
 #endif // QVARIANT_P_H
index a7f2f83..4510013 100644 (file)
@@ -94,8 +94,6 @@
 
 QT_BEGIN_NAMESPACE
 
-Q_GUI_EXPORT const QVariant::Handler *qt_widgets_variant_handler = 0;
-
 Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
 
 namespace {
@@ -136,53 +134,35 @@ template<> struct TypeDefiniton<QVector4D> { static const bool IsAvailable = fal
 template<> struct TypeDefiniton<QQuaternion> { static const bool IsAvailable = false; };
 #endif
 
-struct CoreAndGuiTypesFilter {
+struct GuiTypesFilter {
     template<typename T>
     struct Acceptor {
-        static const bool IsAccepted = (QTypeModuleInfo<T>::IsCore || QTypeModuleInfo<T>::IsGui) && TypeDefiniton<T>::IsAvailable;
+        static const bool IsAccepted = QTypeModuleInfo<T>::IsGui && TypeDefiniton<T>::IsAvailable;
     };
 };
-} // namespace
+} // namespace used to hide TypeDefinition
 
+namespace {
 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;
-        }
-        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);
-            }
-        }
+    if (Q_UNLIKELY(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;
     }
+    QVariantConstructor<GuiTypesFilter> constructor(x, copy);
+    QMetaTypeSwitcher::switcher<void>(constructor, type, 0);
 }
 
 static void clear(QVariant::Private *d)
 {
-    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;
-        }
-    }
-    QVariantDestructor<CoreAndGuiTypesFilter> destructor(d);
-    QMetaTypeSwitcher::switcher<void>(destructor, type, 0);
+    QVariantDestructor<GuiTypesFilter> destructor(d);
+    QMetaTypeSwitcher::switcher<void>(destructor, d->type, 0);
 }
 
 // This class is a hack that customizes access to QPolygon
@@ -200,7 +180,7 @@ public:
 };
 static bool isNull(const QVariant::Private *d)
 {
-    QGuiVariantIsNull<CoreAndGuiTypesFilter> isNull(d);
+    QGuiVariantIsNull<GuiTypesFilter> isNull(d);
     return QMetaTypeSwitcher::switcher<bool>(isNull, d->type, 0);
 }
 
@@ -215,11 +195,6 @@ public:
     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*)
@@ -241,7 +216,7 @@ public:
 
 static bool compare(const QVariant::Private *a, const QVariant::Private *b)
 {
-    QGuiVariantComparator<CoreAndGuiTypesFilter> comparator(a, b);
+    QGuiVariantComparator<GuiTypesFilter> comparator(a, b);
     return QMetaTypeSwitcher::switcher<bool>(comparator, a->type, 0);
 }
 
@@ -474,8 +449,6 @@ const QVariant::Handler qt_gui_variant_handler = {
 #endif
 };
 
-extern Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper;
-
 #define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \
     QT_METATYPE_INTERFACE_INIT(RealName),
 
@@ -484,19 +457,20 @@ static const QMetaTypeInterface qVariantGuiHelper[] = {
 };
 
 #undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES
+} // namespace used to hide QVariant handler
+
+extern Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper;
 
-static const QVariant::Handler *qt_guivariant_last_handler = 0;
 void qRegisterGuiVariant()
 {
-    qt_guivariant_last_handler = QVariant::handler;
-    QVariant::handler = &qt_gui_variant_handler;
+    QVariantPrivate::registerHandler(QModulesPrivate::Gui, &qt_gui_variant_handler);
     qMetaTypeGuiHelper = qVariantGuiHelper;
 }
 Q_CONSTRUCTOR_FUNCTION(qRegisterGuiVariant)
 
 void qUnregisterGuiVariant()
 {
-    QVariant::handler = qt_guivariant_last_handler;
+    QVariantPrivate::unregisterHandler(QModulesPrivate::Gui);
     qMetaTypeGuiHelper = 0;
 }
 Q_DESTRUCTOR_FUNCTION(qUnregisterGuiVariant)
index 97a8238..92c8d9e 100644 (file)
@@ -49,7 +49,7 @@
 
 QT_BEGIN_NAMESPACE
 
-
+namespace {
 static void construct(QVariant::Private *x, const void *copy)
 {
     switch (x->type) {
@@ -97,10 +97,8 @@ static bool isNull(const QVariant::Private *d)
     case QVariant::Icon:
         return v_cast<QIcon>(d)->isNull();
 #endif
-    default:
-        Q_ASSERT(false);
     }
-    return true;
+    return false;
 }
 
 static bool compare(const QVariant::Private *a, const QVariant::Private *b)
@@ -119,6 +117,15 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b)
     return false;
 }
 
+static bool convert(const QVariant::Private *d, QVariant::Type type, void *result, bool *ok)
+{
+    Q_UNUSED(d);
+    Q_UNUSED(type);
+    Q_UNUSED(result);
+    if (ok)
+        *ok = false;
+    return false;
+}
 
 static const QVariant::Handler widgets_handler = {
     construct,
@@ -129,7 +136,7 @@ static const QVariant::Handler widgets_handler = {
     0,
 #endif
     compare,
-    0,
+    convert,
     0,
 #if !defined(QT_NO_DEBUG_STREAM) && !defined(Q_BROKEN_DEBUG_STREAM)
     0
@@ -138,8 +145,6 @@ static const QVariant::Handler widgets_handler = {
 #endif
 };
 
-extern Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeWidgetsHelper;
-
 #define QT_IMPL_METATYPEINTERFACE_WIDGETS_TYPES(MetaTypeName, MetaTypeId, RealName) \
     QT_METATYPE_INTERFACE_INIT(RealName),
 
@@ -149,18 +154,20 @@ static const QMetaTypeInterface qVariantWidgetsHelper[] = {
 
 #undef QT_IMPL_METATYPEINTERFACE_WIDGETS_TYPES
 
-extern Q_GUI_EXPORT const QVariant::Handler *qt_widgets_variant_handler;
+}  // namespace
+
+extern Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeWidgetsHelper;
 
 void qRegisterWidgetsVariant()
 {
-    qt_widgets_variant_handler = &widgets_handler;
     qMetaTypeWidgetsHelper = qVariantWidgetsHelper;
+    QVariantPrivate::registerHandler(QModulesPrivate::Widgets, &widgets_handler);
 }
 Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant)
 
 void qUnregisterWidgetsVariant()
 {
-    qt_widgets_variant_handler = 0;
+    QVariantPrivate::unregisterHandler(QModulesPrivate::Widgets);
     qMetaTypeWidgetsHelper = 0;
 }
 Q_DESTRUCTOR_FUNCTION(qUnregisterWidgetsVariant)
index 9404130..d615361 100644 (file)
@@ -1376,8 +1376,29 @@ void tst_QVariant::quaternion()
     QMetaType::destroy(QVariant::Quaternion, pquaternion);
 }
 
+struct CustomStreamableClass
+{
+    int i;
+    bool operator==(const CustomStreamableClass& other) const
+    {
+        return i == other.i;
+    }
+};
+Q_DECLARE_METATYPE(CustomStreamableClass);
+
+QDataStream &operator<<(QDataStream &out, const CustomStreamableClass &myObj)
+{
+    return out << myObj.i;
+}
+
+QDataStream &operator>>(QDataStream &in, CustomStreamableClass &myObj)
+{
+    return in >> myObj.i;
+}
+
 void tst_QVariant::writeToReadFromDataStream_data()
 {
+    qRegisterMetaTypeStreamOperators<CustomStreamableClass>();
 
     QTest::addColumn<QVariant>("writeVariant");
     QTest::addColumn<bool>("isNull");
@@ -1484,6 +1505,8 @@ void tst_QVariant::writeToReadFromDataStream_data()
     QTest::newRow("QMetaType::Float invalid") << QVariant(QMetaType::Float, (void *) 0) << false;
     float f = 1.234f;
     QTest::newRow("QMetaType::Float") << QVariant(QMetaType::Float, &f) << false;
+    CustomStreamableClass custom = {123};
+    QTest::newRow("Custom type") << QVariant::fromValue(custom) << false;
 }
 
 void tst_QVariant::writeToReadFromDataStream()
@@ -1502,8 +1525,10 @@ void tst_QVariant::writeToReadFromDataStream()
     // Best way to confirm the readVariant contains the same data?
     // Since only a few won't match since the serial numbers are different
     // I won't bother adding another bool in the data test.
-    QVariant::Type writeType = writeVariant.type();
-    if ( writeType != QVariant::Invalid && writeType != QVariant::Bitmap && writeType != QVariant::Pixmap
+    const int writeType = writeVariant.userType();
+    if (writeType == qMetaTypeId<CustomStreamableClass>())
+        QCOMPARE(qvariant_cast<CustomStreamableClass>(readVariant), qvariant_cast<CustomStreamableClass>(writeVariant));
+    else if ( writeType != QVariant::Invalid && writeType != QVariant::Bitmap && writeType != QVariant::Pixmap
         && writeType != QVariant::Image) {
         switch (writeType) {
         default:
@@ -1563,6 +1588,7 @@ void tst_QVariant::writeToReadFromOldDataStream()
 
 void tst_QVariant::checkDataStream()
 {
+    QTest::ignoreMessage(QtWarningMsg, "Trying to construct an instance of an invalid type, type id: 46");
     const QByteArray settingsHex("0000002effffffffff");
     const QByteArray settings = QByteArray::fromHex(settingsHex);
     QDataStream in(settings);