summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2020-06-04 21:56:09 +0200
committerMarc Mutz <marc.mutz@kdab.com>2020-06-22 17:24:07 +0000
commitffb73175e6c5b35e6367c88479cc0bf160482016 (patch)
tree1dc68ee77b96196a4731f38000150e285bb7de5d /src
parent670c5bd140b86a8b589595cb6cae62ae4e24cb2d (diff)
QVarLengthArray: add missing move special member functions
A QVLA is copyable, so it should be movable, too. Added a helper function a la P1144's uninitialized_relocate_n to deal with the QTypeInfoQuery stuff. This way, the code is re-usable everywhere it's needed. The same cannot be said for QArrayDataOps, which only a parent can love... [ChangeLog][QtCore][QVarLengthArray] Added missing move constructor and move-assignment operator. Task-number: QTBUG-39111 Change-Id: If0dc2aa78eb29062d73dcd3dc4647ba345ae39e6 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/tools/qcontainertools_impl.h21
-rw-r--r--src/corelib/tools/qvarlengtharray.h41
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc11
3 files changed, 73 insertions, 0 deletions
diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h
index 3a0c4381f1..b43c3bb1c4 100644
--- a/src/corelib/tools/qcontainertools_impl.h
+++ b/src/corelib/tools/qcontainertools_impl.h
@@ -47,12 +47,33 @@
#define QCONTAINERTOOLS_IMPL_H
#include <QtCore/qglobal.h>
+#include <QtCore/qtypeinfo.h>
+
#include <iterator>
+#include <memory>
QT_BEGIN_NAMESPACE
namespace QtPrivate
{
+
+template <typename T, typename N>
+void q_uninitialized_relocate_n(T* first, N n, T* out)
+{
+ if constexpr (QTypeInfoQuery<T>::isRelocatable) {
+ if (n != N(0)) { // even if N == 0, out == nullptr or first == nullptr are UB for memmove()
+ memmove(static_cast<void*>(out),
+ static_cast<const void*>(first),
+ n * sizeof(T));
+ }
+ } else {
+ std::uninitialized_move_n(first, n, out);
+ if constexpr (QTypeInfoQuery<T>::isComplex)
+ std::destroy_n(first, n);
+ }
+}
+
+
template <typename Iterator>
using IfIsInputIterator = typename std::enable_if<
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>::value,
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index f90e455fe4..cea0e14d41 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -71,6 +71,26 @@ public:
append(other.constData(), other.size());
}
+ QVarLengthArray(QVarLengthArray &&other)
+ noexcept(std::is_nothrow_move_constructible_v<T>)
+ : a{other.a},
+ s{other.s},
+ ptr{other.ptr}
+ {
+ const auto otherInlineStorage = reinterpret_cast<T*>(other.array);
+ if (ptr == otherInlineStorage) {
+ // inline buffer - move into our inline buffer:
+ ptr = reinterpret_cast<T*>(array);
+ QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, s, ptr);
+ } else {
+ // heap buffer - we just stole the memory
+ }
+ // reset other to internal storage:
+ other.a = Prealloc;
+ other.s = 0;
+ other.ptr = otherInlineStorage;
+ }
+
QVarLengthArray(std::initializer_list<T> args)
: QVarLengthArray(args.begin(), args.end())
{
@@ -102,6 +122,27 @@ public:
return *this;
}
+ QVarLengthArray &operator=(QVarLengthArray &&other)
+ noexcept(std::is_nothrow_move_constructible_v<T>)
+ {
+ // we're only required to be self-move-assignment-safe
+ // when we're in the moved-from state (Hinnant criterion)
+ // the moved-from state is the empty state, so we're good with the clear() here:
+ clear();
+ Q_ASSERT(capacity() >= Prealloc);
+ const auto otherInlineStorage = reinterpret_cast<T*>(other.array);
+ if (other.ptr != otherInlineStorage) {
+ // heap storage: steal the external buffer, reset other to otherInlineStorage
+ a = std::exchange(other.a, Prealloc);
+ ptr = std::exchange(other.ptr, otherInlineStorage);
+ } else {
+ // inline storage: move into our storage (doesn't matter whether inline or external)
+ QtPrivate::q_uninitialized_relocate_n(other.ptr, other.s, ptr);
+ }
+ s = std::exchange(other.s, 0);
+ return *this;
+ }
+
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
{
resize(qsizetype(list.size()));
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index e43d6f152a..6371419ae5 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -404,6 +404,12 @@
Assigns \a other to this array and returns a reference to this array.
*/
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(QVarLengthArray<T, Prealloc> &&other)
+ Move-assigns \a other to this array and returns a reference to this array.
+ After the move, \a other is empty.
+ \since 6.0
+ */
+
/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(std::initializer_list<T> list)
\since 5.5
@@ -417,6 +423,11 @@
Constructs a copy of \a other.
*/
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(QVarLengthArray<T, Prealloc> &&other)
+ Move-constructs this variable-length array from \a other. After the move, \a other is empty.
+ \since 6.0
+ */
+
/*! \fn template<class T, qsizetype Prealloc> const T &QVarLengthArray<T, Prealloc>::at(qsizetype i) const
Returns a reference to the item at index position \a i.