Use strings more conservatively
authorAaron Kennedy <aaron.kennedy@nokia.com>
Thu, 21 Jul 2011 04:20:05 +0000 (14:20 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 30 Aug 2011 11:18:28 +0000 (13:18 +0200)
Also adds the ability to efficiently estimate the length of, and
write out to, UTF8 from QHashedStringRef.

Change-Id: I8b6226ba41d855246ddf7d6268f8045c92ae219e
Reviewed-on: http://codereview.qt.nokia.com/3764
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
src/declarative/qml/ftw/qdeclarativepool_p.h
src/declarative/qml/ftw/qfastmetabuilder_p.h
src/declarative/qml/ftw/qhashedstring.cpp
src/declarative/qml/ftw/qhashedstring_p.h
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativecompiler_p.h
src/declarative/qml/qdeclarativeparser.cpp
src/declarative/qml/qdeclarativeparser_p.h
src/declarative/qml/qdeclarativescriptparser.cpp
src/declarative/qml/v8/qv8engine.cpp
src/declarative/qml/v8/qv8engine_p.h

index a087779..a30839a 100644 (file)
@@ -99,10 +99,13 @@ public:
     inline T *New();
 
     inline QString *NewString(const QString &);
+    inline QByteArray *NewByteArray(const QByteArray &);
 
 private:
     struct StringClass : public QString, public Class {
     };
+    struct ByteArrayClass : public QByteArray, public Class {
+    };
 
     inline void *allocate(int size);
     void newpage();
@@ -155,6 +158,13 @@ QString *QDeclarativePool::NewString(const QString &s)
     return rv;
 }
 
+QByteArray *QDeclarativePool::NewByteArray(const QByteArray &s)
+{
+    QByteArray *rv = New<ByteArrayClass>();
+    *rv = s;
+    return rv;
+}
+
 void *QDeclarativePool::allocate(int size)
 {
     if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize))
index c0cb0fc..eb4852d 100644 (file)
@@ -56,6 +56,8 @@
 #include <QtCore/qglobal.h>
 #include <QtCore/qmetatype.h>
 
+#include <private/qhashedstring_p.h>
+
 QT_BEGIN_NAMESPACE
 
 class QFastMetaBuilder
@@ -70,6 +72,7 @@ public:
         inline StringRef(const StringRef &);
         inline StringRef &operator=(const StringRef &);
 
+        inline void load(const QHashedStringRef &);
         inline void load(const QByteArray &);
         inline void load(const char *);
 
@@ -176,6 +179,13 @@ int QFastMetaBuilder::StringRef::length() const
     return _l;
 }
 
+void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str)
+{
+    Q_ASSERT(str.length() == _l);
+    str.writeUtf8(data());
+    *(data() + _l) = 0;
+}
+
 void QFastMetaBuilder::StringRef::load(const QByteArray &str)
 {
     Q_ASSERT(str.length() == _l);
@@ -184,7 +194,7 @@ void QFastMetaBuilder::StringRef::load(const QByteArray &str)
 
 void QFastMetaBuilder::StringRef::load(const char *str)
 {
-    Q_ASSERT(strlen(str) == _l);
+    Q_ASSERT(strlen(str) == (uint)_l);
     strcpy(data(), str);
 }
 
index 936f818..296d0c4 100644 (file)
@@ -173,3 +173,209 @@ bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
     }
     return true;
 }
+
+// Unicode stuff
+static inline bool isUnicodeNonCharacter(uint ucs4)
+{
+    // Unicode has a couple of "non-characters" that one can use internally,
+    // but are not allowed to be used for text interchange.
+    //
+    // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
+    // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
+    // U+FDEF (inclusive)
+
+    return (ucs4 & 0xfffe) == 0xfffe
+            || (ucs4 - 0xfdd0U) < 16;
+}
+
+static int utf8LengthFromUtf16(const QChar *uc, int len)
+{
+    int length = 0;
+
+    int surrogate_high = -1;
+
+    const QChar *ch = uc;
+    int invalid = 0;
+
+    const QChar *end = ch + len;
+    while (ch < end) {
+        uint u = ch->unicode();
+        if (surrogate_high >= 0) {
+            if (u >= 0xdc00 && u < 0xe000) {
+                u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000;
+                surrogate_high = -1;
+            } else {
+                // high surrogate without low
+                ++ch;
+                ++invalid;
+                surrogate_high = -1;
+                continue;
+            }
+        } else if (u >= 0xdc00 && u < 0xe000) {
+            // low surrogate without high
+            ++ch;
+            ++invalid;
+            continue;
+        } else if (u >= 0xd800 && u < 0xdc00) {
+            surrogate_high = u;
+            ++ch;
+            continue;
+        }
+
+        if (u < 0x80) {
+            ++length;
+        } else {
+            if (u < 0x0800) {
+                ++length;
+            } else {
+                // is it one of the Unicode non-characters?
+                if (isUnicodeNonCharacter(u)) {
+                    ++length;
+                    ++ch;
+                    ++invalid;
+                    continue;
+                }
+
+                if (u > 0xffff) {
+                    ++length;
+                    ++length;
+                } else {
+                    ++length;
+                }
+                ++length;
+            }
+            ++length;
+        }
+        ++ch;
+    }
+
+    return length;
+}
+
+// Writes the utf8 version of uc to output.  uc is of length len.
+// There must be at least utf8LengthFromUtf16(uc, len) bytes in output.
+// A null terminator is not written.
+static void utf8FromUtf16(char *output, const QChar *uc, int len)
+{
+    uchar replacement = '?';
+    int surrogate_high = -1;
+
+    uchar* cursor = (uchar*)output;
+    const QChar *ch = uc;
+    int invalid = 0;
+
+    const QChar *end = ch + len;
+    while (ch < end) {
+        uint u = ch->unicode();
+        if (surrogate_high >= 0) {
+            if (u >= 0xdc00 && u < 0xe000) {
+                u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000;
+                surrogate_high = -1;
+            } else {
+                // high surrogate without low
+                *cursor = replacement;
+                ++ch;
+                ++invalid;
+                surrogate_high = -1;
+                continue;
+            }
+        } else if (u >= 0xdc00 && u < 0xe000) {
+            // low surrogate without high
+            *cursor = replacement;
+            ++ch;
+            ++invalid;
+            continue;
+        } else if (u >= 0xd800 && u < 0xdc00) {
+            surrogate_high = u;
+            ++ch;
+            continue;
+        }
+
+        if (u < 0x80) {
+            *cursor++ = (uchar)u;
+        } else {
+            if (u < 0x0800) {
+                *cursor++ = 0xc0 | ((uchar) (u >> 6));
+            } else {
+                // is it one of the Unicode non-characters?
+                if (isUnicodeNonCharacter(u)) {
+                    *cursor++ = replacement;
+                    ++ch;
+                    ++invalid;
+                    continue;
+                }
+
+                if (u > 0xffff) {
+                    *cursor++ = 0xf0 | ((uchar) (u >> 18));
+                    *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
+                } else {
+                    *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
+                }
+                *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
+            }
+            *cursor++ = 0x80 | ((uchar) (u&0x3f));
+        }
+        ++ch;
+    }
+}
+
+void QHashedStringRef::computeUtf8Length() const
+{
+    if (m_length) 
+        m_utf8length = utf8LengthFromUtf16(m_data, m_length);
+    else
+        m_utf8length = 0;
+}
+
+QHashedStringRef QHashedStringRef::mid(int offset, int length) const
+{
+    Q_ASSERT(offset < m_length);
+    return QHashedStringRef(m_data + offset, 
+                            (length == -1 || (offset + length) > m_length)?(m_length - offset):length);
+}
+
+bool QHashedStringRef::endsWith(const QString &s) const
+{
+    return s.length() < m_length && 
+           QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length());
+}
+
+bool QHashedStringRef::startsWith(const QString &s) const
+{
+    return s.length() < m_length && 
+           QHashedString::compare(s.constData(), m_data, s.length());
+}
+
+QString QHashedStringRef::toString() const
+{
+    if (m_length == 0)
+        return QString();
+    return QString(m_data, m_length);
+}
+
+QByteArray QHashedStringRef::toUtf8() const
+{
+    if (m_length == 0)
+        return QByteArray();
+
+    QByteArray result;
+    result.resize(utf8length());
+    writeUtf8(result.data());
+    return result;
+}
+
+void QHashedStringRef::writeUtf8(char *output) const
+{
+    if (m_length) {
+        int ulen = utf8length();
+        if (ulen == m_length) {
+            // Must be a latin1 string
+            uchar *o = (uchar *)output;
+            const QChar *c = m_data;
+            while (ulen--) 
+                *o++ = (uchar)((*c++).unicode());
+        } else {
+            utf8FromUtf16(output, m_data, m_length);
+        }
+    }
+}
index 1633855..c04e504 100644 (file)
@@ -76,16 +76,16 @@ public:
     inline quint32 existingHash() const;
 
     static inline bool isUpper(const QChar &);
+
+    static bool compare(const QChar *lhs, const QChar *rhs, int length);
+    static inline bool compare(const QChar *lhs, const char *rhs, int length);
+    static inline bool compare(const char *lhs, const char *rhs, int length);
 private:
     friend class QHashedStringRef;
     friend class QStringHashNode;
 
     void computeHash() const;
     mutable quint32 m_hash;
-
-    static bool compare(const QChar *lhs, const QChar *rhs, int length);
-    static inline bool compare(const QChar *lhs, const char *rhs, int length);
-    static inline bool compare(const char *lhs, const char *rhs, int length);
 };
 
 class Q_AUTOTEST_EXPORT QHashedV8String 
@@ -114,27 +114,46 @@ class Q_AUTOTEST_EXPORT QHashedStringRef
 public:
     inline QHashedStringRef();
     inline QHashedStringRef(const QString &);
+    inline QHashedStringRef(const QStringRef &);
     inline QHashedStringRef(const QChar *, int);
     inline QHashedStringRef(const QChar *, int, quint32);
     inline QHashedStringRef(const QHashedString &);
     inline QHashedStringRef(const QHashedStringRef &);
+    inline QHashedStringRef &operator=(const QHashedStringRef &);
 
+    inline bool operator==(const QString &string) const;
     inline bool operator==(const QHashedString &string) const;
     inline bool operator==(const QHashedStringRef &string) const;
+    inline bool operator!=(const QString &string) const;
+    inline bool operator!=(const QHashedString &string) const;
+    inline bool operator!=(const QHashedStringRef &string) const;
 
     inline quint32 hash() const;
 
+    inline const QChar &at(int) const;
     inline const QChar *constData() const;
+    bool startsWith(const QString &) const;
+    bool endsWith(const QString &) const;
+    QHashedStringRef mid(int, int) const;
+
+    inline bool isEmpty() const;
     inline int length() const;
     inline bool startsWithUpper() const;
 
+    QString toString() const;
+
+    inline int utf8length() const;
+    QByteArray toUtf8() const;
+    void writeUtf8(char *) const;
 private:
     friend class QHashedString;
 
     void computeHash() const;
+    void computeUtf8Length() const;
 
     const QChar *m_data;
     int m_length;
+    mutable int m_utf8length;
     mutable quint32 m_hash;
 };
 
@@ -163,20 +182,23 @@ class Q_AUTOTEST_EXPORT QStringHashNode
 {
 public:
     QStringHashNode()
-    : nlist(0), next(0), length(0), hash(0), pooled(0), ckey(0), symbolId()
+    : nlist(0), next(0), length(0), hash(0), pooled(0), ckey(0), ukey(0), symbolId()
     {
     }
 
     QStringHashNode(const QHashedString &key)
-    : nlist(0), next(0), length(key.length()), hash(key.hash()), pooled(0), ckey(0), key(key), symbolId(0) {
+    : nlist(0), next(0), length(key.length()), hash(key.hash()), pooled(0), ckey(0), key(key), 
+      ukey(key.constData()), symbolId(0) {
     }
 
     QStringHashNode(const QHashedCStringRef &key)
-    : nlist(0), next(0), length(key.length()), hash(key.hash()), pooled(0), ckey(key.constData()), symbolId(0) {
+    : nlist(0), next(0), length(key.length()), hash(key.hash()), pooled(0), ckey(key.constData()), 
+      ukey(0), symbolId(0) {
     }
 
     QStringHashNode(const QStringHashNode &o)
-    : nlist(0), next(0), length(o.length), hash(o.hash), pooled(0), ckey(o.ckey), key(o.key), symbolId(o.symbolId) {
+    : nlist(0), next(0), length(o.length), hash(o.hash), pooled(0), ckey(o.ckey), key(o.key), 
+      ukey(o.ukey), symbolId(o.symbolId) {
     }
 
     QStringHashNode *nlist;
@@ -187,12 +209,13 @@ public:
     quint32 pooled:1;
     const char *ckey;
     QString key;
+    const QChar *ukey;
     
     quint32 symbolId;
 
     inline bool equals(v8::Handle<v8::String> string) {
         return ckey?string->Equals((char*)ckey, length):
-                    string->Equals((uint16_t*)key.constData(), length);
+                    string->Equals((uint16_t*)ukey, length);
     }
 
     inline bool symbolEquals(const QHashedV8String &string) {
@@ -209,15 +232,15 @@ public:
     inline bool equals(const QHashedStringRef &string) {
         return length == string.length() && 
                hash == string.hash() && 
-               ckey?(QHashedString::compare(string.constData(), ckey, length)):
-                    (QHashedString::compare(string.constData(), key.constData(), length));
+               (ckey?(QHashedString::compare(string.constData(), ckey, length)):
+                     (QHashedString::compare(string.constData(), ukey, length)));
     }
 
     inline bool equals(const QHashedCStringRef &string) {
         return length == string.length() && 
                hash == string.hash() && 
-               ckey?(QHashedString::compare(string.constData(), ckey, length)):
-                    (QHashedString::compare(key.constData(), string.constData(), length));
+               (ckey?(QHashedString::compare(string.constData(), ckey, length)):
+                     (QHashedString::compare(ukey, string.constData(), length)));
     }
 };
 
@@ -434,6 +457,7 @@ typename QStringHash<T,SmallThreshold>::Node *QStringHash<T,SmallThreshold>::tak
         rv->length = key.length();
         rv->hash = key.hash();
         rv->key = key;
+        rv->ukey = rv->key.constData();
         rv->pooled = 1;
         rv->value = value;
         return rv;
@@ -467,6 +491,7 @@ typename QStringHash<T,SmallThreshold>::Node *QStringHash<T,SmallThreshold>::tak
         rv->hash = o.hash;
         rv->ckey = o.ckey;
         rv->key = o.key;
+        rv->ukey = o.ukey;
         rv->pooled = 1;
         rv->symbolId = o.symbolId;
         rv->value = o.value;
@@ -883,35 +908,56 @@ v8::Handle<v8::String> QHashedV8String::string() const
 }
 
 QHashedStringRef::QHashedStringRef() 
-: m_data(0), m_length(0), m_hash(0) 
+: m_data(0), m_length(0), m_utf8length(-1), m_hash(0) 
 {
 }
 
 QHashedStringRef::QHashedStringRef(const QString &str)
-: m_data(str.constData()), m_length(str.length()), m_hash(0)
+: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QStringRef &str)
+: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
 {
 }
 
 QHashedStringRef::QHashedStringRef(const QChar *data, int length)
-: m_data(data), m_length(length), m_hash(0)
+: m_data(data), m_length(length), m_utf8length(0), m_hash(0)
 {
 }
 
 QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
-: m_data(data), m_length(length), m_hash(hash)
+: m_data(data), m_length(length), m_utf8length(0), m_hash(hash)
 {
 }
 
 QHashedStringRef::QHashedStringRef(const QHashedString &string)
-: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
+: m_data(string.constData()), m_length(string.length()), m_utf8length(0), m_hash(string.m_hash)
 {
 }
 
 QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
-: m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
+: m_data(string.m_data), m_length(string.m_length), m_utf8length(string.m_utf8length), 
+  m_hash(string.m_hash)
 {
 }
 
+QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
+{
+    m_data = o.m_data;
+    m_length = o.m_length;
+    m_utf8length = o.m_utf8length;
+    m_hash = o.m_hash;
+    return *this;
+}
+
+bool QHashedStringRef::operator==(const QString &string) const
+{
+    return m_length == string.length() &&
+           QHashedString::compare(string.constData(), m_data, m_length);
+}
+
 bool QHashedStringRef::operator==(const QHashedString &string) const
 {
     return m_length == string.length() && 
@@ -926,16 +972,54 @@ bool QHashedStringRef::operator==(const QHashedStringRef &string) const
            QHashedString::compare(string.m_data, m_data, m_length);
 }
 
+bool QHashedStringRef::operator!=(const QString &string) const
+{
+    return m_length != string.length() ||
+           !QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedString &string) const
+{
+    return m_length != string.length() || 
+           (m_hash != string.m_hash && m_hash && string.m_hash) ||
+           !QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedStringRef &string) const
+{
+    return m_length != string.m_length ||
+           (m_hash != string.m_hash && m_hash && string.m_hash) ||
+           QHashedString::compare(string.m_data, m_data, m_length);
+}
+
+const QChar &QHashedStringRef::at(int index) const
+{
+    Q_ASSERT(index < m_length);
+    return m_data[index];
+}
+
 const QChar *QHashedStringRef::constData() const
 {
     return m_data;
 }
 
+bool QHashedStringRef::isEmpty() const
+{
+    return m_length == 0;
+}
+
 int QHashedStringRef::length() const
 {
     return m_length;
 }
 
+int QHashedStringRef::utf8length() const
+{
+    if (m_utf8length < m_length)
+        computeUtf8Length();
+    return m_utf8length;
+}
+
 bool QHashedStringRef::startsWithUpper() const
 {
     if (m_length < 1) return false;
index 95d1ffb..31f5490 100644 (file)
@@ -125,10 +125,10 @@ QList<QDeclarativeError> QDeclarativeCompiler::errors() const
 */
 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
 {
-    return isAttachedPropertyName(QStringRef(&name));
+    return isAttachedPropertyName(QHashedStringRef(&name));
 }
 
-bool QDeclarativeCompiler::isAttachedPropertyName(const QStringRef &name)
+bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &name)
 {
     return !name.isEmpty() && QDeclarativeUtils::isUpper(name.at(0));
 }
@@ -149,11 +149,11 @@ bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
     return isSignalPropertyName(QStringRef(&name));
 }
 
-bool QDeclarativeCompiler::isSignalPropertyName(const QStringRef &name)
+bool QDeclarativeCompiler::isSignalPropertyName(const QHashedStringRef &name)
 {
     if (name.length() < 3) return false;
     if (!name.startsWith(on_string)) return false;
-    int ns = name.size();
+    int ns = name.length();
     for (int i = 2; i < ns; ++i) {
         const QChar curr = name.at(i);
         if (curr.unicode() == '_') continue;
@@ -777,10 +777,10 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
         enginePrivate->registerCompositeType(output);
 }
 
-static bool QStringList_contains(const QStringList &list, const QStringRef &string)
+static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
 {
     for (int ii = 0; ii < list.count(); ++ii)
-        if (list.at(ii) == string)
+        if (string == list.at(ii))
             return true;
 
     return false;
@@ -1413,9 +1413,10 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl
 {
     Q_ASSERT(obj->metaObject());
 
-    QStringRef propName = prop->name();
+    const QHashedStringRef &propName = prop->name();
+
     Q_ASSERT(propName.startsWith(on_string));
-    QString name = propName.string()->mid(propName.position() + 2, propName.length() - 2);
+    QString name = propName.mid(2, -1).toString();
 
     // Note that the property name could start with any alpha or '_' or '$' character,
     // so we need to do the lower-casing of the first alpha character.
@@ -2382,7 +2383,8 @@ int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QStrin
 // Ensures that the dynamic meta specification on obj is valid
 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
 {
-    QSet<QByteArray> propNames;
+    // XXX aakenned - inefficient copying of the string ref
+    QStringHash<bool> propNames;
     QSet<QByteArray> methodNames;
     bool seenDefaultProperty = false;
 
@@ -2400,14 +2402,13 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
         if (propNames.contains(prop.name))
             COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
 
-        QString propName = QString::fromUtf8(prop.name);
-        if (QDeclarativeUtils::isUpper(propName.at(0)))
+        if (QDeclarativeUtils::isUpper(prop.name.at(0)))
             COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
 
-        if (enginePrivate->v8engine()->illegalNames().contains(propName))
+        if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
             COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
 
-        propNames.insert(prop.name);
+        propNames.insert(prop.name.toString(), true);
     }
 
     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
@@ -2507,8 +2508,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
 
         if (!resolveAlias) {
             // No point doing this for both the alias and non alias cases
-            QString name = QString::fromUtf8(p.name);
-            QDeclarativePropertyCache::Data *d = property(obj, QStringRef(&name));
+            QDeclarativePropertyCache::Data *d = property(obj, p.name);
             if (d && d->isFinal())
                 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
         }
@@ -2577,7 +2577,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
             Object::DynamicProperty &p = obj->dynamicProperties[ii];
 
             // Reserve space for name
-            p.nameRef = builder.newString(p.name.length());
+            p.nameRef = builder.newString(p.name.utf8length());
 
             int propertyType = 0;
             bool readonly = false;
@@ -2598,10 +2598,12 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
                 Q_ASSERT(p.type == Object::DynamicProperty::CustomList ||
                          p.type == Object::DynamicProperty::Custom);
 
+                // XXX don't double resolve this in the case of an alias run
+
                 QByteArray customTypeName;
                 QDeclarativeType *qmltype = 0;
                 QString url;
-                if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0)) 
+                if (!unit->imports().resolveType(p.customType.toUtf8(), &qmltype, &url, 0, 0, 0)) 
                     COMPILE_EXCEPTION(&p, tr("Invalid property type"));
 
                 if (!qmltype) {
@@ -2626,7 +2628,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
                     propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
                 }
 
-                p.resolvedCustomTypeName = customTypeName;
+                p.resolvedCustomTypeName = pool->NewByteArray(customTypeName);
                 p.typeRef = builder.newString(customTypeName.length());
                 typeRef = p.typeRef;
             }
@@ -2646,7 +2648,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
                                     readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, 
                                     effectivePropertyIndex);
 
-            p.changedSignatureRef = builder.newString(p.name.length() + strlen("Changed()"));
+            p.changedSignatureRef = builder.newString(p.name.utf8length() + strlen("Changed()"));
             builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
 
             effectivePropertyIndex++;
@@ -2664,7 +2666,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
                     }
                     // Even if we aren't resolving the alias, we need a fake signal so that the 
                     // metaobject remains consistent across the resolve and non-resolve alias runs
-                    p.changedSignatureRef = builder.newString(p.name.length() + strlen("Changed()"));
+                    p.changedSignatureRef = builder.newString(p.name.utf8length() + strlen("Changed()"));
                     builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
                     effectivePropertyIndex++;
                     aliasIndex++;
@@ -2763,16 +2765,18 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
         Object::DynamicProperty &p = obj->dynamicProperties[ii];
 
         char *d = p.changedSignatureRef.data();
-        strcpy(d, p.name.constData());
-        strcpy(d + p.name.length(), "Changed()");
+        p.name.writeUtf8(d);
+        strcpy(d + p.name.utf8length(), "Changed()");
 
         if (p.type == Object::DynamicProperty::Alias && !resolveAlias)
             continue;
 
         p.nameRef.load(p.name);
 
-        if (p.type >= builtinTypeCount) 
-            p.typeRef.load(p.resolvedCustomTypeName);
+        if (p.type >= builtinTypeCount) {
+            Q_ASSERT(p.resolvedCustomTypeName);
+            p.typeRef.load(*p.resolvedCustomTypeName);
+        }
     }
 
     // Allocate default property if necessary
@@ -2988,7 +2992,7 @@ bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
     *(vmd->aliasData() + aliasIndex) = aliasData;
 
     prop.nameRef = builder.newString(prop.name.length());
-    prop.resolvedCustomTypeName = typeName;
+    prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
     prop.typeRef = builder.newString(typeName.length());
 
     builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type, 
@@ -3006,6 +3010,7 @@ bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
     Q_ASSERT(prop->parent);
     Q_ASSERT(prop->parent->metaObject());
 
+    // XXX aakenned
     QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
     if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
@@ -3158,7 +3163,7 @@ bool QDeclarativeCompiler::completeComponentBuild()
         QString expression = binding.expression.asScript();
 
         QDeclarativeRewrite::RewriteBinding rewriteBinding;
-        rewriteBinding.setName(QLatin1Char('$')+binding.property->name());
+        rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
         bool isSharable = false;
         binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
 
@@ -3341,7 +3346,7 @@ QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
 }
 
 QDeclarativePropertyCache::Data *
-QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QStringRef &name, bool *notInRevision)
+QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
 {
     if (notInRevision) *notInRevision = false;
 
@@ -3354,7 +3359,7 @@ QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QString
     else
         cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
 
-    QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
+    QDeclarativePropertyCache::Data *d = cache->property(name);
 
     // Find the first property
     while (d && d->isFunction())
@@ -3370,7 +3375,7 @@ QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QString
 
 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
 QDeclarativePropertyCache::Data *
-QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QStringRef &name, bool *notInRevision)
+QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
 {
     if (notInRevision) *notInRevision = false;
 
@@ -3384,7 +3389,7 @@ QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QStringRe
         cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
 
 
-    QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
+    QDeclarativePropertyCache::Data *d = cache->property(name);
     if (notInRevision) *notInRevision = false;
 
     while (d && !(d->isFunction()))
@@ -3398,7 +3403,7 @@ QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QStringRe
     }
 
     if (name.endsWith(Changed_string)) {
-        QStringRef propName(name.string(), name.position(), name.length() - Changed_string.length());
+        QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
 
         d = property(object, propName, notInRevision);
         if (d) 
@@ -3422,7 +3427,7 @@ int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, co
     return indexOfProperty(object, QStringRef(&name), notInRevision);
 }
 
-int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QStringRef &name, 
+int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QHashedStringRef &name, 
                                           bool *notInRevision)
 {
     QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
index e8f5c6a..587e401 100644 (file)
@@ -230,8 +230,8 @@ public:
 
     static bool isAttachedPropertyName(const QString &);
     static bool isSignalPropertyName(const QString &);
-    static bool isAttachedPropertyName(const QStringRef &);
-    static bool isSignalPropertyName(const QStringRef &);
+    static bool isAttachedPropertyName(const QHashedStringRef &);
+    static bool isSignalPropertyName(const QHashedStringRef &);
 
     int evaluateEnum(const QByteArray& script) const; // for QDeclarativeCustomParser::evaluateEnum
     const QMetaObject *resolveType(const QByteArray& name) const; // for QDeclarativeCustomParser::resolveType
@@ -340,11 +340,11 @@ private:
     QStringList deferredProperties(QDeclarativeParser::Object *);
 
     QDeclarativePropertyCache::Data *property(QDeclarativeParser::Object *, int);
-    QDeclarativePropertyCache::Data *property(QDeclarativeParser::Object *, const QStringRef &, 
+    QDeclarativePropertyCache::Data *property(QDeclarativeParser::Object *, const QHashedStringRef &, 
                                               bool *notInRevision = 0);
-    QDeclarativePropertyCache::Data *signal(QDeclarativeParser::Object *, const QStringRef &, 
+    QDeclarativePropertyCache::Data *signal(QDeclarativeParser::Object *, const QHashedStringRef &, 
                                             bool *notInRevision = 0);
-    int indexOfProperty(QDeclarativeParser::Object *, const QStringRef &, bool *notInRevision = 0);
+    int indexOfProperty(QDeclarativeParser::Object *, const QHashedStringRef &, bool *notInRevision = 0);
     int indexOfProperty(QDeclarativeParser::Object *, const QString &, bool *notInRevision = 0);
     int indexOfSignal(QDeclarativeParser::Object *, const QString &, bool *notInRevision = 0);
 
index a34eceb..123bb7f 100644 (file)
@@ -132,7 +132,7 @@ void QDeclarativeParser::Object::addScriptStringProperty(Property *p)
     scriptStringProperties.append(p);
 }
 
-Property *QDeclarativeParser::Object::getProperty(const QStringRef &name, bool create)
+Property *QDeclarativeParser::Object::getProperty(const QHashedStringRef &name, bool create)
 {
     for (Property *p = properties.first(); p; p = properties.next(p)) {
         if (p->name() == name)
@@ -151,6 +151,11 @@ Property *QDeclarativeParser::Object::getProperty(const QStringRef &name, bool c
     }
 }
 
+Property *QDeclarativeParser::Object::getProperty(const QStringRef &name, bool create)
+{
+    return getProperty(QHashedStringRef(name), create);
+}
+
 Property *QDeclarativeParser::Object::getProperty(const QString &name, bool create)
 {
     for (Property *p = properties.first(); p; p = properties.next(p)) {
@@ -171,7 +176,7 @@ Property *QDeclarativeParser::Object::getProperty(const QString &name, bool crea
 }
 
 QDeclarativeParser::Object::DynamicProperty::DynamicProperty()
-: isDefaultProperty(false), type(Variant), defaultValue(0)
+: isDefaultProperty(false), type(Variant), defaultValue(0), resolvedCustomTypeName(0)
 {
 }
 
@@ -181,7 +186,8 @@ QDeclarativeParser::Object::DynamicProperty::DynamicProperty(const DynamicProper
   customType(o.customType),
   name(o.name),
   defaultValue(o.defaultValue),
-  location(o.location)
+  location(o.location),
+  resolvedCustomTypeName(o.resolvedCustomTypeName)
 {
 }
 
@@ -229,7 +235,7 @@ int QDeclarativeParser::Object::DynamicSlot::parameterNamesLength() const
 }
 
 QDeclarativeParser::Property::Property()
-: parent(0), type(0), index(-1), value(0), _name(0), isDefault(true), isDeferred(false), 
+: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false), 
   isValueTypeSubProperty(false), isAlias(false), scriptStringScope(-1), nextProperty(0), 
   nextMainProperty(0)
 {
index 023cb9c..18c93fe 100644 (file)
@@ -68,6 +68,7 @@
 #include <private/qfieldlist_p.h>
 #include <private/qdeclarativepropertycache_p.h>
 #include <private/qfastmetabuilder_p.h>
+#include <private/qhashedstring_p.h>
 
 QT_BEGIN_HEADER
 
@@ -251,8 +252,8 @@ namespace QDeclarativeParser
         // Content in value and values are mutually exclusive.
         Object *value;
         // The property name
-        QStringRef name() const { return _name; }
-        void setName(const QString &n) { _name = QStringRef(pool()->NewString(n)); }
+        const QHashedStringRef &name() const { return _name; }
+        void setName(const QString &n) { _name = QHashedStringRef(pool()->NewString(n)); }
         // True if this property was accessed as the default property.  
         bool isDefault;
         // True if the setting of this property will be deferred.  Set by the
@@ -278,7 +279,7 @@ namespace QDeclarativeParser
 
     private:
         friend class Object;
-        QStringRef _name;
+        QHashedStringRef _name;
     };
 
     class Object : public QDeclarativePool::Class
@@ -318,6 +319,7 @@ namespace QDeclarativeParser
 
         Property *getDefaultProperty();
         // name ptr must be guarenteed to remain valid
+        Property *getProperty(const QHashedStringRef &name, bool create=true);
         Property *getProperty(const QStringRef &name, bool create=true);
         Property *getProperty(const QString &name, bool create=true);
 
@@ -367,17 +369,19 @@ namespace QDeclarativeParser
             DynamicProperty();
             DynamicProperty(const DynamicProperty &);
 
-            enum Type { Variant, Int, Bool, Real, String, Url, Color, Time, Date, DateTime, Alias, Custom, CustomList };
+            enum Type { Variant, Int, Bool, Real, String, Url, Color, Time, 
+                        Date, DateTime, Alias, Custom, CustomList };
 
             bool isDefaultProperty;
             Type type;
-            QByteArray customType;
-            QByteArray name;
+
+            QHashedStringRef customType;
+            QHashedStringRef name;
             QDeclarativeParser::Property *defaultValue;
             LocationSpan location;
 
             // Used by the compiler
-            QByteArray resolvedCustomTypeName;
+            QByteArray *resolvedCustomTypeName;
             QFastMetaBuilder::StringRef typeRef;
             QFastMetaBuilder::StringRef nameRef;
             QFastMetaBuilder::StringRef changedSignatureRef;
@@ -387,7 +391,7 @@ namespace QDeclarativeParser
             DynamicSignal(const DynamicSignal &);
 
             QByteArray name;
-            QList<QByteArray> parameterTypes;
+            QList<QHashedCStringRef> parameterTypes;
             QList<QByteArray> parameterNames;
 
             int parameterTypesLength() const;
index 9e5a427..458fd5e 100644 (file)
@@ -512,46 +512,51 @@ bool ProcessAST::visit(AST::UiImport *node)
 
 bool ProcessAST::visit(AST::UiPublicMember *node)
 {
-    const struct TypeNameToType {
+    static const struct TypeNameToType {
         const char *name;
+        int nameLength;
         Object::DynamicProperty::Type type;
         const char *qtName;
+        int qtNameLength;
     } propTypeNameToTypes[] = {
-        { "int", Object::DynamicProperty::Int, "int" },
-        { "bool", Object::DynamicProperty::Bool, "bool" },
-        { "double", Object::DynamicProperty::Real, "double" },
-        { "real", Object::DynamicProperty::Real, "qreal" },
-        { "string", Object::DynamicProperty::String, "QString" },
-        { "url", Object::DynamicProperty::Url, "QUrl" },
-        { "color", Object::DynamicProperty::Color, "QColor" },
+        { "int", strlen("int"), Object::DynamicProperty::Int, "int", strlen("int") },
+        { "bool", strlen("bool"), Object::DynamicProperty::Bool, "bool", strlen("bool") },
+        { "double", strlen("double"), Object::DynamicProperty::Real, "double", strlen("double") },
+        { "real", strlen("real"), Object::DynamicProperty::Real, "qreal", strlen("qreal") },
+        { "string", strlen("string"), Object::DynamicProperty::String, "QString", strlen("QString") },
+        { "url", strlen("url"), Object::DynamicProperty::Url, "QUrl", strlen("QUrl") },
+        { "color", strlen("color"), Object::DynamicProperty::Color, "QColor", strlen("QColor") },
         // Internally QTime, QDate and QDateTime are all supported.
         // To be more consistent with JavaScript we expose only
         // QDateTime as it matches closely with the Date JS type.
         // We also call it "date" to match.
-        // { "time", Object::DynamicProperty::Time, "QTime" },
-        // { "date", Object::DynamicProperty::Date, "QDate" },
-        { "date", Object::DynamicProperty::DateTime, "QDateTime" },
-        { "variant", Object::DynamicProperty::Variant, "QVariant" }
+        // { "time", strlen("time"), Object::DynamicProperty::Time, "QTime", strlen("QTime") },
+        // { "date", strlen("date"), Object::DynamicProperty::Date, "QDate", strlen("QDate") },
+        { "date", strlen("date"), Object::DynamicProperty::DateTime, "QDateTime", strlen("QDateTime") },
+        { "variant", strlen("variant"), Object::DynamicProperty::Variant, "QVariant", strlen("QVariant") }
     };
-    const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
-                                         sizeof(propTypeNameToTypes[0]);
+    static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+                                                sizeof(propTypeNameToTypes[0]);
 
     if(node->type == AST::UiPublicMember::Signal) {
-        const QString name = node->name.toString();
-
         Object::DynamicSignal signal;
-        signal.name = name.toUtf8();
+        signal.name = node->name.toUtf8();
 
         AST::UiParameterList *p = node->parameters;
         while (p) {
-            const QString memberType = p->type.toString();
-            const char *qtType = 0;
-            for(int ii = 0; !qtType && ii < propTypeNameToTypesCount; ++ii) {
-                if(QLatin1String(propTypeNameToTypes[ii].name) == memberType)
-                    qtType = propTypeNameToTypes[ii].qtName;
+            const QStringRef &memberType = p->type;
+
+            const TypeNameToType *type = 0;
+            for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
+                const TypeNameToType *t = propTypeNameToTypes + typeIndex;
+                if (t->nameLength == memberType.length() && 
+                    QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+                    type = t;
+                    break;
+                }
             }
 
-            if (!qtType) {
+            if (!type) {
                 QDeclarativeError error;
                 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected parameter type"));
                 error.setLine(node->typeToken.startLine);
@@ -560,7 +565,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
                 return false;
             }
             
-            signal.parameterTypes << qtType;
+            signal.parameterTypes << QHashedCStringRef(type->qtName, type->qtNameLength);
             signal.parameterNames << p->name.toUtf8();
             p = p->finish();
         }
@@ -568,31 +573,34 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
         signal.location = location(node->typeToken, node->semicolonToken);
         _stateStack.top().object->dynamicSignals << signal;
     } else {
-        const QString memberType = node->memberType.toString();
-        const QString name = node->name.toString();
+        const QStringRef &memberType = node->memberType;
+        const QStringRef &name = node->name;
 
         bool typeFound = false;
         Object::DynamicProperty::Type type;
 
-        if (memberType == QLatin1String("alias")) {
+        if (memberType.length() == strlen("alias") && 
+            QHashedString::compare(memberType.constData(), "alias", strlen("alias"))) {
             type = Object::DynamicProperty::Alias;
             typeFound = true;
-        }
+        } 
 
         for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
-            if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) {
-                type = propTypeNameToTypes[ii].type;
+            const TypeNameToType *t = propTypeNameToTypes + ii;
+            if (t->nameLength == memberType.length() && 
+                QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+                type = t->type;
                 typeFound = true;
             }
         }
 
         if (!typeFound && memberType.at(0).isUpper()) {
-            QString typemodifier;
-            if(!node->typeModifier.isNull())
-                typemodifier = node->typeModifier.toString();
-            if (typemodifier.isEmpty()) {
+            const QStringRef &typeModifier = node->typeModifier;
+
+            if (typeModifier.isEmpty()) {
                 type = Object::DynamicProperty::Custom;
-            } else if(typemodifier == QLatin1String("list")) {
+            } else if(typeModifier.length() == strlen("list") && 
+                      QHashedString::compare(typeModifier.constData(), "list", strlen("list"))) {
                 type = Object::DynamicProperty::CustomList;
             } else {
                 QDeclarativeError error;
@@ -630,16 +638,18 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
             return false;
 
         }
+
         Object::DynamicProperty property;
         property.isDefaultProperty = node->isDefaultMember;
         property.type = type;
         if (type >= Object::DynamicProperty::Custom) {
             QDeclarativeScriptParser::TypeReference *typeRef =
-                _parser->findOrCreateType(memberType);
+                _parser->findOrCreateType(memberType.toString());
             typeRef->refObjects.append(_stateStack.top().object);
+            property.customType = memberType;
         }
-        property.customType = memberType.toUtf8();
-        property.name = name.toUtf8();
+
+        property.name = QHashedStringRef(name);
         property.location = location(node->firstSourceLocation(),
                                      node->lastSourceLocation());
 
index 4f5caa1..8eaf902 100644 (file)
@@ -391,7 +391,7 @@ QNetworkAccessManager *QV8Engine::networkAccessManager()
     return QDeclarativeEnginePrivate::get(m_engine)->getNetworkAccessManager();
 }
 
-const QSet<QString> &QV8Engine::illegalNames() const
+const QStringHash<bool> &QV8Engine::illegalNames() const
 {
     return m_illegalNames;
 }
@@ -561,7 +561,7 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
     v8::Local<v8::Value> names = m_getOwnPropertyNames->Call(global, 1, args);
     v8::Local<v8::Array> namesArray = v8::Local<v8::Array>::Cast(names);
     for (quint32 ii = 0; ii < namesArray->Length(); ++ii) 
-        m_illegalNames.insert(toString(namesArray->Get(ii)));
+        m_illegalNames.insert(toString(namesArray->Get(ii)), true);
     }
 
     {
index 43ef982..bd5f360 100644 (file)
@@ -330,7 +330,7 @@ public:
     virtual QNetworkAccessManager *networkAccessManager();
 
     // Return the list of illegal id names (the names of the properties on the global object)
-    const QSet<QString> &illegalNames() const;
+    const QStringHash<bool> &illegalNames() const;
 
     inline void collectGarbage() { gc(); }
     static void gc();
@@ -419,7 +419,7 @@ protected:
     QVector<Deletable *> m_extensionData;
     Deletable *m_listModelData;
 
-    QSet<QString> m_illegalNames;
+    QStringHash<bool> m_illegalNames;
 
     Exception m_exception;