9#include <QtCore/qarraydata.h>
10#include <QtCore/qcontainertools_impl.h>
11#include <QtCore/qnamespace.h>
13#include <QtCore/q20functional.h>
14#include <QtCore/q20memory.h>
23template <
class T>
struct QArrayDataPointer;
31 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
44 Q_ASSERT(
this->isMutable() || b == e);
45 Q_ASSERT(!
this->isShared() || b == e);
47 Q_ASSERT((e - b) <=
this->freeSpaceAtEnd());
52 ::memcpy(
static_cast<
void *>(
this->end()),
static_cast<
const void *>(b), (e - b) *
sizeof(T));
53 this->size += (e - b);
58 Q_ASSERT(!
this->isShared() || n == 0);
59 Q_ASSERT(
this->freeSpaceAtEnd() >= n);
63 T *where =
this->end();
64 this->size += qsizetype(n);
76 Q_ASSERT(
this->isMutable());
77 Q_ASSERT(!
this->isShared());
78 Q_ASSERT(newSize <= size_t(
this->size));
80 this->size = qsizetype(newSize);
86 Q_ASSERT(
this->d->ref_.loadRelaxed() == 0);
92 T *
createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
94 Q_ASSERT((pos == QArrayData::GrowsAtBeginning && n <=
this->freeSpaceAtBegin()) ||
95 (pos == QArrayData::GrowsAtEnd && n <=
this->freeSpaceAtEnd()));
97 T *insertionPoint =
this->ptr + where;
98 if (pos == QArrayData::GrowsAtEnd) {
99 if (where <
this->size)
100 ::memmove(
static_cast<
void *>(insertionPoint + n),
static_cast<
void *>(insertionPoint), (
this->size - where) *
sizeof(T));
102 Q_ASSERT(where == 0);
107 return insertionPoint;
110 void insert(qsizetype i,
const T *data, qsizetype n)
112 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
113 if (
this->size != 0 && i == 0)
114 pos = Data::GrowsAtBeginning;
117 this->detachAndGrow(pos, n, &data, &oldData);
118 Q_ASSERT((pos == Data::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n) ||
119 (pos == Data::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n));
121 T *where = createHole(pos, i, n);
122 ::memcpy(
static_cast<
void *>(where),
static_cast<
const void *>(data), n *
sizeof(T));
129 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
130 if (
this->size != 0 && i == 0)
131 pos = Data::GrowsAtBeginning;
133 this->detachAndGrow(pos, n,
nullptr,
nullptr);
134 Q_ASSERT((pos == Data::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n) ||
135 (pos == Data::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n));
137 T *where = createHole(pos, i, n);
142 template<
typename... Args>
145 bool detach =
this->needsDetach();
147 if (i ==
this->size &&
this->freeSpaceAtEnd()) {
148 new (
this->end()) T(
std::forward<Args>(args)...);
152 if (i == 0 &&
this->freeSpaceAtBegin()) {
153 new (
this->begin() - 1) T(
std::forward<Args>(args)...);
159 T tmp(
std::forward<Args>(args)...);
160 typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
161 if (
this->size != 0 && i == 0)
162 pos = QArrayData::GrowsAtBeginning;
164 this->detachAndGrow(pos, 1,
nullptr,
nullptr);
166 T *where = createHole(pos, i, 1);
167 new (where) T(
std::move(tmp));
173 Q_ASSERT(
this->isMutable());
175 Q_ASSERT(b >=
this->begin() && b <
this->end());
176 Q_ASSERT(e >
this->begin() && e <=
this->end());
182 if (b ==
this->begin() && e !=
this->end()) {
184 }
else if (e !=
this->end()) {
185 ::memmove(
static_cast<
void *>(b),
static_cast<
void *>(e),
186 (
static_cast<T *>(
this->end()) - e) *
sizeof(T));
193 Q_ASSERT(
this->isMutable());
194 Q_ASSERT(
this->size);
201 Q_ASSERT(
this->isMutable());
202 Q_ASSERT(
this->size);
206 template <
typename Predicate>
209 qsizetype result = 0;
213 if (!
this->needsDetach()) {
214 auto end =
this->end();
215 auto it = std::remove_if(
this->begin(), end, pred);
217 result =
std::distance(it, end);
221 const auto begin =
this->begin();
222 const auto end =
this->end();
223 auto it = std::find_if(begin, end, pred);
228 Q_CHECK_PTR(other.data());
229 auto dest = other.begin();
231 dest = std::uninitialized_copy(begin, it, dest);
232 dest = q_uninitialized_remove_copy_if(
std::next(it), end, dest, pred);
233 other.size =
std::distance(other.data(), dest);
234 result =
this->size - other.size;
244 auto it =
this->begin();
245 std::for_each(ranges.begin(), ranges.end(), [&it](
const auto &span) {
246 it = std::copy(span.begin, span.end, it);
248 this->size =
std::distance(
this->begin(), it);
254 Q_ASSERT(b >=
this->begin() && e <=
this->end());
257 ::memcpy(
static_cast<
void *>(b++),
static_cast<
const void *>(&t),
sizeof(T));
260 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
262 auto pair = Data::reallocateUnaligned(
this->d,
this->ptr, alloc, option);
263 Q_CHECK_PTR(pair.second);
264 Q_ASSERT(pair.first !=
nullptr);
265 this->d = pair.first;
266 this->ptr = pair.second;
274 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
285 Q_ASSERT(
this->isMutable() || b == e);
286 Q_ASSERT(!
this->isShared() || b == e);
288 Q_ASSERT((e - b) <=
this->freeSpaceAtEnd());
293 T *data =
this->begin();
295 new (data +
this->size) T(*b);
303 Q_ASSERT(!
this->isShared() || n == 0);
304 Q_ASSERT(
this->freeSpaceAtEnd() >= n);
308 T *data =
this->begin();
310 new (data +
this->size) T(t);
317 Q_ASSERT(
this->isMutable() || b == e);
318 Q_ASSERT(!
this->isShared() || b == e);
320 Q_ASSERT((e - b) <=
this->freeSpaceAtEnd());
325 T *data =
this->begin();
327 new (data +
this->size) T(
std::move(*b));
335 Q_ASSERT(
this->isMutable());
336 Q_ASSERT(!
this->isShared());
337 Q_ASSERT(newSize <= size_t(
this->size));
339 std::destroy(
this->begin() + newSize,
this->end());
340 this->size = newSize;
349 Q_ASSERT(
this->d->ref_.loadRelaxed() == 0);
351 std::destroy(
this->begin(),
this->end());
481 void insert(qsizetype i,
const T *data, qsizetype n)
483 const bool growsAtBegin =
this->size != 0 && i == 0;
484 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
487 this->detachAndGrow(pos, n, &data, &oldData);
488 Q_ASSERT((pos == Data::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n) ||
489 (pos == Data::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n));
493 Q_ASSERT(
this->freeSpaceAtBegin() >= n);
496 new (
this->begin() - 1) T(data[n]);
509 const bool growsAtBegin =
this->size != 0 && i == 0;
510 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
512 this->detachAndGrow(pos, n,
nullptr,
nullptr);
513 Q_ASSERT((pos == Data::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n) ||
514 (pos == Data::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n));
518 Q_ASSERT(
this->freeSpaceAtBegin() >= n);
520 new (
this->begin() - 1) T(copy);
529 template<
typename... Args>
532 bool detach =
this->needsDetach();
534 if (i ==
this->size &&
this->freeSpaceAtEnd()) {
535 new (
this->end()) T(
std::forward<Args>(args)...);
539 if (i == 0 &&
this->freeSpaceAtBegin()) {
540 new (
this->begin() - 1) T(
std::forward<Args>(args)...);
546 T tmp(
std::forward<Args>(args)...);
547 const bool growsAtBegin =
this->size != 0 && i == 0;
548 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
550 this->detachAndGrow(pos, 1,
nullptr,
nullptr);
553 Q_ASSERT(
this->freeSpaceAtBegin());
554 new (
this->begin() - 1) T(
std::move(tmp));
565 Q_ASSERT(
this->isMutable());
567 Q_ASSERT(b >=
this->begin() && b <
this->end());
568 Q_ASSERT(e >
this->begin() && e <=
this->end());
574 if (b ==
this->begin() && e !=
this->end()) {
577 const T *
const end =
this->end();
593 Q_ASSERT(
this->isMutable());
594 Q_ASSERT(
this->size);
602 Q_ASSERT(
this->isMutable());
603 Q_ASSERT(
this->size);
604 (
this->end() - 1)->~T();
612 Q_ASSERT(b >=
this->begin() && e <=
this->end());
623 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
647 explicit Inserter(QArrayDataPointer<T> *d, qsizetype pos, qsizetype n)
697 void insert(qsizetype i,
const T *data, qsizetype n)
699 const bool growsAtBegin =
this->size != 0 && i == 0;
700 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
703 this->detachAndGrow(pos, n, &data, &oldData);
704 Q_ASSERT((pos == Data::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n) ||
705 (pos == Data::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n));
709 Q_ASSERT(
this->freeSpaceAtBegin() >= n);
712 new (
this->begin() - 1) T(data[n]);
717 Inserter(
this, i, n).insertRange(data, n);
725 const bool growsAtBegin =
this->size != 0 && i == 0;
726 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
728 this->detachAndGrow(pos, n,
nullptr,
nullptr);
729 Q_ASSERT((pos == Data::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n) ||
730 (pos == Data::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n));
734 Q_ASSERT(
this->freeSpaceAtBegin() >= n);
736 new (
this->begin() - 1) T(copy);
741 Inserter(
this, i, n).insertFill(copy, n);
745 template<
typename... Args>
748 bool detach =
this->needsDetach();
750 if (i ==
this->size &&
this->freeSpaceAtEnd()) {
751 new (
this->end()) T(
std::forward<Args>(args)...);
755 if (i == 0 &&
this->freeSpaceAtBegin()) {
756 new (
this->begin() - 1) T(
std::forward<Args>(args)...);
762 T tmp(
std::forward<Args>(args)...);
763 const bool growsAtBegin =
this->size != 0 && i == 0;
764 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
766 this->detachAndGrow(pos, 1,
nullptr,
nullptr);
768 Q_ASSERT(
this->freeSpaceAtBegin());
769 new (
this->begin() - 1) T(
std::move(tmp));
781 Q_ASSERT(
this->isMutable());
783 Q_ASSERT(b >=
this->begin() && b <
this->end());
784 Q_ASSERT(e >
this->begin() && e <=
this->end());
792 if (b ==
this->begin() && e !=
this->end()) {
794 }
else if (e !=
this->end()) {
795 memmove(
static_cast<
void *>(b),
static_cast<
const void *>(e), (
static_cast<
const T *>(
this->end()) - e)*
sizeof(T));
800 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
802 auto pair = Data::reallocateUnaligned(
this->d,
this->ptr, alloc, option);
803 Q_CHECK_PTR(pair.second);
804 Q_ASSERT(pair.first !=
nullptr);
805 this->d = pair.first;
806 this->ptr = pair.second;
810template <
class T,
class =
void>
849 template<
typename It>
852 Q_ASSERT(
this->isMutable() || b == e);
853 Q_ASSERT(!
this->isShared() || b == e);
854 const qsizetype distance =
std::distance(b, e);
855 Q_ASSERT(distance >= 0 && distance <=
this->allocatedCapacity() -
this->size);
858#if __cplusplus
>= 202002L
&& defined(__cpp_concepts) && defined(__cpp_lib_concepts)
859 constexpr bool canUseCopyAppend =
860 std::contiguous_iterator<It> &&
862 std::remove_cv_t<
typename std::iterator_traits<It>::value_type>,
865 if constexpr (canUseCopyAppend) {
866 this->copyAppend(std::to_address(b), std::to_address(e));
870 T *iter =
this->end();
871 for (; b != e; ++iter, ++b) {
884 const qsizetype n = e - b;
888 if (QtPrivate::q_points_into_range(b, *
this))
889 this->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
891 this->detachAndGrow(QArrayData::GrowsAtEnd, n,
nullptr,
nullptr);
892 Q_ASSERT(
this->freeSpaceAtEnd() >= n);
894 this->copyAppend(b, b + n);
899 Q_ASSERT(
this->isMutable());
900 Q_ASSERT(!
this->isShared());
901 Q_ASSERT(newSize >
this->size);
902 Q_ASSERT(newSize -
this->size <=
this->freeSpaceAtEnd());
905 T *
const b =
this->begin() +
this->size;
906 T *
const e =
this->begin() + newSize;
907 if constexpr (std::is_constructible_v<T, Qt::Initialization>)
908 std::uninitialized_fill(b, e, Qt::Uninitialized);
910 std::uninitialized_default_construct(b, e);
911 this->size = newSize;
916 template <
typename InputIterator,
typename Projection =
q20::
identity>
917 void assign(InputIterator first, InputIterator last, Projection proj = {})
920 using Category =
typename std::iterator_traits<InputIterator>::iterator_category;
921 constexpr bool IsFwdIt =
std::is_convertible_v<Category,
std::forward_iterator_tag>;
923 const qsizetype n = IsFwdIt ?
std::distance(first, last) : 0;
924 bool undoPrependOptimization =
true;
925 bool needCapacity = n >
this->constAllocatedCapacity();
926 if (needCapacity ||
this->needsDetach()) {
927 qsizetype newCapacity =
this->detachCapacity(n);
928 bool wasLastRef = !
this->deref();
929 if (wasLastRef && needCapacity) {
932 Data::deallocate(
this->d);
934 if (!needCapacity && wasLastRef) {
936 this->d->ref_.storeRelaxed(1);
939 std::tie(
this->d,
this->ptr) = Data::allocate(newCapacity);
941 undoPrependOptimization =
false;
945 if constexpr (!std::is_nothrow_constructible_v<T,
decltype(std::invoke(proj, *first))>
946 || !std::is_nothrow_invocable_v<Projection,
decltype(*first)>)
951 if (undoPrependOptimization) {
953 this->setBegin(Data::dataStart(
this->d,
alignof(
typename Data::AlignmentDummy)));
954 undoPrependOptimization =
false;
958 const auto dend =
this->end();
959 T *dst =
this->begin();
960 T *capacityBegin = dst;
961 if (undoPrependOptimization) {
962 capacityBegin = Data::dataStart(
this->d,
alignof(
typename Data::AlignmentDummy));
963 this->setBegin(capacityBegin);
966 assign_impl(first, last, capacityBegin, dst, dend, proj, Category{});
969 template <
typename InputIterator,
typename Projection>
970 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
971 Projection proj,
std::input_iterator_tag)
973 if (qsizetype offset = dst - capacityBegin) {
974 T *prependBufferEnd = dst;
983 if (dst == prependBufferEnd) {
984 this->size += offset;
989 std::destroy(prependBufferEnd, dend);
990 this->size = dst -
this->begin();
994 q20::construct_at(dst, std::invoke(proj, *first));
1000 if (first == last) {
1001 std::destroy(dst, dend);
1006 this->emplace(
this->size, std::invoke(proj, *first));
1007 }
while (++first != last);
1010 *dst = std::invoke(proj, *first);
1014 this->size = dst -
this->begin();
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)
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) {
1028 std::copy(first, last, capacityBegin);
1039 while (first != last && capacityBegin != dst) {
1040 q20::construct_at(capacityBegin, std::invoke(proj, *first));
1046 while (first != last && dst != dend) {
1047 *dst = std::invoke(proj, *first);
1053 while (first != last) {
1054 q20::construct_at(dst, std::invoke(proj, *first));
1060 std::destroy(dst, dend);
QGenericArrayOps< T > Type
void appendUninitialized(qsizetype newSize)
void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend, Projection proj, std::input_iterator_tag)
QCommonArrayOps< T > Self
void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend, Projection proj, std::forward_iterator_tag)
void assign(InputIterator first, InputIterator last, Projection proj={})
void appendIteratorRange(It b, It e, QtPrivate::IfIsForwardIterator< It >=true)
void growAppend(const T *b, const T *e)
qsizetype sourceCopyConstruct
QArrayDataPointer< T > * data
qsizetype sourceCopyAssign
void truncate(size_t newSize)
void insert(qsizetype i, qsizetype n, parameter_type t)
QArrayDataPointer< T >::parameter_type parameter_type
void moveAppend(T *b, T *e)
QTypedArrayData< T > Data
void emplace(qsizetype i, Args &&... args)
void copyAppend(const T *b, const T *e)
void eraseFirst() noexcept
void eraseLast() noexcept
void assign(T *b, T *e, parameter_type t)
void erase(T *b, qsizetype n)
void insert(qsizetype i, const T *data, qsizetype n)
void copyAppend(qsizetype n, parameter_type t)
QArrayDataPointer< T > *const data
QTypedArrayData< T > Data
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
void insert(qsizetype i, const T *data, qsizetype n)
void emplace(qsizetype i, Args &&... args)
QGenericArrayOps< T >::parameter_type parameter_type
void erase(T *b, qsizetype n)
void insert(qsizetype i, qsizetype n, parameter_type t)
void moveAppend(T *b, T *e) noexcept
void eraseFirst() noexcept
QArrayDataPointer< T >::parameter_type parameter_type
void copyRanges(std::initializer_list< Span > ranges)
void erase(T *b, qsizetype n)
void eraseLast() noexcept
T * createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
void insert(qsizetype i, const T *data, qsizetype n)
void truncate(size_t newSize) noexcept
void emplace(qsizetype i, Args &&... args)
qsizetype eraseIf(Predicate pred)
void assign(T *b, T *e, parameter_type t) noexcept
void copyAppend(const T *b, const T *e) noexcept
void copyAppend(qsizetype n, parameter_type t) noexcept
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
void insert(qsizetype i, qsizetype n, parameter_type t)
QTypedArrayData< T > Data
void destroyAll() noexcept