diff options
Diffstat (limited to 'src/corelib/serialization/qjsonparser.cpp')
-rw-r--r-- | src/corelib/serialization/qjsonparser.cpp | 94 |
1 files changed, 64 insertions, 30 deletions
diff --git a/src/corelib/serialization/qjsonparser.cpp b/src/corelib/serialization/qjsonparser.cpp index 7421902135..2e40b6c8fb 100644 --- a/src/corelib/serialization/qjsonparser.cpp +++ b/src/corelib/serialization/qjsonparser.cpp @@ -1,13 +1,12 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:COMM$ -** +** $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 @@ -16,25 +15,26 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** $QT_END_LICENSE$ -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** -** +** 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$ ** ****************************************************************************/ @@ -379,10 +379,30 @@ error: return QCborValue(); } +// We need to retain the _last_ value for any duplicate keys and we need to deref containers. +// Therefore the manual implementation of std::unique(). +template<typename Iterator, typename Compare, typename Assign> +static Iterator customAssigningUniqueLast(Iterator first, Iterator last, + Compare compare, Assign assign) +{ + first = std::adjacent_find(first, last, compare); + if (first == last) + return last; + + Iterator result = first; + while (++first != last) { + if (!compare(*result, *first)) + ++result; + if (result != first) + assign(*result, *first); + } + + return ++result; +} + static void sortContainer(QCborContainerPrivate *container) { using Forward = QJsonPrivate::KeyIterator; - using Reverse = std::reverse_iterator<Forward>; using Value = Forward::value_type; auto compare = [container](const Value &a, const Value &b) @@ -420,17 +440,31 @@ static void sortContainer(QCborContainerPrivate *container) } }; - std::sort(Forward(container->elements.begin()), Forward(container->elements.end()), - [&compare](const Value &a, const Value &b) { return compare(a, b) < 0; }); + // The elements' containers are owned by the outer container, not by the elements themselves. + auto move = [](Forward::reference target, Forward::reference source) + { + QtCbor::Element &targetValue = target.value(); + + // If the target has a container, deref it before overwriting, so that we don't leak. + if (targetValue.flags & QtCbor::Element::IsContainer) + targetValue.container->deref(); + + // Do not move, so that we can clear the value afterwards. + target = source; + + // Clear the source value, so that we don't store the same container twice. + source.value() = QtCbor::Element(); + }; + + std::stable_sort( + Forward(container->elements.begin()), Forward(container->elements.end()), + [&compare](const Value &a, const Value &b) { return compare(a, b) < 0; }); - // We need to retain the _last_ value for any duplicate keys. Therefore the reverse dance here. - auto it = std::unique(Reverse(container->elements.end()), Reverse(container->elements.begin()), - [&compare](const Value &a, const Value &b) { - return compare(a, b) == 0; - }).base().elementsIterator(); + Forward result = customAssigningUniqueLast( + Forward(container->elements.begin()), Forward(container->elements.end()), + [&compare](const Value &a, const Value &b) { return compare(a, b) == 0; }, move); - // The erase from beginning is expensive but hopefully rare. - container->elements.erase(container->elements.begin(), it); + container->elements.erase(result.elementsIterator(), container->elements.end()); } |