diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2020-03-20 18:43:09 -0300 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2020-04-10 14:46:02 -0300 |
commit | 67f54c1ebeb60be93bfc7ef3caf2e964f045e6b9 (patch) | |
tree | 055364c0987c8b58921bc0a93562ca5b96fd6d2a /src | |
parent | 07e8390b455b9aa81b7472b401fcaf5dfd48d3c1 (diff) |
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 <edward.welbourne@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit f581b041199ba7c825fbffd9110727360d1f2668)
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/serialization/qcborvalue.cpp | 56 | ||||
-rw-r--r-- | 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 6c60e43d80..6110c9a864 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -1369,9 +1369,35 @@ static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader & return nullptr; } - auto d = new QCborContainerPrivate; - d->ref.store(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.store(1); + d->elements.reserve(qsizetype(len) << mapShift); + } + } else { + d = new QCborContainerPrivate; + d->ref.store(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; } @@ -1628,30 +1654,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 1677ed5d65..97bfb3a2dc 100644 --- a/src/corelib/serialization/qcborvalue_p.h +++ b/src/corelib/serialization/qcborvalue_p.h @@ -390,7 +390,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); }; |