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