File indexing completed on 2026-11-07 10:27:17
0001
0002
0003
0004
0005 #ifndef QARRAYDATAPOINTER_H
0006 #define QARRAYDATAPOINTER_H
0007
0008 #include <QtCore/qarraydataops.h>
0009 #include <QtCore/qcontainertools_impl.h>
0010
0011 QT_BEGIN_NAMESPACE
0012
0013 template <class T>
0014 struct QArrayDataPointer
0015 {
0016 private:
0017 typedef QTypedArrayData<T> Data;
0018 typedef QArrayDataOps<T> DataOps;
0019
0020 public:
0021 enum {
0022 pass_parameter_by_value = std::disjunction_v<
0023 std::is_arithmetic<T>,
0024 std::is_pointer<T>,
0025 std::is_enum<T>
0026 >,
0027 };
0028
0029 typedef typename std::conditional<pass_parameter_by_value, T, const T &>::type parameter_type;
0030
0031 Q_NODISCARD_CTOR
0032 constexpr QArrayDataPointer() noexcept
0033 : d(nullptr), ptr(nullptr), size(0)
0034 {
0035 }
0036
0037 Q_NODISCARD_CTOR
0038 QArrayDataPointer(const QArrayDataPointer &other) noexcept
0039 : d(other.d), ptr(other.ptr), size(other.size)
0040 {
0041 ref();
0042 }
0043
0044 Q_NODISCARD_CTOR
0045 constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0) noexcept
0046 : d(header), ptr(adata), size(n)
0047 {
0048 }
0049
0050 Q_NODISCARD_CTOR
0051 explicit QArrayDataPointer(QTypedArrayAllocationResult<T> adata, qsizetype n = 0) noexcept
0052 : d(adata.header), ptr(adata.ptr), size(n)
0053 {
0054 }
0055
0056 Q_NODISCARD_CTOR explicit
0057 QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
0058 QArrayData::AllocationOption option = QArrayData::KeepSize)
0059 : QArrayDataPointer(Data::allocate(alloc, option), n)
0060 {
0061 }
0062
0063 Q_NODISCARD_CTOR
0064 static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
0065 {
0066 Q_ASSERT(rawData || !length);
0067 return { nullptr, const_cast<T *>(rawData), length };
0068 }
0069
0070 QArrayDataPointer &operator=(const QArrayDataPointer &other) noexcept
0071 {
0072 QArrayDataPointer tmp(other);
0073 this->swap(tmp);
0074 return *this;
0075 }
0076
0077 Q_NODISCARD_CTOR
0078 QArrayDataPointer(QArrayDataPointer &&other) noexcept
0079 : d(std::exchange(other.d, nullptr)),
0080 ptr(std::exchange(other.ptr, nullptr)),
0081 size(std::exchange(other.size, 0))
0082 {
0083 }
0084
0085 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
0086
0087 DataOps operator*() noexcept
0088 {
0089 return DataOps(*this);
0090 }
0091
0092 DataOps operator->() noexcept
0093 {
0094 return DataOps(*this);
0095 }
0096
0097 ~QArrayDataPointer()
0098 {
0099 if (!deref()) {
0100 (*this)->destroyAll();
0101 Data::deallocate(d);
0102 }
0103 }
0104
0105 constexpr bool isNull() const noexcept
0106 {
0107 return !ptr;
0108 }
0109
0110 T *data() noexcept { return ptr; }
0111 const T *data() const noexcept { return ptr; }
0112
0113 T *begin() noexcept { return data(); }
0114 T *end() noexcept { return data() + size; }
0115 const T *begin() const noexcept { return data(); }
0116 const T *end() const noexcept { return data() + size; }
0117 const T *constBegin() const noexcept { return data(); }
0118 const T *constEnd() const noexcept { return data() + size; }
0119
0120 void swap(QArrayDataPointer &other) noexcept
0121 {
0122 qt_ptr_swap(d, other.d);
0123 qt_ptr_swap(ptr, other.ptr);
0124 std::swap(size, other.size);
0125 }
0126
0127 void clear() noexcept(std::is_nothrow_destructible<T>::value)
0128 {
0129 QArrayDataPointer tmp;
0130 swap(tmp);
0131 }
0132
0133 void detach(QArrayDataPointer *old = nullptr)
0134 {
0135 if (needsDetach())
0136 reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 template <typename X> QArrayDataPointer<X> reinterpreted() &&
0151 {
0152 if (sizeof(T) != sizeof(X)) {
0153 Q_ASSERT(!d->isShared());
0154 d->alloc = d->alloc * sizeof(T) / sizeof(X);
0155 }
0156 auto od = reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d, nullptr));
0157 auto optr = reinterpret_cast<X *>(std::exchange(ptr, nullptr));
0158 return { od, optr, std::exchange(size, 0) };
0159 }
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, const T **data,
0185 QArrayDataPointer *old)
0186 {
0187 const bool detach = needsDetach();
0188 bool readjusted = false;
0189 if (!detach) {
0190 if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
0191 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
0192 return;
0193 readjusted = tryReadjustFreeSpace(where, n, data);
0194 Q_ASSERT(!readjusted
0195 || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
0196 || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
0197 }
0198
0199 if (!readjusted)
0200 reallocateAndGrow(where, n, old);
0201 }
0202
0203
0204
0205
0206
0207
0208
0209 Q_NEVER_INLINE void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
0210 QArrayDataPointer *old = nullptr)
0211 {
0212 if constexpr (QTypeInfo<T>::isRelocatable && alignof(T) <= alignof(std::max_align_t)) {
0213 if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
0214 (*this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow);
0215 return;
0216 }
0217 }
0218
0219 QArrayDataPointer dp(allocateGrow(*this, n, where));
0220 if (n > 0)
0221 Q_CHECK_PTR(dp.data());
0222 if (where == QArrayData::GrowsAtBeginning) {
0223 Q_ASSERT(dp.freeSpaceAtBegin() >= n);
0224 } else {
0225 Q_ASSERT(dp.freeSpaceAtEnd() >= n);
0226 }
0227 if (size) {
0228 qsizetype toCopy = size;
0229 if (n < 0)
0230 toCopy += n;
0231 if (needsDetach() || old)
0232 dp->copyAppend(begin(), begin() + toCopy);
0233 else
0234 dp->moveAppend(begin(), begin() + toCopy);
0235 Q_ASSERT(dp.size == toCopy);
0236 }
0237
0238 swap(dp);
0239 if (old)
0240 old->swap(dp);
0241 }
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260 bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n, const T **data = nullptr)
0261 {
0262 Q_ASSERT(!this->needsDetach());
0263 Q_ASSERT(n > 0);
0264 Q_ASSERT((pos == QArrayData::GrowsAtEnd && this->freeSpaceAtEnd() < n)
0265 || (pos == QArrayData::GrowsAtBeginning && this->freeSpaceAtBegin() < n));
0266
0267 const qsizetype capacity = this->constAllocatedCapacity();
0268 const qsizetype freeAtBegin = this->freeSpaceAtBegin();
0269 const qsizetype freeAtEnd = this->freeSpaceAtEnd();
0270
0271 qsizetype dataStartOffset = 0;
0272
0273
0274
0275
0276
0277
0278
0279
0280 if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
0281 && ((3 * this->size) < (2 * capacity))) {
0282
0283 } else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
0284 && ((3 * this->size) < capacity)) {
0285
0286 dataStartOffset = n + qMax(0, (capacity - this->size - n) / 2);
0287 } else {
0288
0289 return false;
0290 }
0291
0292 relocate(dataStartOffset - freeAtBegin, data);
0293
0294 Q_ASSERT((pos == QArrayData::GrowsAtEnd && this->freeSpaceAtEnd() >= n)
0295 || (pos == QArrayData::GrowsAtBeginning && this->freeSpaceAtBegin() >= n));
0296 return true;
0297 }
0298
0299
0300
0301
0302
0303
0304 void relocate(qsizetype offset, const T **data = nullptr)
0305 {
0306 T *res = this->ptr + offset;
0307 QtPrivate::q_relocate_overlap_n(this->ptr, this->size, res);
0308
0309 if (data && QtPrivate::q_points_into_range(*data, *this))
0310 *data += offset;
0311 this->ptr = res;
0312 }
0313
0314 QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
0315 {
0316 QArrayDataPointer result(n);
0317 std::uninitialized_copy_n(begin() + pos, n, result.begin());
0318 result.size = n;
0319 return result;
0320 }
0321
0322 QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
0323 {
0324 if (needsDetach())
0325 return sliced(pos, n);
0326 T *newBeginning = begin() + pos;
0327 std::destroy(begin(), newBeginning);
0328 std::destroy(newBeginning + n, end());
0329 setBegin(newBeginning);
0330 size = n;
0331 return std::move(*this);
0332 }
0333
0334 void appendInitialize(qsizetype newSize)
0335 {
0336 Q_ASSERT(this->isMutable());
0337 Q_ASSERT(!this->isShared());
0338 Q_ASSERT(newSize > this->size);
0339 Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
0340
0341 T *const b = this->begin() + this->size;
0342 T *const e = this->begin() + newSize;
0343 q17::uninitialized_value_construct(b, e);
0344 this->size = newSize;
0345 }
0346
0347
0348 qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
0349 qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
0350 void ref() noexcept { if (d) d->ref(); }
0351 bool deref() noexcept { return !d || d->deref(); }
0352 bool isMutable() const noexcept { return d; }
0353 bool isShared() const noexcept { return !d || d->isShared(); }
0354 bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; }
0355 bool needsDetach() const noexcept { return !d || d->needsDetach(); }
0356 qsizetype detachCapacity(qsizetype newSize) const noexcept { return d ? d->detachCapacity(newSize) : newSize; }
0357 const typename Data::ArrayOptions flags() const noexcept { return d ? d->flags : Data::ArrayOptionDefault; }
0358 void setFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags |= f; }
0359 void clearFlag(typename Data::ArrayOptions f) noexcept { if (d) d->flags &= ~f; }
0360
0361 Data *d_ptr() noexcept { return d; }
0362 void setBegin(T *begin) noexcept { ptr = begin; }
0363
0364 qsizetype freeSpaceAtBegin() const noexcept
0365 {
0366 if (d == nullptr)
0367 return 0;
0368 return this->ptr - Data::dataStart(d, alignof(typename Data::AlignmentDummy));
0369 }
0370
0371 qsizetype freeSpaceAtEnd() const noexcept
0372 {
0373 if (d == nullptr)
0374 return 0;
0375 return d->constAllocatedCapacity() - freeSpaceAtBegin() - this->size;
0376 }
0377
0378
0379 static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
0380 {
0381
0382
0383
0384
0385 qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
0386
0387
0388 minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
0389 qsizetype capacity = from.detachCapacity(minimalCapacity);
0390 const bool grows = capacity > from.constAllocatedCapacity();
0391 auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
0392 const bool valid = header != nullptr && dataPtr != nullptr;
0393 if (!valid)
0394 return QArrayDataPointer(header, dataPtr);
0395
0396
0397
0398 dataPtr += (position == QArrayData::GrowsAtBeginning)
0399 ? n + qMax(0, (header->alloc - from.size - n) / 2)
0400 : from.freeSpaceAtBegin();
0401 header->flags = from.flags();
0402 return QArrayDataPointer(header, dataPtr);
0403 }
0404
0405 friend bool operator==(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
0406 {
0407 return lhs.data() == rhs.data() && lhs.size == rhs.size;
0408 }
0409
0410 friend bool operator!=(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
0411 {
0412 return lhs.data() != rhs.data() || lhs.size != rhs.size;
0413 }
0414
0415 Data *d;
0416 T *ptr;
0417 qsizetype size;
0418 };
0419
0420 template <class T>
0421 inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
0422 {
0423 p1.swap(p2);
0424 }
0425
0426
0427
0428
0429
0430
0431
0432
0433 #define Q_ARRAY_LITERAL(Type, ...) \
0434 ([]() -> QArrayDataPointer<Type> { \
0435 static Type const data[] = { __VA_ARGS__ }; \
0436 return QArrayDataPointer<Type>::fromRawData(const_cast<Type *>(data), std::size(data)); \
0437 }())
0438
0439
0440 QT_END_NAMESPACE
0441
0442 #endif