summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/serialization/qjson_p.h61
-rw-r--r--src/corelib/serialization/qjsonobject.cpp148
-rw-r--r--src/corelib/serialization/qjsonobject.h14
-rw-r--r--tests/auto/corelib/serialization/json/tst_qtjson.cpp42
4 files changed, 221 insertions, 44 deletions
diff --git a/src/corelib/serialization/qjson_p.h b/src/corelib/serialization/qjson_p.h
index 78082a920d..7978bed7da 100644
--- a/src/corelib/serialization/qjson_p.h
+++ b/src/corelib/serialization/qjson_p.h
@@ -66,11 +66,13 @@
#include <limits.h>
#include <limits>
+#include <type_traits>
QT_BEGIN_NAMESPACE
// in qstring.cpp
void qt_to_latin1_unchecked(uchar *dst, const ushort *uc, qsizetype len);
+void qt_from_latin1(ushort *dst, const char *str, size_t size) noexcept;
/*
This defines a binary data structure for Json data. The data structure is optimised for fast reading
@@ -153,16 +155,24 @@ typedef qle_uint offset;
// round the size up to the next 4 byte boundary
inline int alignedSize(int size) { return (size + 3) & ~3; }
+const int MaxLatin1Length = 0x7fff;
+
static inline bool useCompressed(QStringView s)
{
- if (s.length() >= 0x8000)
+ if (s.length() > MaxLatin1Length)
return false;
return QtPrivate::isLatin1(s);
}
-static inline int qStringSize(QStringView string, bool compress)
+static inline bool useCompressed(QLatin1String s)
+{
+ return s.size() <= MaxLatin1Length;
+}
+
+template <typename T>
+static inline int qStringSize(T string, bool compress)
{
- int l = 2 + string.length();
+ int l = 2 + string.size();
if (!compress)
l *= 2;
return alignedSize(l);
@@ -218,11 +228,29 @@ public:
{
d->length = str.length();
qToLittleEndian<quint16>(str.utf16(), str.length(), d->utf16);
- if (str.length() & 1)
- d->utf16[str.length()] = 0;
+ fillTrailingZeros();
return *this;
}
+ inline String &operator=(QLatin1String str)
+ {
+ d->length = str.size();
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ for (int i = 0; i < str.size(); ++i)
+ d->utf16[i] = str[i].unicode();
+#else
+ qt_from_latin1((ushort *)d->utf16, str.data(), str.size());
+#endif
+ fillTrailingZeros();
+ return *this;
+ }
+
+ void fillTrailingZeros()
+ {
+ if (d->length & 1)
+ d->utf16[d->length] = 0;
+ }
+
inline bool operator ==(QStringView str) const {
int slen = str.length();
int l = d->length;
@@ -293,11 +321,27 @@ public:
const ushort *uc = (const ushort *)str.utf16();
qt_to_latin1_unchecked(l, uc, len);
- for ( ; (quintptr)(l+len) & 0x3; ++len)
- l[len] = 0;
+ fillTrailingZeros();
+ return *this;
+ }
+
+ inline Latin1String &operator=(QLatin1String str)
+ {
+ int len = d->length = str.size();
+ uchar *l = (uchar *)d->latin1;
+ memcpy(l, str.data(), len);
+
+ fillTrailingZeros();
return *this;
}
+ void fillTrailingZeros()
+ {
+ uchar *l = (uchar *)d->latin1;
+ for (int len = d->length; (quintptr)(l + len) & 0x3; ++len)
+ l[len] = 0;
+ }
+
QLatin1String toQLatin1String() const noexcept {
return QLatin1String(d->latin1, d->length);
}
@@ -413,7 +457,8 @@ inline bool String::operator<(const Latin1String &str) const
}
-static inline void copyString(char *dest, QStringView str, bool compress)
+template <typename T>
+static inline void copyString(char *dest, T str, bool compress)
{
if (compress) {
Latin1String string(dest);
diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp
index 19a16d8537..99ab25f265 100644
--- a/src/corelib/serialization/qjsonobject.cpp
+++ b/src/corelib/serialization/qjsonobject.cpp
@@ -397,14 +397,7 @@ QJsonValue QJsonObject::value(const QString &key) const
*/
QJsonValue QJsonObject::value(QStringView 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);
+ return valueImpl(key);
}
/*!
@@ -413,6 +406,15 @@ QJsonValue QJsonObject::value(QStringView key) const
*/
QJsonValue QJsonObject::value(QLatin1String key) const
{
+ return valueImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+QJsonValue QJsonObject::valueImpl(T key) const
+{
if (!d)
return QJsonValue(QJsonValue::Undefined);
@@ -477,13 +479,7 @@ QJsonValueRef QJsonObject::operator [](const QString &key)
*/
QJsonValueRef QJsonObject::operator [](QStringView key)
{
- bool keyExists = false;
- int index = o ? o->indexOf(key, &keyExists) : 0;
- if (!keyExists) {
- iterator i = insertAt(index, key, QJsonValue(), false);
- index = i.i;
- }
- return QJsonValueRef(this, index);
+ return atImpl(key);
}
/*!
@@ -492,8 +488,22 @@ QJsonValueRef QJsonObject::operator [](QStringView key)
*/
QJsonValueRef QJsonObject::operator [](QLatin1String key)
{
- // ### optimize me
- return operator[](QString(key));
+ return atImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+QJsonValueRef QJsonObject::atImpl(T key)
+{
+ bool keyExists = false;
+ int index = o ? o->indexOf(key, &keyExists) : 0;
+ if (!keyExists) {
+ iterator i = insertAt(index, key, QJsonValue(), false);
+ index = i.i;
+ }
+ return QJsonValueRef(this, index);
}
#if QT_STRINGVIEW_LEVEL < 2
@@ -522,6 +532,24 @@ QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue &
*/
QJsonObject::iterator QJsonObject::insert(QStringView key, const QJsonValue &value)
{
+ return insertImpl(key, value);
+}
+
+/*!
+ \overload
+ \since 5.14
+*/
+QJsonObject::iterator QJsonObject::insert(QLatin1String key, const QJsonValue &value)
+{
+ return insertImpl(key, value);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+QJsonObject::iterator QJsonObject::insertImpl(T key, const QJsonValue &value)
+{
if (value.t == QJsonValue::Undefined) {
remove(key);
return end();
@@ -534,7 +562,8 @@ QJsonObject::iterator QJsonObject::insert(QStringView key, const QJsonValue &val
/*!
\internal
*/
-QJsonObject::iterator QJsonObject::insertAt(int pos, QStringView key, const QJsonValue &value, bool keyExists)
+template <typename T>
+QJsonObject::iterator QJsonObject::insertAt(int pos, T key, const QJsonValue &value, bool keyExists)
{
QJsonValue val = value;
@@ -590,6 +619,24 @@ void QJsonObject::remove(const QString &key)
*/
void QJsonObject::remove(QStringView key)
{
+ removeImpl(key);
+}
+
+/*!
+ \overload
+ \since 5.14
+*/
+void QJsonObject::remove(QLatin1String key)
+{
+ removeImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+void QJsonObject::removeImpl(T key)
+{
if (!d)
return;
@@ -623,6 +670,24 @@ QJsonValue QJsonObject::take(const QString &key)
*/
QJsonValue QJsonObject::take(QStringView key)
{
+ return takeImpl(key);
+}
+
+/*!
+ \overload
+ \since 5.14
+*/
+QJsonValue QJsonObject::take(QLatin1String key)
+{
+ return takeImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+QJsonValue QJsonObject::takeImpl(T key)
+{
if (!o)
return QJsonValue(QJsonValue::Undefined);
@@ -655,12 +720,7 @@ bool QJsonObject::contains(const QString &key) const
*/
bool QJsonObject::contains(QStringView key) const
{
- if (!o)
- return false;
-
- bool keyExists;
- o->indexOf(key, &keyExists);
- return keyExists;
+ return containsImpl(key);
}
/*!
@@ -669,6 +729,15 @@ bool QJsonObject::contains(QStringView key) const
*/
bool QJsonObject::contains(QLatin1String key) const
{
+ return containsImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+bool QJsonObject::containsImpl(T key) const
+{
if (!o)
return false;
@@ -751,12 +820,7 @@ QJsonObject::iterator QJsonObject::find(const QString &key)
*/
QJsonObject::iterator QJsonObject::find(QStringView key)
{
- bool keyExists = false;
- int index = o ? o->indexOf(key, &keyExists) : 0;
- if (!keyExists)
- return end();
- detach2();
- return iterator(this, index);
+ return findImpl(key);
}
/*!
@@ -765,6 +829,15 @@ QJsonObject::iterator QJsonObject::find(QStringView key)
*/
QJsonObject::iterator QJsonObject::find(QLatin1String key)
{
+ return findImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+QJsonObject::iterator QJsonObject::findImpl(T key)
+{
bool keyExists = false;
int index = o ? o->indexOf(key, &keyExists) : 0;
if (!keyExists)
@@ -812,11 +885,7 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
*/
QJsonObject::const_iterator QJsonObject::constFind(QStringView key) const
{
- bool keyExists = false;
- int index = o ? o->indexOf(key, &keyExists) : 0;
- if (!keyExists)
- return end();
- return const_iterator(this, index);
+ return constFindImpl(key);
}
/*!
@@ -825,6 +894,15 @@ QJsonObject::const_iterator QJsonObject::constFind(QStringView key) const
*/
QJsonObject::const_iterator QJsonObject::constFind(QLatin1String key) const
{
+ return constFindImpl(key);
+}
+
+/*!
+ \internal
+*/
+template <typename T>
+QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
+{
bool keyExists = false;
int index = o ? o->indexOf(key, &keyExists) : 0;
if (!keyExists)
diff --git a/src/corelib/serialization/qjsonobject.h b/src/corelib/serialization/qjsonobject.h
index bdaf85b460..05463f6f36 100644
--- a/src/corelib/serialization/qjsonobject.h
+++ b/src/corelib/serialization/qjsonobject.h
@@ -118,7 +118,9 @@ public:
bool contains(const QString &key) const;
#endif
void remove(QStringView key);
+ void remove(QLatin1String key);
QJsonValue take(QStringView key);
+ QJsonValue take(QLatin1String key);
bool contains(QStringView key) const;
bool contains(QLatin1String key) const;
@@ -241,6 +243,7 @@ public:
const_iterator constFind(QStringView key) const;
const_iterator constFind(QLatin1String key) const;
iterator insert(QStringView key, const QJsonValue &value);
+ iterator insert(QLatin1String key, const QJsonValue &value);
// STL compatibility
typedef QJsonValue mapped_type;
@@ -265,11 +268,20 @@ private:
void compact();
void compactIfNeeded();
+ template <typename T> QJsonValue valueImpl(T key) const;
+ template <typename T> QJsonValueRef atImpl(T key);
+ template <typename T> void removeImpl(T key);
+ template <typename T> QJsonValue takeImpl(T key);
+ template <typename T> bool containsImpl(T key) const;
+ template <typename T> iterator findImpl(T key);
+ template <typename T> const_iterator constFindImpl(T key) const;
+ template <typename T> iterator insertImpl(T key, const QJsonValue &value);
+
QString keyAt(int i) const;
QJsonValue valueAt(int i) const;
void setValueAt(int i, const QJsonValue &val);
void removeAt(int i);
- iterator insertAt(int i, QStringView key, const QJsonValue &val, bool exists);
+ template <typename T> iterator insertAt(int i, T key, const QJsonValue &val, bool exists);
QJsonPrivate::Data *d;
QJsonPrivate::Object *o;
diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
index 28c84fd30f..7b055b5b63 100644
--- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
@@ -437,6 +437,7 @@ void tst_QtJson::testObjectSimple()
QCOMPARE(object.value("boolean").toBool(), true);
QCOMPARE(object.value(QLatin1String("boolean")).toBool(), true);
QJsonObject object2 = object;
+ QJsonObject object3 = object;
QStringList keys = object.keys();
QVERIFY2(keys.contains("number"), "key number not found");
@@ -479,6 +480,23 @@ void tst_QtJson::testObjectSimple()
object2.insert(QStringView(u"string"), QString::fromLatin1("foo"));
QVERIFY2(object2.value(QStringView(u"string")).toString() != before, "value should have been updated");
+ // same tests again but with QLatin1String keys
+ object3.insert(QLatin1String("value"), value);
+ QCOMPARE(object3.value("value"), value);
+
+ size = object3.size();
+ object3.remove(QLatin1String("boolean"));
+ QCOMPARE(object3.size(), size - 1);
+ QVERIFY2(!object3.contains("boolean"), "key boolean should have been removed");
+
+ taken = object3.take(QLatin1String("value"));
+ QCOMPARE(taken, value);
+ QVERIFY2(!object3.contains("value"), "key value should have been removed");
+
+ before = object3.value("string").toString();
+ object3.insert(QLatin1String("string"), QString::fromLatin1("foo"));
+ QVERIFY2(object3.value(QLatin1String("string")).toString() != before, "value should have been updated");
+
size = object.size();
QJsonObject subobject;
subobject.insert("number", 42);
@@ -2716,6 +2734,8 @@ void tst_QtJson::longStrings()
// test around 15 and 16 bit boundaries, as these are limits
// in the data structures (for Latin1String in qjson_p.h)
QString s(0x7ff0, 'a');
+ QByteArray ba(0x7ff0, 'a');
+ ba.append(0x8010 - 0x7ff0, 'c');
for (int i = 0x7ff0; i < 0x8010; i++) {
s.append(QLatin1Char('c'));
@@ -2732,9 +2752,21 @@ void tst_QtJson::longStrings()
/* ... and a QByteArray from the QJsonDocument */
QByteArray a2 = d2.toJson();
QCOMPARE(a1, a2);
+
+ // Test long keys
+ QJsonObject o1, o2;
+ o1[s] = 42;
+ o2[QLatin1String(ba.data(), i + 1)] = 42;
+ d1.setObject(o1);
+ d2.setObject(o2);
+ a1 = d1.toJson();
+ a2 = d2.toJson();
+ QCOMPARE(a1, a2);
}
s = QString(0xfff0, 'a');
+ ba = QByteArray(0xfff0, 'a');
+ ba.append(0x10010 - 0xfff0, 'c');
for (int i = 0xfff0; i < 0x10010; i++) {
s.append(QLatin1Char('c'));
@@ -2751,6 +2783,16 @@ void tst_QtJson::longStrings()
/* ... and a QByteArray from the QJsonDocument */
QByteArray a2 = d2.toJson();
QCOMPARE(a1, a2);
+
+ // Test long keys
+ QJsonObject o1, o2;
+ o1[s] = 42;
+ o2[QLatin1String(ba.data(), i + 1)] = 42;
+ d1.setObject(o1);
+ d2.setObject(o2);
+ a1 = d1.toJson();
+ a2 = d2.toJson();
+ QCOMPARE(a1, a2);
}
}