summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qvector.cpp23
-rw-r--r--src/corelib/tools/qarraydataops.h58
-rw-r--r--src/corelib/tools/qvector.h64
-rw-r--r--src/corelib/tools/qvector.qdoc53
4 files changed, 147 insertions, 51 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qvector.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qvector.cpp
index a05233049f..76a8d68f64 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qvector.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qvector.cpp
@@ -115,6 +115,29 @@ vector.append(std::move(three));
//! [move-append]
+//! [emplace]
+QVector<QString> vector{"a", "ccc"};
+vector.emplace(1, 2, 'b');
+// vector: ["a", "bb", "ccc"]
+//! [emplace]
+
+
+//! [emplace-back]
+QVector<QString> vector{"one", "two"};
+vector.emplaceBack(3, 'a');
+qDebug() << vector;
+// vector: ["one", "two", "aaa"]
+//! [emplace-back]
+
+
+//! [emplace-back-ref]
+QVector<QString> vector;
+auto &ref = vector.emplaceBack();
+ref = "one";
+// vector: ["one"]
+//! [emplace-back-ref]
+
+
//! [8]
QVector<QString> vector;
vector.prepend("one");
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 0d2be5d51c..1d74f49993 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -117,6 +117,9 @@ struct QPodArrayOps
this->size += int(n);
}
+ template <typename ...Args>
+ void emplaceBack(Args&&... args) { this->emplace(this->end(), T(std::forward<Args>(args)...)); }
+
void truncate(size_t newSize)
{
Q_ASSERT(this->isMutable());
@@ -163,16 +166,28 @@ struct QPodArrayOps
*where++ = t;
}
- void insert(T *where, T &&t)
+ template <typename ...Args>
+ void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); }
+
+ template <typename ...Args>
+ void emplace(T *where, Args&&... args)
{
Q_ASSERT(!this->isShared());
Q_ASSERT(where >= this->begin() && where <= this->end());
Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
- ::memmove(static_cast<void *>(where + 1), static_cast<void *>(where),
- (static_cast<const T*>(this->end()) - where) * sizeof(T));
- this->size += 1;
- new (where) T(std::move(t));
+ if (where == this->end()) {
+ new (this->end()) T(std::forward<Args>(args)...);
+ } else {
+ // Preserve the value, because it might be a reference to some part of the moved chunk
+ T t(std::forward<Args>(args)...);
+
+ ::memmove(static_cast<void *>(where + 1), static_cast<void *>(where),
+ (static_cast<const T*>(this->end()) - where) * sizeof(T));
+ *where = t;
+ }
+
+ ++this->size;
}
@@ -289,6 +304,12 @@ struct QGenericArrayOps
}
}
+ template <typename ...Args>
+ void emplaceBack(Args&&... args)
+ {
+ this->emplace(this->end(), std::forward<Args>(args)...);
+ }
+
void truncate(size_t newSize)
{
Q_ASSERT(this->isMutable());
@@ -444,31 +465,20 @@ struct QGenericArrayOps
}
}
- void insert(T *where, T &&t)
+ template <typename ...Args>
+ void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); }
+
+ template <typename iterator, typename ...Args>
+ void emplace(iterator where, Args&&... args)
{
Q_ASSERT(!this->isShared());
Q_ASSERT(where >= this->begin() && where <= this->end());
Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
- // Array may be truncated at where in case of exceptions
- T *const end = this->end();
-
- if (where != end) {
- // Move elements in array
- T *readIter = end - 1;
- T *writeIter = end;
- new (writeIter) T(std::move(*readIter));
- while (readIter > where) {
- --readIter;
- --writeIter;
- *writeIter = std::move(*readIter);
- }
- *where = std::move(t);
- } else {
- new (where) T(std::move(t));
- }
-
+ createInPlace(this->end(), std::forward<Args>(args)...);
++this->size;
+
+ std::rotate(where, this->end() - 1, this->end());
}
void erase(T *b, T *e)
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 3e98de41f4..2cfcb2e5dc 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -242,10 +242,14 @@ public:
void append(const_reference t)
{ append(const_iterator(std::addressof(t)), const_iterator(std::addressof(t)) + 1); }
void append(const_iterator i1, const_iterator i2);
- void append(value_type &&t);
+ void append(rvalue_ref t) { emplaceBack(std::move(t)); }
void append(const QVector<T> &l) { append(l.constBegin(), l.constEnd()); }
void prepend(rvalue_ref t);
void prepend(const T &t);
+
+ template <typename ...Args>
+ reference emplaceBack(Args&&... args) { return *emplace(count(), std::forward<Args>(args)...); }
+
iterator insert(int i, parameter_type t)
{ return insert(i, 1, t); }
iterator insert(int i, int n, parameter_type t);
@@ -264,7 +268,17 @@ public:
Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
return insert(std::distance(constBegin(), before), std::move(t));
}
- iterator insert(int i, rvalue_ref t);
+ iterator insert(int i, rvalue_ref t) { return emplace(i, std::move(t)); }
+
+ template <typename ...Args>
+ iterator emplace(const_iterator before, Args&&... args)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QVector::emplace", "The specified iterator argument 'before' is invalid");
+ return emplace(std::distance(constBegin(), before), std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ iterator emplace(int i, Args&&... args);
#if 0
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );
@@ -388,6 +402,10 @@ public:
inline void push_front(const T &t) { prepend(t); }
void pop_back() { removeLast(); }
void pop_front() { removeFirst(); }
+
+ template <typename ...Args>
+ reference emplace_back(Args&&... args) { return emplaceBack(std::forward<Args>(args)...); }
+
inline bool empty() const
{ return d->size == 0; }
inline reference front() { return first(); }
@@ -538,27 +556,6 @@ inline void QVector<T>::append(const_iterator i1, const_iterator i2)
}
template <typename T>
-inline void QVector<T>::append(value_type &&t)
-{
- const size_t newSize = size() + 1;
- const bool isTooSmall = newSize > d->allocatedCapacity();
- const bool isOverlapping = std::addressof(*d->begin()) <= std::addressof(t)
- && std::addressof(t) < std::addressof(*d->end());
- if (isTooSmall || d->needsDetach() || Q_UNLIKELY(isOverlapping)) {
- typename Data::ArrayOptions flags = d->detachFlags();
- if (isTooSmall)
- flags |= Data::GrowsForward;
- DataPointer detached(Data::allocate(d->detachCapacity(newSize), flags));
- detached->copyAppend(constBegin(), constEnd());
- detached->moveAppend(std::addressof(t), std::addressof(t) + 1);
- d.swap(detached);
- } else {
- // we're detached and we can just move data around
- d->moveAppend(std::addressof(t), std::addressof(t) + 1);
- }
-}
-
-template <typename T>
inline typename QVector<T>::iterator
QVector<T>::insert(int i, int n, parameter_type t)
{
@@ -592,10 +589,11 @@ QVector<T>::insert(int i, int n, parameter_type t)
}
template <typename T>
+template <typename ...Args>
typename QVector<T>::iterator
-QVector<T>::insert(int i, rvalue_ref t)
+QVector<T>::emplace(int i, Args&&... args)
{
- Q_ASSERT_X(size_t(i) <= size_t(d->size), "QVector<T>::insert", "index out of range");
+ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
const size_t newSize = size() + 1;
if (d->needsDetach() || newSize > d->allocatedCapacity()) {
@@ -605,12 +603,24 @@ QVector<T>::insert(int i, rvalue_ref t)
DataPointer detached(Data::allocate(d->detachCapacity(newSize), flags));
const_iterator where = constBegin() + i;
+
+ // First, create an element to handle cases, when a user moves
+ // the element from a container to the same container
+ detached->createInPlace(detached.begin() + i, std::forward<Args>(args)...);
+
+ // Then, put the first part of the elements to the new location
detached->copyAppend(constBegin(), where);
- detached->moveAppend(std::addressof(t), std::addressof(t) + 1);
+
+ // After that, increase the actual size, because we created
+ // one extra element
+ ++detached.size;
+
+ // Finally, put the rest of the elements to the new location
detached->copyAppend(where, constEnd());
+
d.swap(detached);
} else {
- d->insert(d.begin() + i, std::move(t));
+ d->emplace(d.begin() + i, std::forward<Args>(args)...);
}
return d.begin() + i;
}
diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc
index 116d962411..a5ea4073f8 100644
--- a/src/corelib/tools/qvector.qdoc
+++ b/src/corelib/tools/qvector.qdoc
@@ -646,6 +646,28 @@
\sa append(), insert()
*/
+/*!
+ \fn template <typename T> template <typename ...Args> T &QVector<T>::emplaceBack(Args&&... args)
+ \fn template <typename T> template <typename ...Args> T &QVector<T>::emplace_back(Args&&... args)
+
+ Adds a new element to the end for the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
+
+ Returns a reference to the new element.
+
+ Example:
+ \snippet code/src_corelib_tools_qvector.cpp emplace-back
+
+ It is also possible to access a newly created object by using
+ returned reference:
+ \snippet code/src_corelib_tools_qvector.cpp emplace-back-ref
+
+ This is the same as vector.emplace(vector.size(), \a args).
+
+ \sa emplace
+*/
+
/*! \fn template <typename T> void QVector<T>::insert(int i, const T &value)
\fn template <typename T> void QVector<T>::insert(int i, T &&value)
@@ -693,6 +715,26 @@
first of the inserted items.
*/
+/*!
+ \fn template <typename T> template <typename ...Args> QVector<T>::iterator QVector<T>::emplace(int i, Args&&... args)
+
+ Extends the container by inserting a new element at position \a i.
+ This new element is constructed in-place using \a args as the
+ arguments for its construction.
+
+ Returns an iterator to the new element.
+
+ Example:
+ \snippet code/src_corelib_tools_qvector.cpp emplace
+
+ \note It is garanteed that the element will be created in place
+ at the beginning, but after that it might be copied or
+ moved to the right position.
+
+ \sa emplaceBack
+*/
+
+
/*! \fn template <typename T> void QVector<T>::replace(int i, const T &value)
Replaces the item at index position \a i with \a value.
@@ -838,6 +880,17 @@
\sa takeFirst(), removeLast()
*/
+/*!
+ \fn template <typename T> template <typename ...Args> QVector<T>::iterator QVector<T>::emplace(QVector<T>::iterator before, Args&&... args)
+
+ \overload
+
+ Creates a new element in front of the item pointed to by the
+ iterator \a before. This new element is constructed in-place
+ using \a args as the arguments for its construction.
+
+ Returns an iterator to the new element.
+*/
/*! \fn template <typename T> QVector<T> &QVector<T>::fill(const T &value, int size = -1)