File indexing completed on 2026-07-31 09:15:22
0001
0002
0003
0004
0005
0006 #ifndef QARRAYDATAOPS_H
0007 #define QARRAYDATAOPS_H
0008
0009 #include <QtCore/qarraydata.h>
0010 #include <QtCore/qcontainertools_impl.h>
0011 #include <QtCore/qnamespace.h>
0012
0013 #include <QtCore/q20functional.h>
0014 #include <QtCore/q20memory.h>
0015 #include <new>
0016 #include <string.h>
0017 #include <utility>
0018 #include <iterator>
0019 #include <type_traits>
0020
0021 QT_BEGIN_NAMESPACE
0022
0023 template <class T> struct QArrayDataPointer;
0024
0025 namespace QtPrivate {
0026
0027 template <class T>
0028 struct QPodArrayOps
0029 : public QArrayDataPointer<T>
0030 {
0031 static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0032
0033 protected:
0034 typedef QTypedArrayData<T> Data;
0035 using DataPointer = QArrayDataPointer<T>;
0036
0037 public:
0038 typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
0039
0040 using QArrayDataPointer<T>::QArrayDataPointer;
0041
0042 void copyAppend(const T *b, const T *e) noexcept
0043 {
0044 Q_ASSERT(this->isMutable() || b == e);
0045 Q_ASSERT(!this->isShared() || b == e);
0046 Q_ASSERT(b <= e);
0047 Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
0048
0049 if (b == e)
0050 return;
0051
0052 ::memcpy(static_cast<void *>(this->end()), static_cast<const void *>(b), (e - b) * sizeof(T));
0053 this->size += (e - b);
0054 }
0055
0056 void copyAppend(qsizetype n, parameter_type t) noexcept
0057 {
0058 Q_ASSERT(!this->isShared() || n == 0);
0059 Q_ASSERT(this->freeSpaceAtEnd() >= n);
0060 if (!n)
0061 return;
0062
0063 T *where = this->end();
0064 this->size += qsizetype(n);
0065 while (n--)
0066 *where++ = t;
0067 }
0068
0069 void moveAppend(T *b, T *e) noexcept
0070 {
0071 copyAppend(b, e);
0072 }
0073
0074 void truncate(size_t newSize) noexcept
0075 {
0076 Q_ASSERT(this->isMutable());
0077 Q_ASSERT(!this->isShared());
0078 Q_ASSERT(newSize <= size_t(this->size));
0079
0080 this->size = qsizetype(newSize);
0081 }
0082
0083 void destroyAll() noexcept
0084 {
0085 Q_ASSERT(this->d);
0086 Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
0087
0088
0089
0090 }
0091
0092 T *createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
0093 {
0094 Q_ASSERT((pos == QArrayData::GrowsAtBeginning && n <= this->freeSpaceAtBegin()) ||
0095 (pos == QArrayData::GrowsAtEnd && n <= this->freeSpaceAtEnd()));
0096
0097 T *insertionPoint = this->ptr + where;
0098 if (pos == QArrayData::GrowsAtEnd) {
0099 if (where < this->size)
0100 ::memmove(static_cast<void *>(insertionPoint + n), static_cast<void *>(insertionPoint), (this->size - where) * sizeof(T));
0101 } else {
0102 Q_ASSERT(where == 0);
0103 this->ptr -= n;
0104 insertionPoint -= n;
0105 }
0106 this->size += n;
0107 return insertionPoint;
0108 }
0109
0110 void insert(qsizetype i, const T *data, qsizetype n)
0111 {
0112 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
0113 if (this->size != 0 && i == 0)
0114 pos = Data::GrowsAtBeginning;
0115
0116 DataPointer oldData;
0117 this->detachAndGrow(pos, n, &data, &oldData);
0118 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
0119 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
0120
0121 T *where = createHole(pos, i, n);
0122 ::memcpy(static_cast<void *>(where), static_cast<const void *>(data), n * sizeof(T));
0123 }
0124
0125 void insert(qsizetype i, qsizetype n, parameter_type t)
0126 {
0127 T copy(t);
0128
0129 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
0130 if (this->size != 0 && i == 0)
0131 pos = Data::GrowsAtBeginning;
0132
0133 this->detachAndGrow(pos, n, nullptr, nullptr);
0134 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
0135 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
0136
0137 T *where = createHole(pos, i, n);
0138 while (n--)
0139 *where++ = copy;
0140 }
0141
0142 template<typename... Args>
0143 void emplace(qsizetype i, Args &&... args)
0144 {
0145 bool detach = this->needsDetach();
0146 if (!detach) {
0147 if (i == this->size && this->freeSpaceAtEnd()) {
0148 new (this->end()) T(std::forward<Args>(args)...);
0149 ++this->size;
0150 return;
0151 }
0152 if (i == 0 && this->freeSpaceAtBegin()) {
0153 new (this->begin() - 1) T(std::forward<Args>(args)...);
0154 --this->ptr;
0155 ++this->size;
0156 return;
0157 }
0158 }
0159 T tmp(std::forward<Args>(args)...);
0160 typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
0161 if (this->size != 0 && i == 0)
0162 pos = QArrayData::GrowsAtBeginning;
0163
0164 this->detachAndGrow(pos, 1, nullptr, nullptr);
0165
0166 T *where = createHole(pos, i, 1);
0167 new (where) T(std::move(tmp));
0168 }
0169
0170 void erase(T *b, qsizetype n)
0171 {
0172 T *e = b + n;
0173 Q_ASSERT(this->isMutable());
0174 Q_ASSERT(b < e);
0175 Q_ASSERT(b >= this->begin() && b < this->end());
0176 Q_ASSERT(e > this->begin() && e <= this->end());
0177
0178
0179
0180
0181
0182 if (b == this->begin() && e != this->end()) {
0183 this->ptr = e;
0184 } else if (e != this->end()) {
0185 ::memmove(static_cast<void *>(b), static_cast<void *>(e),
0186 (static_cast<T *>(this->end()) - e) * sizeof(T));
0187 }
0188 this->size -= n;
0189 }
0190
0191 void eraseFirst() noexcept
0192 {
0193 Q_ASSERT(this->isMutable());
0194 Q_ASSERT(this->size);
0195 ++this->ptr;
0196 --this->size;
0197 }
0198
0199 void eraseLast() noexcept
0200 {
0201 Q_ASSERT(this->isMutable());
0202 Q_ASSERT(this->size);
0203 --this->size;
0204 }
0205
0206 template <typename Predicate>
0207 qsizetype eraseIf(Predicate pred)
0208 {
0209 qsizetype result = 0;
0210 if (this->size == 0)
0211 return result;
0212
0213 if (!this->needsDetach()) {
0214 auto end = this->end();
0215 auto it = std::remove_if(this->begin(), end, pred);
0216 if (it != end) {
0217 result = std::distance(it, end);
0218 erase(it, result);
0219 }
0220 } else {
0221 const auto begin = this->begin();
0222 const auto end = this->end();
0223 auto it = std::find_if(begin, end, pred);
0224 if (it == end)
0225 return result;
0226
0227 QPodArrayOps<T> other(this->size);
0228 Q_CHECK_PTR(other.data());
0229 auto dest = other.begin();
0230
0231 dest = std::uninitialized_copy(begin, it, dest);
0232 dest = q_uninitialized_remove_copy_if(std::next(it), end, dest, pred);
0233 other.size = std::distance(other.data(), dest);
0234 result = this->size - other.size;
0235 this->swap(other);
0236 }
0237 return result;
0238 }
0239
0240 struct Span { T *begin; T *end; };
0241
0242 void copyRanges(std::initializer_list<Span> ranges)
0243 {
0244 auto it = this->begin();
0245 std::for_each(ranges.begin(), ranges.end(), [&it](const auto &span) {
0246 it = std::copy(span.begin, span.end, it);
0247 });
0248 this->size = std::distance(this->begin(), it);
0249 }
0250
0251 void assign(T *b, T *e, parameter_type t) noexcept
0252 {
0253 Q_ASSERT(b <= e);
0254 Q_ASSERT(b >= this->begin() && e <= this->end());
0255
0256 while (b != e)
0257 ::memcpy(static_cast<void *>(b++), static_cast<const void *>(&t), sizeof(T));
0258 }
0259
0260 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
0261 {
0262 auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
0263 Q_CHECK_PTR(pair.second);
0264 Q_ASSERT(pair.first != nullptr);
0265 this->d = pair.first;
0266 this->ptr = pair.second;
0267 }
0268 };
0269
0270 template <class T>
0271 struct QGenericArrayOps
0272 : public QArrayDataPointer<T>
0273 {
0274 static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0275
0276 protected:
0277 typedef QTypedArrayData<T> Data;
0278 using DataPointer = QArrayDataPointer<T>;
0279
0280 public:
0281 typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
0282
0283 void copyAppend(const T *b, const T *e)
0284 {
0285 Q_ASSERT(this->isMutable() || b == e);
0286 Q_ASSERT(!this->isShared() || b == e);
0287 Q_ASSERT(b <= e);
0288 Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
0289
0290 if (b == e)
0291 return;
0292
0293 T *data = this->begin();
0294 while (b < e) {
0295 new (data + this->size) T(*b);
0296 ++b;
0297 ++this->size;
0298 }
0299 }
0300
0301 void copyAppend(qsizetype n, parameter_type t)
0302 {
0303 Q_ASSERT(!this->isShared() || n == 0);
0304 Q_ASSERT(this->freeSpaceAtEnd() >= n);
0305 if (!n)
0306 return;
0307
0308 T *data = this->begin();
0309 while (n--) {
0310 new (data + this->size) T(t);
0311 ++this->size;
0312 }
0313 }
0314
0315 void moveAppend(T *b, T *e)
0316 {
0317 Q_ASSERT(this->isMutable() || b == e);
0318 Q_ASSERT(!this->isShared() || b == e);
0319 Q_ASSERT(b <= e);
0320 Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
0321
0322 if (b == e)
0323 return;
0324
0325 T *data = this->begin();
0326 while (b < e) {
0327 new (data + this->size) T(std::move(*b));
0328 ++b;
0329 ++this->size;
0330 }
0331 }
0332
0333 void truncate(size_t newSize)
0334 {
0335 Q_ASSERT(this->isMutable());
0336 Q_ASSERT(!this->isShared());
0337 Q_ASSERT(newSize <= size_t(this->size));
0338
0339 std::destroy(this->begin() + newSize, this->end());
0340 this->size = newSize;
0341 }
0342
0343 void destroyAll()
0344 {
0345 Q_ASSERT(this->d);
0346
0347
0348
0349 Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
0350
0351 std::destroy(this->begin(), this->end());
0352 }
0353
0354 struct Inserter
0355 {
0356 QArrayDataPointer<T> *data;
0357 T *begin;
0358 qsizetype size;
0359
0360 qsizetype sourceCopyConstruct = 0, nSource = 0, move = 0, sourceCopyAssign = 0;
0361 T *end = nullptr, *last = nullptr, *where = nullptr;
0362
0363 Inserter(QArrayDataPointer<T> *d) : data(d)
0364 {
0365 begin = d->ptr;
0366 size = d->size;
0367 }
0368 ~Inserter() {
0369 data->ptr = begin;
0370 data->size = size;
0371 }
0372 Q_DISABLE_COPY(Inserter)
0373
0374 void setup(qsizetype pos, qsizetype n)
0375 {
0376 end = begin + size;
0377 last = end - 1;
0378 where = begin + pos;
0379 qsizetype dist = size - pos;
0380 sourceCopyConstruct = 0;
0381 nSource = n;
0382 move = n - dist;
0383 sourceCopyAssign = n;
0384 if (n > dist) {
0385 sourceCopyConstruct = n - dist;
0386 move = 0;
0387 sourceCopyAssign -= sourceCopyConstruct;
0388 }
0389 }
0390
0391 void insert(qsizetype pos, const T *source, qsizetype n)
0392 {
0393 qsizetype oldSize = size;
0394 Q_UNUSED(oldSize);
0395
0396 setup(pos, n);
0397
0398
0399
0400 for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
0401 new (end + i) T(source[nSource - sourceCopyConstruct + i]);
0402 ++size;
0403 }
0404 Q_ASSERT(size <= oldSize + n);
0405
0406
0407
0408 for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
0409 new (end + i) T(std::move(*(end + i - nSource)));
0410 ++size;
0411 }
0412
0413 Q_ASSERT(size == oldSize + n);
0414
0415
0416 for (qsizetype i = 0; i != move; --i)
0417 last[i] = std::move(last[i - nSource]);
0418
0419
0420 for (qsizetype i = 0; i != sourceCopyAssign; ++i)
0421 where[i] = source[i];
0422 }
0423
0424 void insert(qsizetype pos, const T &t, qsizetype n)
0425 {
0426 const qsizetype oldSize = size;
0427 Q_UNUSED(oldSize);
0428
0429 setup(pos, n);
0430
0431
0432
0433 for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
0434 new (end + i) T(t);
0435 ++size;
0436 }
0437 Q_ASSERT(size <= oldSize + n);
0438
0439
0440
0441 for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
0442 new (end + i) T(std::move(*(end + i - nSource)));
0443 ++size;
0444 }
0445
0446 Q_ASSERT(size == oldSize + n);
0447
0448
0449 for (qsizetype i = 0; i != move; --i)
0450 last[i] = std::move(last[i - nSource]);
0451
0452
0453 for (qsizetype i = 0; i != sourceCopyAssign; ++i)
0454 where[i] = t;
0455 }
0456
0457 void insertOne(qsizetype pos, T &&t)
0458 {
0459 setup(pos, 1);
0460
0461 if (sourceCopyConstruct) {
0462 Q_ASSERT(sourceCopyConstruct == 1);
0463 new (end) T(std::move(t));
0464 ++size;
0465 } else {
0466
0467
0468 new (end) T(std::move(*(end - 1)));
0469 ++size;
0470
0471
0472 for (qsizetype i = 0; i != move; --i)
0473 last[i] = std::move(last[i - 1]);
0474
0475
0476 *where = std::move(t);
0477 }
0478 }
0479 };
0480
0481 void insert(qsizetype i, const T *data, qsizetype n)
0482 {
0483 const bool growsAtBegin = this->size != 0 && i == 0;
0484 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
0485
0486 DataPointer oldData;
0487 this->detachAndGrow(pos, n, &data, &oldData);
0488 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
0489 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
0490
0491 if (growsAtBegin) {
0492
0493 Q_ASSERT(this->freeSpaceAtBegin() >= n);
0494 while (n) {
0495 --n;
0496 new (this->begin() - 1) T(data[n]);
0497 --this->ptr;
0498 ++this->size;
0499 }
0500 } else {
0501 Inserter(this).insert(i, data, n);
0502 }
0503 }
0504
0505 void insert(qsizetype i, qsizetype n, parameter_type t)
0506 {
0507 T copy(t);
0508
0509 const bool growsAtBegin = this->size != 0 && i == 0;
0510 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
0511
0512 this->detachAndGrow(pos, n, nullptr, nullptr);
0513 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
0514 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
0515
0516 if (growsAtBegin) {
0517
0518 Q_ASSERT(this->freeSpaceAtBegin() >= n);
0519 while (n--) {
0520 new (this->begin() - 1) T(copy);
0521 --this->ptr;
0522 ++this->size;
0523 }
0524 } else {
0525 Inserter(this).insert(i, copy, n);
0526 }
0527 }
0528
0529 template<typename... Args>
0530 void emplace(qsizetype i, Args &&... args)
0531 {
0532 bool detach = this->needsDetach();
0533 if (!detach) {
0534 if (i == this->size && this->freeSpaceAtEnd()) {
0535 new (this->end()) T(std::forward<Args>(args)...);
0536 ++this->size;
0537 return;
0538 }
0539 if (i == 0 && this->freeSpaceAtBegin()) {
0540 new (this->begin() - 1) T(std::forward<Args>(args)...);
0541 --this->ptr;
0542 ++this->size;
0543 return;
0544 }
0545 }
0546 T tmp(std::forward<Args>(args)...);
0547 const bool growsAtBegin = this->size != 0 && i == 0;
0548 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
0549
0550 this->detachAndGrow(pos, 1, nullptr, nullptr);
0551
0552 if (growsAtBegin) {
0553 Q_ASSERT(this->freeSpaceAtBegin());
0554 new (this->begin() - 1) T(std::move(tmp));
0555 --this->ptr;
0556 ++this->size;
0557 } else {
0558 Inserter(this).insertOne(i, std::move(tmp));
0559 }
0560 }
0561
0562 void erase(T *b, qsizetype n)
0563 {
0564 T *e = b + n;
0565 Q_ASSERT(this->isMutable());
0566 Q_ASSERT(b < e);
0567 Q_ASSERT(b >= this->begin() && b < this->end());
0568 Q_ASSERT(e > this->begin() && e <= this->end());
0569
0570
0571
0572
0573
0574 if (b == this->begin() && e != this->end()) {
0575 this->ptr = e;
0576 } else {
0577 const T *const end = this->end();
0578
0579
0580
0581 while (e != end) {
0582 *b = std::move(*e);
0583 ++b;
0584 ++e;
0585 }
0586 }
0587 this->size -= n;
0588 std::destroy(b, e);
0589 }
0590
0591 void eraseFirst() noexcept
0592 {
0593 Q_ASSERT(this->isMutable());
0594 Q_ASSERT(this->size);
0595 this->begin()->~T();
0596 ++this->ptr;
0597 --this->size;
0598 }
0599
0600 void eraseLast() noexcept
0601 {
0602 Q_ASSERT(this->isMutable());
0603 Q_ASSERT(this->size);
0604 (this->end() - 1)->~T();
0605 --this->size;
0606 }
0607
0608
0609 void assign(T *b, T *e, parameter_type t)
0610 {
0611 Q_ASSERT(b <= e);
0612 Q_ASSERT(b >= this->begin() && e <= this->end());
0613
0614 while (b != e)
0615 *b++ = t;
0616 }
0617 };
0618
0619 template <class T>
0620 struct QMovableArrayOps
0621 : QGenericArrayOps<T>
0622 {
0623 static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
0624
0625 protected:
0626 typedef QTypedArrayData<T> Data;
0627 using DataPointer = QArrayDataPointer<T>;
0628
0629 public:
0630
0631
0632
0633
0634 typedef typename QGenericArrayOps<T>::parameter_type parameter_type;
0635
0636 struct Inserter
0637 {
0638 QArrayDataPointer<T> * const data;
0639 T *displaceFrom;
0640 T * const displaceTo;
0641 const qsizetype nInserts = 0;
0642 const size_t bytes;
0643
0644 void verifyPost()
0645 { Q_ASSERT(displaceFrom == displaceTo); }
0646
0647 explicit Inserter(QArrayDataPointer<T> *d, qsizetype pos, qsizetype n)
0648 : data{d},
0649 displaceFrom{d->ptr + pos},
0650 displaceTo{displaceFrom + n},
0651 nInserts{n},
0652 bytes{(data->size - pos) * sizeof(T)}
0653 {
0654 ::memmove(static_cast<void *>(displaceTo), static_cast<void *>(displaceFrom), bytes);
0655 }
0656 ~Inserter() {
0657 auto inserts = nInserts;
0658 if constexpr (!std::is_nothrow_copy_constructible_v<T>) {
0659 if (displaceFrom != displaceTo) {
0660 ::memmove(static_cast<void *>(displaceFrom), static_cast<void *>(displaceTo), bytes);
0661 inserts -= qAbs(displaceFrom - displaceTo);
0662 }
0663 }
0664 data->size += inserts;
0665 }
0666 Q_DISABLE_COPY(Inserter)
0667
0668 void insertRange(const T *source, qsizetype n)
0669 {
0670 while (n--) {
0671 new (displaceFrom) T(*source);
0672 ++source;
0673 ++displaceFrom;
0674 }
0675 verifyPost();
0676 }
0677
0678 void insertFill(const T &t, qsizetype n)
0679 {
0680 while (n--) {
0681 new (displaceFrom) T(t);
0682 ++displaceFrom;
0683 }
0684 verifyPost();
0685 }
0686
0687 void insertOne(T &&t)
0688 {
0689 new (displaceFrom) T(std::move(t));
0690 ++displaceFrom;
0691 verifyPost();
0692 }
0693
0694 };
0695
0696
0697 void insert(qsizetype i, const T *data, qsizetype n)
0698 {
0699 const bool growsAtBegin = this->size != 0 && i == 0;
0700 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
0701
0702 DataPointer oldData;
0703 this->detachAndGrow(pos, n, &data, &oldData);
0704 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
0705 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
0706
0707 if (growsAtBegin) {
0708
0709 Q_ASSERT(this->freeSpaceAtBegin() >= n);
0710 while (n) {
0711 --n;
0712 new (this->begin() - 1) T(data[n]);
0713 --this->ptr;
0714 ++this->size;
0715 }
0716 } else {
0717 Inserter(this, i, n).insertRange(data, n);
0718 }
0719 }
0720
0721 void insert(qsizetype i, qsizetype n, parameter_type t)
0722 {
0723 T copy(t);
0724
0725 const bool growsAtBegin = this->size != 0 && i == 0;
0726 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
0727
0728 this->detachAndGrow(pos, n, nullptr, nullptr);
0729 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
0730 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
0731
0732 if (growsAtBegin) {
0733
0734 Q_ASSERT(this->freeSpaceAtBegin() >= n);
0735 while (n--) {
0736 new (this->begin() - 1) T(copy);
0737 --this->ptr;
0738 ++this->size;
0739 }
0740 } else {
0741 Inserter(this, i, n).insertFill(copy, n);
0742 }
0743 }
0744
0745 template<typename... Args>
0746 void emplace(qsizetype i, Args &&... args)
0747 {
0748 bool detach = this->needsDetach();
0749 if (!detach) {
0750 if (i == this->size && this->freeSpaceAtEnd()) {
0751 new (this->end()) T(std::forward<Args>(args)...);
0752 ++this->size;
0753 return;
0754 }
0755 if (i == 0 && this->freeSpaceAtBegin()) {
0756 new (this->begin() - 1) T(std::forward<Args>(args)...);
0757 --this->ptr;
0758 ++this->size;
0759 return;
0760 }
0761 }
0762 T tmp(std::forward<Args>(args)...);
0763 const bool growsAtBegin = this->size != 0 && i == 0;
0764 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
0765
0766 this->detachAndGrow(pos, 1, nullptr, nullptr);
0767 if (growsAtBegin) {
0768 Q_ASSERT(this->freeSpaceAtBegin());
0769 new (this->begin() - 1) T(std::move(tmp));
0770 --this->ptr;
0771 ++this->size;
0772 } else {
0773 Inserter(this, i, 1).insertOne(std::move(tmp));
0774 }
0775 }
0776
0777 void erase(T *b, qsizetype n)
0778 {
0779 T *e = b + n;
0780
0781 Q_ASSERT(this->isMutable());
0782 Q_ASSERT(b < e);
0783 Q_ASSERT(b >= this->begin() && b < this->end());
0784 Q_ASSERT(e > this->begin() && e <= this->end());
0785
0786
0787
0788
0789
0790
0791 std::destroy(b, e);
0792 if (b == this->begin() && e != this->end()) {
0793 this->ptr = e;
0794 } else if (e != this->end()) {
0795 memmove(static_cast<void *>(b), static_cast<const void *>(e), (static_cast<const T *>(this->end()) - e)*sizeof(T));
0796 }
0797 this->size -= n;
0798 }
0799
0800 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
0801 {
0802 auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
0803 Q_CHECK_PTR(pair.second);
0804 Q_ASSERT(pair.first != nullptr);
0805 this->d = pair.first;
0806 this->ptr = pair.second;
0807 }
0808 };
0809
0810 template <class T, class = void>
0811 struct QArrayOpsSelector
0812 {
0813 typedef QGenericArrayOps<T> Type;
0814 };
0815
0816 template <class T>
0817 struct QArrayOpsSelector<T,
0818 typename std::enable_if<
0819 !QTypeInfo<T>::isComplex && QTypeInfo<T>::isRelocatable
0820 >::type>
0821 {
0822 typedef QPodArrayOps<T> Type;
0823 };
0824
0825 template <class T>
0826 struct QArrayOpsSelector<T,
0827 typename std::enable_if<
0828 QTypeInfo<T>::isComplex && QTypeInfo<T>::isRelocatable
0829 >::type>
0830 {
0831 typedef QMovableArrayOps<T> Type;
0832 };
0833
0834 template <class T>
0835 struct QCommonArrayOps : QArrayOpsSelector<T>::Type
0836 {
0837 using Base = typename QArrayOpsSelector<T>::Type;
0838 using Data = QTypedArrayData<T>;
0839 using DataPointer = QArrayDataPointer<T>;
0840 using parameter_type = typename Base::parameter_type;
0841
0842 protected:
0843 using Self = QCommonArrayOps<T>;
0844
0845 public:
0846
0847
0848
0849 template<typename It>
0850 void appendIteratorRange(It b, It e, QtPrivate::IfIsForwardIterator<It> = true)
0851 {
0852 Q_ASSERT(this->isMutable() || b == e);
0853 Q_ASSERT(!this->isShared() || b == e);
0854 const qsizetype distance = std::distance(b, e);
0855 Q_ASSERT(distance >= 0 && distance <= this->allocatedCapacity() - this->size);
0856 Q_UNUSED(distance);
0857
0858 #if __cplusplus >= 202002L && defined(__cpp_concepts) && defined(__cpp_lib_concepts)
0859 constexpr bool canUseCopyAppend =
0860 std::contiguous_iterator<It> &&
0861 std::is_same_v<
0862 std::remove_cv_t<typename std::iterator_traits<It>::value_type>,
0863 T
0864 >;
0865 if constexpr (canUseCopyAppend) {
0866 this->copyAppend(std::to_address(b), std::to_address(e));
0867 } else
0868 #endif
0869 {
0870 T *iter = this->end();
0871 for (; b != e; ++iter, ++b) {
0872 new (iter) T(*b);
0873 ++this->size;
0874 }
0875 }
0876 }
0877
0878
0879 void growAppend(const T *b, const T *e)
0880 {
0881 if (b == e)
0882 return;
0883 Q_ASSERT(b < e);
0884 const qsizetype n = e - b;
0885 DataPointer old;
0886
0887
0888 if (QtPrivate::q_points_into_range(b, *this))
0889 this->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
0890 else
0891 this->detachAndGrow(QArrayData::GrowsAtEnd, n, nullptr, nullptr);
0892 Q_ASSERT(this->freeSpaceAtEnd() >= n);
0893
0894 this->copyAppend(b, b + n);
0895 }
0896
0897 void appendUninitialized(qsizetype newSize)
0898 {
0899 Q_ASSERT(this->isMutable());
0900 Q_ASSERT(!this->isShared());
0901 Q_ASSERT(newSize > this->size);
0902 Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
0903
0904
0905 T *const b = this->begin() + this->size;
0906 T *const e = this->begin() + newSize;
0907 if constexpr (std::is_constructible_v<T, Qt::Initialization>)
0908 std::uninitialized_fill(b, e, Qt::Uninitialized);
0909 else
0910 std::uninitialized_default_construct(b, e);
0911 this->size = newSize;
0912 }
0913
0914 using Base::assign;
0915
0916 template <typename InputIterator, typename Projection = q20::identity>
0917 void assign(InputIterator first, InputIterator last, Projection proj = {})
0918 {
0919
0920 using Category = typename std::iterator_traits<InputIterator>::iterator_category;
0921 constexpr bool IsFwdIt = std::is_convertible_v<Category, std::forward_iterator_tag>;
0922
0923 const qsizetype n = IsFwdIt ? std::distance(first, last) : 0;
0924 bool undoPrependOptimization = true;
0925 bool needCapacity = n > this->constAllocatedCapacity();
0926 if (needCapacity || this->needsDetach()) {
0927 qsizetype newCapacity = this->detachCapacity(n);
0928 bool wasLastRef = !this->deref();
0929 if (wasLastRef && needCapacity) {
0930
0931 this->destroyAll();
0932 Data::deallocate(this->d);
0933 }
0934 if (!needCapacity && wasLastRef) {
0935
0936 this->d->ref_.storeRelaxed(1);
0937 } else {
0938
0939 std::tie(this->d, this->ptr) = Data::allocate(newCapacity);
0940 this->size = 0;
0941 undoPrependOptimization = false;
0942 }
0943 }
0944
0945 if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>
0946 || !std::is_nothrow_invocable_v<Projection, decltype(*first)>)
0947 {
0948
0949
0950
0951 if (undoPrependOptimization) {
0952 this->truncate(0);
0953 this->setBegin(Data::dataStart(this->d, alignof(typename Data::AlignmentDummy)));
0954 undoPrependOptimization = false;
0955 }
0956 }
0957
0958 const auto dend = this->end();
0959 T *dst = this->begin();
0960 T *capacityBegin = dst;
0961 if (undoPrependOptimization) {
0962 capacityBegin = Data::dataStart(this->d, alignof(typename Data::AlignmentDummy));
0963 this->setBegin(capacityBegin);
0964 }
0965
0966 assign_impl(first, last, capacityBegin, dst, dend, proj, Category{});
0967 }
0968
0969 template <typename InputIterator, typename Projection>
0970 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
0971 Projection proj, std::input_iterator_tag)
0972 {
0973 if (qsizetype offset = dst - capacityBegin) {
0974 T *prependBufferEnd = dst;
0975 dst = capacityBegin;
0976
0977
0978
0979
0980
0981
0982 while (true) {
0983 if (dst == prependBufferEnd) {
0984 this->size += offset;
0985
0986 break;
0987 }
0988 if (first == last) {
0989 std::destroy(prependBufferEnd, dend);
0990 this->size = dst - this->begin();
0991 return;
0992 }
0993
0994 q20::construct_at(dst, std::invoke(proj, *first));
0995 ++dst;
0996 ++first;
0997 }
0998 }
0999 while (true) {
1000 if (first == last) {
1001 std::destroy(dst, dend);
1002 break;
1003 }
1004 if (dst == dend) {
1005 do {
1006 this->emplace(this->size, std::invoke(proj, *first));
1007 } while (++first != last);
1008 return;
1009 }
1010 *dst = std::invoke(proj, *first);
1011 ++dst;
1012 ++first;
1013 }
1014 this->size = dst - this->begin();
1015 }
1016
1017 template <typename InputIterator, typename Projection>
1018 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
1019 Projection proj, std::forward_iterator_tag)
1020 {
1021 constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
1022 const qsizetype n = std::distance(first, last);
1023 if constexpr (IsIdentity && !QTypeInfo<T>::isComplex) {
1024
1025
1026
1027
1028 std::copy(first, last, capacityBegin);
1029 } else {
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039 while (first != last && capacityBegin != dst) {
1040 q20::construct_at(capacityBegin, std::invoke(proj, *first));
1041 ++first;
1042 ++capacityBegin;
1043 }
1044
1045
1046 while (first != last && dst != dend) {
1047 *dst = std::invoke(proj, *first);
1048 ++first;
1049 ++dst;
1050 }
1051
1052
1053 while (first != last) {
1054 q20::construct_at(dst, std::invoke(proj, *first));
1055 ++first;
1056 ++dst;
1057 }
1058
1059 if (dst < dend)
1060 std::destroy(dst, dend);
1061 }
1062 this->size = n;
1063 }
1064 };
1065
1066 }
1067
1068 template <class T>
1069 struct QArrayDataOps
1070 : QtPrivate::QCommonArrayOps<T>
1071 {
1072 };
1073
1074 QT_END_NAMESPACE
1075
1076 #endif