Optimize type resolution
authorMartin Jones <martin.jones@nokia.com>
Wed, 16 May 2012 07:49:32 +0000 (17:49 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 17 May 2012 11:42:27 +0000 (13:42 +0200)
Faster qmlType() and resolveType() lookup.

Change-Id: I096439f23bf6071e8bfdf0cda366cc71e00293ba
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
src/qml/qml/ftw/qhashedstring.cpp
src/qml/qml/ftw/qhashedstring_p.h
src/qml/qml/qqmlcompiler.cpp
src/qml/qml/qqmldirparser.cpp
src/qml/qml/qqmldirparser_p.h
src/qml/qml/qqmlimport.cpp
src/qml/qml/qqmlimport_p.h
src/qml/qml/qqmlmetatype.cpp
src/qml/qml/qqmlmetatype_p.h
tests/auto/qml/qqmlmetatype/qqmlmetatype.pro
tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp

index 1f09d50..2dc717b 100644 (file)
@@ -443,6 +443,27 @@ bool QHashedStringRef::startsWith(const QString &s) const
            QHashedString::compare(s.constData(), m_data, s.length());
 }
 
+static int findChar(const QChar *str, int len, QChar ch, int from)
+{
+    const ushort *s = (const ushort *)str;
+    ushort c = ch.unicode();
+    if (from < 0)
+        from = qMax(from + len, 0);
+    if (from < len) {
+        const ushort *n = s + from - 1;
+        const ushort *e = s + len;
+        while (++n != e)
+            if (*n == c)
+                return  n - s;
+    }
+    return -1;
+}
+
+int QHashedStringRef::indexOf(const QChar &c, int from) const
+{
+    return findChar(m_data, m_length, c, from);
+}
+
 QString QHashedStringRef::toString() const
 {
     if (m_length == 0)
index f058f21..f8099d5 100644 (file)
@@ -148,6 +148,7 @@ public:
     inline const QChar *constData() const;
     bool startsWith(const QString &) const;
     bool endsWith(const QString &) const;
+    int indexOf(const QChar &, int from=0) const;
     QHashedStringRef mid(int, int) const;
 
     inline bool isEmpty() const;
index c423d93..54035fc 100644 (file)
@@ -90,7 +90,8 @@ using namespace QQmlCompilerTypes;
 static QString id_string(QLatin1String("id"));
 static QString on_string(QLatin1String("on"));
 static QString Changed_string(QLatin1String("Changed"));
-static QString Component_import_string(QLatin1String("QML/Component"));
+static QString Component_string(QLatin1String("Component"));
+static QString Component_module_string(QLatin1String("QML"));
 static QString qsTr_string(QLatin1String("qsTr"));
 static QString qsTrId_string(QLatin1String("qsTrId"));
 
@@ -1603,7 +1604,7 @@ bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext
 int QQmlCompiler::componentTypeRef()
 {
     if (cachedComponentTypeRef == -1) {
-        QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
+        QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
         for (int ii = output->types.count() - 1; ii >= 0; --ii) {
             if (output->types.at(ii).type == t) {
                 cachedComponentTypeRef = ii;
@@ -1739,7 +1740,7 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
 
         QQmlType *type = 0;
         QQmlImportNamespace *typeNamespace = 0;
-        unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
+        unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
 
         if (typeNamespace) {
             COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, 
@@ -1861,7 +1862,7 @@ bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
         // Setup attached property data
 
         QQmlType *type = 0;
-        unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
+        unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
 
         if (!type || !type->attachedPropertiesType()) 
             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
@@ -2875,7 +2876,7 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
                 QByteArray customTypeName;
                 QQmlType *qmltype = 0;
                 QString url;
-                if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
+                if (!unit->imports().resolveType(p->customType, &qmltype, &url, 0, 0, 0))
                     COMPILE_EXCEPTION(p, tr("Invalid property type"));
 
                 if (!qmltype) {
index 2da4a33..2fb47cc 100644 (file)
@@ -156,7 +156,7 @@ bool QQmlDirParser::parse()
             }
             Component entry(sections[1], sections[2], -1, -1);
             entry.internal = true;
-            _components.append(entry);
+            _components.insertMulti(entry.typeName, entry);
         } else if (sections[0] == QLatin1String("typeinfo")) {
             if (sectionCount != 2) {
                 reportError(lineNumber, -1,
@@ -171,7 +171,7 @@ bool QQmlDirParser::parse()
         } else if (sectionCount == 2) {
             // No version specified (should only be used for relative qmldir files)
             const Component entry(sections[0], sections[1], -1, -1);
-            _components.append(entry);
+            _components.insertMulti(entry.typeName, entry);
         } else if (sectionCount == 3) {
             const QString &version = sections[1];
             const int dotIndex = version.indexOf(QLatin1Char('.'));
@@ -196,7 +196,7 @@ bool QQmlDirParser::parse()
                             _scripts.append(entry);
                         } else {
                             const Component entry(sections[0], fileName, majorVersion, minorVersion);
-                            _components.append(entry);
+                            _components.insertMulti(entry.typeName, entry);
                         }
                     }
                 }
@@ -250,7 +250,7 @@ QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
     return _plugins;
 }
 
-QList<QQmlDirParser::Component> QQmlDirParser::components() const
+QHash<QHashedStringRef,QQmlDirParser::Component> QQmlDirParser::components() const
 {
     return _components;
 }
index 77fe277..4de39e0 100644 (file)
@@ -56,6 +56,7 @@
 #include <QtCore/QUrl>
 #include <QtCore/QHash>
 #include <QtCore/QDebug>
+#include <private/qhashedstring_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -120,7 +121,7 @@ public:
         int minorVersion;
     };
 
-    QList<Component> components() const;
+    QHash<QHashedStringRef,Component> components() const;
     QList<Script> scripts() const;
     QList<Plugin> plugins() const;
 
@@ -143,7 +144,7 @@ private:
 private:
     QList<QQmlError> _errors;
     QString _source;
-    QList<Component> _components;
+    QHash<QHashedStringRef,Component> _components; // multi hash
     QList<Script> _scripts;
     QList<Plugin> _plugins;
 #ifdef QT_CREATOR
@@ -152,7 +153,7 @@ private:
     unsigned _isParsed: 1;
 };
 
-typedef QList<QQmlDirParser::Component> QQmlDirComponents;
+typedef QHash<QHashedStringRef,QQmlDirParser::Component> QQmlDirComponents;
 typedef QList<QQmlDirParser::Script> QQmlDirScripts;
 
 QDebug &operator<< (QDebug &, const QQmlDirParser::Component &);
index 610257d..9bdc67a 100644 (file)
@@ -125,20 +125,20 @@ public:
         QQmlDirComponents qmlDirComponents;
         QQmlDirScripts qmlDirScripts;
 
-        bool resolveType(QQmlTypeLoader *typeLoader, const QString& type,
+        bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
                          int *vmajor, int *vminor,
                          QQmlType** type_return, QString* url_return,
                          QString *base = 0, bool *typeRecursionDetected = 0) const;
     };
     QList<Import> imports;
 
-    bool resolveType(QQmlTypeLoader *typeLoader, const QString& type,
+    bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
                      int *vmajor, int *vminor,
                      QQmlType** type_return, QString* url_return,
                      QString *base = 0, QList<QQmlError> *errors = 0);
 
     // Prefix when used as a qualified import.  Otherwise empty.
-    QString prefix;
+    QHashedString prefix;
 
     // Used by QQmlImportsPrivate::qualifiedSets
     QQmlImportNamespace *nextNamespace;
@@ -156,7 +156,7 @@ public:
                    bool isImplicitImport, QQmlImportDatabase *database,
                    QString *, QList<QQmlError> *errors);
 
-    bool resolveType(const QString& type, int *vmajor, int *vminor,
+    bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
                      QQmlType** type_return, QString* url_return,
                      QList<QQmlError> *errors);
 
@@ -166,7 +166,7 @@ public:
 
     QQmlImportNamespace unqualifiedset;
 
-    QQmlImportNamespace *findQualifiedNamespace(const QString &);
+    QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &);
     QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
 
     QQmlTypeLoader *typeLoader;
@@ -325,7 +325,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
 
   \sa addImport()
 */
-bool QQmlImports::resolveType(const QString& type,
+bool QQmlImports::resolveType(const QHashedStringRef &type,
                               QQmlType** type_return, QString* url_return, int *vmaj, int *vmin,
                               QQmlImportNamespace** ns_return, QList<QQmlError> *errors) const
 {
@@ -339,7 +339,7 @@ bool QQmlImports::resolveType(const QString& type,
         if (d->resolveType(type,vmaj,vmin,type_return,url_return, errors)) {
             if (qmlImportTrace()) {
 #define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
-                                              << ')' << "::resolveType: " << type << " => "
+                                              << ')' << "::resolveType: " << type.toString() << " => "
 
                 if (type_return && *type_return && url_return && !url_return->isEmpty())
                     RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << *url_return;
@@ -366,7 +366,7 @@ bool QQmlImports::resolveType(const QString& type,
 
   If either return pointer is 0, the corresponding search is not done.
 */
-bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QString& type,
+bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &type,
                               QQmlType** type_return, QString* url_return,
                               int *vmaj, int *vmin) const
 {
@@ -374,13 +374,12 @@ bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QString& type,
 }
 
 bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
-                                              const QString& type, int *vmajor, int *vminor,
+                                              const QHashedStringRef& type, int *vmajor, int *vminor,
                                               QQmlType** type_return, QString* url_return,
                                               QString *base, bool *typeRecursionDetected) const
 {
     if (majversion >= 0 && minversion >= 0) {
-        QString qt = uri + QLatin1Char('/') + type;
-        QQmlType *t = QQmlMetaType::qmlType(qt, majversion, minversion);
+        QQmlType *t = QQmlMetaType::qmlType(type, uri, majversion, minversion);
         if (t) {
             if (vmajor) *vmajor = majversion;
             if (vminor) *vminor = minversion;
@@ -392,14 +391,21 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
 
     bool typeWasDeclaredInQmldir = false;
     if (!qmlDirComponents.isEmpty()) {
-        foreach (const QQmlDirParser::Component &c, qmlDirComponents) {
-            if (type == c.typeName) {
-                typeWasDeclaredInQmldir = true;
+        QQmlDirComponents::ConstIterator it = qmlDirComponents.find(type);
+        if (it != qmlDirComponents.end()) {
+            typeWasDeclaredInQmldir = true;
+            // first found is last inserted - process in reverse
+            QQmlDirComponents::ConstIterator begin = it;
+            while (++it != qmlDirComponents.end() && it.key() == type) {}
+            do {
+                --it;
+                const QQmlDirParser::Component &c = *it;
+
                 // importing version -1 means import ALL versions
                 if ((majversion == -1) || (c.majorVersion == majversion &&
                                            minversion >= c.minorVersion)) {
 
-                    QString candidate = resolveLocalUrl(QString(url + type + dotqml_string), c.fileName);
+                    QString candidate = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
                     if (c.internal && base) {
                         if (resolveLocalUrl(*base, c.fileName) != candidate)
                             continue; // failed attempt to access an internal type
@@ -413,19 +419,18 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
                         *url_return = candidate;
                     return true;
                 }
-            }
+            } while (it != begin);
         }
     }
 
     if (!typeWasDeclaredInQmldir && !isLibrary) {
-        QString qmlUrl = url + type + dotqml_string;
+        QString qmlUrl = url + QString::fromRawData(type.constData(), type.length()) + dotqml_string;
 
         bool exists = false;
 
         if (QQmlFile::isBundle(qmlUrl)) {
             exists = QQmlFile::bundleFileExists(qmlUrl, typeLoader->engine());
         } else {
-            QString file = QQmlFile::urlToLocalFileOrQrc(qmlUrl);
             exists = !typeLoader->absoluteFilePath(QQmlFile::urlToLocalFileOrQrc(qmlUrl)).isEmpty();
         }
 
@@ -444,19 +449,19 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
     return false;
 }
 
-bool QQmlImportsPrivate::resolveType(const QString& type, int *vmajor, int *vminor,
+bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor,
                                      QQmlType** type_return, QString* url_return,
                                      QList<QQmlError> *errors)
 {
     QQmlImportNamespace *s = 0;
     int dot = type.indexOf(QLatin1Char('.'));
     if (dot >= 0) {
-        QString namespaceName = type.left(dot);
+        QHashedStringRef namespaceName(type.constData(), dot);
         s = findQualifiedNamespace(namespaceName);
         if (!s) {
             if (errors) {
                 QQmlError error;
-                error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName));
+                error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName.toString()));
                 errors->prepend(error);
             }
             return false;
@@ -473,13 +478,13 @@ bool QQmlImportsPrivate::resolveType(const QString& type, int *vmajor, int *vmin
     } else {
         s = &unqualifiedset;
     }
-    QString unqualifiedtype = dot < 0 ? type : type.mid(dot+1, -1);
+    QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
     if (s) {
         if (s->resolveType(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
             return true;
         if (s->imports.count() == 1 && !s->imports.at(0).isLibrary && url_return && s != &unqualifiedset) {
             // qualified, and only 1 url
-            *url_return = resolveLocalUrl(s->imports.at(0).url, unqualifiedtype + QLatin1String(".qml"));
+            *url_return = resolveLocalUrl(s->imports.at(0).url, unqualifiedtype.toString() + QLatin1String(".qml"));
             return true;
         }
     }
@@ -487,7 +492,7 @@ bool QQmlImportsPrivate::resolveType(const QString& type, int *vmajor, int *vmin
     return false;
 }
 
-bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QString& type,
+bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
                                       int *vmajor, int *vminor, QQmlType** type_return,
                                       QString* url_return, QString *base, QList<QQmlError> *errors)
 {
@@ -560,7 +565,7 @@ QQmlImportsPrivate::~QQmlImportsPrivate()
         delete ns;
 }
 
-QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QString &prefix)
+QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStringRef &prefix)
 {
     for (QQmlImportNamespace *ns = qualifiedSets.first(); ns; ns = qualifiedSets.next(ns)) {
         if (prefix == ns->prefix)
@@ -844,11 +849,11 @@ bool QQmlImportsPrivate::addImport(const QQmlDirComponents &qmldircomponentsnetw
             } else {
                 int lowest_min = INT_MAX;
                 int highest_min = INT_MIN;
-                typedef QList<QQmlDirParser::Component>::const_iterator ConstIterator;
+                typedef QQmlDirComponents::const_iterator ConstIterator;
                 typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
 
-                for (ConstIterator cit = qmldircomponents.constBegin();
-                     cit != qmldircomponents.constEnd(); ++cit) {
+                ConstIterator cend = qmldircomponents.end();
+                for (ConstIterator cit = qmldircomponents.begin(); cit != cend; ++cit) {
                     if (cit->majorVersion == vmaj) {
                         lowest_min = qMin(lowest_min, cit->minorVersion);
                         highest_min = qMax(highest_min, cit->minorVersion);
index ad0bbc6..111bf29 100644 (file)
@@ -83,13 +83,13 @@ public:
     void setBaseUrl(const QUrl &url, const QString &urlString = QString());
     QUrl baseUrl() const;
 
-    bool resolveType(const QString& type,
+    bool resolveType(const QHashedStringRef &type,
                      QQmlType** type_return, QString* url_return,
                      int *version_major, int *version_minor,
                      QQmlImportNamespace** ns_return,
                      QList<QQmlError> *errors = 0) const;
     bool resolveType(QQmlImportNamespace*,
-                     const QString& type,
+                     const QHashedStringRef& type,
                      QQmlType** type_return, QString* url_return,
                      int *version_major, int *version_minor) const;
 
index 856f75f..1566d83 100644 (file)
@@ -73,7 +73,7 @@ struct QQmlMetaTypeData
     QList<QQmlType *> types;
     typedef QHash<int, QQmlType *> Ids;
     Ids idToType;
-    typedef QHash<QString, QQmlType *> Names;
+    typedef QHash<QHashedStringRef,QQmlType *> Names;
     Names nameToType;
     typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
     MetaObjects metaObjectToType;
@@ -83,12 +83,12 @@ struct QQmlMetaTypeData
     struct VersionedUri {
         VersionedUri()
         : majorVersion(0) {}
-        VersionedUri(const QString &uri, int majorVersion)
+        VersionedUri(const QHashedString &uri, int majorVersion)
         : uri(uri), majorVersion(majorVersion) {}
         bool operator==(const VersionedUri &other) const {
             return other.majorVersion == majorVersion && other.uri == uri;
         }
-        QString uri;
+        QHashedString uri;
         int majorVersion;
     };
     typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
@@ -99,7 +99,7 @@ struct QQmlMetaTypeData
         QList<QQmlMetaType::ModuleApi> moduleApis;
         bool sorted;
     };
-    typedef QHash<QString, ModuleApiList> ModuleApis;
+    typedef QStringHash<ModuleApiList> ModuleApis;
     ModuleApis moduleApis;
     int moduleApiCount;
 
@@ -132,7 +132,7 @@ Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
 
 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
 {
-    return qHash(v.uri) ^ qHash(v.majorVersion);
+    return v.uri.hash() ^ qHash(v.majorVersion);
 }
 
 QQmlMetaTypeData::QQmlMetaTypeData()
@@ -156,7 +156,7 @@ public:
 
     bool m_isInterface : 1;
     const char *m_iid;
-    QString m_module;
+    QHashedString m_module;
     QString m_name;
     QString m_elementName;
     int m_version_maj;
@@ -219,12 +219,14 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
 : d(new QQmlTypePrivate)
 {
-    QString name = QString::fromUtf8(type.uri);
-    if (type.uri) name += QLatin1Char('/');
-    name += QString::fromUtf8(type.elementName);
-
     d->m_module = QString::fromUtf8(type.uri);
-    d->m_name = name;
+    d->m_elementName = QString::fromUtf8(type.elementName);
+
+    if (!d->m_module.isEmpty())
+        d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
+    else
+        d->m_name = d->m_elementName;
+
     d->m_version_maj = type.versionMajor;
     d->m_version_min = type.versionMinor;
     if (type.version >= 1) // revisions added in version 1
@@ -262,7 +264,7 @@ QQmlType::~QQmlType()
     delete d;
 }
 
-QString QQmlType::module() const
+const QHashedString &QQmlType::module() const
 {
     return d->m_module;
 }
@@ -283,7 +285,7 @@ bool QQmlType::availableInVersion(int vmajor, int vminor) const
     return vmajor == d->m_version_maj && vminor >= d->m_version_min;
 }
 
-bool QQmlType::availableInVersion(const QString &module, int vmajor, int vminor) const
+bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
 {
     Q_ASSERT(vmajor >= 0 && vminor >= 0);
     return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
@@ -491,11 +493,6 @@ QByteArray QQmlType::typeName() const
 
 const QString &QQmlType::elementName() const
 {
-    if (d->m_elementName.isEmpty()) {
-        QString n = qmlTypeName();
-        int idx = n.lastIndexOf(QLatin1Char('/'));
-        d->m_elementName = n.mid(idx + 1);
-    }
     return d->m_elementName;
 }
 
@@ -699,8 +696,6 @@ int QQmlTypeModule::maximumMinorVersion() const
 
 void QQmlTypeModulePrivate::add(QQmlType *type)
 {
-    types << type;
-
     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
 
@@ -714,25 +709,6 @@ void QQmlTypeModulePrivate::add(QQmlType *type)
     list.append(type);
 }
 
-QList<QQmlType *> QQmlTypeModule::types()
-{
-    QList<QQmlType *> rv;
-    QReadLocker lock(metaTypeDataLock());
-    rv = d->types;
-    return rv;
-}
-
-QList<QQmlType *> QQmlTypeModule::type(const QString &name)
-{
-    QReadLocker lock(metaTypeDataLock());
-    QList<QQmlType *> rv;
-    for (int ii = 0; ii < d->types.count(); ++ii) {
-        if (d->types.at(ii)->elementName() == name)
-            rv << d->types.at(ii);
-    }
-    return rv;
-}
-
 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
 {
     QReadLocker lock(metaTypeDataLock());
@@ -835,8 +811,8 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface)
     data->idToType.insert(type->typeId(), type);
     data->idToType.insert(type->qListTypeId(), type);
     // XXX No insertMulti, so no multi-version interfaces?
-    if (!type->qmlTypeName().isEmpty())
-        data->nameToType.insert(type->qmlTypeName(), type);
+    if (!type->elementName().isEmpty())
+        data->nameToType.insert(type->elementName(), type);
 
     if (data->interfaces.size() <= interface.typeId)
         data->interfaces.resize(interface.typeId + 16);
@@ -869,8 +845,8 @@ int registerType(const QQmlPrivate::RegisterType &type)
     data->idToType.insert(dtype->typeId(), dtype);
     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
 
-    if (!dtype->qmlTypeName().isEmpty())
-        data->nameToType.insertMulti(dtype->qmlTypeName(), dtype);
+    if (!dtype->elementName().isEmpty())
+        data->nameToType.insertMulti(dtype->elementName(), dtype);
 
     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
 
@@ -881,8 +857,8 @@ int registerType(const QQmlPrivate::RegisterType &type)
     data->objects.setBit(type.typeId, true);
     if (type.listId) data->lists.setBit(type.listId, true);
 
-    if (type.uri) {
-        QString mod = QString::fromUtf8(type.uri);
+    if (!dtype->module().isEmpty()) {
+        const QHashedString &mod = dtype->module();
 
         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
@@ -915,14 +891,14 @@ int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
 
     int index = data->moduleApiCount++;
 
-    QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
-    if (iter == data->moduleApis.end()) {
+    QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
+    if (!apiList) {
         QQmlMetaTypeData::ModuleApiList apis;
         apis.moduleApis << import;
         data->moduleApis.insert(uri, apis);
     } else {
-        iter->moduleApis << import;
-        iter->sorted = false;
+        apiList->moduleApis << import;
+        apiList->sorted = false;
     }
 
     return index;
@@ -985,9 +961,12 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version
         return true;
 
     // then, check ModuleApis
-    foreach (const QQmlMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
-        if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
-            return true;
+    QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(module);
+    if (apiList) {
+        foreach (const QQmlMetaType::ModuleApi &mApi, apiList->moduleApis) {
+            if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
+                return true;
+        }
     }
 
     return false;
@@ -1018,17 +997,17 @@ QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
     QReadLocker lock(metaTypeDataLock());
     QQmlMetaTypeData *data = metaTypeData();
 
-    QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
-    if (iter == data->moduleApis.end())
+    QQmlMetaTypeData::ModuleApiList *apiList = data->moduleApis.value(uri);
+    if (!apiList)
         return ModuleApi();
 
-    if (iter->sorted == false) {
-        qSort(iter->moduleApis.begin(), iter->moduleApis.end());
-        iter->sorted = true;
+    if (apiList->sorted == false) {
+        qSort(apiList->moduleApis.begin(), apiList->moduleApis.end());
+        apiList->sorted = true;
     }
 
-    for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
-        const ModuleApi &import = iter->moduleApis.at(ii);
+    for (int ii = apiList->moduleApis.count() - 1; ii >= 0; --ii) {
+        const ModuleApi &import = apiList->moduleApis.at(ii);
         if (import.major == versionMajor && import.minor <= versionMinor)
             return import;
     }
@@ -1042,11 +1021,9 @@ QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
     QQmlMetaTypeData *data = metaTypeData();
 
     QHash<QString, QList<ModuleApi> > moduleApis;
-    QHashIterator<QString, QQmlMetaTypeData::ModuleApiList> it(data->moduleApis);
-    while (it.hasNext()) {
-        it.next();
+    QStringHash<QQmlMetaTypeData::ModuleApiList>::ConstIterator it = data->moduleApis.begin();
+    for (; it != data->moduleApis.end(); ++it)
         moduleApis[it.key()] = it.value().moduleApis;
-    }
 
     return moduleApis;
 }
@@ -1241,19 +1218,35 @@ QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
 }
 
 /*!
-    Returns the type (if any) of URI-qualified named \a name in version specified
+    Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
     by \a version_major and \a version_minor.
 */
-QQmlType *QQmlMetaType::qmlType(const QString &name, int version_major, int version_minor)
+QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
+{
+    int slash = qualifiedName.indexOf(QLatin1Char('/'));
+    if (slash <= 0)
+        return 0;
+
+    QHashedStringRef module(qualifiedName.constData(), slash);
+    QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
+
+    return qmlType(name, module, version_major, version_minor);
+}
+
+/*!
+    Returns the type (if any) of \a name in \a module and version specified
+    by \a version_major and \a version_minor.
+*/
+QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
 {
     Q_ASSERT(version_major >= 0 && version_minor >= 0);
     QReadLocker lock(metaTypeDataLock());
     QQmlMetaTypeData *data = metaTypeData();
 
     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
-    while (it != data->nameToType.end()) {
+    while (it != data->nameToType.end() && it.key() == name) {
         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
-        if (it.key() == name && (version_major<0 || (*it)->availableInVersion(version_major,version_minor)))
+        if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
             return (*it);
         ++it;
     }
@@ -1278,7 +1271,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
     type is registered.
 */
-QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor)
+QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
 {
     Q_ASSERT(version_major >= 0 && version_minor >= 0);
     QReadLocker lock(metaTypeDataLock());
@@ -1319,7 +1312,14 @@ QList<QString> QQmlMetaType::qmlTypeNames()
     QReadLocker lock(metaTypeDataLock());
     QQmlMetaTypeData *data = metaTypeData();
 
-    return data->nameToType.keys();
+    QList<QString> names;
+    QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
+    while (it != data->nameToType.end()) {
+        names += (*it)->qmlTypeName();
+        ++it;
+    }
+
+    return names;
 }
 
 /*!
index 03017ca..fbbc410 100644 (file)
@@ -67,6 +67,8 @@ class QQmlType;
 class QQmlCustomParser;
 class QQmlTypePrivate;
 class QQmlTypeModule;
+class QHashedString;
+class QHashedStringRef;
 
 class Q_QML_PRIVATE_EXPORT QQmlMetaType
 {
@@ -74,9 +76,10 @@ public:
     static QList<QString> qmlTypeNames();
     static QList<QQmlType*> qmlTypes();
 
-    static QQmlType *qmlType(const QString &, int, int);
+    static QQmlType *qmlType(const QString &qualifiedName, int, int);
+    static QQmlType *qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int);
     static QQmlType *qmlType(const QMetaObject *);
-    static QQmlType *qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor);
+    static QQmlType *qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor);
     static QQmlType *qmlType(int);
 
     static QMetaProperty defaultProperty(const QMetaObject *);
@@ -140,7 +143,6 @@ private:
     static CompareFunction anchorLineCompareFunction;
 };
 
-class QHashedStringRef;
 class QHashedV8String;
 class Q_QML_PRIVATE_EXPORT QQmlType
 {
@@ -149,12 +151,12 @@ public:
     const QString &qmlTypeName() const;
     const QString &elementName() const;
 
-    QString module() const;
+    const QHashedString &module() const;
     int majorVersion() const;
     int minorVersion() const;
 
     bool availableInVersion(int vmajor, int vminor) const;
-    bool availableInVersion(const QString &module, int vmajor, int vminor) const;
+    bool availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const;
 
     QObject *create() const;
     void create(QObject **, void **, size_t) const;
@@ -214,9 +216,6 @@ public:
     int minimumMinorVersion() const;
     int maximumMinorVersion() const;
 
-    QList<QQmlType *> types();
-    QList<QQmlType *> type(const QString &);
-
     QQmlType *type(const QHashedStringRef &, int);
     QQmlType *type(const QHashedV8String &, int);
 
index d723907..5e45672 100644 (file)
@@ -4,4 +4,4 @@ SOURCES += tst_qqmlmetatype.cpp
 macx:CONFIG -= app_bundle
 
 CONFIG += parallel_test
-QT += core-private gui-private qml-private testlib
+QT += core-private gui-private qml-private testlib v8-private
index 6e577ec..a3f311e 100644 (file)
@@ -44,6 +44,7 @@
 
 #include <private/qqmlmetatype_p.h>
 #include <private/qqmlpropertyvalueinterceptor_p.h>
+#include <private/qhashedstring_p.h>
 
 class tst_qqmlmetatype : public QObject
 {
@@ -57,6 +58,7 @@ private slots:
     void qmlParserStatusCast();
     void qmlPropertyValueSourceCast();
     void qmlPropertyValueInterceptorCast();
+    void qmlType();
 
     void isList();
 
@@ -171,6 +173,19 @@ void tst_qqmlmetatype::qmlPropertyValueInterceptorCast()
     QCOMPARE(interceptor, (QQmlPropertyValueInterceptor*)&t);
 }
 
+void tst_qqmlmetatype::qmlType()
+{
+    QQmlType *type = QQmlMetaType::qmlType(QString("ParserStatusTestType"), QString("Test"), 1, 0);
+    QVERIFY(type);
+    QVERIFY(type->module() == QLatin1String("Test"));
+    QVERIFY(type->elementName() == QLatin1String("ParserStatusTestType"));
+
+    type = QQmlMetaType::qmlType("Test/ParserStatusTestType", 1, 0);
+    QVERIFY(type);
+    QVERIFY(type->module() == QLatin1String("Test"));
+    QVERIFY(type->elementName() == QLatin1String("ParserStatusTestType"));
+}
+
 void tst_qqmlmetatype::isList()
 {
     QCOMPARE(QQmlMetaType::isList(QVariant::Invalid), false);