1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <qjsonobject.h>
6#include <qjsonvalue.h>
7#include <qjsonarray.h>
8#include <qjsondocument.h>
9#include <qurl.h>
10#include <quuid.h>
11#include <qvariant.h>
12#include <qstringlist.h>
13#include <qmap.h>
14#include <qhash.h>
15#include <qdebug.h>
16#include "qdatastream.h"
17
18#include <private/qnumeric_p.h>
19#include <private/qcborvalue_p.h>
20
21#include <qcborarray.h>
22#include <qcbormap.h>
23
24#include "qjson_p.h"
25
26QT_BEGIN_NAMESPACE
27
28static QJsonValue::Type convertFromCborType(QCborValue::Type type) noexcept
29{
30 switch (type) {
31 case QCborValue::Null:
32 return QJsonValue::Null;
33 case QCborValue::True:
34 case QCborValue::False:
35 return QJsonValue::Bool;
36 case QCborValue::Double:
37 case QCborValue::Integer:
38 return QJsonValue::Double;
39 case QCborValue::String:
40 return QJsonValue::String;
41 case QCborValue::Array:
42 return QJsonValue::Array;
43 case QCborValue::Map:
44 return QJsonValue::Object;
45 case QCborValue::Undefined:
46 default:
47 return QJsonValue::Undefined;
48 }
49}
50
51/*!
52 \class QJsonValue
53 \inmodule QtCore
54 \ingroup json
55 \ingroup shared
56 \ingroup qtserialization
57 \reentrant
58 \since 5.0
59
60 \brief The QJsonValue class encapsulates a value in JSON.
61
62 A value in JSON can be one of 6 basic types:
63
64 JSON is a format to store structured data. It has 6 basic data types:
65
66 \list
67 \li bool QJsonValue::Bool
68 \li double QJsonValue::Double
69 \li string QJsonValue::String
70 \li array QJsonValue::Array
71 \li object QJsonValue::Object
72 \li null QJsonValue::Null
73 \endlist
74
75 A value can represent any of the above data types. In addition, QJsonValue has one special
76 flag to represent undefined values. This can be queried with isUndefined().
77
78 The type of the value can be queried with type() or accessors like isBool(), isString(), and so on.
79 Likewise, the value can be converted to the type stored in it using the toBool(), toString() and so on.
80
81 Values are strictly typed internally and contrary to QVariant will not attempt to do any implicit type
82 conversions. This implies that converting to a type that is not stored in the value will return a default
83 constructed return value.
84
85 \section1 QJsonValueRef
86
87 QJsonValueRef is a helper class for QJsonArray and QJsonObject.
88 When you get an object of type QJsonValueRef, you can
89 use it as if it were a reference to a QJsonValue. If you assign to it,
90 the assignment will apply to the element in the QJsonArray or QJsonObject
91 from which you got the reference.
92
93 The following methods return QJsonValueRef:
94 \list
95 \li \l {QJsonArray}::operator[](qsizetype i)
96 \li \l {QJsonObject}::operator[](const QString & key) const
97 \endlist
98
99 \sa {JSON Support in Qt}, {JSON Save Game Example}
100*/
101
102/*!
103 Creates a QJsonValue of type \a type.
104
105 The default is to create a Null value.
106 */
107QJsonValue::QJsonValue(Type type)
108{
109 switch (type) {
110 case Null:
111 value = QCborValue::Null;
112 break;
113 case Bool:
114 value = QCborValue::False;
115 break;
116 case Double:
117 value = QCborValue::Double;
118 break;
119 case String:
120 value = QCborValue::String;
121 break;
122 case Array:
123 value = QCborValue::Array;
124 break;
125 case Object:
126 value = QCborValue::Map;
127 break;
128 case Undefined:
129 break;
130 }
131}
132
133/*!
134 Creates a value of type Bool, with value \a b.
135 */
136QJsonValue::QJsonValue(bool b)
137 : value(b)
138{
139}
140
141static inline QCborValue doubleValueHelper(double v)
142{
143 qint64 n = 0;
144 // Convert to integer if the number is an integer and changing wouldn't
145 // introduce additional digit precision not present in the double.
146 if (convertDoubleTo<qint64>(v, value: &n, allow_precision_upgrade: false /* allow_precision_upgrade */))
147 return n;
148 else
149 return v;
150}
151
152/*!
153 Creates a value of type Double, with value \a v.
154 */
155QJsonValue::QJsonValue(double v)
156 : value(doubleValueHelper(v))
157{
158}
159
160/*!
161 \overload
162 Creates a value of type Double, with value \a v.
163 */
164QJsonValue::QJsonValue(int v)
165 : value(v)
166{
167}
168
169/*!
170 \overload
171 Creates a value of type Double, with value \a v.
172 NOTE: the integer limits for IEEE 754 double precision data is 2^53 (-9007199254740992 to +9007199254740992).
173 If you pass in values outside this range expect a loss of precision to occur.
174 */
175QJsonValue::QJsonValue(qint64 v)
176 : value(v)
177{
178}
179
180/*!
181 Creates a value of type String, with value \a s.
182 */
183QJsonValue::QJsonValue(const QString &s)
184 : value(s)
185{
186}
187
188/*!
189 \fn QJsonValue::QJsonValue(const char *s)
190
191 Creates a value of type String with value \a s, assuming
192 UTF-8 encoding of the input.
193
194 You can disable this constructor by defining \c
195 QT_NO_CAST_FROM_ASCII when you compile your applications.
196
197 \since 5.3
198 */
199
200/*!
201 Creates a value of type String, with the Latin-1 string viewed by \a s.
202 */
203QJsonValue::QJsonValue(QLatin1StringView s)
204 : value(s)
205{
206}
207
208/*!
209 Creates a value of type Array, with value \a a.
210 */
211QJsonValue::QJsonValue(const QJsonArray &a)
212 : value(QCborArray::fromJsonArray(array: a))
213{
214}
215
216/*!
217 \overload
218 \since 6.3
219 */
220QJsonValue::QJsonValue(QJsonArray &&a) noexcept
221 : value(QCborArray::fromJsonArray(array: std::move(a)))
222{
223}
224
225/*!
226 Creates a value of type Object, with value \a o.
227 */
228QJsonValue::QJsonValue(const QJsonObject &o)
229 : value(QCborMap::fromJsonObject(o))
230{
231}
232
233/*!
234 \overload
235 \since 6.3
236 */
237QJsonValue::QJsonValue(QJsonObject &&o) noexcept
238 : value(QCborMap::fromJsonObject(o: std::move(o)))
239{
240}
241
242
243/*!
244 Destroys the value.
245 */
246QJsonValue::~QJsonValue() = default;
247
248/*!
249 Creates a copy of \a other.
250 */
251QJsonValue::QJsonValue(const QJsonValue &other) noexcept = default;
252
253/*!
254 Assigns the value stored in \a other to this object.
255 */
256QJsonValue &QJsonValue::operator =(const QJsonValue &other) noexcept
257{
258 QJsonValue copy(other);
259 swap(other&: copy);
260 return *this;
261}
262
263QJsonValue::QJsonValue(QJsonValue &&other) noexcept
264 : value(std::move(other.value))
265{
266 other.value = QCborValue(nullptr);
267}
268
269void QJsonValue::swap(QJsonValue &other) noexcept
270{
271 value.swap(other&: other.value);
272}
273
274/*!
275 \fn QJsonValue::QJsonValue(QJsonValue &&other)
276 \since 5.10
277
278 Move-constructs a QJsonValue from \a other.
279*/
280
281/*!
282 \fn QJsonValue &QJsonValue::operator =(QJsonValue &&other)
283 \since 5.10
284
285 Move-assigns \a other to this value.
286*/
287
288/*!
289 \fn void QJsonValue::swap(QJsonValue &other)
290 \since 5.10
291
292 Swaps the value \a other with this. This operation is very fast and never fails.
293*/
294
295/*!
296 \fn bool QJsonValue::isNull() const
297
298 Returns \c true if the value is null.
299*/
300
301/*!
302 \fn bool QJsonValue::isBool() const
303
304 Returns \c true if the value contains a boolean.
305
306 \sa toBool()
307 */
308
309/*!
310 \fn bool QJsonValue::isDouble() const
311
312 Returns \c true if the value contains a double.
313
314 \sa toDouble()
315 */
316
317/*!
318 \fn bool QJsonValue::isString() const
319
320 Returns \c true if the value contains a string.
321
322 \sa toString()
323 */
324
325/*!
326 \fn bool QJsonValue::isArray() const
327
328 Returns \c true if the value contains an array.
329
330 \sa toArray()
331 */
332
333/*!
334 \fn bool QJsonValue::isObject() const
335
336 Returns \c true if the value contains an object.
337
338 \sa toObject()
339 */
340
341/*!
342 \fn bool QJsonValue::isUndefined() const
343
344 Returns \c true if the value is undefined. This can happen in certain
345 error cases as e.g. accessing a non existing key in a QJsonObject.
346 */
347
348/*!
349 Converts \a variant to a QJsonValue and returns it.
350
351 The conversion will convert QVariant types as follows:
352
353 \table
354 \header
355 \li Source type
356 \li Destination type
357 \row
358 \li
359 \list
360 \li QMetaType::Nullptr
361 \endlist
362 \li QJsonValue::Null
363 \row
364 \li
365 \list
366 \li QMetaType::Bool
367 \endlist
368 \li QJsonValue::Bool
369 \row
370 \li
371 \list
372 \li QMetaType::Int
373 \li QMetaType::UInt
374 \li QMetaType::LongLong
375 \li QMetaType::ULongLong
376 \li QMetaType::Float
377 \li QMetaType::Double
378 \endlist
379 \li QJsonValue::Double
380 \row
381 \li
382 \list
383 \li QMetaType::QString
384 \endlist
385 \li QJsonValue::String
386 \row
387 \li
388 \list
389 \li QMetaType::QStringList
390 \li QMetaType::QVariantList
391 \endlist
392 \li QJsonValue::Array
393 \row
394 \li
395 \list
396 \li QMetaType::QVariantMap
397 \li QMetaType::QVariantHash
398 \endlist
399 \li QJsonValue::Object
400
401 \row
402 \li
403 \list
404 \li QMetaType::QUrl
405 \endlist
406 \li QJsonValue::String. The conversion will use QUrl::toString() with flag
407 QUrl::FullyEncoded, so as to ensure maximum compatibility in parsing the URL
408 \row
409 \li
410 \list
411 \li QMetaType::QUuid
412 \endlist
413 \li QJsonValue::String. Since Qt 5.11, the resulting string will not include braces
414 \row
415 \li
416 \list
417 \li QMetaType::QCborValue
418 \endlist
419 \li Whichever type QCborValue::toJsonValue() returns.
420 \row
421 \li
422 \list
423 \li QMetaType::QCborArray
424 \endlist
425 \li QJsonValue::Array. See QCborValue::toJsonValue() for conversion restrictions.
426 \row
427 \li
428 \list
429 \li QMetaType::QCborMap
430 \endlist
431 \li QJsonValue::Map. See QCborValue::toJsonValue() for conversion restrictions and the
432 "stringification" of map keys.
433 \endtable
434
435 \section2 Loss of information and other types
436
437 QVariant can carry more information than is representable in JSON. If the
438 QVariant is not one of the types above, the conversion is not guaranteed
439 and is subject to change in future versions of Qt, as the UUID one did.
440 Code should strive not to use any other types than those listed above.
441
442 If QVariant::isNull() returns true, a null QJsonValue is returned or
443 inserted into the list or object, regardless of the type carried by
444 QVariant. Note the behavior change in Qt 6.0 affecting QVariant::isNull()
445 also affects this function.
446
447 A floating point value that is either an infinity or NaN will be converted
448 to a null JSON value. Since Qt 6.0, QJsonValue can store the full precision
449 of any 64-bit signed integer without loss, but in previous versions values
450 outside the range of ±2^53 may lose precision. Unsigned 64-bit values
451 greater than or equal to 2^63 will either lose precision or alias to
452 negative values, so QMetaType::ULongLong should be avoided.
453
454 For other types not listed above, a conversion to string will be attempted,
455 usually but not always by calling QVariant::toString(). If the conversion
456 fails the value is replaced by a null JSON value. Note that
457 QVariant::toString() is also lossy for the majority of types. For example,
458 if the passed QVariant is representing raw byte array data, it is recommended
459 to pre-encode it to \l {RFC 4686}{Base64} (or
460 another lossless encoding), otherwise a lossy conversion using QString::fromUtf8()
461 will be used.
462
463 Please note that the conversions via QVariant::toString() are subject to
464 change at any time. Both QVariant and QJsonValue may be extended in the
465 future to support more types, which will result in a change in how this
466 function performs conversions.
467
468 \sa toVariant(), QCborValue::fromVariant()
469 */
470QJsonValue QJsonValue::fromVariant(const QVariant &variant)
471{
472 switch (variant.metaType().id()) {
473 case QMetaType::Nullptr:
474 return QJsonValue(Null);
475 case QMetaType::Bool:
476 return QJsonValue(variant.toBool());
477 case QMetaType::Short:
478 case QMetaType::UShort:
479 case QMetaType::Int:
480 case QMetaType::UInt:
481 case QMetaType::LongLong:
482 return QJsonValue(variant.toLongLong());
483 case QMetaType::ULongLong:
484 if (variant.toULongLong() <= static_cast<uint64_t>(std::numeric_limits<qint64>::max()))
485 return QJsonValue(variant.toLongLong());
486 Q_FALLTHROUGH();
487 case QMetaType::Float:
488 case QMetaType::Double: {
489 double v = variant.toDouble();
490 return qt_is_finite(d: v) ? QJsonValue(v) : QJsonValue();
491 }
492 case QMetaType::QString:
493 return QJsonValue(variant.toString());
494 case QMetaType::QStringList:
495 return QJsonValue(QJsonArray::fromStringList(list: variant.toStringList()));
496 case QMetaType::QVariantList:
497 return QJsonValue(QJsonArray::fromVariantList(list: variant.toList()));
498 case QMetaType::QVariantMap:
499 return QJsonValue(QJsonObject::fromVariantMap(map: variant.toMap()));
500 case QMetaType::QVariantHash:
501 return QJsonValue(QJsonObject::fromVariantHash(map: variant.toHash()));
502#ifndef QT_BOOTSTRAPPED
503 case QMetaType::QUrl:
504 return QJsonValue(variant.toUrl().toString(options: QUrl::FullyEncoded));
505 case QMetaType::QUuid:
506 return variant.toUuid().toString(mode: QUuid::WithoutBraces);
507 case QMetaType::QJsonValue:
508 return variant.toJsonValue();
509 case QMetaType::QJsonObject:
510 return variant.toJsonObject();
511 case QMetaType::QJsonArray:
512 return variant.toJsonArray();
513 case QMetaType::QJsonDocument: {
514 QJsonDocument doc = variant.toJsonDocument();
515 return doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object());
516 }
517 case QMetaType::QCborValue:
518 return qvariant_cast<QCborValue>(v: variant).toJsonValue();
519 case QMetaType::QCborArray:
520 return qvariant_cast<QCborArray>(v: variant).toJsonArray();
521 case QMetaType::QCborMap:
522 return qvariant_cast<QCborMap>(v: variant).toJsonObject();
523#endif
524 default:
525 break;
526 }
527 QString string = variant.toString();
528 if (string.isEmpty())
529 return QJsonValue();
530 return QJsonValue(string);
531}
532
533/*!
534 Converts the value to a \l {QVariant::}{QVariant()}.
535
536 The QJsonValue types will be converted as follows:
537
538 \value Null QMetaType::Nullptr
539 \value Bool QMetaType::Bool
540 \value Double QMetaType::Double or QMetaType::LongLong
541 \value String QString
542 \value Array QVariantList
543 \value Object QVariantMap
544 \value Undefined \l {QVariant::}{QVariant()}
545
546 \sa fromVariant()
547 */
548QVariant QJsonValue::toVariant() const
549{
550 switch (value.type()) {
551 case QCborValue::True:
552 return true;
553 case QCborValue::False:
554 return false;
555 case QCborValue::Integer:
556 return toInteger();
557 case QCborValue::Double:
558 return toDouble();
559 case QCborValue::String:
560 return toString();
561 case QCborValue::Array:
562 return toArray().toVariantList();
563 case QCborValue::Map:
564 return toObject().toVariantMap();
565 case QCborValue::Null:
566 return QVariant::fromValue(value: nullptr);
567 case QCborValue::Undefined:
568 default:
569 break;
570 }
571 return QVariant();
572}
573
574/*!
575 \enum QJsonValue::Type
576
577 This enum describes the type of the JSON value.
578
579 \value Null A Null value
580 \value Bool A boolean value. Use toBool() to convert to a bool.
581 \value Double A number value. Use toDouble() to convert to a double,
582 or toInteger() to convert to a qint64.
583 \value String A string. Use toString() to convert to a QString.
584 \value Array An array. Use toArray() to convert to a QJsonArray.
585 \value Object An object. Use toObject() to convert to a QJsonObject.
586 \value Undefined The value is undefined. This is usually returned as an
587 error condition, when trying to read an out of bounds value
588 in an array or a non existent key in an object.
589*/
590
591/*!
592 Returns the type of the value.
593
594 \sa QJsonValue::Type
595 */
596QJsonValue::Type QJsonValue::type() const
597{
598 return convertFromCborType(type: value.type());
599}
600
601/*!
602 Converts the value to a bool and returns it.
603
604 If type() is not bool, the \a defaultValue will be returned.
605 */
606bool QJsonValue::toBool(bool defaultValue) const
607{
608 switch (value.type()) {
609 case QCborValue::True:
610 return true;
611 case QCborValue::False:
612 return false;
613 default:
614 return defaultValue;
615 }
616}
617
618/*!
619 \since 5.2
620 Converts the value to an int and returns it.
621
622 If type() is not Double or the value is not a whole number,
623 the \a defaultValue will be returned.
624 */
625int QJsonValue::toInt(int defaultValue) const
626{
627 switch (value.type()) {
628 case QCborValue::Double: {
629 int dblInt;
630 if (convertDoubleTo<int>(v: toDouble(), value: &dblInt))
631 return dblInt;
632 break;
633 }
634 case QCborValue::Integer: {
635 const auto n = value.toInteger();
636 if (qint64(int(n)) == n)
637 return int(n);
638 break;
639 }
640 default:
641 break;
642 }
643 return defaultValue;
644}
645
646/*!
647 \since 6.0
648 Converts the value to an integer and returns it.
649
650 If type() is not Double or the value is not a whole number
651 representable as qint64, the \a defaultValue will be returned.
652 */
653qint64 QJsonValue::toInteger(qint64 defaultValue) const
654{
655 switch (value.type()) {
656 case QCborValue::Integer:
657 return value.toInteger();
658 case QCborValue::Double: {
659 qint64 dblInt;
660 if (convertDoubleTo<qint64>(v: toDouble(), value: &dblInt))
661 return dblInt;
662 break;
663 }
664 default:
665 break;
666 }
667 return defaultValue;
668}
669
670/*!
671 Converts the value to a double and returns it.
672
673 If type() is not Double, the \a defaultValue will be returned.
674 */
675double QJsonValue::toDouble(double defaultValue) const
676{
677 return value.toDouble(defaultValue);
678}
679
680/*!
681 Converts the value to a QString and returns it.
682
683 If type() is not String, the \a defaultValue will be returned.
684 */
685QString QJsonValue::toString(const QString &defaultValue) const
686{
687 return value.toString(defaultValue);
688}
689
690/*!
691 Converts the value to a QString and returns it.
692
693 If type() is not String, a null QString will be returned.
694
695 \sa QString::isNull()
696 */
697QString QJsonValue::toString() const
698{
699 return value.toString();
700}
701
702/*!
703 Converts the value to an array and returns it.
704
705 If type() is not Array, the \a defaultValue will be returned.
706 */
707QJsonArray QJsonValue::toArray(const QJsonArray &defaultValue) const
708{
709 if (!isArray())
710 return defaultValue;
711 QCborContainerPrivate *dd = nullptr;
712 const auto n = QJsonPrivate::Value::valueHelper(v: value);
713 const auto container = QJsonPrivate::Value::container(v: value);
714 Q_ASSERT(n == -1 || container == nullptr);
715 if (n < 0)
716 dd = container;
717 return QJsonArray(dd);
718}
719
720/*!
721 \overload
722
723 Converts the value to an array and returns it.
724
725 If type() is not Array, a \l{QJsonArray::}{QJsonArray()} will be returned.
726 */
727QJsonArray QJsonValue::toArray() const
728{
729 return toArray(defaultValue: QJsonArray());
730}
731
732/*!
733 Converts the value to an object and returns it.
734
735 If type() is not Object, the \a defaultValue will be returned.
736 */
737QJsonObject QJsonValue::toObject(const QJsonObject &defaultValue) const
738{
739 if (!isObject())
740 return defaultValue;
741 QCborContainerPrivate *dd = nullptr;
742 const auto container = QJsonPrivate::Value::container(v: value);
743 const auto n = QJsonPrivate::Value::valueHelper(v: value);
744 Q_ASSERT(n == -1 || container == nullptr);
745 if (n < 0)
746 dd = container;
747 return QJsonObject(dd);
748}
749
750/*!
751 \overload
752
753 Converts the value to an object and returns it.
754
755 If type() is not Object, the \l {QJsonObject::}{QJsonObject()} will be returned.
756*/
757QJsonObject QJsonValue::toObject() const
758{
759 return toObject(defaultValue: QJsonObject());
760}
761
762/*!
763 Returns a QJsonValue representing the value for the key \a key.
764
765 Equivalent to calling toObject().value(key).
766
767 The returned QJsonValue is QJsonValue::Undefined if the key does not exist,
768 or if isObject() is false.
769
770 \since 5.10
771
772 \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject
773 */
774const QJsonValue QJsonValue::operator[](const QString &key) const
775{
776 return (*this)[QStringView(key)];
777}
778
779/*!
780 \overload
781 \since 5.14
782*/
783const QJsonValue QJsonValue::operator[](QStringView key) const
784{
785 if (!isObject())
786 return QJsonValue(QJsonValue::Undefined);
787
788 return toObject().value(key);
789}
790
791/*!
792 \overload
793 \since 5.10
794*/
795const QJsonValue QJsonValue::operator[](QLatin1StringView key) const
796{
797 if (!isObject())
798 return QJsonValue(QJsonValue::Undefined);
799
800 return toObject().value(key);
801}
802
803/*!
804 Returns a QJsonValue representing the value for index \a i.
805
806 Equivalent to calling toArray().at(i).
807
808 The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds,
809 or if isArray() is false.
810
811 \since 5.10
812
813 \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray
814 */
815const QJsonValue QJsonValue::operator[](qsizetype i) const
816{
817 if (!isArray())
818 return QJsonValue(QJsonValue::Undefined);
819
820 return toArray().at(i);
821}
822
823/*!
824 Returns \c true if the value is equal to \a other.
825 */
826bool QJsonValue::operator==(const QJsonValue &other) const
827{
828 if (value.type() != other.value.type()) {
829 if (isDouble() && other.isDouble()) {
830 // One value Cbor integer, one Cbor double, should interact as doubles.
831 return toDouble() == other.toDouble();
832 }
833 return false;
834 }
835
836 switch (value.type()) {
837 case QCborValue::Undefined:
838 case QCborValue::Null:
839 case QCborValue::True:
840 case QCborValue::False:
841 break;
842 case QCborValue::Double:
843 return toDouble() == other.toDouble();
844 case QCborValue::Integer:
845 return QJsonPrivate::Value::valueHelper(v: value)
846 == QJsonPrivate::Value::valueHelper(v: other.value);
847 case QCborValue::String:
848 return toString() == other.toString();
849 case QCborValue::Array:
850 return toArray() == other.toArray();
851 case QCborValue::Map:
852 return toObject() == other.toObject();
853 default:
854 return false;
855 }
856 return true;
857}
858
859/*!
860 Returns \c true if the value is not equal to \a other.
861 */
862bool QJsonValue::operator!=(const QJsonValue &other) const
863{
864 return !(*this == other);
865}
866
867/*!
868 \class QJsonValueRef
869 \inmodule QtCore
870 \reentrant
871 \brief The QJsonValueRef class is a helper class for QJsonValue.
872
873 \internal
874
875 \ingroup json
876
877 When you get an object of type QJsonValueRef, if you can assign to it,
878 the assignment will apply to the character in the string from
879 which you got the reference. That is its whole purpose in life.
880
881 You can use it exactly in the same way as a reference to a QJsonValue.
882
883 The QJsonValueRef becomes invalid once modifications are made to the
884 string: if you want to keep the character, copy it into a QJsonValue.
885
886 Most of the QJsonValue member functions also exist in QJsonValueRef.
887 However, they are not explicitly documented here.
888*/
889
890void QJsonValueRef::detach()
891{
892#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
893 QCborContainerPrivate *d = QJsonPrivate::Value::container(r: *this);
894 d = QCborContainerPrivate::detach(d, reserved: d->elements.size());
895
896 if (is_object)
897 o->o.reset(ptr: d);
898 else
899 a->a.reset(ptr: d);
900#else
901 d = QCborContainerPrivate::detach(d, d->elements.size());
902#endif
903}
904
905static QJsonValueRef &assignToRef(QJsonValueRef &ref, const QCborValue &value, bool is_object)
906{
907 QCborContainerPrivate *d = QJsonPrivate::Value::container(r: ref);
908 qsizetype index = QJsonPrivate::Value::indexHelper(r: ref);
909 if (is_object && value.isUndefined()) {
910 d->removeAt(idx: index);
911 d->removeAt(idx: index - 1);
912 } else {
913 d->replaceAt(idx: index, value);
914 }
915
916 return ref;
917}
918
919QJsonValueRef &QJsonValueRef::operator =(const QJsonValue &val)
920{
921 detach();
922 return assignToRef(ref&: *this, value: QCborValue::fromJsonValue(v: val), is_object);
923}
924
925QJsonValueRef &QJsonValueRef::operator =(const QJsonValueRef &ref)
926{
927 // ### optimize more?
928 const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: ref);
929 qsizetype index = QJsonPrivate::Value::indexHelper(r: ref);
930
931 if (d == QJsonPrivate::Value::container(r: *this) &&
932 index == QJsonPrivate::Value::indexHelper(r: *this))
933 return *this; // self assignment
934
935 detach();
936 return assignToRef(ref&: *this, value: d->valueAt(idx: index), is_object);
937}
938
939QVariant QJsonValueConstRef::toVariant() const
940{
941 return concrete(self: *this).toVariant();
942}
943
944QJsonArray QJsonValueConstRef::toArray() const
945{
946 return concrete(self: *this).toArray();
947}
948
949QJsonObject QJsonValueConstRef::toObject() const
950{
951 return concrete(self: *this).toObject();
952}
953
954QJsonValue::Type QJsonValueConstRef::concreteType(QJsonValueConstRef self) noexcept
955{
956 return convertFromCborType(type: QJsonPrivate::Value::elementHelper(r: self).type);
957}
958
959bool QJsonValueConstRef::concreteBool(QJsonValueConstRef self, bool defaultValue) noexcept
960{
961 auto &e = QJsonPrivate::Value::elementHelper(r: self);
962 if (e.type == QCborValue::False)
963 return false;
964 if (e.type == QCborValue::True)
965 return true;
966 return defaultValue;
967}
968
969qint64 QJsonValueConstRef::concreteInt(QJsonValueConstRef self, qint64 defaultValue, bool clamp) noexcept
970{
971 auto &e = QJsonPrivate::Value::elementHelper(r: self);
972 qint64 v = defaultValue;
973 if (e.type == QCborValue::Double) {
974 // convertDoubleTo modifies the output even on returning false
975 if (!convertDoubleTo<qint64>(v: e.fpvalue(), value: &v))
976 v = defaultValue;
977 } else if (e.type == QCborValue::Integer) {
978 v = e.value;
979 }
980 if (clamp && qint64(int(v)) != v)
981 return defaultValue;
982 return v;
983}
984
985double QJsonValueConstRef::concreteDouble(QJsonValueConstRef self, double defaultValue) noexcept
986{
987 auto &e = QJsonPrivate::Value::elementHelper(r: self);
988 if (e.type == QCborValue::Double)
989 return e.fpvalue();
990 if (e.type == QCborValue::Integer)
991 return e.value;
992 return defaultValue;
993}
994
995QString QJsonValueConstRef::concreteString(QJsonValueConstRef self, const QString &defaultValue)
996{
997 const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: self);
998 qsizetype index = QJsonPrivate::Value::indexHelper(r: self);
999 if (d->elements.at(i: index).type != QCborValue::String)
1000 return defaultValue;
1001 return d->stringAt(idx: index);
1002}
1003
1004QJsonValue QJsonValueConstRef::concrete(QJsonValueConstRef self) noexcept
1005{
1006 const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: self);
1007 qsizetype index = QJsonPrivate::Value::indexHelper(r: self);
1008 return QJsonPrivate::Value::fromTrustedCbor(v: d->valueAt(idx: index));
1009}
1010
1011QString QJsonValueConstRef::objectKey(QJsonValueConstRef self)
1012{
1013 Q_ASSERT(self.is_object);
1014 Q_ASSUME(self.is_object);
1015 const QCborContainerPrivate *d = QJsonPrivate::Value::container(r: self);
1016 qsizetype index = QJsonPrivate::Value::indexHelper(r: self);
1017
1018 Q_ASSERT(d);
1019 Q_ASSERT(index < d->elements.size());
1020 return d->stringAt(idx: index - 1);
1021}
1022
1023#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
1024QVariant QJsonValueRef::toVariant() const
1025{
1026 return QJsonValueConstRef::toVariant();
1027}
1028
1029QJsonArray QJsonValueRef::toArray() const
1030{
1031 return QJsonValueConstRef::toArray();
1032}
1033
1034QJsonObject QJsonValueRef::toObject() const
1035{
1036 return QJsonValueConstRef::toObject();
1037}
1038
1039QJsonValue QJsonValueRef::toValue() const
1040{
1041 return concrete(self: *this);
1042}
1043#else
1044QJsonValueRef QJsonValueRef::operator[](qsizetype key)
1045{
1046 if (d->elements.at(index).type != QCborValue::Array)
1047 d->replaceAt(index, QCborValue::Array);
1048
1049 auto &e = d->elements[index];
1050 e.container = QCborContainerPrivate::grow(e.container, key); // detaches
1051 e.flags |= QtCbor::Element::IsContainer;
1052
1053 return QJsonValueRef(e.container, key, false);
1054}
1055
1056QJsonValueRef QJsonValueRef::operator[](QAnyStringView key)
1057{
1058 // must go through QJsonObject because some of the machinery is non-static
1059 // member or file-static in qjsonobject.cpp
1060 QJsonObject o = QJsonPrivate::Value::fromTrustedCbor(d->valueAt(index)).toObject();
1061 QJsonValueRef ret = key.visit([&](auto v) {
1062 if constexpr (std::is_same_v<decltype(v), QUtf8StringView>)
1063 return o[QString::fromUtf8(v)];
1064 else
1065 return o[v];
1066 });
1067
1068 // ### did the QJsonObject::operator[] above detach?
1069 QCborContainerPrivate *x = o.o.take();
1070 Q_ASSERT(x->ref.loadRelaxed() == 1);
1071
1072 auto &e = d->elements[index];
1073 if (e.flags & QtCbor::Element::IsContainer && e.container != x)
1074 o.o.reset(e.container); // might not an object!
1075
1076 e.flags |= QtCbor::Element::IsContainer;
1077 e.container = x;
1078
1079 return ret;
1080}
1081#endif
1082
1083size_t qHash(const QJsonValue &value, size_t seed)
1084{
1085 switch (value.type()) {
1086 case QJsonValue::Null:
1087 return qHash(nullptr, seed);
1088 case QJsonValue::Bool:
1089 return qHash(t: value.toBool(), seed);
1090 case QJsonValue::Double:
1091 return qHash(key: value.toDouble(), seed);
1092 case QJsonValue::String:
1093 return qHash(key: value.toString(), seed);
1094 case QJsonValue::Array:
1095 return qHash(array: value.toArray(), seed);
1096 case QJsonValue::Object:
1097 return qHash(object: value.toObject(), seed);
1098 case QJsonValue::Undefined:
1099 return seed;
1100 }
1101 Q_UNREACHABLE_RETURN(0);
1102}
1103
1104#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
1105QDebug operator<<(QDebug dbg, const QJsonValue &o)
1106{
1107 QDebugStateSaver saver(dbg);
1108 switch (o.value.type()) {
1109 case QCborValue::Undefined:
1110 dbg << "QJsonValue(undefined)";
1111 break;
1112 case QCborValue::Null:
1113 dbg << "QJsonValue(null)";
1114 break;
1115 case QCborValue::True:
1116 case QCborValue::False:
1117 dbg.nospace() << "QJsonValue(bool, " << o.toBool() << ')';
1118 break;
1119 case QCborValue::Integer:
1120 dbg.nospace() << "QJsonValue(double, " << o.toInteger() << ')';
1121 break;
1122 case QCborValue::Double:
1123 dbg.nospace() << "QJsonValue(double, " << o.toDouble() << ')';
1124 break;
1125 case QCborValue::String:
1126 dbg.nospace() << "QJsonValue(string, " << o.toString() << ')';
1127 break;
1128 case QCborValue::Array:
1129 dbg.nospace() << "QJsonValue(array, ";
1130 dbg << o.toArray();
1131 dbg << ')';
1132 break;
1133 case QCborValue::Map:
1134 dbg.nospace() << "QJsonValue(object, ";
1135 dbg << o.toObject();
1136 dbg << ')';
1137 break;
1138 default:
1139 Q_UNREACHABLE();
1140 }
1141 return dbg;
1142}
1143#endif
1144
1145#ifndef QT_NO_DATASTREAM
1146QDataStream &operator<<(QDataStream &stream, const QJsonValue &v)
1147{
1148 quint8 type = v.type();
1149 stream << type;
1150 switch (type) {
1151 case QJsonValue::Undefined:
1152 case QJsonValue::Null:
1153 break;
1154 case QJsonValue::Bool:
1155 stream << v.toBool();
1156 break;
1157 case QJsonValue::Double:
1158 stream << v.toDouble();
1159 break;
1160 case QJsonValue::String:
1161 stream << v.toString();
1162 break;
1163 case QJsonValue::Array:
1164 stream << v.toArray();
1165 break;
1166 case QJsonValue::Object:
1167 stream << v.toObject();
1168 break;
1169 }
1170 return stream;
1171}
1172
1173QDataStream &operator>>(QDataStream &stream, QJsonValue &v)
1174{
1175 quint8 type;
1176 stream >> type;
1177 switch (type) {
1178 case QJsonValue::Undefined:
1179 case QJsonValue::Null:
1180 v = QJsonValue{QJsonValue::Type(type)};
1181 break;
1182 case QJsonValue::Bool: {
1183 bool b;
1184 stream >> b;
1185 v = QJsonValue(b);
1186 break;
1187 } case QJsonValue::Double: {
1188 double d;
1189 stream >> d;
1190 v = QJsonValue{d};
1191 break;
1192 } case QJsonValue::String: {
1193 QString s;
1194 stream >> s;
1195 v = QJsonValue{s};
1196 break;
1197 }
1198 case QJsonValue::Array: {
1199 QJsonArray a;
1200 stream >> a;
1201 v = QJsonValue{a};
1202 break;
1203 }
1204 case QJsonValue::Object: {
1205 QJsonObject o;
1206 stream >> o;
1207 v = QJsonValue{o};
1208 break;
1209 }
1210 default: {
1211 stream.setStatus(QDataStream::ReadCorruptData);
1212 v = QJsonValue{QJsonValue::Undefined};
1213 }
1214 }
1215 return stream;
1216}
1217#endif
1218
1219QT_END_NAMESPACE
1220

source code of qtbase/src/corelib/serialization/qjsonvalue.cpp