/****************************************************************************
**
** Copyright (C) 2016 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$
**
****************************************************************************/

#include <qjsonobject.h>
#include <qjsonvalue.h>
#include <qjsonarray.h>
#include <qjsondocument.h>
#include <qstringlist.h>
#include <qdebug.h>
#include <qvariant.h>
#include <qcbormap.h>

#include <private/qcborvalue_p.h>
#include "qjsonwriter_p.h"
#include "qjson_p.h"

#include <algorithm>

QT_BEGIN_NAMESPACE

/*!
    \class QJsonObject
    \inmodule QtCore
    \ingroup json
    \ingroup shared
    \reentrant
    \since 5.0

    \brief The QJsonObject class encapsulates a JSON object.

    A JSON object is a list of key value pairs, where the keys are unique strings
    and the values are represented by a QJsonValue.

    A QJsonObject can be converted to and from a QVariantMap. You can query the
    number of (key, value) pairs with size(), insert(), and remove() entries from it
    and iterate over its content using the standard C++ iterator pattern.

    QJsonObject is an implicitly shared class, and shares the data with the document
    it has been created from as long as it is not being modified.

    You can convert the object to and from text based JSON through QJsonDocument.

    \sa {JSON Support in Qt}, {JSON Save Game Example}
*/

/*!
    \typedef QJsonObject::Iterator

    Qt-style synonym for QJsonObject::iterator.
*/

/*!
    \typedef QJsonObject::ConstIterator

    Qt-style synonym for QJsonObject::const_iterator.
*/

/*!
    \typedef QJsonObject::key_type

    Typedef for QString. Provided for STL compatibility.
*/

/*!
    \typedef QJsonObject::mapped_type

    Typedef for QJsonValue. Provided for STL compatibility.
*/

/*!
    \typedef QJsonObject::size_type

    Typedef for int. Provided for STL compatibility.
*/


/*!
    Constructs an empty JSON object.

    \sa isEmpty()
 */
QJsonObject::QJsonObject() = default;

/*!
    \fn QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args)
    \since 5.4
    Constructs a QJsonObject instance initialized from \a args initialization list.
    For example:
    \code
    QJsonObject object
    {
        {"property1", 1},
        {"property2", 2}
    };
    \endcode
*/

/*!
    \internal
 */
QJsonObject::QJsonObject(QCborContainerPrivate *object)
    : o(object)
{
    Q_ASSERT(o);
}

/*!
    This method replaces part of the QJsonObject(std::initializer_list<QPair<QString, QJsonValue>> args) body.
    The constructor needs to be inline, but we do not want to leak implementation details
    of this class.
    \note this method is called for an uninitialized object
    \internal
 */

void QJsonObject::initialize()
{
    // Because we're being called with uninitialized state, we can't do:
    //    o = nullptr;
    // QExplicitlyDataSharedPointer::operator= will read the current value
    void *ptr = &o;
    memset(ptr, 0, sizeof(o));
}

/*!
    Destroys the object.
 */
QJsonObject::~QJsonObject() = default;

QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args)
{
    for (const auto &arg : args)
        insert(arg.first, arg.second);
}

/*!
    Creates a copy of \a other.

    Since QJsonObject is implicitly shared, the copy is shallow
    as long as the object does not get modified.
 */
QJsonObject::QJsonObject(const QJsonObject &other)
{
    o = other.o;
}

QJsonObject::QJsonObject(QJsonObject &&other) noexcept
    : o(other.o)
{
    other.o = nullptr;
}

/*!
    Assigns \a other to this object.
 */
QJsonObject &QJsonObject::operator =(const QJsonObject &other)
{
    o = other.o;
    return *this;
}

/*!
    \fn QJsonObject::QJsonObject(QJsonObject &&other)
    \since 5.10

    Move-constructs a QJsonObject from \a other.
*/

/*!
    \fn QJsonObject &QJsonObject::operator =(QJsonObject &&other)
    \since 5.10

    Move-assigns \a other to this object.
*/

/*!
    \fn void QJsonObject::swap(QJsonObject &other)
    \since 5.10

    Swaps the object \a other with this. This operation is very fast and never fails.
*/


/*!
    Converts the variant map \a map to a QJsonObject.

    The keys in \a map will be used as the keys in the JSON object,
    and the QVariant values will be converted to JSON values.

    \note Conversion from \l QVariant is not completely lossless. Please see
    the documentation in QJsonValue::fromVariant() for more information.

    \sa fromVariantHash(), toVariantMap(), QJsonValue::fromVariant()
 */
QJsonObject QJsonObject::fromVariantMap(const QVariantMap &map)
{
    return QJsonPrivate::Variant::toJsonObject(map);
}

/*!
    Converts this object to a QVariantMap.

    Returns the created map.

    \sa toVariantHash()
 */
QVariantMap QJsonObject::toVariantMap() const
{
    return QCborMap::fromJsonObject(*this).toVariantMap();
}

/*!
    Converts the variant hash \a hash to a QJsonObject.
    \since 5.5

    The keys in \a hash will be used as the keys in the JSON object,
    and the QVariant values will be converted to JSON values.

    \note Conversion from \l QVariant is not completely lossless. Please see
    the documentation in QJsonValue::fromVariant() for more information.

    \sa fromVariantMap(), toVariantHash(), QJsonValue::fromVariant()
 */
QJsonObject QJsonObject::fromVariantHash(const QVariantHash &hash)
{
    // ### this is implemented the trivial way, not the most efficient way

    QJsonObject object;
    for (QVariantHash::const_iterator it = hash.constBegin(); it != hash.constEnd(); ++it)
        object.insert(it.key(), QJsonValue::fromVariant(it.value()));
    return object;
}

/*!
    Converts this object to a QVariantHash.
    \since 5.5

    Returns the created hash.

    \sa toVariantMap()
 */
QVariantHash QJsonObject::toVariantHash() const
{
    return QCborMap::fromJsonObject(*this).toVariantHash();
}

/*!
    Returns a list of all keys in this object.

    The list is sorted lexographically.
 */
QStringList QJsonObject::keys() const
{
    QStringList keys;
    if (o) {
        keys.reserve(o->elements.length() / 2);
        for (int i = 0, end = o->elements.length(); i < end; i += 2)
            keys.append(o->stringAt(i));
    }
    return keys;
}

/*!
    Returns the number of (key, value) pairs stored in the object.
 */
int QJsonObject::size() const
{
    return o ? o->elements.length() / 2 : 0;
}

/*!
    Returns \c true if the object is empty. This is the same as size() == 0.

    \sa size()
 */
bool QJsonObject::isEmpty() const
{
    return !o || o->elements.isEmpty();
}

template<typename String>
static int indexOf(const QExplicitlySharedDataPointer<QCborContainerPrivate> &o,
                   String key, bool *keyExists)
{
    const auto begin = QJsonPrivate::ConstKeyIterator(o->elements.constBegin());
    const auto end = QJsonPrivate::ConstKeyIterator(o->elements.constEnd());

    const auto it = std::lower_bound(
                begin, end, key,
                [&](const QJsonPrivate::ConstKeyIterator::value_type &e, const String &key) {
        return o->stringCompareElement(e.key(), key) < 0;
    });

    *keyExists = (it != end) && o->stringEqualsElement((*it).key(), key);
    return (it - begin) * 2;
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Returns a QJsonValue representing the value for the key \a key.

    The returned QJsonValue is QJsonValue::Undefined if the key does not exist.

    \sa QJsonValue, QJsonValue::isUndefined()
 */
QJsonValue QJsonObject::value(const QString &key) const
{
    return value(QStringView(key));
}
#endif

/*!
    \overload
    \since 5.14
*/
QJsonValue QJsonObject::value(QStringView key) const
{
    return valueImpl(key);
}

/*!
    \overload
    \since 5.7
*/
QJsonValue QJsonObject::value(QLatin1String key) const
{
    return valueImpl(key);
}

/*!
    \internal
*/
template <typename T>
QJsonValue QJsonObject::valueImpl(T key) const
{
    if (!o)
        return QJsonValue(QJsonValue::Undefined);

    bool keyExists;
    int i = indexOf(o, key, &keyExists);
    if (!keyExists)
        return QJsonValue(QJsonValue::Undefined);
    return QJsonPrivate::Value::fromTrustedCbor(o->valueAt(i + 1));
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Returns a QJsonValue representing the value for the key \a key.

    This does the same as value().

    The returned QJsonValue is QJsonValue::Undefined if the key does not exist.

    \sa value(), QJsonValue, QJsonValue::isUndefined()
 */
QJsonValue QJsonObject::operator [](const QString &key) const
{
    return (*this)[QStringView(key)];
}
#endif

/*!
    \fn QJsonValue QJsonObject::operator [](QStringView key) const

    \overload
    \since 5.14
*/

/*!
    \fn QJsonValue QJsonObject::operator [](QLatin1String key) const

    \overload
    \since 5.7
*/

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Returns a reference to the value for \a key. If there is no value with key
    \a key in the object, one is created with a QJsonValue::Null value and then
    returned.

    The return value is of type QJsonValueRef, a helper class for QJsonArray
    and QJsonObject. When you get an object of type QJsonValueRef, you can
    use it as if it were a reference to a QJsonValue. If you assign to it,
    the assignment will apply to the element in the QJsonArray or QJsonObject
    from which you got the reference.

    \sa value()
 */
QJsonValueRef QJsonObject::operator [](const QString &key)
{
    return (*this)[QStringView(key)];
}
#endif

/*!
    \overload
    \since 5.14
*/
QJsonValueRef QJsonObject::operator [](QStringView key)
{
    return atImpl(key);
}

/*!
    \overload
    \since 5.7
*/
QJsonValueRef QJsonObject::operator [](QLatin1String key)
{
    return atImpl(key);
}

/*!
    \internal
*/
template <typename T>
QJsonValueRef QJsonObject::atImpl(T key)
{
    if (!o)
        o = new QCborContainerPrivate;

    bool keyExists = false;
    int index = indexOf(o, key, &keyExists);
    if (!keyExists) {
        detach2(o->elements.length() / 2 + 1);
        o->insertAt(index, key);
        o->insertAt(index + 1, QCborValue::fromJsonValue(QJsonValue()));
    }
    // detaching will happen if and when this QJsonValueRef is assigned to
    return QJsonValueRef(this, index / 2);
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Inserts a new item with the key \a key and a value of \a value.

    If there is already an item with the key \a key, then that item's value
    is replaced with \a value.

    Returns an iterator pointing to the inserted item.

    If the value is QJsonValue::Undefined, it will cause the key to get removed
    from the object. The returned iterator will then point to end().

    \sa remove(), take(), QJsonObject::iterator, end()
 */
QJsonObject::iterator QJsonObject::insert(const QString &key, const QJsonValue &value)
{
    return insert(QStringView(key), value);
}
#endif

/*!
    \overload
    \since 5.14
*/
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.type() == QJsonValue::Undefined) {
        remove(key);
        return end();
    }
    bool keyExists = false;
    int pos = o ? indexOf(o, key, &keyExists) : 0;
    return insertAt(pos, key, value, keyExists);
}

/*!
    \internal
 */
template <typename T>
QJsonObject::iterator QJsonObject::insertAt(int pos, T key, const QJsonValue &value, bool keyExists)
{
    if (o)
        detach2(o->elements.length() / 2 + (keyExists ? 0 : 1));
    else
        o = new QCborContainerPrivate;

    if (keyExists) {
        o->replaceAt(pos + 1, QCborValue::fromJsonValue(value));
    } else {
        o->insertAt(pos, key);
        o->insertAt(pos + 1, QCborValue::fromJsonValue(value));
    }
    return {this, pos / 2};
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Removes \a key from the object.

    \sa insert(), take()
 */
void QJsonObject::remove(const QString &key)
{
    remove(QStringView(key));
}
#endif

/*!
    \overload
    \since 5.14
*/
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 (!o)
        return;

    bool keyExists;
    int index = indexOf(o, key, &keyExists);
    if (!keyExists)
        return;

    removeAt(index / 2);
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Removes \a key from the object.

    Returns a QJsonValue containing the value referenced by \a key.
    If \a key was not contained in the object, the returned QJsonValue
    is QJsonValue::Undefined.

    \sa insert(), remove(), QJsonValue
 */
QJsonValue QJsonObject::take(const QString &key)
{
    return take(QStringView(key));
}
#endif

/*!
    \overload
    \since 5.14
*/
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);

    bool keyExists;
    int index = indexOf(o, key, &keyExists);
    if (!keyExists)
        return QJsonValue(QJsonValue::Undefined);

    detach();
    const QJsonValue v = QJsonPrivate::Value::fromTrustedCbor(o->extractAt(index + 1));
    removeAt(index / 2);
    return v;
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Returns \c true if the object contains key \a key.

    \sa insert(), remove(), take()
 */
bool QJsonObject::contains(const QString &key) const
{
    return contains(QStringView(key));
}
#endif

/*!
    \overload
    \since 5.14
*/
bool QJsonObject::contains(QStringView key) const
{
    return containsImpl(key);
}

/*!
    \overload
    \since 5.7
*/
bool QJsonObject::contains(QLatin1String key) const
{
    return containsImpl(key);
}

/*!
    \internal
*/
template <typename T>
bool QJsonObject::containsImpl(T key) const
{
    if (!o)
        return false;

    bool keyExists;
    indexOf(o, key, &keyExists);
    return keyExists;
}

/*!
    Returns \c true if \a other is equal to this object.
 */
bool QJsonObject::operator==(const QJsonObject &other) const
{
    if (o == other.o)
        return true;

    if (!o)
        return !other.o->elements.length();
    if (!other.o)
        return !o->elements.length();
    if (o->elements.length() != other.o->elements.length())
        return false;

    for (int i = 0, end = o->elements.length(); i < end; ++i) {
        if (o->valueAt(i) != other.o->valueAt(i))
            return false;
    }

    return true;
}

/*!
    Returns \c true if \a other is not equal to this object.
 */
bool QJsonObject::operator!=(const QJsonObject &other) const
{
    return !(*this == other);
}

/*!
    Removes the (key, value) pair pointed to by the iterator \a it
    from the map, and returns an iterator to the next item in the
    map.

    \sa remove()
 */
QJsonObject::iterator QJsonObject::erase(QJsonObject::iterator it)
{
    if (it.o != this || it.i < 0 || it.i >= o->elements.length())
        return {this, o->elements.length()};

    int index = it.i;

    removeAt(index);

    // iterator hasn't changed
    return it;
}

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Returns an iterator pointing to the item with key \a key in the
    map.

    If the map contains no item with key \a key, the function
    returns end().
 */
QJsonObject::iterator QJsonObject::find(const QString &key)
{
    return find(QStringView(key));
}
#endif

/*!
    \overload
    \since 5.14
*/
QJsonObject::iterator QJsonObject::find(QStringView key)
{
    return findImpl(key);
}

/*!
    \overload
    \since 5.7
*/
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 ? indexOf(o, key, &keyExists) : 0;
    if (!keyExists)
        return end();
    detach2();
    return {this, index / 2};
}

#if QT_STRINGVIEW_LEVEL < 2
/*! \fn QJsonObject::const_iterator QJsonObject::find(const QString &key) const

    \overload
*/
#endif

/*! \fn QJsonObject::const_iterator QJsonObject::find(QStringView key) const

    \overload
    \since 5.14
*/

/*! \fn QJsonObject::const_iterator QJsonObject::find(QLatin1String key) const

    \overload
    \since 5.7
*/

#if QT_STRINGVIEW_LEVEL < 2
/*!
    Returns a const iterator pointing to the item with key \a key in the
    map.

    If the map contains no item with key \a key, the function
    returns constEnd().
 */
QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
{
    return constFind(QStringView(key));
}
#endif

/*!
    \overload
    \since 5.14
*/
QJsonObject::const_iterator QJsonObject::constFind(QStringView key) const
{
    return constFindImpl(key);
}

/*!
    \overload
    \since 5.7
*/
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 ? indexOf(o, key, &keyExists) : 0;
    if (!keyExists)
        return end();
    return {this, index / 2};
}

/*! \fn int QJsonObject::count() const

    \overload

    Same as size().
*/

/*! \fn int QJsonObject::length() const

    \overload

    Same as size().
*/

/*! \fn QJsonObject::iterator QJsonObject::begin()

    Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
    the object.

    \sa constBegin(), end()
*/

/*! \fn QJsonObject::const_iterator QJsonObject::begin() const

    \overload
*/

/*! \fn QJsonObject::const_iterator QJsonObject::constBegin() const

    Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
    in the object.

    \sa begin(), constEnd()
*/

/*! \fn QJsonObject::iterator QJsonObject::end()

    Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
    after the last item in the object.

    \sa begin(), constEnd()
*/

/*! \fn QJsonObject::const_iterator QJsonObject::end() const

    \overload
*/

/*! \fn QJsonObject::const_iterator QJsonObject::constEnd() const

    Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
    item after the last item in the object.

    \sa constBegin(), end()
*/

/*!
    \fn bool QJsonObject::empty() const

    This function is provided for STL compatibility. It is equivalent
    to isEmpty(), returning \c true if the object is empty; otherwise
    returning \c false.
*/

/*! \class QJsonObject::iterator
    \inmodule QtCore
    \ingroup json
    \reentrant
    \since 5.0

    \brief The QJsonObject::iterator class provides an STL-style non-const iterator for QJsonObject.

    QJsonObject::iterator allows you to iterate over a QJsonObject
    and to modify the value (but not the key) stored under
    a particular key. If you want to iterate over a const QJsonObject, you
    should use QJsonObject::const_iterator. It is generally good practice to
    use QJsonObject::const_iterator on a non-const QJsonObject as well, unless you
    need to change the QJsonObject through the iterator. Const iterators are
    slightly faster, and improve code readability.

    The default QJsonObject::iterator constructor creates an uninitialized
    iterator. You must initialize it using a QJsonObject function like
    QJsonObject::begin(), QJsonObject::end(), or QJsonObject::find() before you can
    start iterating.

    Multiple iterators can be used on the same object. Existing iterators will however
    become dangling once the object gets modified.

    \sa QJsonObject::const_iterator, {JSON Support in Qt}, {JSON Save Game Example}
*/

/*! \typedef QJsonObject::iterator::difference_type

    \internal
*/

/*! \typedef QJsonObject::iterator::iterator_category

    A synonym for \e {std::random_access_iterator_tag} indicating
    this iterator is a random-access iterator.

    \note In Qt versions before 5.6, this was set by mistake to
    \e {std::bidirectional_iterator_tag}.
*/

/*! \typedef QJsonObject::iterator::reference

    \internal
*/

/*! \typedef QJsonObject::iterator::value_type

    \internal
*/

/*! \typedef QJsonObject::iterator::pointer

    \internal
*/

/*! \fn QJsonObject::iterator::iterator()

    Constructs an uninitialized iterator.

    Functions like key(), value(), and operator++() must not be
    called on an uninitialized iterator. Use operator=() to assign a
    value to it before using it.

    \sa QJsonObject::begin(), QJsonObject::end()
*/

/*! \fn QJsonObject::iterator::iterator(QJsonObject *obj, int index)
    \internal
*/

/*! \fn QString QJsonObject::iterator::key() const

    Returns the current item's key.

    There is no direct way of changing an item's key through an
    iterator, although it can be done by calling QJsonObject::erase()
    followed by QJsonObject::insert().

    \sa value()
*/

/*! \fn QJsonValueRef QJsonObject::iterator::value() const

    Returns a modifiable reference to the current item's value.

    You can change the value of an item by using value() on
    the left side of an assignment.

    The return value is of type QJsonValueRef, a helper class for QJsonArray
    and QJsonObject. When you get an object of type QJsonValueRef, you can
    use it as if it were a reference to a QJsonValue. If you assign to it,
    the assignment will apply to the element in the QJsonArray or QJsonObject
    from which you got the reference.

    \sa key(), operator*()
*/

/*! \fn QJsonValueRef QJsonObject::iterator::operator*() const

    Returns a modifiable reference to the current item's value.

    Same as value().

    The return value is of type QJsonValueRef, a helper class for QJsonArray
    and QJsonObject. When you get an object of type QJsonValueRef, you can
    use it as if it were a reference to a QJsonValue. If you assign to it,
    the assignment will apply to the element in the QJsonArray or QJsonObject
    from which you got the reference.

    \sa key()
*/

/*! \fn QJsonValueRef *QJsonObject::iterator::operator->() const

    Returns a pointer to a modifiable reference to the current item.
*/

/*! \fn const QJsonValueRef QJsonObject::iterator::operator[](int j)

    Returns a modifiable reference to the item at offset \a j from the
    item pointed to by this iterator (the item at position \c{*this + j}).

    This function is provided to make QJsonObject iterators behave like C++
    pointers.

    The return value is of type QJsonValueRef, a helper class for QJsonArray
    and QJsonObject. When you get an object of type QJsonValueRef, you can
    use it as if it were a reference to a QJsonValue. If you assign to it,
    the assignment will apply to the element in the QJsonArray or QJsonObject
    from which you got the reference.

    \sa operator+()
*/

/*!
    \fn bool QJsonObject::iterator::operator==(const iterator &other) const
    \fn bool QJsonObject::iterator::operator==(const const_iterator &other) const

    Returns \c true if \a other points to the same item as this
    iterator; otherwise returns \c false.

    \sa operator!=()
*/

/*!
    \fn bool QJsonObject::iterator::operator!=(const iterator &other) const
    \fn bool QJsonObject::iterator::operator!=(const const_iterator &other) const

    Returns \c true if \a other points to a different item than this
    iterator; otherwise returns \c false.

    \sa operator==()
*/

/*!
    \fn bool QJsonObject::iterator::operator<(const iterator& other) const
    \fn bool QJsonObject::iterator::operator<(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is less than
    the item pointed to by the \a other iterator.
*/

/*!
    \fn bool QJsonObject::iterator::operator<=(const iterator& other) const
    \fn bool QJsonObject::iterator::operator<=(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is less than
    or equal to the item pointed to by the \a other iterator.
*/

/*!
    \fn bool QJsonObject::iterator::operator>(const iterator& other) const
    \fn bool QJsonObject::iterator::operator>(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is greater
    than the item pointed to by the \a other iterator.
*/

/*!
    \fn bool QJsonObject::iterator::operator>=(const iterator& other) const
    \fn bool QJsonObject::iterator::operator>=(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is greater
    than or equal to the item pointed to by the \a other iterator.
*/

/*! \fn QJsonObject::iterator QJsonObject::iterator::operator++()

    The prefix ++ operator, \c{++i}, advances the iterator to the
    next item in the object and returns an iterator to the new current
    item.

    Calling this function on QJsonObject::end() leads to undefined results.

    \sa operator--()
*/

/*! \fn QJsonObject::iterator QJsonObject::iterator::operator++(int)

    \overload

    The postfix ++ operator, \c{i++}, advances the iterator to the
    next item in the object and returns an iterator to the previously
    current item.
*/

/*! \fn QJsonObject::iterator QJsonObject::iterator::operator--()

    The prefix -- operator, \c{--i}, makes the preceding item
    current and returns an iterator pointing to the new current item.

    Calling this function on QJsonObject::begin() leads to undefined
    results.

    \sa operator++()
*/

/*! \fn QJsonObject::iterator QJsonObject::iterator::operator--(int)

    \overload

    The postfix -- operator, \c{i--}, makes the preceding item
    current and returns an iterator pointing to the previously
    current item.
*/

/*! \fn QJsonObject::iterator QJsonObject::iterator::operator+(int j) const

    Returns an iterator to the item at \a j positions forward from
    this iterator. If \a j is negative, the iterator goes backward.

    \sa operator-()

*/

/*! \fn QJsonObject::iterator QJsonObject::iterator::operator-(int j) const

    Returns an iterator to the item at \a j positions backward from
    this iterator. If \a j is negative, the iterator goes forward.

    \sa operator+()
*/

/*! \fn QJsonObject::iterator &QJsonObject::iterator::operator+=(int j)

    Advances the iterator by \a j items. If \a j is negative, the
    iterator goes backward.

    \sa operator-=(), operator+()
*/

/*! \fn QJsonObject::iterator &QJsonObject::iterator::operator-=(int j)

    Makes the iterator go back by \a j items. If \a j is negative,
    the iterator goes forward.

    \sa operator+=(), operator-()
*/

/*! \fn int QJsonObject::iterator::operator-(iterator other) const

    Returns the number of items between the item pointed to by \a
    other and the item pointed to by this iterator.
*/

/*!
    \class QJsonObject::const_iterator
    \inmodule QtCore
    \ingroup json
    \since 5.0
    \brief The QJsonObject::const_iterator class provides an STL-style const iterator for QJsonObject.

    QJsonObject::const_iterator allows you to iterate over a QJsonObject.
    If you want to modify the QJsonObject as you iterate
    over it, you must use QJsonObject::iterator instead. It is generally
    good practice to use QJsonObject::const_iterator on a non-const QJsonObject as
    well, unless you need to change the QJsonObject through the iterator.
    Const iterators are slightly faster and improve code
    readability.

    The default QJsonObject::const_iterator constructor creates an
    uninitialized iterator. You must initialize it using a QJsonObject
    function like QJsonObject::constBegin(), QJsonObject::constEnd(), or
    QJsonObject::find() before you can start iterating.

    Multiple iterators can be used on the same object. Existing iterators
    will however become dangling if the object gets modified.

    \sa QJsonObject::iterator, {JSON Support in Qt}, {JSON Save Game Example}
*/

/*! \typedef QJsonObject::const_iterator::difference_type

    \internal
*/

/*! \typedef QJsonObject::const_iterator::iterator_category

    A synonym for \e {std::random_access_iterator_tag} indicating
    this iterator is a random-access iterator.

    \note In Qt versions before 5.6, this was set by mistake to
    \e {std::bidirectional_iterator_tag}.
*/

/*! \typedef QJsonObject::const_iterator::reference

    \internal
*/

/*! \typedef QJsonObject::const_iterator::value_type

    \internal
*/

/*! \typedef QJsonObject::const_iterator::pointer

    \internal
*/

/*! \fn QJsonObject::const_iterator::const_iterator()

    Constructs an uninitialized iterator.

    Functions like key(), value(), and operator++() must not be
    called on an uninitialized iterator. Use operator=() to assign a
    value to it before using it.

    \sa QJsonObject::constBegin(), QJsonObject::constEnd()
*/

/*! \fn QJsonObject::const_iterator::const_iterator(const QJsonObject *obj, int index)
    \internal
*/

/*! \fn QJsonObject::const_iterator::const_iterator(const iterator &other)

    Constructs a copy of \a other.
*/

/*! \fn QString QJsonObject::const_iterator::key() const

    Returns the current item's key.

    \sa value()
*/

/*! \fn QJsonValue QJsonObject::const_iterator::value() const

    Returns the current item's value.

    \sa key(), operator*()
*/

/*! \fn QJsonValue QJsonObject::const_iterator::operator*() const

    Returns the current item's value.

    Same as value().

    \sa key()
*/

/*! \fn QJsonValue *QJsonObject::const_iterator::operator->() const

    Returns a pointer to the current item.
*/

/*! \fn const QJsonValue QJsonObject::const_iterator::operator[](int j)

    Returns the item at offset \a j from the item pointed to by this iterator (the item at
    position \c{*this + j}).

    This function is provided to make QJsonObject iterators behave like C++
    pointers.

    \sa operator+()
*/


/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &other) const
    \fn bool QJsonObject::const_iterator::operator==(const iterator &other) const

    Returns \c true if \a other points to the same item as this
    iterator; otherwise returns \c false.

    \sa operator!=()
*/

/*! \fn bool QJsonObject::const_iterator::operator!=(const const_iterator &other) const
    \fn bool QJsonObject::const_iterator::operator!=(const iterator &other) const

    Returns \c true if \a other points to a different item than this
    iterator; otherwise returns \c false.

    \sa operator==()
*/

/*!
    \fn bool QJsonObject::const_iterator::operator<(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is less than
    the item pointed to by the \a other iterator.
*/

/*!
    \fn bool QJsonObject::const_iterator::operator<=(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is less than
    or equal to the item pointed to by the \a other iterator.
*/

/*!
    \fn bool QJsonObject::const_iterator::operator>(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is greater
    than the item pointed to by the \a other iterator.
*/

/*!
    \fn bool QJsonObject::const_iterator::operator>=(const const_iterator& other) const

    Returns \c true if the item pointed to by this iterator is greater
    than or equal to the item pointed to by the \a other iterator.
*/

/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator++()

    The prefix ++ operator, \c{++i}, advances the iterator to the
    next item in the object and returns an iterator to the new current
    item.

    Calling this function on QJsonObject::end() leads to undefined results.

    \sa operator--()
*/

/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator++(int)

    \overload

    The postfix ++ operator, \c{i++}, advances the iterator to the
    next item in the object and returns an iterator to the previously
    current item.
*/

/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator--()

    The prefix -- operator, \c{--i}, makes the preceding item
    current and returns an iterator pointing to the new current item.

    Calling this function on QJsonObject::begin() leads to undefined
    results.

    \sa operator++()
*/

/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator--(int)

    \overload

    The postfix -- operator, \c{i--}, makes the preceding item
    current and returns an iterator pointing to the previously
    current item.
*/

/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator+(int j) const

    Returns an iterator to the item at \a j positions forward from
    this iterator. If \a j is negative, the iterator goes backward.

    This operation can be slow for large \a j values.

    \sa operator-()
*/

/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator-(int j) const

    Returns an iterator to the item at \a j positions backward from
    this iterator. If \a j is negative, the iterator goes forward.

    This operation can be slow for large \a j values.

    \sa operator+()
*/

/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator+=(int j)

    Advances the iterator by \a j items. If \a j is negative, the
    iterator goes backward.

    This operation can be slow for large \a j values.

    \sa operator-=(), operator+()
*/

/*! \fn QJsonObject::const_iterator &QJsonObject::const_iterator::operator-=(int j)

    Makes the iterator go back by \a j items. If \a j is negative,
    the iterator goes forward.

    This operation can be slow for large \a j values.

    \sa operator+=(), operator-()
*/

/*! \fn int QJsonObject::const_iterator::operator-(const_iterator other) const

    Returns the number of items between the item pointed to by \a
    other and the item pointed to by this iterator.
*/


/*!
    \internal
 */
void QJsonObject::detach(uint reserve)
{
    Q_UNUSED(reserve)
    Q_ASSERT(!reserve);
    detach2(reserve);
}

bool QJsonObject::detach2(uint reserve)
{
    if (!o)
        return true;
    o = QCborContainerPrivate::detach(o.data(), reserve ? reserve * 2 : o->elements.length());
    return o;
}

/*!
    \internal
 */
void QJsonObject::compact()
{
    if (!o)
        return;

    detach2();
    o->compact(o->elements.length());
}

/*!
    \internal
 */
QString QJsonObject::keyAt(int i) const
{
    Q_ASSERT(o && i >= 0 && i * 2 < o->elements.length());
    return o->stringAt(i * 2);
}

/*!
    \internal
 */
QJsonValue QJsonObject::valueAt(int i) const
{
    if (!o || i < 0 || 2 * i + 1 >= o->elements.length())
        return QJsonValue(QJsonValue::Undefined);
    return QJsonPrivate::Value::fromTrustedCbor(o->valueAt(2 * i + 1));
}

/*!
    \internal
 */
void QJsonObject::setValueAt(int i, const QJsonValue &val)
{
    Q_ASSERT(o && i >= 0 && 2 * i + 1 < o->elements.length());
    detach2();
    if (val.isUndefined()) {
        o->removeAt(2 * i + 1);
        o->removeAt(2 * i);
    } else {
        o->replaceAt(2 * i + 1, QCborValue::fromJsonValue(val));
    }
}

/*!
    \internal
 */
void QJsonObject::removeAt(int index)
{
    detach2();
    o->removeAt(2 * index + 1);
    o->removeAt(2 * index);
}

uint qHash(const QJsonObject &object, uint seed)
{
    QtPrivate::QHashCombine hash;
    for (auto it = object.begin(), end = object.end(); it != end; ++it) {
        const QString key = it.key();
        const QJsonValue value = it.value();
        seed = hash(seed, std::pair<const QString&, const QJsonValue&>(key, value));
    }
    return seed;
}

#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
QDebug operator<<(QDebug dbg, const QJsonObject &o)
{
    QDebugStateSaver saver(dbg);
    if (!o.o) {
        dbg << "QJsonObject()";
        return dbg;
    }
    QByteArray json;
    QJsonPrivate::Writer::objectToJson(o.o.data(), json, 0, true);
    dbg.nospace() << "QJsonObject("
                  << json.constData() // print as utf-8 string without extra quotation marks
                  << ")";
    return dbg;
}
#endif

#ifndef QT_NO_DATASTREAM
QDataStream &operator<<(QDataStream &stream, const QJsonObject &object)
{
    QJsonDocument doc{object};
    stream << doc.toJson(QJsonDocument::Compact);
    return stream;
}

QDataStream &operator>>(QDataStream &stream, QJsonObject &object)
{
    QJsonDocument doc;
    stream >> doc;
    object = doc.object();
    return stream;
}
#endif

QT_END_NAMESPACE
