Allow QMetaType to register information about movability
authorJędrzej Nowacki <jedrzej.nowacki@nokia.com>
Tue, 13 Dec 2011 11:07:47 +0000 (12:07 +0100)
committerQt by Nokia <qt-info@nokia.com>
Thu, 22 Dec 2011 12:20:40 +0000 (13:20 +0100)
We need that information to perform some optimizations in QVariant.

Change-Id: Id9a1716e49e4cedd17cd09a32fea4ff003ef61f2
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
src/corelib/kernel/qmetatype.cpp
src/corelib/kernel/qmetatype.h
src/corelib/kernel/qmetatype_p.h
tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
tests/auto/gui/kernel/qguimetatype/tst_qguimetatype.cpp

index d5a22ef..02cf9ae 100644 (file)
@@ -240,6 +240,16 @@ template<> struct TypeDefiniton<QRegExp> { static const bool IsAvailable = false
 */
 
 /*!
+    \enum QMetaType::TypeFlags
+
+    The enum describes attributes of a type supported by QMetaType.
+
+    \value NeedsConstruction This type has non-trivial constructors. If the flag is not set instances can be safely initialized with memset to 0.
+    \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set calls to the destructor are not necessary before discarding objects.
+    \value MovableType An instance of a type having this attribute can be safely moved by memcpy.
+*/
+
+/*!
     \class QMetaType
     \brief The QMetaType class manages named types in the meta-object system.
 
@@ -423,7 +433,7 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length)
 int QMetaType::registerType(const char *typeName, Deleter deleter,
                             Creator creator)
 {
-    return registerType(typeName, deleter, creator, 0, 0, 0);
+    return registerType(typeName, deleter, creator, 0, 0, 0, TypeFlags());
 }
 
 /*! \internal
@@ -438,7 +448,7 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
                             Creator creator,
                             Destructor destructor,
                             Constructor constructor,
-                            int size)
+                            int size, TypeFlags flags)
 {
     QVector<QCustomTypeInfo> *ct = customTypes();
     if (!ct || !typeName || !deleter || !creator)
@@ -470,6 +480,7 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
             inf.constructor = constructor;
             inf.destructor = destructor;
             inf.size = size;
+            inf.flags = flags;
             idx = ct->size() + User;
             ct->append(inf);
         }
@@ -1633,6 +1644,73 @@ int QMetaType::sizeOf(int type)
     return QMetaTypeSwitcher::switcher<int>(sizeOf, type, 0);
 }
 
+namespace {
+class Flags
+{
+    template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>
+    struct FlagsImpl
+    {
+        static quint32 Flags(const int)
+        {
+            return (!QTypeInfo<T>::isStatic * QMetaType::MovableType)
+                    | (QTypeInfo<T>::isComplex * QMetaType::NeedsConstruction)
+                    | (QTypeInfo<T>::isComplex * QMetaType::NeedsDestruction);
+        }
+    };
+    template<typename T>
+    struct FlagsImpl<T, /* IsAcceptedType = */ false>
+    {
+        static quint32 Flags(const int type)
+        {
+            return Flags::undefinedTypeFlags(type);
+        }
+    };
+public:
+    Flags(const int type)
+        : m_type(type)
+    {}
+    template<typename T>
+    quint32 delegate(const T*) { return FlagsImpl<T>::Flags(m_type); }
+    quint32 delegate(const QMetaTypeSwitcher::UnknownType*) { return customTypeFlags(m_type); }
+private:
+    const int m_type;
+    static quint32 customTypeFlags(const int type)
+    {
+        const QVector<QCustomTypeInfo> * const ct = customTypes();
+        if (!ct)
+            return 0;
+        QReadLocker locker(customTypesLock());
+        if (ct->count() <= type - QMetaType::User)
+            return 0;
+        return ct->at(type - QMetaType::User).flags;
+    }
+    static quint32 undefinedTypeFlags(const int type);
+};
+
+quint32 Flags::undefinedTypeFlags(const int type)
+{
+    if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType)
+        return qMetaTypeGuiHelper ? qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].flags : 0;
+    else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType)
+        return qMetaTypeWidgetsHelper ? qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].flags : 0;
+    return customTypeFlags(type);
+}
+
+}  // namespace
+
+/*!
+    \since 5.0
+
+    Returns flags of the given \a type.
+
+    \sa TypeFlags()
+*/
+QMetaType::TypeFlags QMetaType::typeFlags(int type)
+{
+    Flags flags(type);
+    return static_cast<QMetaType::TypeFlags>(QMetaTypeSwitcher::switcher<quint32>(flags, type, 0));
+}
+
 /*!
     \fn int qRegisterMetaType(const char *typeName)
     \relates QMetaType
index 717e72c..dd5b1f8 100644 (file)
@@ -202,6 +202,13 @@ public:
         User = 256
     };
 
+    enum TypeFlag {
+        NeedsConstruction = 0x1,
+        NeedsDestruction = 0x2,
+        MovableType = 0x4
+    };
+    Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
+
     typedef void (*Deleter)(void *);
     typedef void *(*Creator)(const void *);
 
@@ -222,11 +229,13 @@ public:
                             Creator creator,
                             Destructor destructor,
                             Constructor constructor,
-                            int size);
+                            int size,
+                            QMetaType::TypeFlags flags);
     static int registerTypedef(const char *typeName, int aliasId);
     static int type(const char *typeName);
     static const char *typeName(int type);
     static int sizeOf(int type);
+    static TypeFlags typeFlags(int type);
     static bool isRegistered(int type);
     static void *create(int type, const void *copy = 0);
 #if QT_DEPRECATED_SINCE(5, 0)
@@ -246,6 +255,8 @@ public:
 
 #undef QT_DEFINE_METATYPE_ID
 
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags)
+
 template <typename T>
 void qMetaTypeDeleteHelper(T *t)
 {
@@ -334,11 +345,20 @@ int qRegisterMetaType(const char *typeName
     typedef void(*DestructPtr)(T*);
     DestructPtr ipdptr = qMetaTypeDestructHelper<T>;
 
+    QMetaType::TypeFlags flags;
+    if (!QTypeInfo<T>::isStatic)
+        flags |= QMetaType::MovableType;
+    if (QTypeInfo<T>::isComplex) {
+        flags |= QMetaType::NeedsConstruction;
+        flags |= QMetaType::NeedsDestruction;
+    }
+
     return QMetaType::registerType(typeName, reinterpret_cast<QMetaType::Deleter>(dptr),
                                    reinterpret_cast<QMetaType::Creator>(cptr),
                                    reinterpret_cast<QMetaType::Destructor>(ipdptr),
                                    reinterpret_cast<QMetaType::Constructor>(ipcptr),
-                                   sizeof(T));
+                                   sizeof(T),
+                                   flags);
 }
 
 #ifndef QT_NO_DATASTREAM
index 448c6de..46c5697 100644 (file)
@@ -150,6 +150,7 @@ public:
     QMetaType::Constructor constructor;
     QMetaType::Destructor destructor;
     int size;
+    quint32 flags; // same as QMetaType::TypeFlags
 };
 
 #ifndef QT_NO_DATASTREAM
@@ -167,7 +168,10 @@ public:
     QT_METATYPE_INTERFACE_INIT_DATASTREAM_IMPL(Type) \
     /*constructor*/(reinterpret_cast<QMetaType::Constructor>(QMetaTypeInterface::Impl<Type>::constructor)), \
     /*destructor*/(reinterpret_cast<QMetaType::Destructor>(QMetaTypeInterface::Impl<Type>::destructor)), \
-    /*size*/(sizeof(Type)) \
+    /*size*/(sizeof(Type)), \
+    /*flags*/(!QTypeInfo<Type>::isStatic * QMetaType::MovableType) \
+            | (QTypeInfo<Type>::isComplex * QMetaType::NeedsConstruction) \
+            | (QTypeInfo<Type>::isComplex * QMetaType::NeedsDestruction) \
 }
 
 QT_END_NAMESPACE
index e0433ea..12a5744 100644 (file)
@@ -78,6 +78,8 @@ private slots:
     void createCopy();
     void sizeOf_data();
     void sizeOf();
+    void flags_data();
+    void flags();
     void construct_data();
     void construct();
     void constructCopy_data();
@@ -129,6 +131,10 @@ protected:
 #ifdef Q_OS_LINUX
             pthread_yield();
 #endif
+            if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) {
+                ++failureCount;
+                qWarning() << "Wrong typeInfo returned for" << tp;
+            }
             if (!QMetaType::isRegistered(tp)) {
                 ++failureCount;
                 qWarning() << name << "is not a registered metatype";
@@ -578,6 +584,40 @@ void tst_QMetaType::sizeOf()
     QCOMPARE(QMetaType::sizeOf(type), size);
 }
 
+struct CustomMovable {};
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(CustomMovable);
+
+void tst_QMetaType::flags_data()
+{
+    QTest::addColumn<int>("type");
+    QTest::addColumn<bool>("isMovable");
+    QTest::addColumn<bool>("isComplex");
+
+#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
+    QTest::newRow(#RealType) << MetaTypeId << bool(!QTypeInfo<RealType>::isStatic) << bool(QTypeInfo<RealType>::isComplex);
+QT_FOR_EACH_STATIC_CORE_CLASS(ADD_METATYPE_TEST_ROW)
+QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW)
+QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW)
+#undef ADD_METATYPE_TEST_ROW
+    QTest::newRow("TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true;
+    QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << false << true;
+    QTest::newRow("CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true;
+}
+
+void tst_QMetaType::flags()
+{
+    QFETCH(int, type);
+    QFETCH(bool, isMovable);
+    QFETCH(bool, isComplex);
+
+    QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex);
+    QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex);
+    QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable);
+}
+
 void tst_QMetaType::construct_data()
 {
     create_data();
index 98314a9..79eebbc 100644 (file)
@@ -56,6 +56,8 @@ private slots:
     void createCopy();
     void sizeOf_data();
     void sizeOf();
+    void flags_data();
+    void flags();
     void construct_data();
     void construct();
     void constructCopy_data();
@@ -320,6 +322,30 @@ struct TypeAlignment
 #endif
 };
 
+void tst_QGuiMetaType::flags_data()
+{
+    QTest::addColumn<int>("type");
+    QTest::addColumn<bool>("isMovable");
+    QTest::addColumn<bool>("isComplex");
+
+#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
+    QTest::newRow(#RealType) << MetaTypeId << bool(!QTypeInfo<RealType>::isStatic) << bool(QTypeInfo<RealType>::isComplex);
+QT_FOR_EACH_STATIC_GUI_CLASS(ADD_METATYPE_TEST_ROW)
+#undef ADD_METATYPE_TEST_ROW
+}
+
+void tst_QGuiMetaType::flags()
+{
+    QFETCH(int, type);
+    QFETCH(bool, isMovable);
+    QFETCH(bool, isComplex);
+
+    QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex);
+    QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex);
+    QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable);
+}
+
+
 void tst_QGuiMetaType::construct_data()
 {
     create_data();