diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2018-05-31 20:13:05 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2018-07-05 14:56:15 +0000 |
commit | 514972544a34aca0fd679b3a78521a0a1558d4e0 (patch) | |
tree | 8dbec4023d90d4022256071fadad39d67723c3c4 /src/corelib/serialization | |
parent | fddf09363e1bbc6f6549eaf28def7699b2d87341 (diff) |
QCborArray & Map: implement move semantics
There isn't a lot of efficiency gain, since QCborValue was already
refcounted. This saves two atomic operations and an out-of-line call. In
the case of QCborValueRef (which includes QCborMap), because we reset
the container pointer in inline code, the call to QCborValue::dispose()
is also suppressed.
Change-Id: Icc2c231dc2c44abdb087fffd1533eaba7a9c70fa
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/corelib/serialization')
-rw-r--r-- | src/corelib/serialization/qcborarray.cpp | 15 | ||||
-rw-r--r-- | src/corelib/serialization/qcborarray.h | 3 | ||||
-rw-r--r-- | src/corelib/serialization/qcborvalue.cpp | 36 | ||||
-rw-r--r-- | src/corelib/serialization/qcborvalue.h | 13 | ||||
-rw-r--r-- | src/corelib/serialization/qcborvalue_p.h | 19 |
5 files changed, 70 insertions, 16 deletions
diff --git a/src/corelib/serialization/qcborarray.cpp b/src/corelib/serialization/qcborarray.cpp index a1b0d1573c..e35738adcc 100644 --- a/src/corelib/serialization/qcborarray.cpp +++ b/src/corelib/serialization/qcborarray.cpp @@ -298,6 +298,9 @@ QCborValue QCborArray::at(qsizetype i) const */ /*! + \fn void QCborArray::insert(qsizetype i, const QCborValue &value) + \fn void QCborArray::insert(qsizetype i, QCborValue &&value) + Inserts \a value into the array at position \a i in this array. The array must have at least \a i elements before the insertion. @@ -313,6 +316,16 @@ void QCborArray::insert(qsizetype i, const QCborValue &value) d->insertAt(i, value); } +void QCborArray::insert(qsizetype i, QCborValue &&value) +{ + Q_ASSERT(size_t(i) <= size_t(size()) || i == -1); + if (i < 0) + i = size(); + detach(qMax(i + 1, size())); + d->insertAt(i, value, QCborContainerPrivate::MoveContainer); + QCborContainerPrivate::resetValue(value); +} + /*! Extracts a value from the array at the position indicated by iterator \a it and returns the value so extracted. @@ -330,6 +343,7 @@ QCborValue QCborArray::extract(iterator it) /*! \fn void QCborArray::prepend(const QCborValue &value) + \fn void QCborArray::prepend(QCborValue &&value) Prepends \a value into the array before any other elements it may already contain. @@ -340,6 +354,7 @@ QCborValue QCborArray::extract(iterator it) /*! \fn void QCborArray::append(const QCborValue &value) + \fn void QCborArray::append(QCborValue &&value) Appends \a value into the array after all other elements it may already contain. diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h index 218fa8e133..07ef6428b2 100644 --- a/src/corelib/serialization/qcborarray.h +++ b/src/corelib/serialization/qcborarray.h @@ -190,8 +190,11 @@ public: QCborValueRef operator[](qsizetype i) { Q_ASSERT(i < size()); return begin()[i]; } void insert(qsizetype i, const QCborValue &value); + void insert(qsizetype i, QCborValue &&value); void prepend(const QCborValue &value) { insert(0, value); } + void prepend(QCborValue &&value) { insert(0, std::move(value)); } void append(const QCborValue &value) { insert(-1, value); } + void append(QCborValue &&value) { insert(-1, std::move(value)); } QCborValue extract(Iterator it); void removeAt(qsizetype i); QCborValue takeAt(qsizetype i) { Q_ASSERT(i < size()); return extract(begin() + i); } diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index 0631e8d7a2..7409bed4e9 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -1053,7 +1053,12 @@ QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, q return d; } -void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &value) +// Copies or moves \a value into element at position \a e. If \a disp is +// CopyContainer, then this function increases the reference count of the +// container, but otherwise leaves it unmodified. If \a disp is MoveContainer, +// then it transfers ownership (move semantics) and the caller must set +// value.container back to nullptr. +void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &value, ContainerDisposition disp) { if (value.n < 0) { // This QCborValue is an array, map, or tagged value (container points @@ -1062,14 +1067,18 @@ void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &valu // detect self-assignment if (Q_UNLIKELY(this == value.container)) { Q_ASSERT(ref.load() >= 2); + if (disp == MoveContainer) + ref.deref(); // not deref() because it can't drop to 0 QCborContainerPrivate *d = QCborContainerPrivate::clone(this); d->elements.detach(); + d->ref.store(1); e.container = d; } else { e.container = value.container; + if (disp == CopyContainer) + e.container->ref.ref(); } - e.container->ref.ref(); e.type = value.type(); e.flags = Element::IsContainer; } else { @@ -1079,6 +1088,9 @@ void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &valu // Copy string data, if any if (const ByteData *b = value.container->byteData(value.n)) e.value = addByteData(b->byte(), b->len); + + if (disp == MoveContainer) + value.container->deref(); } } @@ -1847,6 +1859,9 @@ QCborValue::QCborValue(QLatin1String s) } /*! + \fn QCborValue::QCborValue(const QCborArray &a) + \fn QCborValue::QCborValue(QCborArray &&a) + Creates a QCborValue with the array \a a. The array can later be retrieved using toArray(). @@ -1860,6 +1875,9 @@ QCborValue::QCborValue(const QCborArray &a) } /*! + \fn QCborValue::QCborValue(const QCborMap &m) + \fn QCborValue::QCborValue(QCborMap &&m) + Creates a QCborValue with the map \a m. The map can later be retrieved using toMap(). @@ -2526,16 +2544,20 @@ void QCborValueRef::toCbor(QCborStreamWriter &writer, QCborValue::EncodingOption concrete().toCbor(writer, opt); } -QCborValueRef &QCborValueRef::operator=(const QCborValue &other) +void QCborValueRef::assign(QCborValueRef that, const QCborValue &other) { - d->replaceAt(i, other); - return *this; + that.d->replaceAt(that.i, other); +} + +void QCborValueRef::assign(QCborValueRef that, QCborValue &&other) +{ + that.d->replaceAt(that.i, other, QCborContainerPrivate::MoveContainer); } -QCborValueRef &QCborValueRef::operator=(const QCborValueRef &other) +void QCborValueRef::assign(QCborValueRef that, const QCborValueRef other) { // ### optimize? - return *this = other.concrete(); + assign(that, other.concrete()); } QCborValue QCborValueRef::concrete(QCborValueRef self) Q_DECL_NOTHROW diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h index 717b123e68..b0282b0cd6 100644 --- a/src/corelib/serialization/qcborvalue.h +++ b/src/corelib/serialization/qcborvalue.h @@ -323,8 +323,14 @@ class Q_CORE_EXPORT QCborValueRef public: operator QCborValue() const { return concrete(); } - QCborValueRef &operator=(const QCborValue &other); - QCborValueRef &operator=(const QCborValueRef &other); + QCborValueRef(const QCborValueRef &) Q_DECL_NOTHROW = default; + QCborValueRef(QCborValueRef &&) Q_DECL_NOTHROW = default; + QCborValueRef &operator=(const QCborValue &other) + { assign(*this, other); return *this; } + QCborValueRef &operator=(QCborValue &&other) + { assign(*this, std::move(other)); other.container = nullptr; return *this; } + QCborValueRef &operator=(const QCborValueRef &other) + { assign(*this, other); return *this; } QCborValue::Type type() const { return concreteType(); } bool isInteger() const { return type() == QCborValue::Integer; } @@ -426,6 +432,9 @@ private: friend class QCborValueRefPtr; // static so we can pass this by value + static void assign(QCborValueRef that, const QCborValue &other); + static void assign(QCborValueRef that, QCborValue &&other); + static void assign(QCborValueRef that, const QCborValueRef other); static QCborValue concrete(QCborValueRef that) Q_DECL_NOTHROW; QCborValue concrete() const Q_DECL_NOTHROW { return concrete(*this); } diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h index eb6fe09147..f6c0cfae3d 100644 --- a/src/corelib/serialization/qcborvalue_p.h +++ b/src/corelib/serialization/qcborvalue_p.h @@ -187,18 +187,18 @@ public: return e.container; } - void replaceAt_complex(QtCbor::Element &e, const QCborValue &value); - void replaceAt_internal(QtCbor::Element &e, const QCborValue &value) + void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp); + void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp) { if (value.container) - return replaceAt_complex(e, value); + return replaceAt_complex(e, value, disp); e.value = value.value_helper(); e.type = value.type(); if (value.isContainer()) e.container = nullptr; } - void replaceAt(qsizetype idx, const QCborValue &value) + void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer) { QtCbor::Element &e = elements[idx]; if (e.flags & QtCbor::Element::IsContainer) { @@ -208,11 +208,11 @@ public: } else if (e.flags & QtCbor::Element::HasByteData) { usedData -= byteData(idx)->len + sizeof(QtCbor::ByteData); } - replaceAt_internal(e, value); + replaceAt_internal(e, value, disp); } - void insertAt(qsizetype idx, const QCborValue &value) + void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer) { - replaceAt_internal(*elements.insert(elements.begin() + idx, {}), value); + replaceAt_internal(*elements.insert(elements.begin() + idx, {}), value, disp); } void append(QtCbor::Undefined) @@ -277,6 +277,11 @@ public: return data->toUtf8String(); } + static void resetValue(QCborValue &v) + { + v.container = nullptr; + } + static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr, ContainerDisposition disp = CopyContainer) { |