diff options
| author | Andrei Golubev <andrei.golubev@qt.io> | 2021-03-24 16:47:33 +0100 |
|---|---|---|
| committer | Andrei Golubev <andrei.golubev@qt.io> | 2021-04-27 14:12:34 +0200 |
| commit | 1f2d0cd983d08f1b8d791cb3674b0965d5e89f1a (patch) | |
| tree | 40dbbc2cf53bc154c3758a2fb60f492d8b20d41d /src/corelib/tools/qarraydataops.h | |
| parent | 4b518d878aadb132256e8cea48fd6249667f59bb (diff) | |
Resurrect data moves in QList
Use the data moves to readjust the free space in the QList,
which ultimately fixes the out-of-memory issues caused by
cases like:
forever {
list.prepend(list.back());
list.removeLast();
}
Task-number: QTBUG-91801
Task-number: QTBUG-91360
Task-number: QTBUG-93019
Change-Id: Iacff69cbf36b8b5b176bb2663df635ec972c875c
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit a0253f5f0249024580050e4ec22d50cb139ef8d9)
Diffstat (limited to 'src/corelib/tools/qarraydataops.h')
| -rw-r--r-- | src/corelib/tools/qarraydataops.h | 56 |
1 files changed, 38 insertions, 18 deletions
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 4ee09a4dfb8..b70e8e4d9a1 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -164,8 +164,9 @@ public: typename Data::GrowthPosition pos = Data::GrowsAtEnd; if (this->size != 0 && i <= (this->size >> 1)) 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)); @@ -180,7 +181,8 @@ public: typename Data::GrowthPosition pos = Data::GrowsAtEnd; if (this->size != 0 && i <= (this->size >> 1)) 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)); @@ -210,10 +212,8 @@ public: 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); + + this->detachAndGrow(pos, 1, nullptr, nullptr); T *where = createHole(pos, i, 1); new (where) T(std::move(tmp)); @@ -547,8 +547,9 @@ public: typename Data::GrowthPosition pos = Data::GrowsAtEnd; if (this->size != 0 && i <= (this->size >> 1)) 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)); @@ -562,7 +563,8 @@ public: typename Data::GrowthPosition pos = Data::GrowsAtEnd; if (this->size != 0 && i <= (this->size >> 1)) 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)); @@ -590,10 +592,8 @@ public: 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); + + this->detachAndGrow(pos, 1, nullptr, nullptr); Inserter(this, pos).insertOne(i, std::move(tmp)); } @@ -774,8 +774,9 @@ public: typename Data::GrowthPosition pos = Data::GrowsAtEnd; if (this->size != 0 && i <= (this->size >> 1)) 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)); @@ -789,7 +790,8 @@ public: typename Data::GrowthPosition pos = Data::GrowsAtEnd; if (this->size != 0 && i <= (this->size >> 1)) 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)); @@ -817,10 +819,8 @@ public: 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); + + this->detachAndGrow(pos, 1, nullptr, nullptr); Inserter(this, pos).insertOne(i, std::move(tmp)); } @@ -914,6 +914,26 @@ public: ++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->begin(), this->end())) { + 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); + } }; } // namespace QtPrivate |
