28 typedef typename std::conditional<pass_parameter_by_value, T,
const T &>::type parameter_type;
56 QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
57 QArrayData::AllocationOption option = QArrayData::KeepSize)
58 : QArrayDataPointer(Data::allocate(alloc, option), n)
63 static QArrayDataPointer fromRawData(
const T *rawData, qsizetype length)
noexcept
65 Q_ASSERT(rawData || !length);
66 return {
nullptr,
const_cast<T *>(rawData), length };
77 QArrayDataPointer(QArrayDataPointer &&other)
noexcept
78 : d(std::exchange(other.d,
nullptr)),
79 ptr(std::exchange(other.ptr,
nullptr)),
80 size(std::exchange(other.size, 0))
159 template <
typename X> QArrayDataPointer<X> reinterpreted() &&
161 if (
sizeof(T) !=
sizeof(X)) {
162 Q_ASSERT(!d->isShared());
163 d->alloc = d->alloc *
sizeof(T) /
sizeof(X);
165 auto od =
reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d,
nullptr));
166 auto optr =
reinterpret_cast<X *>(std::exchange(ptr,
nullptr));
167 return { od, optr, std::exchange(size, 0) };
193 void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n,
const T **data,
194 QArrayDataPointer *old)
196 const bool detach = needsDetach();
197 bool readjusted =
false;
199 if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
200 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
202 readjusted = tryReadjustFreeSpace(where, n, data);
204 || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
205 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
209 reallocateAndGrow(where, n, old);
218 Q_NEVER_INLINE
void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
219 QArrayDataPointer *old =
nullptr)
221 if constexpr (QTypeInfo<T>::isRelocatable &&
alignof(T) <=
alignof(std::max_align_t)) {
222 if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
223 (*
this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow);
228 QArrayDataPointer dp(allocateGrow(*
this, n, where));
230 Q_CHECK_PTR(dp.data());
231 if (where == QArrayData::GrowsAtBeginning) {
232 Q_ASSERT(dp.freeSpaceAtBegin() >= n);
234 Q_ASSERT(dp.freeSpaceAtEnd() >= n);
237 qsizetype toCopy = size;
240 if (needsDetach() || old)
241 dp->copyAppend(begin(), begin() + toCopy);
243 dp->moveAppend(begin(), begin() + toCopy);
244 Q_ASSERT(dp.size == toCopy);
269 bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n,
const T **data =
nullptr)
271 Q_ASSERT(!
this->needsDetach());
273 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() < n)
274 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() < n));
276 const qsizetype capacity =
this->constAllocatedCapacity();
277 const qsizetype freeAtBegin =
this->freeSpaceAtBegin();
278 const qsizetype freeAtEnd =
this->freeSpaceAtEnd();
280 qsizetype dataStartOffset = 0;
289 if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
290 && ((3 *
this->size) < (2 * capacity))) {
292 }
else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
293 && ((3 *
this->size) < capacity)) {
295 dataStartOffset = n + qMax(0, (capacity -
this->size - n) / 2);
301 relocate(dataStartOffset - freeAtBegin, data);
303 Q_ASSERT((pos == QArrayData::GrowsAtEnd &&
this->freeSpaceAtEnd() >= n)
304 || (pos == QArrayData::GrowsAtBeginning &&
this->freeSpaceAtBegin() >= n));
324 void assign(InputIterator first, InputIterator last, Projection proj = {})
327 constexpr bool IsFwdIt = std::is_convertible_v<
328 typename std::iterator_traits<InputIterator>::iterator_category,
329 std::forward_iterator_tag>;
330 constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
332 if constexpr (IsFwdIt) {
333 const qsizetype n = std::distance(first, last);
334 if (needsDetach() || n > constAllocatedCapacity()) {
335 QArrayDataPointer allocated(detachCapacity(n));
338 }
else if (needsDetach()) {
339 QArrayDataPointer allocated(allocatedCapacity());
344 auto offset = freeSpaceAtBegin();
345 const auto capacityBegin = begin() - offset;
346 const auto prependBufferEnd = begin();
348 if constexpr (!std::is_nothrow_constructible_v<T,
decltype(std::invoke(proj, *first))>) {
353 (*
this)->truncate(0);
354 setBegin(capacityBegin);
359 auto dst = capacityBegin;
360 const auto dend = end();
362 setBegin(capacityBegin);
370 if (dst == prependBufferEnd) {
376 std::destroy(prependBufferEnd, dend);
377 size = dst - begin();
381 q20::construct_at(dst, std::invoke(proj, *first));
389 std::destroy(dst, dend);
393 if constexpr (IsFwdIt && IsIdentity) {
394 dst = std::uninitialized_copy(first, last, dst);
396 }
else if constexpr (IsFwdIt && !IsIdentity
397 && std::is_nothrow_constructible_v<T,
decltype(std::invoke(proj, *first))>) {
398 for (; first != last; ++dst, ++first)
399 q20::construct_at(dst, std::invoke(proj, *first));
403 (*
this)->emplace(size, std::invoke(proj, *first));
404 }
while (++first != last);
408 *dst = std::invoke(proj, *first);
412 size = dst - begin();
415 QArrayDataPointer sliced(qsizetype pos, qsizetype n)
const &
417 QArrayDataPointer result(n);
418 std::uninitialized_copy_n(begin() + pos, n, result.begin());
423 QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
426 return sliced(pos, n);
427 T *newBeginning = begin() + pos;
428 std::destroy(begin(), newBeginning);
429 std::destroy(newBeginning + n, end());
430 setBegin(newBeginning);
432 return std::move(*
this);
480 static QArrayDataPointer allocateGrow(
const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
486 qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
489 minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
490 qsizetype capacity = from.detachCapacity(minimalCapacity);
491 const bool grows = capacity > from.constAllocatedCapacity();
492 auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
493 const bool valid = header !=
nullptr && dataPtr !=
nullptr;
495 return QArrayDataPointer(header, dataPtr);
499 dataPtr += (position == QArrayData::GrowsAtBeginning)
500 ? n + qMax(0, (header->alloc - from.size - n) / 2)
501 : from.freeSpaceAtBegin();
502 header->flags = from.flags();
503 return QArrayDataPointer(header, dataPtr);