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()
noexcept
30 : d(
nullptr), ptr(
nullptr), size(0)
35 QArrayDataPointer(
const QArrayDataPointer &other)
noexcept
36 : d(other.d), ptr(other.ptr), size(other.size)
42 constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0)
noexcept
43 : d(header), ptr(adata), size(n)
48 explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0)
noexcept
49 : d(adata.first), ptr(adata.second), size(n)
53 Q_NODISCARD_CTOR
explicit
54 QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
55 QArrayData::AllocationOption option = QArrayData::KeepSize)
56 : QArrayDataPointer(Data::allocate(alloc, option), n)
61 static QArrayDataPointer fromRawData(
const T *rawData, qsizetype length)
noexcept
63 Q_ASSERT(rawData || !length);
64 return {
nullptr,
const_cast<T *>(rawData), length };
67 QArrayDataPointer &operator=(
const QArrayDataPointer &other)
noexcept
69 QArrayDataPointer tmp(other);
75 QArrayDataPointer(QArrayDataPointer &&other)
noexcept
76 : d(std::exchange(other.d,
nullptr)),
77 ptr(std::exchange(other.ptr,
nullptr)),
78 size(std::exchange(other.size, 0))
82 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
84 DataOps &operator*()
noexcept
86 return *
static_cast<DataOps *>(
this);
89 DataOps *operator->()
noexcept
91 return static_cast<DataOps *>(
this);
94 const DataOps &operator*()
const noexcept
96 return *
static_cast<
const DataOps *>(
this);
99 const DataOps *operator->()
const noexcept
101 return static_cast<
const DataOps *>(
this);
107 (*
this)->destroyAll();
112 constexpr bool isNull()
const noexcept
117 T *data()
noexcept {
return ptr; }
118 const T *data()
const noexcept {
return ptr; }
120 T *begin()
noexcept {
return data(); }
121 T *end()
noexcept {
return data() + size; }
122 const T *begin()
const noexcept {
return data(); }
123 const T *end()
const noexcept {
return data() + size; }
124 const T *constBegin()
const noexcept {
return data(); }
125 const T *constEnd()
const noexcept {
return data() + size; }
127 void swap(QArrayDataPointer &other)
noexcept
129 qt_ptr_swap(d, other.d);
130 qt_ptr_swap(ptr, other.ptr);
131 std::swap(size, other.size);
134 void clear()
noexcept(std::is_nothrow_destructible<T>::value)
136 QArrayDataPointer tmp;
140 void detach(QArrayDataPointer *old =
nullptr)
143 reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
147
148
149
150
151
152
153
154
155
156
157 template <
typename X> QArrayDataPointer<X> reinterpreted() &&
159 if (
sizeof(T) !=
sizeof(X)) {
160 Q_ASSERT(!d->isShared());
161 d->alloc = d->alloc *
sizeof(T) /
sizeof(X);
163 auto od =
reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d,
nullptr));
164 auto optr =
reinterpret_cast<X *>(std::exchange(ptr,
nullptr));
165 return { od, optr, std::exchange(size, 0) };
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191 void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n,
const T **data,
192 QArrayDataPointer *old)
194 const bool detach = needsDetach();
195 bool readjusted =
false;
197 if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
198 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
200 readjusted = tryReadjustFreeSpace(where, n, data);
202 || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
203 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
207 reallocateAndGrow(where, n, old);
211
212
213
214
215
216 Q_NEVER_INLINE
void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
217 QArrayDataPointer *old =
nullptr)
219 if constexpr (QTypeInfo<T>::isRelocatable &&
alignof(T) <=
alignof(std::max_align_t)) {
220 if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
221 (*
this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow);
226 QArrayDataPointer dp(allocateGrow(*
this, n, where));
228 Q_CHECK_PTR(dp.data());
229 if (where == QArrayData::GrowsAtBeginning) {
230 Q_ASSERT(dp.freeSpaceAtBegin() >= n);
232 Q_ASSERT(dp.freeSpaceAtEnd() >= n);
235 qsizetype toCopy = size;
238 if (needsDetach() || old)
239 dp->copyAppend(begin(), begin() + toCopy);
241 dp->moveAppend(begin(), begin() + toCopy);
242 Q_ASSERT(dp.size == toCopy);
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n,
const T **data =
nullptr)
269 Q_ASSERT(!
this->needsDetach());
271 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() < n)
272 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() < n));
274 const qsizetype capacity =
this->constAllocatedCapacity();
275 const qsizetype freeAtBegin =
this->freeSpaceAtBegin();
276 const qsizetype freeAtEnd =
this->freeSpaceAtEnd();
278 qsizetype dataStartOffset = 0;
287 if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
288 && ((3 *
this->size) < (2 * capacity))) {
290 }
else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
291 && ((3 *
this->size) < capacity)) {
293 dataStartOffset = n + qMax(0, (capacity -
this->size - n) / 2);
299 relocate(dataStartOffset - freeAtBegin, data);
301 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n)
302 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n));
307
308
309
310
311 void relocate(qsizetype offset,
const T **data =
nullptr)
313 T *res =
this->ptr + offset;
314 QtPrivate::q_relocate_overlap_n(
this->ptr,
this->size, res);
316 if (data && QtPrivate::q_points_into_range(*data, *
this))
321 QArrayDataPointer sliced(qsizetype pos, qsizetype n)
const &
323 QArrayDataPointer result(n);
324 std::uninitialized_copy_n(begin() + pos, n, result.begin());
329 QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
332 return sliced(pos, n);
333 T *newBeginning = begin() + pos;
334 std::destroy(begin(), newBeginning);
335 std::destroy(newBeginning + n, end());
336 setBegin(newBeginning);
338 return std::move(*
this);
341 void appendInitialize(qsizetype newSize)
343 Q_ASSERT(
this->isMutable());
344 Q_ASSERT(!
this->isShared());
345 Q_ASSERT(newSize >
this->size);
346 Q_ASSERT(newSize -
this->size <=
this->freeSpaceAtEnd());
348 T *
const b =
this->begin() +
this->size;
349 T *
const e =
this->begin() + newSize;
350 q17::uninitialized_value_construct(b, e);
351 this->size = newSize;
355 qsizetype allocatedCapacity()
noexcept {
return d ? d->allocatedCapacity() : 0; }
356 qsizetype constAllocatedCapacity()
const noexcept {
return d ? d->constAllocatedCapacity() : 0; }
357 void ref()
noexcept {
if (d) d->ref(); }
358 bool deref()
noexcept {
return !d || d->deref(); }
359 bool isMutable()
const noexcept {
return d; }
360 bool isShared()
const noexcept {
return !d || d->isShared(); }
361 bool isSharedWith(
const QArrayDataPointer &other)
const noexcept {
return d && d == other.d; }
362 bool needsDetach()
const noexcept {
return !d || d->needsDetach(); }
363 qsizetype detachCapacity(qsizetype newSize)
const noexcept {
return d ? d->detachCapacity(newSize) : newSize; }
364 const typename Data::ArrayOptions flags()
const noexcept {
return d ? d->flags : Data::ArrayOptionDefault; }
365 void setFlag(
typename Data::ArrayOptions f)
noexcept { Q_ASSERT(d); d->flags |= f; }
366 void clearFlag(
typename Data::ArrayOptions f)
noexcept {
if (d) d->flags &= ~f; }
368 Data *d_ptr()
noexcept {
return d; }
369 void setBegin(T *begin)
noexcept { ptr = begin; }
371 qsizetype freeSpaceAtBegin()
const noexcept
375 return this->ptr - Data::dataStart(d,
alignof(
typename Data::AlignmentDummy));
378 qsizetype freeSpaceAtEnd()
const noexcept
382 return d->constAllocatedCapacity() - freeSpaceAtBegin() -
this->size;
386 static QArrayDataPointer allocateGrow(
const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
392 qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
395 minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
396 qsizetype capacity = from.detachCapacity(minimalCapacity);
397 const bool grows = capacity > from.constAllocatedCapacity();
398 auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
399 const bool valid = header !=
nullptr && dataPtr !=
nullptr;
401 return QArrayDataPointer(header, dataPtr);
405 dataPtr += (position == QArrayData::GrowsAtBeginning)
406 ? n + qMax(0, (header->alloc - from.size - n) / 2)
407 : from.freeSpaceAtBegin();
408 header->flags = from.flags();
409 return QArrayDataPointer(header, dataPtr);
412 friend bool operator==(
const QArrayDataPointer &lhs,
const QArrayDataPointer &rhs)
noexcept
414 return lhs.data() == rhs.data() && lhs.size == rhs.size;
417 friend bool operator!=(
const QArrayDataPointer &lhs,
const QArrayDataPointer &rhs)
noexcept
419 return lhs.data() != rhs.data() || lhs.size != rhs.size;