Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 09:07:18

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // Copyright (C) 2016 Intel Corporation.
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
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 // Call from destructors, ONLY!
0083     {
0084         Q_ASSERT(this->d);
0085         Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
0086 
0087         // As this is to be called only from destructor, it doesn't need to be
0088         // exception safe; size not updated.
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         // Comply with std::vector::erase(): erased elements and all after them
0178         // are invalidated. However, erasing from the beginning effectively
0179         // means that all iterators are invalidated. We can use this freedom to
0180         // erase by moving towards the end.
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             // std::uninitialized_copy will fallback to ::memcpy/memmove()
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) // short-cut and handling the case b and e == nullptr
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() // Call from destructors, ONLY
0343     {
0344         Q_ASSERT(this->d);
0345         // As this is to be called only from destructor, it doesn't need to be
0346         // exception safe; size not updated.
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; // smaller 0
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             // first create new elements at the end, by copying from elements
0398             // to be inserted (if they extend past the current end of the array)
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             // now move construct new elements at the end from existing elements inside
0406             // the array.
0407             for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
0408                 new (end + i) T(std::move(*(end + i - nSource)));
0409                 ++size;
0410             }
0411             // array has the new size now!
0412             Q_ASSERT(size == oldSize + n);
0413 
0414             // now move assign existing elements towards the end
0415             for (qsizetype i = 0; i != move; --i)
0416                 last[i] = std::move(last[i - nSource]);
0417 
0418             // finally copy the remaining elements from source over
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             // first create new elements at the end, by copying from elements
0431             // to be inserted (if they extend past the current end of the array)
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             // now move construct new elements at the end from existing elements inside
0439             // the array.
0440             for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
0441                 new (end + i) T(std::move(*(end + i - nSource)));
0442                 ++size;
0443             }
0444             // array has the new size now!
0445             Q_ASSERT(size == oldSize + n);
0446 
0447             // now move assign existing elements towards the end
0448             for (qsizetype i = 0; i != move; --i)
0449                 last[i] = std::move(last[i - nSource]);
0450 
0451             // finally copy the remaining elements from source over
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                 // create a new element at the end by move constructing one existing element
0466                 // inside the array.
0467                 new (end) T(std::move(*(end - 1)));
0468                 ++size;
0469 
0470                 // now move assign existing elements towards the end
0471                 for (qsizetype i = 0; i != move; --i)
0472                     last[i] = std::move(last[i - 1]);
0473 
0474                 // and move the new item into place
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             // copy construct items in reverse order at the begin
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             // copy construct items in reverse order at the begin
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         // Comply with std::vector::erase(): erased elements and all after them
0570         // are invalidated. However, erasing from the beginning effectively
0571         // means that all iterators are invalidated. We can use this freedom to
0572         // erase by moving towards the end.
0573         if (b == this->begin() && e != this->end()) {
0574             this->ptr = e;
0575         } else {
0576             const T *const end = this->end();
0577 
0578             // move (by assignment) the elements from e to end
0579             // onto b to the new end
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     // using QGenericArrayOps<T>::copyAppend;
0630     // using QGenericArrayOps<T>::moveAppend;
0631     // using QGenericArrayOps<T>::truncate;
0632     // using QGenericArrayOps<T>::destroyAll;
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             // copy construct items in reverse order at the begin
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             // copy construct items in reverse order at the begin
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         // Comply with std::vector::erase(): erased elements and all after them
0786         // are invalidated. However, erasing from the beginning effectively
0787         // means that all iterators are invalidated. We can use this freedom to
0788         // erase by moving towards the end.
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     // using Base::truncate;
0846     // using Base::destroyAll;
0847     // using Base::assign;
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     // slightly higher level API than copyAppend() that also preallocates space
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         // points into range:
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         // b might be updated so use [b, n)
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 } // namespace QtPrivate
0916 
0917 template <class T>
0918 struct QArrayDataOps
0919     : QtPrivate::QCommonArrayOps<T>
0920 {
0921 };
0922 
0923 QT_END_NAMESPACE
0924 
0925 #endif // include guard