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);
525 const bool growsAtBegin = that()->size != 0 && i == 0;
526 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
528 that()->detachAndGrow(pos, n,
nullptr,
nullptr);
529 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
530 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
534 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
536 new (that()->begin() - 1) T(copy);
541 Inserter{that()}.insert(i, copy, n);
545 template<
typename... Args>
548 bool detach = that()->needsDetach();
550 if (i == that()->size && that()->freeSpaceAtEnd()) {
551 new (that()->end()) T(std::forward<Args>(args)...);
555 if (i == 0 && that()->freeSpaceAtBegin()) {
556 new (that()->begin() - 1) T(std::forward<Args>(args)...);
562 T tmp(
std::forward<Args>(args)...);
563 const bool growsAtBegin = that()->size != 0 && i == 0;
564 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
566 that()->detachAndGrow(pos, 1,
nullptr,
nullptr);
569 Q_ASSERT(that()->freeSpaceAtBegin());
570 new (that()->begin() - 1) T(std::move(tmp));
574 Inserter{that()}.insertOne(i, std::move(tmp));
581 Q_ASSERT(that()->isMutable());
583 Q_ASSERT(b >= that()->begin() && b < that()->end());
584 Q_ASSERT(e > that()->begin() && e <= that()->end());
590 if (b == that()->begin() && e != that()->end()) {
593 const T *
const end = that()->end();
609 Q_ASSERT(that()->isMutable());
610 Q_ASSERT(that()->size);
611 that()->begin()->~T();
618 Q_ASSERT(that()->isMutable());
619 Q_ASSERT(that()->size);
620 (that()->end() - 1)->~T();
628 Q_ASSERT(b >= that()->begin() && e <= that()->end());
640 static_assert (
std::is_nothrow_destructible_v<T>,
"Types with throwing destructors are not supported in Qt containers.");
650 {
return Base::that(); }
652 {
return Base::that(); }
671 explicit Inserter(QArrayDataPointer<T> *d, qsizetype pos, qsizetype n)
721 void insert(qsizetype i,
const T *data, qsizetype n)
723 const bool growsAtBegin = that()->size != 0 && i == 0;
724 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
727 that()->detachAndGrow(pos, n, &data, &oldData);
728 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
729 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
733 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
736 new (that()->begin() - 1) T(data[n]);
741 Inserter{that(), i, n}.insertRange(data, n);
749 const bool growsAtBegin = that()->size != 0 && i == 0;
750 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
752 that()->detachAndGrow(pos, n,
nullptr,
nullptr);
753 Q_ASSERT((pos == Data::GrowsAtBeginning && that()->freeSpaceAtBegin() >= n) ||
754 (pos == Data::GrowsAtEnd && that()->freeSpaceAtEnd() >= n));
758 Q_ASSERT(that()->freeSpaceAtBegin() >= n);
760 new (that()->begin() - 1) T(copy);
765 Inserter{that(), i, n}.insertFill(copy, n);
769 template<
typename... Args>
772 bool detach = that()->needsDetach();
774 if (i == that()->size && that()->freeSpaceAtEnd()) {
775 new (that()->end()) T(std::forward<Args>(args)...);
779 if (i == 0 && that()->freeSpaceAtBegin()) {
780 new (that()->begin() - 1) T(std::forward<Args>(args)...);
786 T tmp(
std::forward<Args>(args)...);
787 const bool growsAtBegin = that()->size != 0 && i == 0;
788 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
790 that()->detachAndGrow(pos, 1,
nullptr,
nullptr);
792 Q_ASSERT(that()->freeSpaceAtBegin());
793 new (that()->begin() - 1) T(std::move(tmp));
797 Inserter{that(), i, 1}.insertOne(std::move(tmp));
805 Q_ASSERT(that()->isMutable());
807 Q_ASSERT(b >= that()->begin() && b < that()->end());
808 Q_ASSERT(e > that()->begin() && e <= that()->end());
816 if (b == that()->begin() && e != that()->end()) {
818 }
else if (e != that()->end()) {
819 memmove(
static_cast<
void *>(b),
static_cast<
const void *>(e), (
static_cast<
const T *>(that()->end()) - e)*
sizeof(T));
824 void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
826 auto pair = Data::reallocateUnaligned(that()->d, that()->ptr, alloc, option);
827 Q_CHECK_PTR(pair.ptr);
828 Q_ASSERT(pair.header !=
nullptr);
829 that()->d = pair.header;
830 that()->ptr = pair.ptr;
834template <
class T,
class =
void>
873 {
return Base::that(); }
875 {
return Base::that(); }
880 template<
typename It>
883 Q_ASSERT(that()->isMutable() || b == e);
884 Q_ASSERT(!that()->isShared() || b == e);
885 const qsizetype distance =
std::distance(b, e);
886 Q_ASSERT(distance >= 0 && distance <= that()->allocatedCapacity() - that()->size);
889#if __cplusplus
>= 202002L
&& defined(__cpp_concepts) && defined(__cpp_lib_concepts)
890 constexpr bool canUseCopyAppend =
891 std::contiguous_iterator<It> &&
893 std::remove_cv_t<
typename std::iterator_traits<It>::value_type>,
896 if constexpr (canUseCopyAppend) {
897 Base::copyAppend(std::to_address(b), std::to_address(e));
901 T *iter = that()->end();
902 for (; b != e; ++iter, ++b) {
915 const qsizetype n = e - b;
919 if (QtPrivate::q_points_into_range(b, *that()))
920 that()->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
922 that()->detachAndGrow(QArrayData::GrowsAtEnd, n,
nullptr,
nullptr);
923 Q_ASSERT(that()->freeSpaceAtEnd() >= n);
925 Base::copyAppend(b, b + n);
930 Q_ASSERT(that()->isMutable());
931 Q_ASSERT(!that()->isShared());
932 Q_ASSERT(newSize > that()->size);
933 Q_ASSERT(newSize - that()->size <= that()->freeSpaceAtEnd());
936 T *
const b = that()->begin() + that()->size;
937 T *
const e = that()->begin() + newSize;
938 if constexpr (std::is_constructible_v<T, Qt::Initialization>)
939 std::uninitialized_fill(b, e, Qt::Uninitialized);
941 std::uninitialized_default_construct(b, e);
942 that()->size = newSize;
947 template <
typename InputIterator,
typename Projection =
q20::
identity>
948 void assign(InputIterator first, InputIterator last, Projection proj = {})
951 using Category =
typename std::iterator_traits<InputIterator>::iterator_category;
952 constexpr bool IsFwdIt =
std::is_convertible_v<Category,
std::forward_iterator_tag>;
954 const qsizetype n = IsFwdIt ?
std::distance(first, last) : 0;
955 bool undoPrependOptimization =
true;
956 bool needCapacity = n > that()->constAllocatedCapacity();
957 if (needCapacity || that()->needsDetach()) {
958 qsizetype newCapacity = that()->detachCapacity(n);
959 bool wasLastRef = !that()->deref();
960 if (wasLastRef && needCapacity) {
963 Data::deallocate(that()->d);
965 if (!needCapacity && wasLastRef) {
967 that()->d->ref_.storeRelaxed(1);
970 auto [hdr, p] = Data::allocate(newCapacity);
974 undoPrependOptimization =
false;
978 if constexpr (!std::is_nothrow_constructible_v<T,
decltype(std::invoke(proj, *first))>
979 || !std::is_nothrow_invocable_v<Projection,
decltype(*first)>)
984 if (undoPrependOptimization) {
986 that()->setBegin(Data::dataStart(that()->d,
alignof(
typename Data::AlignmentDummy)));
987 undoPrependOptimization =
false;
991 const auto dend = that()->end();
992 T *dst = that()->begin();
993 T *capacityBegin = dst;
994 if (undoPrependOptimization) {
995 capacityBegin = Data::dataStart(that()->d,
alignof(
typename Data::AlignmentDummy));
996 that()->setBegin(capacityBegin);
999 assign_impl(first, last, capacityBegin, dst, dend, proj, Category{});
1002 template <
typename InputIterator,
typename Projection>
1003 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
1004 Projection proj,
std::input_iterator_tag)
1006 if (qsizetype offset = dst - capacityBegin) {
1007 T *prependBufferEnd = dst;
1008 dst = capacityBegin;
1016 if (dst == prependBufferEnd) {
1017 that()->size += offset;
1021 if (first == last) {
1022 std::destroy(prependBufferEnd, dend);
1023 that()->size = dst - that()->begin();
1027 q20::construct_at(dst, std::invoke(proj, *first));
1033 if (first == last) {
1034 std::destroy(dst, dend);
1039 Base::emplace(that()->size, std::invoke(proj, *first));
1040 }
while (++first != last);
1043 *dst = std::invoke(proj, *first);
1047 that()->size = dst - that()->begin();
1050 template <
typename InputIterator,
typename Projection>
1051 void assign_impl(InputIterator first, InputIterator last, T *capacityBegin, T *dst, T *dend,
1052 Projection proj,
std::forward_iterator_tag)
1054 constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
1055 const qsizetype n =
std::distance(first, last);
1056 if constexpr (IsIdentity && !QTypeInfo<T>::isComplex) {
1061 std::copy(first, last, capacityBegin);
1072 while (first != last && capacityBegin != dst) {
1073 q20::construct_at(capacityBegin, std::invoke(proj, *first));
1079 while (first != last && dst != dend) {
1080 *dst = std::invoke(proj, *first);
1086 while (first != last) {
1087 q20::construct_at(dst, std::invoke(proj, *first));
1093 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