summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qarraydataops.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qarraydataops.h')
-rw-r--r--src/corelib/tools/qarraydataops.h428
1 files changed, 247 insertions, 181 deletions
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 0c7703c588..c3e9821e81 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -1,50 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QARRAYDATAOPS_H
#define QARRAYDATAOPS_H
#include <QtCore/qarraydata.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qnamespace.h>
-#include <algorithm>
+#include <memory>
#include <new>
#include <string.h>
#include <utility>
@@ -58,11 +23,6 @@ template <class T> struct QArrayDataPointer;
namespace QtPrivate {
-QT_WARNING_PUSH
-#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
-QT_WARNING_DISABLE_GCC("-Wstringop-overflow")
-#endif
-
template <class T>
struct QPodArrayOps
: public QArrayDataPointer<T>
@@ -76,6 +36,8 @@ protected:
public:
typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
+ using QArrayDataPointer<T>::QArrayDataPointer;
+
void appendInitialize(qsizetype newSize) noexcept
{
Q_ASSERT(this->isMutable());
@@ -84,7 +46,7 @@ public:
Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
T *where = this->end();
- this->size = qsizetype(newSize);
+ this->size = newSize;
const T *e = this->end();
while (where != e)
*where++ = T();
@@ -150,8 +112,7 @@ public:
if (where < this->size)
::memmove(static_cast<void *>(insertionPoint + n), static_cast<void *>(insertionPoint), (this->size - where) * sizeof(T));
} else {
- if (where > 0)
- ::memmove(static_cast<void *>(this->ptr - n), static_cast<const void *>(this->ptr), where * sizeof(T));
+ Q_ASSERT(where == 0);
this->ptr -= n;
insertionPoint -= n;
}
@@ -162,10 +123,11 @@ public:
void insert(qsizetype i, const T *data, qsizetype n)
{
typename Data::GrowthPosition pos = Data::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
+ if (this->size != 0 && i == 0)
pos = Data::GrowsAtBeginning;
+
DataPointer oldData;
- this->detachAndGrow(pos, n, &oldData);
+ this->detachAndGrow(pos, n, &data, &oldData);
Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
(pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
@@ -178,9 +140,10 @@ public:
T copy(t);
typename Data::GrowthPosition pos = Data::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
+ if (this->size != 0 && i == 0)
pos = Data::GrowsAtBeginning;
- this->detachAndGrow(pos, n);
+
+ this->detachAndGrow(pos, n, nullptr, nullptr);
Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
(pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
@@ -208,12 +171,10 @@ public:
}
T tmp(std::forward<Args>(args)...);
typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
+ if (this->size != 0 && i == 0)
pos = QArrayData::GrowsAtBeginning;
- if (detach ||
- (pos == QArrayData::GrowsAtBeginning && !this->freeSpaceAtBegin()) ||
- (pos == QArrayData::GrowsAtEnd && !this->freeSpaceAtEnd()))
- this->reallocateAndGrow(pos, 1);
+
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
T *where = createHole(pos, i, 1);
new (where) T(std::move(tmp));
@@ -231,10 +192,12 @@ public:
// are invalidated. However, erasing from the beginning effectively
// means that all iterators are invalidated. We can use this freedom to
// erase by moving towards the end.
- if (b == this->begin())
+ if (b == this->begin() && e != this->end()) {
this->ptr = e;
- else if (e != this->end())
- ::memmove(static_cast<void *>(b), static_cast<void *>(e), (static_cast<T *>(this->end()) - e) * sizeof(T));
+ } else if (e != this->end()) {
+ ::memmove(static_cast<void *>(b), static_cast<void *>(e),
+ (static_cast<T *>(this->end()) - e) * sizeof(T));
+ }
this->size -= n;
}
@@ -253,6 +216,51 @@ public:
--this->size;
}
+ template <typename Predicate>
+ qsizetype eraseIf(Predicate pred)
+ {
+ qsizetype result = 0;
+ if (this->size == 0)
+ return result;
+
+ if (!this->needsDetach()) {
+ auto end = this->end();
+ auto it = std::remove_if(this->begin(), end, pred);
+ if (it != end) {
+ result = std::distance(it, end);
+ erase(it, result);
+ }
+ } else {
+ const auto begin = this->begin();
+ const auto end = this->end();
+ auto it = std::find_if(begin, end, pred);
+ if (it == end)
+ return result;
+
+ QPodArrayOps<T> other(this->size);
+ Q_CHECK_PTR(other.data());
+ auto dest = other.begin();
+ // std::uninitialized_copy will fallback to ::memcpy/memmove()
+ dest = std::uninitialized_copy(begin, it, dest);
+ dest = q_uninitialized_remove_copy_if(std::next(it), end, dest, pred);
+ other.size = std::distance(other.data(), dest);
+ result = this->size - other.size;
+ this->swap(other);
+ }
+ return result;
+ }
+
+ struct Span { T *begin; T *end; };
+
+ void copyRanges(std::initializer_list<Span> ranges)
+ {
+ auto it = this->begin();
+ std::for_each(ranges.begin(), ranges.end(), [&it](const auto &span) {
+ it = std::copy(span.begin, span.end, it);
+ });
+ this->size = std::distance(this->begin(), it);
+ }
+
void assign(T *b, T *e, parameter_type t) noexcept
{
Q_ASSERT(b <= e);
@@ -292,7 +300,6 @@ public:
this->ptr = pair.second;
}
};
-QT_WARNING_POP
template <class T>
struct QGenericArrayOps
@@ -394,24 +401,18 @@ public:
struct Inserter
{
QArrayDataPointer<T> *data;
- qsizetype increment = 1;
T *begin;
qsizetype size;
qsizetype sourceCopyConstruct = 0, nSource = 0, move = 0, sourceCopyAssign = 0;
T *end = nullptr, *last = nullptr, *where = nullptr;
- Inserter(QArrayDataPointer<T> *d, QArrayData::GrowthPosition pos)
- : data(d), increment(pos == QArrayData::GrowsAtBeginning ? -1 : 1)
+ Inserter(QArrayDataPointer<T> *d) : data(d)
{
begin = d->ptr;
size = d->size;
- if (increment < 0)
- begin += size - 1;
}
~Inserter() {
- if (increment < 0)
- begin -= size - 1;
data->ptr = begin;
data->size = size;
}
@@ -419,34 +420,18 @@ public:
void setup(qsizetype pos, qsizetype n)
{
-
- if (increment > 0) {
- end = begin + size;
- last = end - 1;
- where = begin + pos;
- qsizetype dist = size - pos;
- sourceCopyConstruct = 0;
- nSource = n;
- move = n - dist; // smaller 0
- sourceCopyAssign = n;
- if (n > dist) {
- sourceCopyConstruct = n - dist;
- move = 0;
- sourceCopyAssign -= sourceCopyConstruct;
- }
- } else {
- end = begin - size;
- last = end + 1;
- where = end + pos;
- sourceCopyConstruct = 0;
- nSource = -n;
- move = pos - n; // larger 0
- sourceCopyAssign = -n;
- if (n > pos) {
- sourceCopyConstruct = pos - n;
- move = 0;
- sourceCopyAssign -= sourceCopyConstruct;
- }
+ end = begin + size;
+ last = end - 1;
+ where = begin + pos;
+ qsizetype dist = size - pos;
+ sourceCopyConstruct = 0;
+ nSource = n;
+ move = n - dist; // smaller 0
+ sourceCopyAssign = n;
+ if (n > dist) {
+ sourceCopyConstruct = n - dist;
+ move = 0;
+ sourceCopyAssign -= sourceCopyConstruct;
}
}
@@ -456,12 +441,10 @@ public:
Q_UNUSED(oldSize);
setup(pos, n);
- if (increment < 0)
- source += n - 1;
// first create new elements at the end, by copying from elements
// to be inserted (if they extend past the current end of the array)
- for (qsizetype i = 0; i != sourceCopyConstruct; i += increment) {
+ for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
new (end + i) T(source[nSource - sourceCopyConstruct + i]);
++size;
}
@@ -469,7 +452,7 @@ public:
// now move construct new elements at the end from existing elements inside
// the array.
- for (qsizetype i = sourceCopyConstruct; i != nSource; i += increment) {
+ for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
new (end + i) T(std::move(*(end + i - nSource)));
++size;
}
@@ -477,24 +460,24 @@ public:
Q_ASSERT(size == oldSize + n);
// now move assign existing elements towards the end
- for (qsizetype i = 0; i != move; i -= increment)
+ for (qsizetype i = 0; i != move; --i)
last[i] = std::move(last[i - nSource]);
// finally copy the remaining elements from source over
- for (qsizetype i = 0; i != sourceCopyAssign; i += increment)
+ for (qsizetype i = 0; i != sourceCopyAssign; ++i)
where[i] = source[i];
}
void insert(qsizetype pos, const T &t, qsizetype n)
{
- qsizetype oldSize = size;
+ const qsizetype oldSize = size;
Q_UNUSED(oldSize);
setup(pos, n);
// first create new elements at the end, by copying from elements
// to be inserted (if they extend past the current end of the array)
- for (qsizetype i = 0; i != sourceCopyConstruct; i += increment) {
+ for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
new (end + i) T(t);
++size;
}
@@ -502,7 +485,7 @@ public:
// now move construct new elements at the end from existing elements inside
// the array.
- for (qsizetype i = sourceCopyConstruct; i != nSource; i += increment) {
+ for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
new (end + i) T(std::move(*(end + i - nSource)));
++size;
}
@@ -510,11 +493,11 @@ public:
Q_ASSERT(size == oldSize + n);
// now move assign existing elements towards the end
- for (qsizetype i = 0; i != move; i -= increment)
+ for (qsizetype i = 0; i != move; --i)
last[i] = std::move(last[i - nSource]);
// finally copy the remaining elements from source over
- for (qsizetype i = 0; i != sourceCopyAssign; i += increment)
+ for (qsizetype i = 0; i != sourceCopyAssign; ++i)
where[i] = t;
}
@@ -523,18 +506,18 @@ public:
setup(pos, 1);
if (sourceCopyConstruct) {
- Q_ASSERT(sourceCopyConstruct == increment);
+ Q_ASSERT(sourceCopyConstruct == 1);
new (end) T(std::move(t));
++size;
} else {
// create a new element at the end by move constructing one existing element
// inside the array.
- new (end) T(std::move(*(end - increment)));
+ new (end) T(std::move(*(end - 1)));
++size;
// now move assign existing elements towards the end
- for (qsizetype i = 0; i != move; i -= increment)
- last[i] = std::move(last[i - increment]);
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - 1]);
// and move the new item into place
*where = std::move(t);
@@ -544,29 +527,50 @@ public:
void insert(qsizetype i, const T *data, qsizetype n)
{
- typename Data::GrowthPosition pos = Data::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
- pos = Data::GrowsAtBeginning;
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
DataPointer oldData;
- this->detachAndGrow(pos, n, &oldData);
+ this->detachAndGrow(pos, n, &data, &oldData);
Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
(pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- Inserter(this, pos).insert(i, data, n);
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n) {
+ --n;
+ new (this->begin() - 1) T(data[n]);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, data, n);
+ }
}
void insert(qsizetype i, qsizetype n, parameter_type t)
{
T copy(t);
- typename Data::GrowthPosition pos = Data::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
- pos = Data::GrowsAtBeginning;
- this->detachAndGrow(pos, n);
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ this->detachAndGrow(pos, n, nullptr, nullptr);
Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
(pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- Inserter(this, pos).insert(i, copy, n);
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n--) {
+ new (this->begin() - 1) T(copy);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, copy, n);
+ }
}
template<typename... Args>
@@ -587,15 +591,19 @@ public:
}
}
T tmp(std::forward<Args>(args)...);
- typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
- pos = QArrayData::GrowsAtBeginning;
- if (detach ||
- (pos == QArrayData::GrowsAtBeginning && !this->freeSpaceAtBegin()) ||
- (pos == QArrayData::GrowsAtEnd && !this->freeSpaceAtEnd()))
- this->reallocateAndGrow(pos, 1);
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
- Inserter(this, pos).insertOne(i, std::move(tmp));
+ if (growsAtBegin) {
+ Q_ASSERT(this->freeSpaceAtBegin());
+ new (this->begin() - 1) T(std::move(tmp));
+ --this->ptr;
+ ++this->size;
+ } else {
+ Inserter(this).insertOne(i, std::move(tmp));
+ }
}
void erase(T *b, qsizetype n)
@@ -610,7 +618,7 @@ public:
// are invalidated. However, erasing from the beginning effectively
// means that all iterators are invalidated. We can use this freedom to
// erase by moving towards the end.
- if (b == this->begin()) {
+ if (b == this->begin() && e != this->end()) {
this->ptr = e;
} else {
const T *const end = this->end();
@@ -694,12 +702,7 @@ public:
qsizetype nInserts = 0;
qsizetype bytes;
- qsizetype increment = 1;
-
- Inserter(QArrayDataPointer<T> *d, QArrayData::GrowthPosition pos)
- : data(d), increment(pos == QArrayData::GrowsAtBeginning ? -1 : 1)
- {
- }
+ Inserter(QArrayDataPointer<T> *d) : data(d) { }
~Inserter() {
if constexpr (!std::is_nothrow_copy_constructible_v<T>) {
if (displaceFrom != displaceTo) {
@@ -707,25 +710,17 @@ public:
nInserts -= qAbs(displaceFrom - displaceTo);
}
}
- if (increment < 0)
- data->ptr -= nInserts;
data->size += nInserts;
}
+ Q_DISABLE_COPY(Inserter)
T *displace(qsizetype pos, qsizetype n)
{
nInserts = n;
T *insertionPoint = data->ptr + pos;
- if (increment > 0) {
- displaceFrom = data->ptr + pos;
- displaceTo = displaceFrom + n;
- bytes = data->size - pos;
- } else {
- displaceFrom = data->ptr;
- displaceTo = displaceFrom - n;
- --insertionPoint;
- bytes = pos;
- }
+ displaceFrom = data->ptr + pos;
+ displaceTo = displaceFrom + n;
+ bytes = data->size - pos;
bytes *= sizeof(T);
::memmove(static_cast<void *>(displaceTo), static_cast<void *>(displaceFrom), bytes);
return insertionPoint;
@@ -735,14 +730,11 @@ public:
{
T *where = displace(pos, n);
- if (increment < 0)
- source += n - 1;
-
while (n--) {
new (where) T(*source);
- where += increment;
- source += increment;
- displaceFrom += increment;
+ ++where;
+ ++source;
+ ++displaceFrom;
}
}
@@ -752,8 +744,8 @@ public:
while (n--) {
new (where) T(t);
- where += increment;
- displaceFrom += increment;
+ ++where;
+ ++displaceFrom;
}
}
@@ -761,7 +753,7 @@ public:
{
T *where = displace(pos, 1);
new (where) T(std::move(t));
- displaceFrom += increment;
+ ++displaceFrom;
Q_ASSERT(displaceFrom == displaceTo);
}
@@ -770,29 +762,50 @@ public:
void insert(qsizetype i, const T *data, qsizetype n)
{
- typename Data::GrowthPosition pos = Data::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
- pos = Data::GrowsAtBeginning;
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
DataPointer oldData;
- this->detachAndGrow(pos, n, &oldData);
+ this->detachAndGrow(pos, n, &data, &oldData);
Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
(pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- Inserter(this, pos).insert(i, data, n);
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n) {
+ --n;
+ new (this->begin() - 1) T(data[n]);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, data, n);
+ }
}
void insert(qsizetype i, qsizetype n, parameter_type t)
{
T copy(t);
- typename Data::GrowthPosition pos = Data::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
- pos = Data::GrowsAtBeginning;
- this->detachAndGrow(pos, n);
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ this->detachAndGrow(pos, n, nullptr, nullptr);
Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
(pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- Inserter(this, pos).insert(i, copy, n);
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n--) {
+ new (this->begin() - 1) T(copy);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, copy, n);
+ }
}
template<typename... Args>
@@ -813,15 +826,18 @@ public:
}
}
T tmp(std::forward<Args>(args)...);
- typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
- if (this->size != 0 && i <= (this->size >> 1))
- pos = QArrayData::GrowsAtBeginning;
- if (detach ||
- (pos == QArrayData::GrowsAtBeginning && !this->freeSpaceAtBegin()) ||
- (pos == QArrayData::GrowsAtEnd && !this->freeSpaceAtEnd()))
- this->reallocateAndGrow(pos, 1);
-
- Inserter(this, pos).insertOne(i, std::move(tmp));
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
+ if (growsAtBegin) {
+ Q_ASSERT(this->freeSpaceAtBegin());
+ new (this->begin() - 1) T(std::move(tmp));
+ --this->ptr;
+ ++this->size;
+ } else {
+ Inserter(this).insertOne(i, std::move(tmp));
+ }
}
void erase(T *b, qsizetype n)
@@ -839,7 +855,7 @@ public:
// erase by moving towards the end.
std::destroy(b, e);
- if (b == this->begin()) {
+ if (b == this->begin() && e != this->end()) {
this->ptr = e;
} else if (e != this->end()) {
memmove(static_cast<void *>(b), static_cast<const void *>(e), (static_cast<const T *>(this->end()) - e)*sizeof(T));
@@ -907,12 +923,62 @@ public:
Q_ASSERT(distance >= 0 && distance <= this->allocatedCapacity() - this->size);
Q_UNUSED(distance);
- T *iter = this->end();
- for (; b != e; ++iter, ++b) {
- new (iter) T(*b);
- ++this->size;
+#if __cplusplus >= 202002L && defined(__cpp_concepts) && defined(__cpp_lib_concepts)
+ constexpr bool canUseCopyAppend =
+ std::contiguous_iterator<It> &&
+ std::is_same_v<
+ std::remove_cv_t<typename std::iterator_traits<It>::value_type>,
+ T
+ >;
+ if constexpr (canUseCopyAppend) {
+ this->copyAppend(std::to_address(b), std::to_address(e));
+ } else
+#endif
+ {
+ T *iter = this->end();
+ for (; b != e; ++iter, ++b) {
+ new (iter) T(*b);
+ ++this->size;
+ }
}
}
+
+ // slightly higher level API than copyAppend() that also preallocates space
+ void growAppend(const T *b, const T *e)
+ {
+ if (b == e)
+ return;
+ Q_ASSERT(b < e);
+ const qsizetype n = e - b;
+ DataPointer old;
+
+ // points into range:
+ if (QtPrivate::q_points_into_range(b, *this))
+ this->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
+ else
+ this->detachAndGrow(QArrayData::GrowsAtEnd, n, nullptr, nullptr);
+ Q_ASSERT(this->freeSpaceAtEnd() >= n);
+ // b might be updated so use [b, n)
+ this->copyAppend(b, b + n);
+ }
+
+ void appendUninitialized(qsizetype newSize)
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
+
+ T *const b = this->begin();
+ do {
+ auto ptr = b + this->size;
+
+ if constexpr (std::is_constructible_v<T, Qt::Initialization>)
+ new (ptr) T(Qt::Uninitialized);
+ else
+ new (ptr) T; // not T() -- default-construct
+ } while (++this->size != newSize);
+ }
};
} // namespace QtPrivate