summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization/qjsonvalue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization/qjsonvalue.cpp')
-rw-r--r--src/corelib/serialization/qjsonvalue.cpp516
1 files changed, 317 insertions, 199 deletions
diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp
index 34fa84cdc1..6c2656d89f 100644
--- a/src/corelib/serialization/qjsonvalue.cpp
+++ b/src/corelib/serialization/qjsonvalue.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qjsonobject.h>
#include <qjsonvalue.h>
@@ -45,6 +10,8 @@
#include <quuid.h>
#include <qvariant.h>
#include <qstringlist.h>
+#include <qmap.h>
+#include <qhash.h>
#include <qdebug.h>
#include "qdatastream.h"
@@ -58,16 +25,44 @@
QT_BEGIN_NAMESPACE
+static QJsonValue::Type convertFromCborType(QCborValue::Type type) noexcept
+{
+ switch (type) {
+ case QCborValue::Null:
+ return QJsonValue::Null;
+ case QCborValue::True:
+ case QCborValue::False:
+ return QJsonValue::Bool;
+ case QCborValue::Double:
+ case QCborValue::Integer:
+ return QJsonValue::Double;
+ case QCborValue::String:
+ return QJsonValue::String;
+ case QCborValue::Array:
+ return QJsonValue::Array;
+ case QCborValue::Map:
+ return QJsonValue::Object;
+ case QCborValue::Undefined:
+ default:
+ return QJsonValue::Undefined;
+ }
+}
+
/*!
\class QJsonValue
\inmodule QtCore
\ingroup json
\ingroup shared
+ \ingroup qtserialization
\reentrant
\since 5.0
\brief The QJsonValue class encapsulates a value in JSON.
+ \compares equality
+ \compareswith equality QJsonValueConstRef QJsonValueRef
+ \endcompareswith
+
A value in JSON can be one of 6 basic types:
JSON is a format to store structured data. It has 6 basic data types:
@@ -101,11 +96,11 @@ QT_BEGIN_NAMESPACE
The following methods return QJsonValueRef:
\list
- \li \l {QJsonArray}::operator[](int i)
+ \li \l {QJsonArray}::operator[](qsizetype i)
\li \l {QJsonObject}::operator[](const QString & key) const
\endlist
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -114,26 +109,25 @@ QT_BEGIN_NAMESPACE
The default is to create a Null value.
*/
QJsonValue::QJsonValue(Type type)
- : d(nullptr), t(QCborValue::Undefined)
{
switch (type) {
case Null:
- t = QCborValue::Null;
+ value = QCborValue::Null;
break;
case Bool:
- t = QCborValue::False;
+ value = QCborValue::False;
break;
case Double:
- t = QCborValue::Double;
+ value = QCborValue::Double;
break;
case String:
- t = QCborValue::String;
+ value = QCborValue::String;
break;
case Array:
- t = QCborValue::Array;
+ value = QCborValue::Array;
break;
case Object:
- t = QCborValue::Map;
+ value = QCborValue::Map;
break;
case Undefined:
break;
@@ -144,24 +138,27 @@ QJsonValue::QJsonValue(Type type)
Creates a value of type Bool, with value \a b.
*/
QJsonValue::QJsonValue(bool b)
- : t(b ? QCborValue::True : QCborValue::False)
+ : value(b)
{
}
+static inline QCborValue doubleValueHelper(double v)
+{
+ qint64 n = 0;
+ // Convert to integer if the number is an integer and changing wouldn't
+ // introduce additional digit precision not present in the double.
+ if (convertDoubleTo<qint64>(v, &n, false /* allow_precision_upgrade */))
+ return n;
+ else
+ return v;
+}
+
/*!
Creates a value of type Double, with value \a v.
*/
QJsonValue::QJsonValue(double v)
- : d(nullptr)
+ : value(doubleValueHelper(v))
{
- // Convert to integer if the number is an integer and changing wouldn't
- // introduce additional digit precision not present in the double.
- if (convertDoubleTo<qint64>(v, &n, false /* allow_precision_upgrade */)) {
- t = QCborValue::Integer;
- } else {
- memcpy(&n, &v, sizeof(n));
- t = QCborValue::Double;
- }
}
/*!
@@ -169,7 +166,7 @@ QJsonValue::QJsonValue(double v)
Creates a value of type Double, with value \a v.
*/
QJsonValue::QJsonValue(int v)
- : n(v), t(QCborValue::Integer)
+ : value(v)
{
}
@@ -180,7 +177,7 @@ QJsonValue::QJsonValue(int v)
If you pass in values outside this range expect a loss of precision to occur.
*/
QJsonValue::QJsonValue(qint64 v)
- : n(v), t(QCborValue::Integer)
+ : value(v)
{
}
@@ -188,7 +185,7 @@ QJsonValue::QJsonValue(qint64 v)
Creates a value of type String, with value \a s.
*/
QJsonValue::QJsonValue(const QString &s)
- : QJsonValue(QJsonPrivate::Value::fromTrustedCbor(s))
+ : value(s)
{
}
@@ -204,25 +201,28 @@ QJsonValue::QJsonValue(const QString &s)
\since 5.3
*/
-// ### Qt6: remove
-void QJsonValue::stringDataFromQStringHelper(const QString &string)
+/*!
+ Creates a value of type String, with the Latin-1 string viewed by \a s.
+ */
+QJsonValue::QJsonValue(QLatin1StringView s)
+ : value(s)
{
- *this = QJsonValue(string);
}
/*!
- Creates a value of type String, with value \a s.
+ Creates a value of type Array, with value \a a.
*/
-QJsonValue::QJsonValue(QLatin1String s)
- : QJsonValue(QJsonPrivate::Value::fromTrustedCbor(s))
+QJsonValue::QJsonValue(const QJsonArray &a)
+ : value(QCborArray::fromJsonArray(a))
{
}
/*!
- Creates a value of type Array, with value \a a.
+ \overload
+ \since 6.3
*/
-QJsonValue::QJsonValue(const QJsonArray &a)
- : n(-1), d(a.a), t(QCborValue::Array)
+QJsonValue::QJsonValue(QJsonArray &&a) noexcept
+ : value(QCborArray::fromJsonArray(std::move(a)))
{
}
@@ -230,7 +230,16 @@ QJsonValue::QJsonValue(const QJsonArray &a)
Creates a value of type Object, with value \a o.
*/
QJsonValue::QJsonValue(const QJsonObject &o)
- : n(-1), d(o.o), t(QCborValue::Map)
+ : value(QCborMap::fromJsonObject(o))
+{
+}
+
+/*!
+ \overload
+ \since 6.3
+ */
+QJsonValue::QJsonValue(QJsonObject &&o) noexcept
+ : value(QCborMap::fromJsonObject(std::move(o)))
{
}
@@ -243,38 +252,27 @@ QJsonValue::~QJsonValue() = default;
/*!
Creates a copy of \a other.
*/
-QJsonValue::QJsonValue(const QJsonValue &other)
-{
- n = other.n;
- t = other.t;
- d = other.d;
-}
+QJsonValue::QJsonValue(const QJsonValue &other) noexcept = default;
/*!
Assigns the value stored in \a other to this object.
*/
-QJsonValue &QJsonValue::operator =(const QJsonValue &other)
+QJsonValue &QJsonValue::operator =(const QJsonValue &other) noexcept
{
QJsonValue copy(other);
swap(copy);
return *this;
}
-QJsonValue::QJsonValue(QJsonValue &&other) noexcept :
- n(other.n),
- d(other.d),
- t(other.t)
+QJsonValue::QJsonValue(QJsonValue &&other) noexcept
+ : value(std::move(other.value))
{
- other.n = 0;
- other.d = nullptr;
- other.t = QCborValue::Null;
+ other.value = QCborValue(nullptr);
}
void QJsonValue::swap(QJsonValue &other) noexcept
{
- qSwap(n, other.n);
- qSwap(d, other.d);
- qSwap(t, other.t);
+ value.swap(other.value);
}
/*!
@@ -351,7 +349,7 @@ void QJsonValue::swap(QJsonValue &other) noexcept
error cases as e.g. accessing a non existing key in a QJsonObject.
*/
-
+#ifndef QT_NO_VARIANT
/*!
Converts \a variant to a QJsonValue and returns it.
@@ -461,7 +459,11 @@ void QJsonValue::swap(QJsonValue &other) noexcept
For other types not listed above, a conversion to string will be attempted,
usually but not always by calling QVariant::toString(). If the conversion
fails the value is replaced by a null JSON value. Note that
- QVariant::toString() is also lossy for the majority of types.
+ QVariant::toString() is also lossy for the majority of types. For example,
+ if the passed QVariant is representing raw byte array data, it is recommended
+ to pre-encode it to \l {RFC 4686}{Base64} (or
+ another lossless encoding), otherwise a lossy conversion using QString::fromUtf8()
+ will be used.
Please note that the conversions via QVariant::toString() are subject to
change at any time. Both QVariant and QJsonValue may be extended in the
@@ -472,7 +474,7 @@ void QJsonValue::swap(QJsonValue &other) noexcept
*/
QJsonValue QJsonValue::fromVariant(const QVariant &variant)
{
- switch (variant.userType()) {
+ switch (variant.metaType().id()) {
case QMetaType::Nullptr:
return QJsonValue(Null);
case QMetaType::Bool:
@@ -488,8 +490,10 @@ QJsonValue QJsonValue::fromVariant(const QVariant &variant)
return QJsonValue(variant.toLongLong());
Q_FALLTHROUGH();
case QMetaType::Float:
- case QMetaType::Double:
- return QJsonValue(variant.toDouble());
+ case QMetaType::Double: {
+ double v = variant.toDouble();
+ return qt_is_finite(v) ? QJsonValue(v) : QJsonValue();
+ }
case QMetaType::QString:
return QJsonValue(variant.toString());
case QMetaType::QStringList:
@@ -548,7 +552,7 @@ QJsonValue QJsonValue::fromVariant(const QVariant &variant)
*/
QVariant QJsonValue::toVariant() const
{
- switch (t) {
+ switch (value.type()) {
case QCborValue::True:
return true;
case QCborValue::False:
@@ -560,13 +564,9 @@ QVariant QJsonValue::toVariant() const
case QCborValue::String:
return toString();
case QCborValue::Array:
- return d ?
- QJsonArray(d.data()).toVariantList() :
- QVariantList();
+ return toArray().toVariantList();
case QCborValue::Map:
- return d ?
- QJsonObject(d.data()).toVariantMap() :
- QVariantMap();
+ return toObject().toVariantMap();
case QCborValue::Null:
return QVariant::fromValue(nullptr);
case QCborValue::Undefined:
@@ -592,6 +592,7 @@ QVariant QJsonValue::toVariant() const
error condition, when trying to read an out of bounds value
in an array or a non existent key in an object.
*/
+#endif // !QT_NO_VARIANT
/*!
Returns the type of the value.
@@ -600,25 +601,7 @@ QVariant QJsonValue::toVariant() const
*/
QJsonValue::Type QJsonValue::type() const
{
- switch (t) {
- case QCborValue::Null:
- return QJsonValue::Null;
- case QCborValue::True:
- case QCborValue::False:
- return QJsonValue::Bool;
- case QCborValue::Double:
- case QCborValue::Integer:
- return QJsonValue::Double;
- case QCborValue::String:
- return QJsonValue::String;
- case QCborValue::Array:
- return QJsonValue::Array;
- case QCborValue::Map:
- return QJsonValue::Object;
- case QCborValue::Undefined:
- default:
- return QJsonValue::Undefined;
- }
+ return convertFromCborType(value.type());
}
/*!
@@ -628,7 +611,7 @@ QJsonValue::Type QJsonValue::type() const
*/
bool QJsonValue::toBool(bool defaultValue) const
{
- switch (t) {
+ switch (value.type()) {
case QCborValue::True:
return true;
case QCborValue::False:
@@ -647,17 +630,19 @@ bool QJsonValue::toBool(bool defaultValue) const
*/
int QJsonValue::toInt(int defaultValue) const
{
- switch (t) {
+ switch (value.type()) {
case QCborValue::Double: {
int dblInt;
if (convertDoubleTo<int>(toDouble(), &dblInt))
return dblInt;
break;
}
- case QCborValue::Integer:
+ case QCborValue::Integer: {
+ const auto n = value.toInteger();
if (qint64(int(n)) == n)
return int(n);
break;
+ }
default:
break;
}
@@ -673,9 +658,9 @@ int QJsonValue::toInt(int defaultValue) const
*/
qint64 QJsonValue::toInteger(qint64 defaultValue) const
{
- switch (t) {
+ switch (value.type()) {
case QCborValue::Integer:
- return n;
+ return value.toInteger();
case QCborValue::Double: {
qint64 dblInt;
if (convertDoubleTo<qint64>(toDouble(), &dblInt))
@@ -695,17 +680,7 @@ qint64 QJsonValue::toInteger(qint64 defaultValue) const
*/
double QJsonValue::toDouble(double defaultValue) const
{
- switch (t) {
- case QCborValue::Double: {
- double d;
- memcpy(&d, &n, sizeof(d));
- return d;
- }
- case QCborValue::Integer:
- return double(n);
- default:
- return defaultValue;
- }
+ return value.toDouble(defaultValue);
}
/*!
@@ -715,7 +690,7 @@ double QJsonValue::toDouble(double defaultValue) const
*/
QString QJsonValue::toString(const QString &defaultValue) const
{
- return (t == QCborValue::String && d) ? d->stringAt(n) : defaultValue;
+ return value.toString(defaultValue);
}
/*!
@@ -727,7 +702,7 @@ QString QJsonValue::toString(const QString &defaultValue) const
*/
QString QJsonValue::toString() const
{
- return (t == QCborValue::String && d) ? d->stringAt(n) : QString();
+ return value.toString();
}
/*!
@@ -737,10 +712,15 @@ QString QJsonValue::toString() const
*/
QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const
{
- if (t != QCborValue::Array || n >= 0 || !d)
+ if (!isArray())
return defaultValue;
-
- return QJsonArray(d.data());
+ QCborContainerPrivate *dd = nullptr;
+ const auto n = QJsonPrivate::Value::valueHelper(value);
+ const auto container = QJsonPrivate::Value::container(value);
+ Q_ASSERT(n == -1 || container == nullptr);
+ if (n < 0)
+ dd = container;
+ return QJsonArray(dd);
}
/*!
@@ -762,10 +742,15 @@ QJsonArray QJsonValue::toArray() const
*/
QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const
{
- if (t != QCborValue::Map || n >= 0 || !d)
+ if (!isObject())
return defaultValue;
-
- return QJsonObject(d.data());
+ QCborContainerPrivate *dd = nullptr;
+ const auto container = QJsonPrivate::Value::container(value);
+ const auto n = QJsonPrivate::Value::valueHelper(value);
+ Q_ASSERT(n == -1 || container == nullptr);
+ if (n < 0)
+ dd = container;
+ return QJsonObject(dd);
}
/*!
@@ -780,7 +765,6 @@ QJsonObject QJsonValue::toObject() const
return toObject(QJsonObject());
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a QJsonValue representing the value for the key \a key.
@@ -797,7 +781,6 @@ const QJsonValue QJsonValue::operator[](const QString &key) const
{
return (*this)[QStringView(key)];
}
-#endif
/*!
\overload
@@ -815,7 +798,7 @@ const QJsonValue QJsonValue::operator[](QStringView key) const
\overload
\since 5.10
*/
-const QJsonValue QJsonValue::operator[](QLatin1String key) const
+const QJsonValue QJsonValue::operator[](QLatin1StringView key) const
{
if (!isObject())
return QJsonValue(QJsonValue::Undefined);
@@ -835,7 +818,7 @@ const QJsonValue QJsonValue::operator[](QLatin1String key) const
\sa QJsonValue, QJsonValue::isUndefined(), QJsonArray
*/
-const QJsonValue QJsonValue::operator[](int i) const
+const QJsonValue QJsonValue::operator[](qsizetype i) const
{
if (!isArray())
return QJsonValue(QJsonValue::Undefined);
@@ -844,42 +827,37 @@ const QJsonValue QJsonValue::operator[](int i) const
}
/*!
- Returns \c true if the value is equal to \a other.
- */
-bool QJsonValue::operator==(const QJsonValue &other) const
+ \fn bool QJsonValue::operator==(const QJsonValue &lhs, const QJsonValue &rhs)
+
+ Returns \c true if the \a lhs value is equal to \a rhs value, \c false otherwise.
+*/
+bool comparesEqual(const QJsonValue &lhs, const QJsonValue &rhs) noexcept
{
- if (t != other.t) {
- if (isDouble() && other.isDouble()) {
+ if (lhs.value.type() != rhs.value.type()) {
+ if (lhs.isDouble() && rhs.isDouble()) {
// One value Cbor integer, one Cbor double, should interact as doubles.
- return toDouble() == other.toDouble();
+ return lhs.toDouble() == rhs.toDouble();
}
return false;
}
- switch (t) {
+ switch (lhs.value.type()) {
case QCborValue::Undefined:
case QCborValue::Null:
case QCborValue::True:
case QCborValue::False:
break;
case QCborValue::Double:
- return toDouble() == other.toDouble();
+ return lhs.toDouble() == rhs.toDouble();
case QCborValue::Integer:
- return n == other.n;
+ return QJsonPrivate::Value::valueHelper(lhs.value)
+ == QJsonPrivate::Value::valueHelper(rhs.value);
case QCborValue::String:
- return toString() == other.toString();
+ return lhs.toString() == rhs.toString();
case QCborValue::Array:
- if (!d)
- return !other.d || other.d->elements.length() == 0;
- if (!other.d)
- return d->elements.length() == 0;
- return QJsonArray(d.data()) == QJsonArray(other.d.data());
+ return lhs.toArray() == rhs.toArray();
case QCborValue::Map:
- if (!d)
- return !other.d || other.d->elements.length() == 0;
- if (!other.d)
- return d->elements.length() == 0;
- return QJsonObject(d.data()) == QJsonObject(other.d.data());
+ return lhs.toObject() == rhs.toObject();
default:
return false;
}
@@ -887,21 +865,10 @@ bool QJsonValue::operator==(const QJsonValue &other) const
}
/*!
- Returns \c true if the value is not equal to \a other.
- */
-bool QJsonValue::operator!=(const QJsonValue &other) const
-{
- return !(*this == other);
-}
-
-/*!
- \internal
- */
-void QJsonValue::detach()
-{
- d.detach();
-}
+ \fn bool QJsonValue::operator!=(const QJsonValue &lhs, const QJsonValue &rhs)
+ Returns \c true if the \a lhs value is not equal to \a rhs value, \c false otherwise.
+*/
/*!
\class QJsonValueRef
@@ -926,48 +893,200 @@ void QJsonValue::detach()
However, they are not explicitly documented here.
*/
-
-QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
+void QJsonValueRef::detach()
{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ QCborContainerPrivate *d = QJsonPrivate::Value::container(*this);
+ d = QCborContainerPrivate::detach(d, d->elements.size());
+
if (is_object)
- o->setValueAt(index, val);
+ o->o.reset(d);
else
- a->replace(index, val);
+ a->a.reset(d);
+#else
+ d = QCborContainerPrivate::detach(d, d->elements.size());
+#endif
+}
- return *this;
+static QJsonValueRef &assignToRef(QJsonValueRef &ref, const QCborValue &value, bool is_object)
+{
+ QCborContainerPrivate *d = QJsonPrivate::Value::container(ref);
+ qsizetype index = QJsonPrivate::Value::indexHelper(ref);
+ if (is_object && value.isUndefined()) {
+ d->removeAt(index);
+ d->removeAt(index - 1);
+ } else {
+ d->replaceAt(index, value);
+ }
+
+ return ref;
+}
+
+QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
+{
+ detach();
+ return assignToRef(*this, QCborValue::fromJsonValue(val), is_object);
}
QJsonValueRef &QJsonValueRef::operator =(const QJsonValueRef &ref)
{
- if (is_object)
- o->setValueAt(index, ref);
- else
- a->replace(index, ref);
+ // ### optimize more?
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(ref);
+ qsizetype index = QJsonPrivate::Value::indexHelper(ref);
- return *this;
+ if (d == QJsonPrivate::Value::container(*this) &&
+ index == QJsonPrivate::Value::indexHelper(*this))
+ return *this; // self assignment
+
+ detach();
+ return assignToRef(*this, d->valueAt(index), is_object);
+}
+
+#ifndef QT_NO_VARIANT
+QVariant QJsonValueConstRef::toVariant() const
+{
+ return concrete(*this).toVariant();
+}
+#endif // !QT_NO_VARIANT
+
+QJsonArray QJsonValueConstRef::toArray() const
+{
+ return concrete(*this).toArray();
+}
+
+QJsonObject QJsonValueConstRef::toObject() const
+{
+ return concrete(*this).toObject();
}
+QJsonValue::Type QJsonValueConstRef::concreteType(QJsonValueConstRef self) noexcept
+{
+ return convertFromCborType(QJsonPrivate::Value::elementHelper(self).type);
+}
+
+bool QJsonValueConstRef::concreteBool(QJsonValueConstRef self, bool defaultValue) noexcept
+{
+ auto &e = QJsonPrivate::Value::elementHelper(self);
+ if (e.type == QCborValue::False)
+ return false;
+ if (e.type == QCborValue::True)
+ return true;
+ return defaultValue;
+}
+
+qint64 QJsonValueConstRef::concreteInt(QJsonValueConstRef self, qint64 defaultValue, bool clamp) noexcept
+{
+ auto &e = QJsonPrivate::Value::elementHelper(self);
+ qint64 v = defaultValue;
+ if (e.type == QCborValue::Double) {
+ // convertDoubleTo modifies the output even on returning false
+ if (!convertDoubleTo<qint64>(e.fpvalue(), &v))
+ v = defaultValue;
+ } else if (e.type == QCborValue::Integer) {
+ v = e.value;
+ }
+ if (clamp && qint64(int(v)) != v)
+ return defaultValue;
+ return v;
+}
+
+double QJsonValueConstRef::concreteDouble(QJsonValueConstRef self, double defaultValue) noexcept
+{
+ auto &e = QJsonPrivate::Value::elementHelper(self);
+ if (e.type == QCborValue::Double)
+ return e.fpvalue();
+ if (e.type == QCborValue::Integer)
+ return e.value;
+ return defaultValue;
+}
+
+QString QJsonValueConstRef::concreteString(QJsonValueConstRef self, const QString &defaultValue)
+{
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ qsizetype index = QJsonPrivate::Value::indexHelper(self);
+ if (d->elements.at(index).type != QCborValue::String)
+ return defaultValue;
+ return d->stringAt(index);
+}
+
+QJsonValue QJsonValueConstRef::concrete(QJsonValueConstRef self) noexcept
+{
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ qsizetype index = QJsonPrivate::Value::indexHelper(self);
+ return QJsonPrivate::Value::fromTrustedCbor(d->valueAt(index));
+}
+
+QString QJsonValueConstRef::objectKey(QJsonValueConstRef self)
+{
+ Q_ASSERT(self.is_object);
+ Q_ASSERT(self.is_object);
+ const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
+ qsizetype index = QJsonPrivate::Value::indexHelper(self);
+
+ Q_ASSERT(d);
+ Q_ASSERT(index < d->elements.size());
+ return d->stringAt(index - 1);
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QVariant QJsonValueRef::toVariant() const
{
- return toValue().toVariant();
+ return QJsonValueConstRef::toVariant();
}
QJsonArray QJsonValueRef::toArray() const
{
- return toValue().toArray();
+ return QJsonValueConstRef::toArray();
}
QJsonObject QJsonValueRef::toObject() const
{
- return toValue().toObject();
+ return QJsonValueConstRef::toObject();
}
QJsonValue QJsonValueRef::toValue() const
{
- if (!is_object)
- return a->at(index);
- return o->valueAt(index);
+ return concrete(*this);
+}
+#else
+QJsonValueRef QJsonValueRef::operator[](qsizetype key)
+{
+ if (d->elements.at(index).type != QCborValue::Array)
+ d->replaceAt(index, QCborValue::Array);
+
+ auto &e = d->elements[index];
+ e.container = QCborContainerPrivate::grow(e.container, key); // detaches
+ e.flags |= QtCbor::Element::IsContainer;
+
+ return QJsonValueRef(e.container, key, false);
+}
+
+QJsonValueRef QJsonValueRef::operator[](QAnyStringView key)
+{
+ // must go through QJsonObject because some of the machinery is non-static
+ // member or file-static in qjsonobject.cpp
+ QJsonObject o = QJsonPrivate::Value::fromTrustedCbor(d->valueAt(index)).toObject();
+ QJsonValueRef ret = key.visit([&](auto v) {
+ if constexpr (std::is_same_v<decltype(v), QUtf8StringView>)
+ return o[QString::fromUtf8(v)];
+ else
+ return o[v];
+ });
+
+ // ### did the QJsonObject::operator[] above detach?
+ QCborContainerPrivate *x = o.o.take();
+ Q_ASSERT(x->ref.loadRelaxed() == 1);
+
+ auto &e = d->elements[index];
+ if (e.flags & QtCbor::Element::IsContainer && e.container != x)
+ o.o.reset(e.container); // might not an object!
+
+ e.flags |= QtCbor::Element::IsContainer;
+ e.container = x;
+
+ return ret;
}
+#endif
size_t qHash(const QJsonValue &value, size_t seed)
{
@@ -987,15 +1106,14 @@ size_t qHash(const QJsonValue &value, size_t seed)
case QJsonValue::Undefined:
return seed;
}
- Q_UNREACHABLE();
- return 0;
+ Q_UNREACHABLE_RETURN(0);
}
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
QDebug operator<<(QDebug dbg, const QJsonValue &o)
{
QDebugStateSaver saver(dbg);
- switch (o.t) {
+ switch (o.value.type()) {
case QCborValue::Undefined:
dbg << "QJsonValue(undefined)";
break;