summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qvarlengtharray.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qvarlengtharray.h')
-rw-r--r--src/corelib/tools/qvarlengtharray.h101
1 files changed, 39 insertions, 62 deletions
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 6be695e317..f0e4342e06 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -49,6 +49,7 @@
#include <algorithm>
#include <initializer_list>
#include <iterator>
+#include <memory>
#include <new>
#include <string.h>
#include <stdlib.h>
@@ -152,30 +153,18 @@ public:
if (s == a) { // i.e. s != 0
T copy(t);
realloc(s, s<<1);
- const int idx = s++;
- if (QTypeInfo<T>::isComplex) {
- new (ptr + idx) T(std::move(copy));
- } else {
- ptr[idx] = std::move(copy);
- }
+ new (end()) T(std::move(copy));
} else {
- const int idx = s++;
- if (QTypeInfo<T>::isComplex) {
- new (ptr + idx) T(t);
- } else {
- ptr[idx] = t;
- }
+ new (end()) T(t);
}
+ ++s;
}
void append(T &&t) {
if (s == a)
realloc(s, s << 1);
- const int idx = s++;
- if (QTypeInfo<T>::isComplex)
- new (ptr + idx) T(std::move(t));
- else
- ptr[idx] = std::move(t);
+ new (end()) T(std::move(t));
+ ++s;
}
void append(const T *buf, int size);
@@ -249,6 +238,20 @@ public:
private:
void realloc(int size, int alloc);
+ void resize_impl(int newSize, const T &t)
+ {
+ const auto increment = newSize - size();
+ if (increment > 0 && QtPrivate::q_points_into_range(&t, cbegin(), cend())) {
+ resize_impl(newSize, T(t));
+ return;
+ }
+ realloc(qMin(size(), newSize), qMax(newSize, capacity()));
+
+ if (increment > 0)
+ std::uninitialized_fill_n(end(), increment, t);
+ s = newSize;
+ }
+
int a; // capacity
int s; // size
T *ptr; // data
@@ -487,57 +490,25 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
- int offset = int(before - ptr);
- reserve(s + 1);
- if (!QTypeInfo<T>::isRelocatable) {
- T *b = ptr + offset;
- T *i = ptr + s;
- T *j = i + 1;
- // The new end-element needs to be constructed, the rest must be move assigned
- if (i != b) {
- new (--j) T(std::move(*--i));
- while (i != b)
- *--j = std::move(*--i);
- *b = std::move(t);
- } else {
- new (b) T(std::move(t));
- }
- } else {
- T *b = ptr + offset;
- memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (s - offset) * sizeof(T));
- new (b) T(std::move(t));
- }
- s += 1;
- return ptr + offset;
+ const int offset = int(before - ptr);
+ append(std::move(t));
+ const auto b = begin() + offset;
+ const auto e = end();
+ QtPrivate::q_rotate(b, e - 1, e);
+ return b;
}
template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, size_type n, const T &t)
+Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, int n, const T &t)
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
- int offset = int(before - ptr);
- if (n != 0) {
- resize(s + n);
- const T copy(t);
- if (!QTypeInfoQuery<T>::isRelocatable) {
- T *b = ptr + offset;
- T *j = ptr + s;
- T *i = j - n;
- while (i != b)
- *--j = *--i;
- i = b + n;
- while (i != b)
- *--i = copy;
- } else {
- T *b = ptr + offset;
- T *i = b + n;
- memmove(static_cast<void *>(i), static_cast<const void *>(b), (s - offset - n) * sizeof(T));
- while (i != b)
- new (--i) T(copy);
- }
- }
- return ptr + offset;
+ const int offset = int(before - cbegin());
+ resize_impl(size() + n, t);
+ const auto b = begin() + offset;
+ const auto e = end();
+ QtPrivate::q_rotate(b, e - n, e);
+ return b;
}
template <class T, int Prealloc>
@@ -549,6 +520,12 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
int f = int(abegin - ptr);
int l = int(aend - ptr);
int n = l - f;
+
+ if (n == 0) // avoid UB in std::copy() below
+ return data() + f;
+
+ Q_ASSERT(n > 0); // aend must be reachable from abegin
+
if (QTypeInfo<T>::isComplex) {
std::copy(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f));
T *i = ptr + s;