Introduce QHashField for use in "contains" tests.
authorAaron Kennedy <aaron.kennedy@nokia.com>
Thu, 21 Jul 2011 13:08:53 +0000 (23:08 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 30 Aug 2011 11:18:28 +0000 (13:18 +0200)
Change-Id: I35aadace15b71b44c1b9e30a76eadf79fe03afad
Reviewed-on: http://codereview.qt.nokia.com/3767
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
src/declarative/qml/ftw/ftw.pri
src/declarative/qml/ftw/qhashfield_p.h [new file with mode: 0644]
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativeparser.cpp
src/declarative/qml/qdeclarativeparser_p.h

index 7e88598..545c47e 100644 (file)
@@ -11,6 +11,7 @@ HEADERS +=  \
     $$PWD/qfieldlist_p.h \
     $$PWD/qdeclarativeutils_p.h \
     $$PWD/qfastmetabuilder_p.h \
+    $$PWD/qhashfield_p.h \
 
 SOURCES += \
     $$PWD/qintrusivelist.cpp \
diff --git a/src/declarative/qml/ftw/qhashfield_p.h b/src/declarative/qml/ftw/qhashfield_p.h
new file mode 100644 (file)
index 0000000..8746264
--- /dev/null
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHFIELD_P_H
+#define QHASHFIELD_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+// QHashField can be used for doing coarse grained set testing, in
+// cases where you do not expect the set to contain the item.  For
+// example where you would write:
+//     QSet<QString> strings;
+//     for (int ii = 0; ii < mystrings.count(); ++ii) {
+//         if (strings.contains(mystrings.at(ii))) 
+//             qFatal("Duplication!");
+//         strings.insert(mystrings);
+//     }
+// You may write:
+//     QHashField strings;
+//     for (int ii = 0; ii < mystrings.count(); ++ii) {
+//         if (strings.testAndSet(qHash(mystrings.at(ii)))) {
+//             // The string *might* be duplicated
+//             for (int jj = 0; jj < ii; ++jj) {
+//                 if (mystrings.at(ii) == mystrings.at(jj)) 
+//                     qFatal("Duplication!");
+//             }
+//          }
+//     }
+// For small lists of things, where the hash is cheap to calculate
+// and you don't expect duplication this will be much faster.
+class QHashField {
+public:
+    inline QHashField();
+
+    inline void clear();
+
+    inline bool test(quint32 hash);
+    inline bool testAndSet(quint32 hash);
+private:
+    quint32 m_field;
+};
+
+QHashField::QHashField()
+: m_field(0)
+{
+}
+
+void QHashField::clear()
+{
+    m_field = 0;
+}
+
+bool QHashField::test(quint32 hash)
+{
+    return m_field & (1 << (hash % 31));
+}
+
+bool QHashField::testAndSet(quint32 hash)
+{
+    quint32 mask = 1 << (hash % 31);
+    bool rv = m_field & mask;
+    m_field |= mask;
+    return rv;
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHFIELD_P_H
index 9c59787..bb2742c 100644 (file)
@@ -848,6 +848,7 @@ bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const Bi
 
         const QMetaObject *metaObject = obj->metaObject();
         Q_ASSERT(metaObject);
+        // XXX aakenned
         QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
         if (p.name()) {
             Property *explicitProperty = obj->getProperty(QString::fromUtf8(p.name()), false);
@@ -2388,8 +2389,8 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
     // We use a coarse grain, 31 bit hash to check if there are duplicates.
     // Calculating the hash for the names is not a waste as we have to test
     // them against the illegalNames set anyway.
-    quint32 propNames = 0;
-    quint32 methodNames = 0;
+    QHashField propNames;
+    QHashField methodNames;
 
     // Check properties
     int dpCount = obj->dynamicProperties.count();
@@ -2402,16 +2403,13 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
             seenDefaultProperty = true;
         }
 
-        quint32 hash = prop.name.hash();
-        quint32 bit = hash % 31;
-        if (propNames & (1 << bit)) {
+        if (propNames.testAndSet(prop.name.hash())) {
             for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p; 
                  p2 = obj->dynamicProperties.next(p2)) {
                 if (p2->name == prop.name)
                     COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
             }
         }
-        propNames |= (1 << bit);
 
         if (QDeclarativeUtils::isUpper(prop.name.at(0)))
             COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
index 00bad1d..6a78598 100644 (file)
@@ -132,14 +132,18 @@ void QDeclarativeParser::Object::addScriptStringProperty(Property *p)
     scriptStringProperties.append(p);
 }
 
+// This lookup is optimized for missing, and having to create a new property.
 Property *QDeclarativeParser::Object::getProperty(const QHashedStringRef &name, bool create)
 {
-    for (Property *p = properties.first(); p; p = properties.next(p)) {
-        if (p->name() == name)
-            return p;
-    }
-
     if (create) {
+        quint32 h = name.hash();
+        if (propertiesHashField.testAndSet(h)) {
+            for (Property *p = properties.first(); p; p = properties.next(p)) {
+                if (p->name() == name)
+                    return p;
+            }
+        }
+
         Property *property = pool()->New<Property>();
         property->parent = this;
         property->_name = name;
@@ -147,7 +151,10 @@ Property *QDeclarativeParser::Object::getProperty(const QHashedStringRef &name,
         properties.prepend(property);
         return property;
     } else {
-        return 0;
+        for (Property *p = properties.first(); p; p = properties.next(p)) {
+            if (p->name() == name)
+                return p;
+        }
     }
 }
 
@@ -167,6 +174,7 @@ Property *QDeclarativeParser::Object::getProperty(const QString &name, bool crea
         Property *property = pool()->New<Property>();
         property->parent = this;
         property->_name = QStringRef(pool()->NewString(name));
+        propertiesHashField.testAndSet(property->_name.hash());
         property->isDefault = false;
         properties.prepend(property);
         return property;
index 86b06de..d7af045 100644 (file)
@@ -69,6 +69,7 @@
 #include <private/qdeclarativepropertycache_p.h>
 #include <private/qfastmetabuilder_p.h>
 #include <private/qhashedstring_p.h>
+#include <private/qhashfield_p.h>
 
 QT_BEGIN_HEADER
 
@@ -327,6 +328,7 @@ namespace QDeclarativeParser
 
         typedef QFieldList<Property, &Property::nextMainProperty> MainPropertyList;
         MainPropertyList properties;
+        QHashField propertiesHashField;
 
         // Output of the compilation phase (these properties continue to exist
         // in either the defaultProperty or properties members too)