From a5159cc50aa0f8a57b6f736621b359a3bcecbf7e Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Apr 2016 09:40:49 +0200 Subject: [PATCH] QJsonObject: add some overloads taking QLatin1String QXmlStreamReader also has QLatin1String overloads, which greatly benefits parsers, since the vast majority of keys in both JSON and XML are US-ASCII. This patch adds such an overload to the JSON parser. The value() function is all typical parsers need, so even though many more QJsonObject functions taking QString could benefit from the same treatment, value() is the single most important one for read-only JSON access. Add some more overloads, too, for functions that don't need more internal scaffolding than value(). Requires adding a dummy op[](QL1S) (forwarding to the QString overload) so as not to make QJsonObject json; json[QLatin1String("key")]; // mutable ambiguous between const op[](QL1S) and mutable op[](QString). [ChangeLog][QtCore][QJsonObject] Added value(), op[] const, find(), constFind(), contains() overloads taking QLatin1String. Change-Id: I00883028956ad949ba5ba2b18dd8a6a25ad5085b Reviewed-by: Lars Knoll --- src/corelib/json/qjson.cpp | 32 ++++++++++- src/corelib/json/qjson_p.h | 18 +++++- src/corelib/json/qjsonobject.cpp | 80 ++++++++++++++++++++++++++ src/corelib/json/qjsonobject.h | 7 +++ tests/auto/corelib/json/tst_qtjson.cpp | 19 +++--- 5 files changed, 145 insertions(+), 11 deletions(-) diff --git a/src/corelib/json/qjson.cpp b/src/corelib/json/qjson.cpp index 24fcaf0937..bb98e25fa5 100644 --- a/src/corelib/json/qjson.cpp +++ b/src/corelib/json/qjson.cpp @@ -179,7 +179,29 @@ void Base::removeItems(int pos, int numItems) length -= numItems; } -int Object::indexOf(const QString &key, bool *exists) +int Object::indexOf(const QString &key, bool *exists) const +{ + int min = 0; + int n = length; + while (n > 0) { + int half = n >> 1; + int middle = min + half; + if (*entryAt(middle) >= key) { + n = half; + } else { + min = middle + 1; + n -= half + 1; + } + } + if (min < (int)length && *entryAt(min) == key) { + *exists = true; + return min; + } + *exists = false; + return min; +} + +int Object::indexOf(QLatin1String key, bool *exists) const { int min = 0; int n = length; @@ -248,6 +270,14 @@ bool Entry::operator ==(const QString &key) const return (shallowKey() == key); } +bool Entry::operator==(QLatin1String key) const +{ + if (value.latinKey) + return shallowLatin1Key() == key; + else + return shallowKey() == key; +} + bool Entry::operator ==(const Entry &other) const { if (value.latinKey) { diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h index 3580e0b61c..5e34845fe3 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/json/qjson_p.h @@ -573,7 +573,8 @@ public: Entry *entryAt(int i) const { return reinterpret_cast(((char *)this) + table()[i]); } - int indexOf(const QString &key, bool *exists); + int indexOf(const QString &key, bool *exists) const; + int indexOf(QLatin1String key, bool *exists) const; bool isValid() const; }; @@ -675,6 +676,10 @@ public: inline bool operator !=(const QString &key) const { return !operator ==(key); } inline bool operator >=(const QString &key) const; + bool operator==(QLatin1String key) const; + inline bool operator!=(QLatin1String key) const { return !operator ==(key); } + inline bool operator>=(QLatin1String key) const; + bool operator ==(const Entry &other) const; bool operator >=(const Entry &other) const; }; @@ -687,9 +692,20 @@ inline bool Entry::operator >=(const QString &key) const return (shallowKey() >= key); } +inline bool Entry::operator >=(QLatin1String key) const +{ + if (value.latinKey) + return shallowLatin1Key() >= key; + else + return shallowKey() >= key; +} + inline bool operator <(const QString &key, const Entry &e) { return e >= key; } +inline bool operator<(QLatin1String key, const Entry &e) +{ return e >= key; } + class Header { public: diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index 7badc9d929..b5b6f36bc6 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -374,6 +374,22 @@ QJsonValue QJsonObject::value(const QString &key) const return QJsonValue(d, o, o->entryAt(i)->value); } +/*! + \overload + \since 5.7 +*/ +QJsonValue QJsonObject::value(QLatin1String key) const +{ + if (!d) + return QJsonValue(QJsonValue::Undefined); + + bool keyExists; + int i = o->indexOf(key, &keyExists); + if (!keyExists) + return QJsonValue(QJsonValue::Undefined); + return QJsonValue(d, o, o->entryAt(i)->value); +} + /*! Returns a QJsonValue representing the value for the key \a key. @@ -388,6 +404,13 @@ QJsonValue QJsonObject::operator [](const QString &key) const return value(key); } +/*! + \fn QJsonValue QJsonObject::operator [](QLatin1String key) const + + \overload + \since 5.7 +*/ + /*! Returns a reference to the value for \a key. @@ -411,6 +434,16 @@ QJsonValueRef QJsonObject::operator [](const QString &key) return QJsonValueRef(this, index); } +/*! + \overload + \since 5.7 +*/ +QJsonValueRef QJsonObject::operator [](QLatin1String key) +{ + // ### optimize me + return operator[](QString(key)); +} + /*! Inserts a new item with the key \a key and a value of \a value. @@ -535,6 +568,20 @@ bool QJsonObject::contains(const QString &key) const return keyExists; } +/*! + \overload + \since 5.7 +*/ +bool QJsonObject::contains(QLatin1String key) const +{ + if (!o) + return false; + + bool keyExists; + o->indexOf(key, &keyExists); + return keyExists; +} + /*! Returns \c true if \a other is equal to this object. */ @@ -609,11 +656,31 @@ QJsonObject::iterator QJsonObject::find(const QString &key) return iterator(this, index); } +/*! + \overload + \since 5.7 +*/ +QJsonObject::iterator QJsonObject::find(QLatin1String key) +{ + bool keyExists = false; + int index = o ? o->indexOf(key, &keyExists) : 0; + if (!keyExists) + return end(); + detach2(); + return iterator(this, index); +} + /*! \fn QJsonObject::const_iterator QJsonObject::find(const QString &key) const \overload */ +/*! \fn QJsonObject::const_iterator QJsonObject::find(QLatin1String key) const + + \overload + \since 5.7 +*/ + /*! Returns a const iterator pointing to the item with key \a key in the map. @@ -630,6 +697,19 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const return const_iterator(this, index); } +/*! + \overload + \since 5.7 +*/ +QJsonObject::const_iterator QJsonObject::constFind(QLatin1String key) const +{ + bool keyExists = false; + int index = o ? o->indexOf(key, &keyExists) : 0; + if (!keyExists) + return end(); + return const_iterator(this, index); +} + /*! \fn int QJsonObject::count() const \overload diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/json/qjsonobject.h index 6cffbce83a..e238c84d98 100644 --- a/src/corelib/json/qjsonobject.h +++ b/src/corelib/json/qjsonobject.h @@ -86,12 +86,16 @@ public: bool isEmpty() const; QJsonValue value(const QString &key) const; + QJsonValue value(QLatin1String key) const; QJsonValue operator[] (const QString &key) const; + QJsonValue operator[] (QLatin1String key) const { return value(key); } QJsonValueRef operator[] (const QString &key); + QJsonValueRef operator[] (QLatin1String key); void remove(const QString &key); QJsonValue take(const QString &key); bool contains(const QString &key) const; + bool contains(QLatin1String key) const; bool operator==(const QJsonObject &other) const; bool operator!=(const QJsonObject &other) const; @@ -200,8 +204,11 @@ public: typedef iterator Iterator; typedef const_iterator ConstIterator; iterator find(const QString &key); + iterator find(QLatin1String key); const_iterator find(const QString &key) const { return constFind(key); } + const_iterator find(QLatin1String key) const { return constFind(key); } const_iterator constFind(const QString &key) const; + const_iterator constFind(QLatin1String key) const; iterator insert(const QString &key, const QJsonValue &value); // STL compatibility diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp index b4f0bd2b3a..5878d56a47 100644 --- a/tests/auto/corelib/json/tst_qtjson.cpp +++ b/tests/auto/corelib/json/tst_qtjson.cpp @@ -374,12 +374,13 @@ void tst_QtJson::testObjectSimple() QJsonObject object; object.insert("number", 999.); QCOMPARE(object.value("number").type(), QJsonValue::Double); - QCOMPARE(object.value("number").toDouble(), 999.); + QCOMPARE(object.value(QLatin1String("number")).toDouble(), 999.); object.insert("string", QString::fromLatin1("test")); QCOMPARE(object.value("string").type(), QJsonValue::String); - QCOMPARE(object.value("string").toString(), QString("test")); + QCOMPARE(object.value(QLatin1String("string")).toString(), QString("test")); object.insert("boolean", true); QCOMPARE(object.value("boolean").toBool(), true); + QCOMPARE(object.value(QLatin1String("boolean")).toBool(), true); QStringList keys = object.keys(); QVERIFY2(keys.contains("number"), "key number not found"); @@ -403,7 +404,7 @@ void tst_QtJson::testObjectSimple() QString before = object.value("string").toString(); object.insert("string", QString::fromLatin1("foo")); - QVERIFY2(object.value("string").toString() != before, "value should have been updated"); + QVERIFY2(object.value(QLatin1String("string")).toString() != before, "value should have been updated"); size = object.size(); QJsonObject subobject; @@ -678,7 +679,7 @@ void tst_QtJson::testValueRef() QCOMPARE(object.value(QLatin1String("null")), QJsonValue()); object[QLatin1String("null")] = 100.; QCOMPARE(object.value(QLatin1String("null")).type(), QJsonValue::Double); - QJsonValue val = object[QLatin1String("null")]; + QJsonValue val = qAsConst(object)[QLatin1String("null")]; QCOMPARE(val.toDouble(), 100.); QCOMPARE(object.size(), 2); @@ -843,13 +844,13 @@ void tst_QtJson::testObjectFind() QJsonObject::iterator it = object.find(QLatin1String("1")); QCOMPARE((*it).toDouble(), 1.); - it = object.find(QLatin1String("11")); + it = object.find(QString("11")); QCOMPARE((*it).type(), QJsonValue::Undefined); QCOMPARE(it, object.end()); QJsonObject::const_iterator cit = object.constFind(QLatin1String("1")); QCOMPARE((*cit).toDouble(), 1.); - cit = object.constFind(QLatin1String("11")); + cit = object.constFind(QString("11")); QCOMPARE((*it).type(), QJsonValue::Undefined); QCOMPARE(it, object.end()); } @@ -911,7 +912,7 @@ void tst_QtJson::testDocument() doc3.setObject(outer.value(QLatin1String("innter")).toObject()); QCOMPARE(doc3.isArray(), false); QCOMPARE(doc3.isObject(), true); - QVERIFY(doc3.object().contains(QLatin1String("innerKey"))); + QVERIFY(doc3.object().contains(QString("innerKey"))); QCOMPARE(doc3.object().value(QLatin1String("innerKey")), QJsonValue(42)); QJsonDocument doc4(outer.value(QLatin1String("innterArray")).toArray()); @@ -938,9 +939,9 @@ void tst_QtJson::nullValues() QJsonObject object; object.insert(QString("key"), QJsonValue()); - QCOMPARE(object.contains("key"), true); + QCOMPARE(object.contains(QLatin1String("key")), true); QCOMPARE(object.size(), 1); - QCOMPARE(object.value("key"), QJsonValue()); + QCOMPARE(object.value(QString("key")), QJsonValue()); } void tst_QtJson::nullArrays()