13struct QArrayDataPointer
16 typedef QTypedArrayData<T> Data;
17 typedef QArrayDataOps<T> DataOps;
21 pass_parameter_by_value =
22 std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_enum<T>::value
25 typedef typename std::conditional<pass_parameter_by_value, T,
const T &>::type parameter_type;
28 constexpr QArrayDataPointer()
noexcept
29 : d(
nullptr), ptr(
nullptr), size(0)
34 QArrayDataPointer(
const QArrayDataPointer &other)
noexcept
35 : d(other.d), ptr(other.ptr), size(other.size)
41 constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0)
noexcept
42 : d(header), ptr(adata), size(n)
47 explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0)
noexcept
48 : d(adata.first), ptr(adata.second), size(n)
52 Q_NODISCARD_CTOR
explicit
53 QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
54 QArrayData::AllocationOption option = QArrayData::KeepSize)
55 : QArrayDataPointer(Data::allocate(alloc, option), n)
60 static QArrayDataPointer fromRawData(
const T *rawData, qsizetype length)
noexcept
62 Q_ASSERT(rawData || !length);
63 return {
nullptr,
const_cast<T *>(rawData), length };
66 QArrayDataPointer &operator=(
const QArrayDataPointer &other)
noexcept
68 QArrayDataPointer tmp(other);
74 QArrayDataPointer(QArrayDataPointer &&other)
noexcept
75 : d(std::exchange(other.d,
nullptr)),
76 ptr(std::exchange(other.ptr,
nullptr)),
77 size(std::exchange(other.size, 0))
81 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
83 DataOps &operator*()
noexcept
85 return *
static_cast<DataOps *>(
this);
88 DataOps *operator->()
noexcept
90 return static_cast<DataOps *>(
this);
93 const DataOps &operator*()
const noexcept
95 return *
static_cast<
const DataOps *>(
this);
98 const DataOps *operator->()
const noexcept
100 return static_cast<
const DataOps *>(
this);
106 (*
this)->destroyAll();
111 constexpr bool isNull()
const noexcept
116 T *data()
noexcept {
return ptr; }
117 const T *data()
const noexcept {
return ptr; }
119 T *begin()
noexcept {
return data(); }
120 T *end()
noexcept {
return data() + size; }
121 const T *begin()
const noexcept {
return data(); }
122 const T *end()
const noexcept {
return data() + size; }
123 const T *constBegin()
const noexcept {
return data(); }
124 const T *constEnd()
const noexcept {
return data() + size; }
126 void swap(QArrayDataPointer &other)
noexcept
128 qt_ptr_swap(d, other.d);
129 qt_ptr_swap(ptr, other.ptr);
130 std::swap(size, other.size);
133 void clear()
noexcept(std::is_nothrow_destructible<T>::value)
135 QArrayDataPointer tmp;
139 void detach(QArrayDataPointer *old =
nullptr)
142 reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
146
147
148
149
150
151
152
153
154
155
156 template <
typename X> QArrayDataPointer<X> reinterpreted() &&
158 if (
sizeof(T) !=
sizeof(X)) {
159 Q_ASSERT(!d->isShared());
160 d->alloc = d->alloc *
sizeof(T) /
sizeof(X);
162 auto od =
reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d,
nullptr));
163 auto optr =
reinterpret_cast<X *>(std::exchange(ptr,
nullptr));
164 return { od, optr, std::exchange(size, 0) };
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n,
const T **data,
191 QArrayDataPointer *old)
193 const bool detach = needsDetach();
194 bool readjusted =
false;
196 if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
197 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
199 readjusted = tryReadjustFreeSpace(where, n, data);
201 || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
202 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
206 reallocateAndGrow(where, n, old);
210
211
212
213
214
215 Q_NEVER_INLINE
void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
216 QArrayDataPointer *old =
nullptr)
218 if constexpr (QTypeInfo<T>::isRelocatable &&
alignof(T) <=
alignof(std::max_align_t)) {
219 if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
220 (*
this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow);
225 QArrayDataPointer dp(allocateGrow(*
this, n, where));
227 Q_CHECK_PTR(dp.data());
228 if (where == QArrayData::GrowsAtBeginning) {
229 Q_ASSERT(dp.freeSpaceAtBegin() >= n);
231 Q_ASSERT(dp.freeSpaceAtEnd() >= n);
234 qsizetype toCopy = size;
237 if (needsDetach() || old)
238 dp->copyAppend(begin(), begin() + toCopy);
240 dp->moveAppend(begin(), begin() + toCopy);
241 Q_ASSERT(dp.size == toCopy);
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266 bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n,
const T **data =
nullptr)
268 Q_ASSERT(!
this->needsDetach());
270 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() < n)
271 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() < n));
273 const qsizetype capacity =
this->constAllocatedCapacity();
274 const qsizetype freeAtBegin =
this->freeSpaceAtBegin();
275 const qsizetype freeAtEnd =
this->freeSpaceAtEnd();
277 qsizetype dataStartOffset = 0;
286 if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
287 && ((3 *
this->size) < (2 * capacity))) {
289 }
else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
290 && ((3 *
this->size) < capacity)) {
292 dataStartOffset = n + qMax(0, (capacity -
this->size - n) / 2);
298 relocate(dataStartOffset - freeAtBegin, data);
300 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n)
301 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n));
306
307
308
309
310 void relocate(qsizetype offset,
const T **data =
nullptr)
312 T *res =
this->ptr + offset;
313 QtPrivate::q_relocate_overlap_n(
this->ptr,
this->size, res);
315 if (data && QtPrivate::q_points_into_range(*data, *
this))
320 QArrayDataPointer sliced(qsizetype pos, qsizetype n)
const &
322 QArrayDataPointer result(n);
323 std::uninitialized_copy_n(begin() + pos, n, result.begin());
328 QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
331 return sliced(pos, n);
332 T *newBeginning = begin() + pos;
333 std::destroy(begin(), newBeginning);
334 std::destroy(newBeginning + n, end());
335 setBegin(newBeginning);
337 return std::move(*
this);
340 void appendInitialize(qsizetype newSize)
342 Q_ASSERT(
this->isMutable());
343 Q_ASSERT(!
this->isShared());
344 Q_ASSERT(newSize >
this->size);
345 Q_ASSERT(newSize -
this->size <=
this->freeSpaceAtEnd());
347 T *
const b =
this->begin() +
this->size;
348 T *
const e =
this->begin() + newSize;
349 q17::uninitialized_value_construct(b, e);
350 this->size = newSize;
354 qsizetype allocatedCapacity()
noexcept {
return d ? d->allocatedCapacity() : 0; }
355 qsizetype constAllocatedCapacity()
const noexcept {
return d ? d->constAllocatedCapacity() : 0; }
356 void ref()
noexcept {
if (d) d->ref(); }
357 bool deref()
noexcept {
return !d || d->deref(); }
358 bool isMutable()
const noexcept {
return d; }
359 bool isShared()
const noexcept {
return !d || d->isShared(); }
360 bool isSharedWith(
const QArrayDataPointer &other)
const noexcept {
return d && d == other.d; }
361 bool needsDetach()
const noexcept {
return !d || d->needsDetach(); }
362 qsizetype detachCapacity(qsizetype newSize)
const noexcept {
return d ? d->detachCapacity(newSize) : newSize; }
363 const typename Data::ArrayOptions flags()
const noexcept {
return d ? d->flags : Data::ArrayOptionDefault; }
364 void setFlag(
typename Data::ArrayOptions f)
noexcept { Q_ASSERT(d); d->flags |= f; }
365 void clearFlag(
typename Data::ArrayOptions f)
noexcept {
if (d) d->flags &= ~f; }
367 Data *d_ptr()
noexcept {
return d; }
368 void setBegin(T *begin)
noexcept { ptr = begin; }
370 qsizetype freeSpaceAtBegin()
const noexcept
374 return this->ptr - Data::dataStart(d,
alignof(
typename Data::AlignmentDummy));
377 qsizetype freeSpaceAtEnd()
const noexcept
381 return d->constAllocatedCapacity() - freeSpaceAtBegin() -
this->size;
385 static QArrayDataPointer allocateGrow(
const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
391 qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
394 minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
395 qsizetype capacity = from.detachCapacity(minimalCapacity);
396 const bool grows = capacity > from.constAllocatedCapacity();
397 auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
398 const bool valid = header !=
nullptr && dataPtr !=
nullptr;
400 return QArrayDataPointer(header, dataPtr);
404 dataPtr += (position == QArrayData::GrowsAtBeginning)
405 ? n + qMax(0, (header->alloc - from.size - n) / 2)
406 : from.freeSpaceAtBegin();
407 header->flags = from.flags();
408 return QArrayDataPointer(header, dataPtr);
411 friend bool operator==(
const QArrayDataPointer &lhs,
const QArrayDataPointer &rhs)
noexcept
413 return lhs.data() == rhs.data() && lhs.size == rhs.size;
416 friend bool operator!=(
const QArrayDataPointer &lhs,
const QArrayDataPointer &rhs)
noexcept
418 return lhs.data() != rhs.data() || lhs.size != rhs.size;