summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2018-05-31 20:13:05 -0700
committerThiago Macieira <thiago.macieira@intel.com>2018-07-05 14:56:15 +0000
commit514972544a34aca0fd679b3a78521a0a1558d4e0 (patch)
tree8dbec4023d90d4022256071fadad39d67723c3c4 /src/corelib/serialization
parentfddf09363e1bbc6f6549eaf28def7699b2d87341 (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.cpp15
-rw-r--r--src/corelib/serialization/qcborarray.h3
-rw-r--r--src/corelib/serialization/qcborvalue.cpp36
-rw-r--r--src/corelib/serialization/qcborvalue.h13
-rw-r--r--src/corelib/serialization/qcborvalue_p.h19
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)
{