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;
30 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
51 Q_ASSERT(that()->isMutable() || b == e);
52 Q_ASSERT(!that()->isShared() || b == e);
54 Q_ASSERT((e - b) <= that()->freeSpaceAtEnd());
59 ::memcpy(
static_cast<
void *>(that()->end()),
static_cast<
const void *>(b), (e - b) *
sizeof(T));
60 that()->size += (e - b);
65 Q_ASSERT(!that()->isShared() || n == 0);
66 Q_ASSERT(that()->freeSpaceAtEnd() >= n);
70 T *where = that()->end();
71 that()->size += qsizetype(n);
83 Q_ASSERT(that()->isMutable());
84 Q_ASSERT(!that()->isShared());
85 Q_ASSERT(newSize <= size_t(that()->size));
87 that()->size = qsizetype(newSize);
93 Q_ASSERT(that()->d->ref_.loadRelaxed() == 0);
99 T *
createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
101 Q_ASSERT((pos == QArrayData::GrowsAtBeginning && n <= that()->freeSpaceAtBegin()) ||
102 (pos == QArrayData::GrowsAtEnd && n <= that()->freeSpaceAtEnd()));
104 T *insertionPoint = that()->ptr + where;
105 if (pos == QArrayData::GrowsAtEnd) {
106 if (where < that()->size)
107 ::memmove(
static_cast<
void *>(insertionPoint + n),
static_cast<
void *>(insertionPoint), (that()->size - where) *
sizeof(T));
109 Q_ASSERT(where == 0);
114 return insertionPoint;
117 void insert(qsizetype i,
const T *data, qsizetype n)
119 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
120 if (that()->size != 0 && i == 0)
121 pos = Data::GrowsAtBeginning;
124 that()->detachAndGrow(pos, n, &data, &oldData);
125 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
126 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
128 T *where = createHole(pos, i, n);
129 ::memcpy(
static_cast<
void *>(where),
static_cast<
const void *>(data), n *
sizeof(T));
136 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
137 if (that()->size != 0 && i == 0)
138 pos = Data::GrowsAtBeginning;
140 that()->detachAndGrow(pos, n,
nullptr,
nullptr);
141 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
142 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
144 T *where = createHole(pos, i, n);
149 template<
typename... Args>
152 bool detach = that()->needsDetach();
154 if (i == that()->size && that()->freeSpaceAtEnd()) {
155 new (that()->end()) T(std::forward<Args>(args)...);
159 if (i == 0 && that()->freeSpaceAtBegin()) {
160 new (that()->begin() - 1) T(std::forward<Args>(args)...);
166 T tmp(
std::forward<Args>(args)...);
167 typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
168 if (that()->size != 0 && i == 0)
169 pos = QArrayData::GrowsAtBeginning;
171 that()->detachAndGrow(pos, 1,
nullptr,
nullptr);
173 T *where = createHole(pos, i, 1);
174 new (where) T(
std::move(tmp));
180 Q_ASSERT(that()->isMutable());
182 Q_ASSERT(b >= that()->begin() && b < that()->end());
183 Q_ASSERT(e > that()->begin() && e <= that()->end());
189 if (b == that()->begin() && e != that()->end()) {
191 }
else if (e != that()->end()) {
192 ::memmove(
static_cast<
void *>(b),
static_cast<
void *>(e),
193 (
static_cast<T *>(that()->end()) - e) *
sizeof(T));
200 Q_ASSERT(that()->isMutable());
201 Q_ASSERT(that()->size);
208 Q_ASSERT(that()->isMutable());
209 Q_ASSERT(that()->size);
213 template <
typename Predicate>
216 qsizetype result = 0;
217 if (that()->size == 0)
220 if (!that()->needsDetach()) {
221 auto end = that()->end();
222 auto it = std::remove_if(that()->begin(), end, pred);
224 result =
std::distance(it, end);
228 const auto begin = that()->begin();
229 const auto end = that()->end();
230 auto it = std::find_if(begin, end, pred);
234 QArrayDataPointer<T> other(that()->size);
235 Q_CHECK_PTR(other.data());
236 auto dest = other.begin();
238 dest = std::uninitialized_copy(begin, it, dest);
239 dest = q_uninitialized_remove_copy_if(
std::next(it), end, dest, pred);
240 other.size = std::distance(other.data(), dest);
241 result = that()->size - other.size;
251 auto it = that()->begin();
252 std::for_each(ranges.begin(), ranges.end(), [&it](
const auto &span) {
253 it = std::copy(span.begin, span.end, it);
255 that()->size = std::distance(that()->begin(), it);
261 Q_ASSERT(b >= that()->begin() && e <= that()->end());
264 ::memcpy(
static_cast<
void *>(b++),
static_cast<
const void *>(&t),
sizeof(T));
267 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
269 auto pair = Data::reallocateUnaligned(that()->d, that()->ptr, alloc, option);
270 Q_CHECK_PTR(pair.ptr);
271 Q_ASSERT(pair.header !=
nullptr);
272 that()->d = pair.header;
273 that()->ptr = pair.ptr;
280 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
301 Q_ASSERT(that()->isMutable() || b == e);
302 Q_ASSERT(!that()->isShared() || b == e);
304 Q_ASSERT((e - b) <= that()->freeSpaceAtEnd());
309 T *data = that()->begin();
311 new (data + that()->size) T(*b);
319 Q_ASSERT(!that()->isShared() || n == 0);
320 Q_ASSERT(that()->freeSpaceAtEnd() >= n);
324 T *data = that()->begin();
326 new (data + that()->size) T(t);
333 Q_ASSERT(that()->isMutable() || b == e);
334 Q_ASSERT(!that()->isShared() || b == e);
336 Q_ASSERT((e - b) <= that()->freeSpaceAtEnd());
341 T *data = that()->begin();
343 new (data + that()->size) T(std::move(*b));
351 Q_ASSERT(that()->isMutable());
352 Q_ASSERT(!that()->isShared());
353 Q_ASSERT(newSize <= size_t(that()->size));
355 std::destroy(that()->begin() + newSize, that()->end());
356 that()->size = newSize;
365 Q_ASSERT(that()->d->ref_.loadRelaxed() == 0);
367 std::destroy(that()->begin(), that()->end());
497 void insert(qsizetype i,
const T *data, qsizetype n)
499 const bool growsAtBegin = that()->size != 0 && i == 0;
500 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
503 that()->detachAndGrow(pos, n, &data, &oldData);
504 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
505 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
509 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
512 new (that()->begin() - 1) T(data[n]);
517 Inserter{that()}.insert(i, data, n);
526 const bool growsAtBegin = that()->size != 0 && i == 0;
527 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
529 that()->detachAndGrow(pos, n,
nullptr,
nullptr);
530 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
531 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
535 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
537 new (that()->begin() - 1) T(copy);
542 Inserter{that()}.insert(i, copy, n);
546 template<
typename... Args>
549 bool detach = that()->needsDetach();
551 if (i == that()->size && that()->freeSpaceAtEnd()) {
552 new (that()->end()) T(std::forward<Args>(args)...);
556 if (i == 0 && that()->freeSpaceAtBegin()) {
557 new (that()->begin() - 1) T(std::forward<Args>(args)...);
564 T tmp(std::forward<Args>(args)...);
565 const bool growsAtBegin = that()->size != 0 && i == 0;
566 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
568 that()->detachAndGrow(pos, 1,
nullptr,
nullptr);
571 Q_ASSERT(that()->freeSpaceAtBegin());
572 new (that()->begin() - 1) T(std::move(tmp));
576 Inserter{that()}.insertOne(i, std::move(tmp));
583 Q_ASSERT(that()->isMutable());
585 Q_ASSERT(b >= that()->begin() && b < that()->end());
586 Q_ASSERT(e > that()->begin() && e <= that()->end());
592 if (b == that()->begin() && e != that()->end()) {
595 const T *
const end = that()->end();
611 Q_ASSERT(that()->isMutable());
612 Q_ASSERT(that()->size);
613 that()->begin()->~T();
620 Q_ASSERT(that()->isMutable());
621 Q_ASSERT(that()->size);
622 (that()->end() - 1)->~T();
630 Q_ASSERT(b >= that()->begin() && e <= that()->end());
642 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
652 {
return Base::that(); }
654 {
return Base::that(); }
673 explicit Inserter(QArrayDataPointer<T> *d, qsizetype pos, qsizetype n)
723 void insert(qsizetype i,
const T *data, qsizetype n)
725 const bool growsAtBegin = that()->size != 0 && i == 0;
726 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
729 that()->detachAndGrow(pos, n, &data, &oldData);
730 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
731 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
735 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
738 new (that()->begin() - 1) T(data[n]);
743 Inserter{that(), i, n}.insertRange(data, n);
752 const bool growsAtBegin = that()->size != 0 && i == 0;
753 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
755 that()->detachAndGrow(pos, n,
nullptr,
nullptr);
756 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
757 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
761 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
763 new (that()->begin() - 1) T(copy);
768 Inserter{that(), i, n}.insertFill(copy, n);
772 template<
typename... Args>
775 bool detach = that()->needsDetach();
777 if (i == that()->size && that()->freeSpaceAtEnd()) {
778 new (that()->end()) T(std::forward<Args>(args)...);
782 if (i == 0 && that()->freeSpaceAtBegin()) {
783 new (that()->begin() - 1) T(std::forward<Args>(args)...);
790 T tmp(std::forward<Args>(args)...);
791 const bool growsAtBegin = that()->size != 0 && i == 0;
792 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
794 that()->detachAndGrow(pos, 1,
nullptr,
nullptr);
796 Q_ASSERT(that()->freeSpaceAtBegin());
797 new (that()->begin() - 1) T(std::move(tmp));
801 Inserter{that(), i, 1}.insertOne(std::move(tmp));
809 Q_ASSERT(that()->isMutable());
811 Q_ASSERT(b >= that()->begin() && b < that()->end());
812 Q_ASSERT(e > that()->begin() && e <= that()->end());
820 if (b == that()->begin() && e != that()->end()) {
822 }
else if (e != that()->end()) {
823 memmove(
static_cast<
void *>(b),
static_cast<
const void *>(e), (
static_cast<
const T *>(that()->end()) - e)*
sizeof(T));
828 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
830 auto pair = Data::reallocateUnaligned(that()->d, that()->ptr, alloc, option);
831 Q_CHECK_PTR(pair.ptr);
832 Q_ASSERT(pair.header !=
nullptr);
833 that()->d = pair.header;
834 that()->ptr = pair.ptr;
838template <
class T,
class =
void>
877 {
return Base::that(); }
879 {
return Base::that(); }
884 template<
typename It>
887 Q_ASSERT(that()->isMutable() || b == e);
888 Q_ASSERT(!that()->isShared() || b == e);
889 const qsizetype distance =
std::distance(b, e);
890 Q_ASSERT(distance >= 0 && distance <= that()->allocatedCapacity() - that()->size);
893#if __cplusplus
>= 202002L
&& defined(__cpp_concepts) && defined(__cpp_lib_concepts)
894 constexpr bool canUseCopyAppend =
895 std::contiguous_iterator<It> &&
897 std::remove_cv_t<
typename std::iterator_traits<It>::value_type>,
900 if constexpr (canUseCopyAppend) {
901 Base::copyAppend(std::to_address(b), std::to_address(e));
905 T *iter = that()->end();
906 for (; b != e; ++iter, ++b) {
919 const qsizetype n = e - b;
923 if (QtPrivate::q_points_into_range(b, *that()))
924 that()->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
926 that()->detachAndGrow(QArrayData::GrowsAtEnd, n,
nullptr,
nullptr);
927 Q_ASSERT(that()->freeSpaceAtEnd() >= n);
929 Base::copyAppend(b, b + n);
934 Q_ASSERT(that()->isMutable());
935 Q_ASSERT(!that()->isShared());
936 Q_ASSERT(newSize > that()->size);
937 Q_ASSERT(newSize - that()->size <= that()->freeSpaceAtEnd());
940 T *
const b = that()->begin() + that()->size;
941 T *
const e = that()->begin() + newSize;
942 if constexpr (std::is_constructible_v<T, Qt::Initialization>)
943 std::uninitialized_fill(b, e, Qt::Uninitialized);
945 std::uninitialized_default_construct(b, e);
946 that()->size = newSize;
951 template <
typename InputIterator,
typename Projection =
q20::
identity>
952 void assign(InputIterator first, InputIterator last, Projection proj = {})
955 using Category =
typename std::iterator_traits<InputIterator>::iterator_category;
956 constexpr bool IsFwdIt =
std::is_convertible_v<Category,
std::forward_iterator_tag>;
958 const qsizetype n = IsFwdIt ?
std::distance(first, last) : 0;
959 bool undoPrependOptimization =
true;
960 bool needCapacity = n > that()->constAllocatedCapacity();
961 if (needCapacity || that()->needsDetach()) {
962 qsizetype newCapacity = that()->detachCapacity(n);
963 bool wasLastRef = !that()->deref();
964 if (wasLastRef && needCapacity) {
967 Data::deallocate(that()->d);
969 if (!needCapacity && wasLastRef) {
971 that()->d->ref_.storeRelaxed(1);
974 auto [hdr, p] = Data::allocate(newCapacity);
978 undoPrependOptimization =
false;
982 if constexpr (!std::is_nothrow_constructible_v<T,
decltype(std::invoke(proj, *first))>
983 || !std::is_nothrow_invocable_v<Projection,
decltype(*first)>)
988 if (undoPrependOptimization) {
990 that()->setBegin(Data::dataStart(that()->d,
alignof(
typename Data::AlignmentDummy)));
991 undoPrependOptimization =
false;
995 const auto dend = that()->end();
996 T *dst = that()->begin();
997 T *capacityBegin = dst;
998 if (undoPrependOptimization) {
999 capacityBegin = Data::dataStart(that()->d,
alignof(
typename Data::AlignmentDummy));
1000 that()->setBegin(capacityBegin);
1003 assign_impl(first, last, capacityBegin, dst, dend, proj, Category{});
1006 template <
typename InputIterator,
typename Projection>
1007 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
1008 Projection proj,
std::input_iterator_tag)
1010 if (qsizetype offset = dst - capacityBegin) {
1011 T *prependBufferEnd = dst;
1012 dst = capacityBegin;
1020 if (dst == prependBufferEnd) {
1021 that()->size += offset;
1025 if (first == last) {
1026 std::destroy(prependBufferEnd, dend);
1027 that()->size = dst - that()->begin();
1031 q20::construct_at(dst, std::invoke(proj, *first));
1037 if (first == last) {
1038 std::destroy(dst, dend);
1043 Base::emplace(that()->size, std::invoke(proj, *first));
1044 }
while (++first != last);
1047 *dst = std::invoke(proj, *first);
1051 that()->size = dst - that()->begin();
1054 template <
typename InputIterator,
typename Projection>
1055 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
1056 Projection proj,
std::forward_iterator_tag)
1058 constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
1059 const qsizetype n =
std::distance(first, last);
1060 if constexpr (IsIdentity && !QTypeInfo<T>::isComplex) {
1065 std::copy(first, last, capacityBegin);
1076 while (first != last && capacityBegin != dst) {
1077 q20::construct_at(capacityBegin, std::invoke(proj, *first));
1083 while (first != last && dst != dend) {
1084 *dst = std::invoke(proj, *first);
1090 while (first != last) {
1091 q20::construct_at(dst, std::invoke(proj, *first));
1097 std::destroy(dst, dend);
const QArrayDataOps * operator->() const noexcept
QArrayDataOps * operator->() noexcept
QGenericArrayOps< T > Type
const DataPointer * that() const
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
const DataPointer * that() const
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)
QGenericArrayOps(DataPointer &dp)
QArrayDataPointer< T > *const data
QTypedArrayData< T > Data
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
QGenericArrayOps< T > Base
void insert(qsizetype i, const T *data, qsizetype n)
void emplace(qsizetype i, Args &&... args)
QGenericArrayOps< T >::parameter_type parameter_type
const DataPointer * that() const
void erase(T *b, qsizetype n)
void insert(qsizetype i, qsizetype n, parameter_type t)
QMovableArrayOps(DataPointer &dp)
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
const DataPointer * that() const
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)
QPodArrayOps(DataPointer &dp)
QTypedArrayData< T > Data
void destroyAll() noexcept