14struct QArrayDataPointer
17 typedef QTypedArrayData<T> Data;
18 typedef QArrayDataOps<T> DataOps;
22 pass_parameter_by_value =
23 std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_enum<T>::value
26 typedef typename std::conditional<pass_parameter_by_value, T,
const T &>::type parameter_type;
29 constexpr QArrayDataPointer() =
default;
32 QArrayDataPointer(
const QArrayDataPointer &other)
noexcept
33 : QArrayDataPointer(other.d, other.ptr, other.size)
39 constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0)
noexcept
40#if QT_VERSION >= QT_VERSION_CHECK(7
, 0
, 0
) || defined(QT_BOOTSTRAPPED)
41 : ptr(adata), size(n), d(header)
43 : d(header), ptr(adata), size(n)
49 explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0)
noexcept
50 : QArrayDataPointer(adata.first, adata.second, n)
54 Q_NODISCARD_CTOR
explicit
55 QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
56 QArrayData::AllocationOption option = QArrayData::KeepSize)
57 : QArrayDataPointer(Data::allocate(alloc, option), n)
62 static QArrayDataPointer fromRawData(
const T *rawData, qsizetype length)
noexcept
64 Q_ASSERT(rawData || !length);
65 return {
nullptr,
const_cast<T *>(rawData), length };
68 QArrayDataPointer &operator=(
const QArrayDataPointer &other)
noexcept
70 QArrayDataPointer tmp(other);
76 QArrayDataPointer(QArrayDataPointer &&other)
noexcept
77 : QArrayDataPointer(std::exchange(other.d,
nullptr),
78 std::exchange(other.ptr,
nullptr),
79 std::exchange(other.size, 0))
83 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
85 DataOps &operator*()
noexcept
87 return *
static_cast<DataOps *>(
this);
90 DataOps *operator->()
noexcept
92 return static_cast<DataOps *>(
this);
95 const DataOps &operator*()
const noexcept
97 return *
static_cast<
const DataOps *>(
this);
100 const DataOps *operator->()
const noexcept
102 return static_cast<
const DataOps *>(
this);
108 (*
this)->destroyAll();
113 constexpr bool isNull()
const noexcept
118 T *data()
noexcept {
return ptr; }
119 const T *data()
const noexcept {
return ptr; }
121 T *begin()
noexcept {
return data(); }
122 T *end()
noexcept {
return data() + size; }
123 const T *begin()
const noexcept {
return data(); }
124 const T *end()
const noexcept {
return data() + size; }
125 const T *constBegin()
const noexcept {
return data(); }
126 const T *constEnd()
const noexcept {
return data() + size; }
128 void swap(QArrayDataPointer &other)
noexcept
130 qt_ptr_swap(d, other.d);
131 qt_ptr_swap(ptr, other.ptr);
132 std::swap(size, other.size);
135 void clear()
noexcept(std::is_nothrow_destructible<T>::value)
137 QArrayDataPointer tmp;
141 void detach(QArrayDataPointer *old =
nullptr)
144 reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
148
149
150
151
152
153
154
155
156
157
158 template <
typename X> QArrayDataPointer<X> reinterpreted() &&
160 if (
sizeof(T) !=
sizeof(X)) {
161 Q_ASSERT(!d->isShared());
162 d->alloc = d->alloc *
sizeof(T) /
sizeof(X);
164 auto od =
reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d,
nullptr));
165 auto optr =
reinterpret_cast<X *>(std::exchange(ptr,
nullptr));
166 return { od, optr, std::exchange(size, 0) };
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n,
const T **data,
193 QArrayDataPointer *old)
195 const bool detach = needsDetach();
196 bool readjusted =
false;
198 if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
199 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
201 readjusted = tryReadjustFreeSpace(where, n, data);
203 || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
204 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
208 reallocateAndGrow(where, n, old);
212
213
214
215
216
217 Q_NEVER_INLINE
void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
218 QArrayDataPointer *old =
nullptr)
220 if constexpr (QTypeInfo<T>::isRelocatable &&
alignof(T) <=
alignof(std::max_align_t)) {
221 if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
222 (*
this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow);
227 QArrayDataPointer dp(allocateGrow(*
this, n, where));
229 Q_CHECK_PTR(dp.data());
230 if (where == QArrayData::GrowsAtBeginning) {
231 Q_ASSERT(dp.freeSpaceAtBegin() >= n);
233 Q_ASSERT(dp.freeSpaceAtEnd() >= n);
236 qsizetype toCopy = size;
239 if (needsDetach() || old)
240 dp->copyAppend(begin(), begin() + toCopy);
242 dp->moveAppend(begin(), begin() + toCopy);
243 Q_ASSERT(dp.size == toCopy);
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n,
const T **data =
nullptr)
270 Q_ASSERT(!
this->needsDetach());
272 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() < n)
273 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() < n));
275 const qsizetype capacity =
this->constAllocatedCapacity();
276 const qsizetype freeAtBegin =
this->freeSpaceAtBegin();
277 const qsizetype freeAtEnd =
this->freeSpaceAtEnd();
279 qsizetype dataStartOffset = 0;
288 if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
289 && ((3 *
this->size) < (2 * capacity))) {
291 }
else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
292 && ((3 *
this->size) < capacity)) {
294 dataStartOffset = n + qMax(0, (capacity -
this->size - n) / 2);
300 relocate(dataStartOffset - freeAtBegin, data);
302 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n)
303 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n));
308
309
310
311
312 void relocate(qsizetype offset,
const T **data =
nullptr)
314 T *res =
this->ptr + offset;
315 QtPrivate::q_relocate_overlap_n(
this->ptr,
this->size, res);
317 if (data && QtPrivate::q_points_into_range(*data, *
this))
322 QArrayDataPointer sliced(qsizetype pos, qsizetype n)
const &
324 QArrayDataPointer result(n);
325 std::uninitialized_copy_n(begin() + pos, n, result.begin());
330 QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
333 return sliced(pos, n);
334 T *newBeginning = begin() + pos;
335 std::destroy(begin(), newBeginning);
336 std::destroy(newBeginning + n, end());
337 setBegin(newBeginning);
339 return std::move(*
this);
342 void appendInitialize(qsizetype newSize)
344 Q_ASSERT(
this->isMutable());
345 Q_ASSERT(!
this->isShared());
346 Q_ASSERT(newSize >
this->size);
347 Q_ASSERT(newSize -
this->size <=
this->freeSpaceAtEnd());
349 T *
const b =
this->begin() +
this->size;
350 T *
const e =
this->begin() + newSize;
351 q17::uninitialized_value_construct(b, e);
352 this->size = newSize;
356 qsizetype allocatedCapacity()
noexcept {
return d ? d->allocatedCapacity() : 0; }
357 qsizetype constAllocatedCapacity()
const noexcept {
return d ? d->constAllocatedCapacity() : 0; }
358 void ref()
noexcept {
if (d) d->ref(); }
359 bool deref()
noexcept {
return !d || d->deref(); }
360 bool isMutable()
const noexcept {
return d; }
361 bool isShared()
const noexcept {
return !d || d->isShared(); }
362 bool isSharedWith(
const QArrayDataPointer &other)
const noexcept {
return d && d == other.d; }
363 bool needsDetach()
const noexcept {
return !d || d->needsDetach(); }
364 qsizetype detachCapacity(qsizetype newSize)
const noexcept {
return d ? d->detachCapacity(newSize) : newSize; }
365 const typename Data::ArrayOptions flags()
const noexcept {
return d ? d->flags : Data::ArrayOptionDefault; }
366 void setFlag(
typename Data::ArrayOptions f)
noexcept { Q_ASSERT(d); d->flags |= f; }
367 void clearFlag(
typename Data::ArrayOptions f)
noexcept {
if (d) d->flags &= ~f; }
369 Data *d_ptr()
noexcept {
return d; }
370 void setBegin(T *begin)
noexcept { ptr = begin; }
372 qsizetype freeSpaceAtBegin()
const noexcept
376 return this->ptr - Data::dataStart(d,
alignof(
typename Data::AlignmentDummy));
379 qsizetype freeSpaceAtEnd()
const noexcept
383 return d->constAllocatedCapacity() - freeSpaceAtBegin() -
this->size;
387 static QArrayDataPointer allocateGrow(
const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
393 qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
396 minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
397 qsizetype capacity = from.detachCapacity(minimalCapacity);
398 const bool grows = capacity > from.constAllocatedCapacity();
399 auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
400 const bool valid = header !=
nullptr && dataPtr !=
nullptr;
402 return QArrayDataPointer(header, dataPtr);
406 dataPtr += (position == QArrayData::GrowsAtBeginning)
407 ? n + qMax(0, (header->alloc - from.size - n) / 2)
408 : from.freeSpaceAtBegin();
409 header->flags = from.flags();
410 return QArrayDataPointer(header, dataPtr);
413 friend bool operator==(
const QArrayDataPointer &lhs,
const QArrayDataPointer &rhs)
noexcept
415 return lhs.data() == rhs.data() && lhs.size == rhs.size;
418 friend bool operator!=(
const QArrayDataPointer &lhs,
const QArrayDataPointer &rhs)
noexcept
420 return lhs.data() != rhs.data() || lhs.size != rhs.size;
423#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
) && !defined(QT_BOOTSTRAPPED)
428#if QT_VERSION >= QT_VERSION_CHECK(7
, 0
, 0
) || defined(QT_BOOTSTRAPPED)