From: Aaron Kennedy Date: Thu, 21 Jul 2011 04:20:05 +0000 (+1000) Subject: Use strings more conservatively X-Git-Tag: qt-v5.0.0-alpha1~1825 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a257441a420d850205a5910bc2d3c1aa67bfc3e8;p=profile%2Fivi%2Fqtdeclarative.git Use strings more conservatively 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 --- diff --git a/src/declarative/qml/ftw/qdeclarativepool_p.h b/src/declarative/qml/ftw/qdeclarativepool_p.h index a087779..a30839a 100644 --- a/src/declarative/qml/ftw/qdeclarativepool_p.h +++ b/src/declarative/qml/ftw/qdeclarativepool_p.h @@ -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(); + *rv = s; + return rv; +} + void *QDeclarativePool::allocate(int size) { if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize)) diff --git a/src/declarative/qml/ftw/qfastmetabuilder_p.h b/src/declarative/qml/ftw/qfastmetabuilder_p.h index c0cb0fc..eb4852d 100644 --- a/src/declarative/qml/ftw/qfastmetabuilder_p.h +++ b/src/declarative/qml/ftw/qfastmetabuilder_p.h @@ -56,6 +56,8 @@ #include #include +#include + 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); } diff --git a/src/declarative/qml/ftw/qhashedstring.cpp b/src/declarative/qml/ftw/qhashedstring.cpp index 936f818..296d0c4 100644 --- a/src/declarative/qml/ftw/qhashedstring.cpp +++ b/src/declarative/qml/ftw/qhashedstring.cpp @@ -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); + } + } +} diff --git a/src/declarative/qml/ftw/qhashedstring_p.h b/src/declarative/qml/ftw/qhashedstring_p.h index 1633855..c04e504 100644 --- a/src/declarative/qml/ftw/qhashedstring_p.h +++ b/src/declarative/qml/ftw/qhashedstring_p.h @@ -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 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::Node *QStringHash::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::Node *QStringHash::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 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; diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 95d1ffb..31f5490 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -125,10 +125,10 @@ QList 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 propNames; + // XXX aakenned - inefficient copying of the string ref + QStringHash propNames; QSet 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 >(); } - 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); diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index e8f5c6a..587e401 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -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); diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp index a34eceb..123bb7f 100644 --- a/src/declarative/qml/qdeclarativeparser.cpp +++ b/src/declarative/qml/qdeclarativeparser.cpp @@ -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) { diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h index 023cb9c..18c93fe 100644 --- a/src/declarative/qml/qdeclarativeparser_p.h +++ b/src/declarative/qml/qdeclarativeparser_p.h @@ -68,6 +68,7 @@ #include #include #include +#include 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 parameterTypes; + QList parameterTypes; QList parameterNames; int parameterTypesLength() const; diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp index 9e5a427..458fd5e 100644 --- a/src/declarative/qml/qdeclarativescriptparser.cpp +++ b/src/declarative/qml/qdeclarativescriptparser.cpp @@ -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()); diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index 4f5caa1..8eaf902 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -391,7 +391,7 @@ QNetworkAccessManager *QV8Engine::networkAccessManager() return QDeclarativeEnginePrivate::get(m_engine)->getNetworkAccessManager(); } -const QSet &QV8Engine::illegalNames() const +const QStringHash &QV8Engine::illegalNames() const { return m_illegalNames; } @@ -561,7 +561,7 @@ void QV8Engine::initializeGlobal(v8::Handle global) v8::Local names = m_getOwnPropertyNames->Call(global, 1, args); v8::Local namesArray = v8::Local::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); } { diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index 43ef982..bd5f360 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -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 &illegalNames() const; + const QStringHash &illegalNames() const; inline void collectGarbage() { gc(); } static void gc(); @@ -419,7 +419,7 @@ protected: QVector m_extensionData; Deletable *m_listModelData; - QSet m_illegalNames; + QStringHash m_illegalNames; Exception m_exception;