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