From f581b041199ba7c825fbffd9110727360d1f2668 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 20 Mar 2020 18:43:09 -0300 Subject: QCborValue: apply a simple optimization to avoid unnecessary allocations If the map or array is known to be empty, we don't need to allocate a QCborContainerPrivate. Change-Id: Ief61acdfbe4d4b5ba1f0fffd15fe212b6a6e77c3 Reviewed-by: Edward Welbourne Reviewed-by: Lars Knoll --- src/corelib/serialization/qcborvalue.cpp | 56 +++++++++++++++++--------------- src/corelib/serialization/qcborvalue_p.h | 1 - 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index 23b4a15c0c..f4ceba3836 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -1445,9 +1445,35 @@ static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader & return nullptr; } - auto d = new QCborContainerPrivate; - d->ref.storeRelaxed(1); - d->decodeContainerFromCbor(reader, remainingRecursionDepth - 1); + QCborContainerPrivate *d = nullptr; + int mapShift = reader.isMap() ? 1 : 0; + if (reader.isLengthKnown()) { + quint64 len = reader.length(); + + // Clamp allocation to 1M elements (avoids crashing due to corrupt + // stream or loss of precision when converting from quint64 to + // QVector::size_type). + len = qMin(len, quint64(1024 * 1024 - 1)); + if (len) { + d = new QCborContainerPrivate; + d->ref.storeRelaxed(1); + d->elements.reserve(qsizetype(len) << mapShift); + } + } else { + d = new QCborContainerPrivate; + d->ref.storeRelaxed(1); + } + + reader.enterContainer(); + if (reader.lastError() != QCborError::NoError) + return d; + + while (reader.hasNext() && reader.lastError() == QCborError::NoError) + d->decodeValueFromCbor(reader, remainingRecursionDepth - 1); + + if (reader.lastError() == QCborError::NoError) + reader.leaveContainer(); + return d; } @@ -1637,30 +1663,6 @@ void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int r } } -void QCborContainerPrivate::decodeContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth) -{ - int mapShift = reader.isMap() ? 1 : 0; - if (reader.isLengthKnown()) { - quint64 len = reader.length(); - - // Clamp allocation to 1M elements (avoids crashing due to corrupt - // stream or loss of precision when converting from quint64 to - // QVector::size_type). - len = qMin(len, quint64(1024 * 1024 - 1)); - elements.reserve(qsizetype(len) << mapShift); - } - - reader.enterContainer(); - if (reader.lastError() != QCborError::NoError) - return; - - while (reader.hasNext() && reader.lastError() == QCborError::NoError) - decodeValueFromCbor(reader, remainingRecursionDepth); - - if (reader.lastError() == QCborError::NoError) - reader.leaveContainer(); -} - /*! Creates a QCborValue with byte array value \a ba. The value can later be retrieved using toByteArray(). diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h index 2358626541..041a20e746 100644 --- a/src/corelib/serialization/qcborvalue_p.h +++ b/src/corelib/serialization/qcborvalue_p.h @@ -406,7 +406,6 @@ public: } void decodeValueFromCbor(QCborStreamReader &reader, int remainiingStackDepth); - void decodeContainerFromCbor(QCborStreamReader &reader, int remainingStackDepth); void decodeStringFromCbor(QCborStreamReader &reader); static inline void setErrorInReader(QCborStreamReader &reader, QCborError error); }; -- cgit v1.2.3