Automatic metatype registration of two-template-argument types.
authorStephen Kelly <stephen.kelly@kdab.com>
Wed, 29 Feb 2012 14:07:12 +0000 (15:07 +0100)
committerQt by Nokia <qt-info@nokia.com>
Fri, 2 Mar 2012 12:22:54 +0000 (13:22 +0100)
This commit is complimentary to the commit which introduced a similar
partial specialization for single template argument types:
6b4f8a68c8da1af7c5be7dc6075b688c9d6ca55f

If T and U are available as metatypes, then QHash<T, U> is too.

Change-Id: I09097b954666418b424c8c23577032beb814343a
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
src/corelib/kernel/qmetatype.h
tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp

index beb7294..f969875 100644 (file)
@@ -565,6 +565,7 @@ template <class T> class QSet;
 template <class T> class QSharedPointer;
 template <class T1, class T2> class QMap;
 template <class T1, class T2> class QHash;
+template <class T1, class T2> struct QPair;
 typedef QList<QVariant> QVariantList;
 typedef QMap<QString, QVariant> QVariantMap;
 typedef QHash<QString, QVariant> QVariantHash;
@@ -586,6 +587,23 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
     } \
 };
 
+#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
+template<typename T, typename U> \
+struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
+{ \
+    enum { \
+        Defined = QMetaTypeId2<T>::Defined && QMetaTypeId2<U>::Defined \
+    }; \
+    static int qt_metatype_id() \
+    { \
+        static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+        if (!metatype_id.load()) \
+            metatype_id.storeRelease(qRegisterMetaType< DOUBLE_ARG_TEMPLATE<T, U> >( QByteArray(QByteArray(#DOUBLE_ARG_TEMPLATE "<") + QMetaType::typeName(qMetaTypeId<T>()) + ", " + QMetaType::typeName(qMetaTypeId<U>()) + ">").constData(), \
+                        reinterpret_cast< DOUBLE_ARG_TEMPLATE<T, U> *>(quintptr(-1)))); \
+        return metatype_id.loadAcquire(); \
+    } \
+};
+
 Q_DECLARE_METATYPE_TEMPLATE_1ARG(QList)
 Q_DECLARE_METATYPE_TEMPLATE_1ARG(QVector)
 Q_DECLARE_METATYPE_TEMPLATE_1ARG(QQueue)
@@ -594,6 +612,10 @@ Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSet)
 Q_DECLARE_METATYPE_TEMPLATE_1ARG(QSharedPointer)
 Q_DECLARE_METATYPE_TEMPLATE_1ARG(QLinkedList)
 
+Q_DECLARE_METATYPE_TEMPLATE_2ARG(QHash)
+Q_DECLARE_METATYPE_TEMPLATE_2ARG(QMap)
+Q_DECLARE_METATYPE_TEMPLATE_2ARG(QPair)
+
 inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
                             Creator creator,
                             Deleter deleter,
index 06919c6..f8403f1 100644 (file)
@@ -1053,6 +1053,61 @@ void tst_QMetaType::registerStreamBuiltin()
 
 Q_DECLARE_METATYPE(QSharedPointer<QObject>)
 
+typedef QHash<int, uint> IntUIntHash;
+Q_DECLARE_METATYPE(IntUIntHash)
+typedef QMap<int, uint> IntUIntMap;
+Q_DECLARE_METATYPE(IntUIntMap)
+typedef QPair<int, uint> IntUIntPair;
+Q_DECLARE_METATYPE(IntUIntPair)
+
+struct CustomComparable
+{
+  CustomComparable(int i_ = 0) :i(i_) { }
+  bool operator==(const CustomComparable &other) const
+  {
+      return i == other.i;
+  }
+  int i;
+};
+
+struct UnregisteredType {};
+
+typedef QHash<int, CustomComparable> IntComparableHash;
+Q_DECLARE_METATYPE(IntComparableHash)
+typedef QMap<int, CustomComparable> IntComparableMap;
+Q_DECLARE_METATYPE(IntComparableMap)
+typedef QPair<int, CustomComparable> IntComparablePair;
+Q_DECLARE_METATYPE(IntComparablePair)
+
+typedef QHash<int, int> IntIntHash;
+typedef int NaturalNumber;
+class AutoMetaTypeObject : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(IntIntHash someHash READ someHash CONSTANT)
+    Q_PROPERTY(NaturalNumber someInt READ someInt CONSTANT)
+public:
+    AutoMetaTypeObject(QObject *parent = 0)
+      : QObject(parent), m_int(42)
+    {
+        m_hash.insert(4, 2);
+    }
+
+    QHash<int,int> someHash() const
+    {
+        return m_hash;
+    }
+
+    int someInt() const
+    {
+        return m_int;
+    }
+
+private:
+    QHash<int,int> m_hash;
+    int m_int;
+};
+
 void tst_QMetaType::automaticTemplateRegistration()
 {
   {
@@ -1094,6 +1149,84 @@ void tst_QMetaType::automaticTemplateRegistration()
     vectorList << sharedPointerList;
     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QSharedPointer<QObject> > > >().first().first() == testObject);
   }
+  {
+    IntIntHash intIntHash;
+    intIntHash.insert(4, 2);
+    QCOMPARE(QVariant::fromValue(intIntHash).value<IntIntHash>().value(4), 2);
+
+    AutoMetaTypeObject amto;
+
+    qRegisterMetaType<QHash<int, int> >("IntIntHash");
+    QVariant hashVariant = amto.property("someHash");
+    QCOMPARE(hashVariant.value<IntIntHash>().value(4), 2);
+
+    qRegisterMetaType<int>("NaturalNumber");
+    QVariant intVariant = amto.property("someInt");
+    QCOMPARE(intVariant.value<NaturalNumber>(), 42);
+  }
+  {
+    IntUIntHash intUIntHash;
+    intUIntHash.insert(4, 2);
+    QCOMPARE(QVariant::fromValue(intUIntHash).value<IntUIntHash>().value(4), (uint)2);
+  }
+  {
+    IntComparableHash intComparableHash;
+    CustomComparable m;
+    intComparableHash.insert(4, m);
+    QCOMPARE(QVariant::fromValue(intComparableHash).value<IntComparableHash>().value(4), m);
+  }
+  {
+    QVariantHash variantHash;
+    variantHash.insert(QStringLiteral("4"), 2);
+    QCOMPARE(QVariant::fromValue(variantHash).value<QVariantHash>().value(QStringLiteral("4")), QVariant(2));
+  }
+  {
+    typedef QMap<int, int> IntIntMap;
+    IntIntMap intIntMap;
+    intIntMap.insert(4, 2);
+    QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>().value(4), 2);
+  }
+  {
+    IntUIntMap intUIntMap;
+    intUIntMap.insert(4, 2);
+    QCOMPARE(QVariant::fromValue(intUIntMap).value<IntUIntMap>().value(4), (uint)2);
+  }
+  {
+    IntComparableMap intComparableMap;
+    CustomComparable m;
+    intComparableMap.insert(4, m);
+    QCOMPARE(QVariant::fromValue(intComparableMap).value<IntComparableMap>().value(4), m);
+  }
+  {
+    QVariantMap variantMap;
+    variantMap.insert(QStringLiteral("4"), 2);
+    QCOMPARE(QVariant::fromValue(variantMap).value<QVariantMap>().value(QStringLiteral("4")), QVariant(2));
+  }
+  {
+    typedef QPair<int, int> IntIntPair;
+    IntIntPair intIntPair = qMakePair(4, 2);
+    QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
+    QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2);
+  }
+  {
+    IntUIntPair intUIntPair = qMakePair<int, uint>(4, 2);
+    QCOMPARE(QVariant::fromValue(intUIntPair).value<IntUIntPair>().first, 4);
+    QCOMPARE(QVariant::fromValue(intUIntPair).value<IntUIntPair>().second, (uint)2);
+  }
+  {
+    CustomComparable m;
+    IntComparablePair intComparablePair = qMakePair(4, m);
+    QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().first, 4);
+    QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().second, m);
+  }
+  {
+    typedef QHash<int, UnregisteredType> IntUnregisteredTypeHash;
+    QVERIFY(qRegisterMetaType<IntUnregisteredTypeHash>("IntUnregisteredTypeHash") > 0);
+  }
+  {
+    typedef QList<UnregisteredType> UnregisteredTypeList;
+    QVERIFY(qRegisterMetaType<UnregisteredTypeList>("UnregisteredTypeList") > 0);
+  }
 }
 
 // Compile-time test, it should be possible to register function pointer types