summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qarraydatapointer.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qarraydatapointer.h')
-rw-r--r--src/corelib/tools/qarraydatapointer.h487
1 files changed, 358 insertions, 129 deletions
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index ad5acdb7fd..6657d40cf9 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QARRAYDATAPOINTER_H
#define QARRAYDATAPOINTER_H
@@ -43,6 +7,9 @@
#include <QtCore/qarraydataops.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/q20functional.h>
+#include <QtCore/q20memory.h>
+
QT_BEGIN_NAMESPACE
template <class T>
@@ -53,33 +20,46 @@ private:
typedef QArrayDataOps<T> DataOps;
public:
- typedef typename Data::iterator iterator;
- typedef typename Data::const_iterator const_iterator;
- enum { pass_parameter_by_value = std::is_fundamental<T>::value || std::is_pointer<T>::value };
+ enum {
+ pass_parameter_by_value =
+ std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_enum<T>::value
+ };
typedef typename std::conditional<pass_parameter_by_value, T, const T &>::type parameter_type;
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer() noexcept
: d(nullptr), ptr(nullptr), size(0)
{
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(const QArrayDataPointer &other) noexcept
: d(other.d), ptr(other.ptr), size(other.size)
{
ref();
}
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0) noexcept
: d(header), ptr(adata), size(n)
{
}
- explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
+ Q_NODISCARD_CTOR
+ explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
: d(adata.first), ptr(adata.second), size(n)
{
}
+ Q_NODISCARD_CTOR explicit
+ QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
+ QArrayData::AllocationOption option = QArrayData::KeepSize)
+ : QArrayDataPointer(Data::allocate(alloc, option), n)
+ {
+ }
+
+ Q_NODISCARD_CTOR
static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
{
Q_ASSERT(rawData || !length);
@@ -93,20 +73,15 @@ public:
return *this;
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(QArrayDataPointer &&other) noexcept
- : d(other.d), ptr(other.ptr), size(other.size)
+ : d(std::exchange(other.d, nullptr)),
+ ptr(std::exchange(other.ptr, nullptr)),
+ size(std::exchange(other.size, 0))
{
- other.d = nullptr;
- other.ptr = nullptr;
- other.size = 0;
}
- QArrayDataPointer &operator=(QArrayDataPointer &&other) noexcept
- {
- QArrayDataPointer moved(std::move(other));
- swap(moved);
- return *this;
- }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
DataOps &operator*() noexcept
{
@@ -132,7 +107,7 @@ public:
{
if (!deref()) {
(*this)->destroyAll();
- Data::deallocate(d);
+ free(d);
}
}
@@ -144,18 +119,18 @@ public:
T *data() noexcept { return ptr; }
const T *data() const noexcept { return ptr; }
- iterator begin(iterator = iterator()) noexcept { return data(); }
- iterator end(iterator = iterator()) noexcept { return data() + size; }
- const_iterator begin(const_iterator = const_iterator()) const noexcept { return data(); }
- const_iterator end(const_iterator = const_iterator()) const noexcept { return data() + size; }
- const_iterator constBegin(const_iterator = const_iterator()) const noexcept { return data(); }
- const_iterator constEnd(const_iterator = const_iterator()) const noexcept { return data() + size; }
+ T *begin() noexcept { return data(); }
+ T *end() noexcept { return data() + size; }
+ const T *begin() const noexcept { return data(); }
+ const T *end() const noexcept { return data() + size; }
+ const T *constBegin() const noexcept { return data(); }
+ const T *constEnd() const noexcept { return data() + size; }
void swap(QArrayDataPointer &other) noexcept
{
- qSwap(d, other.d);
- qSwap(ptr, other.ptr);
- qSwap(size, other.size);
+ qt_ptr_swap(d, other.d);
+ qt_ptr_swap(ptr, other.ptr);
+ std::swap(size, other.size);
}
void clear() noexcept(std::is_nothrow_destructible<T>::value)
@@ -164,33 +139,312 @@ public:
swap(tmp);
}
- bool detach()
+ void detach(QArrayDataPointer *old = nullptr)
+ {
+ if (needsDetach())
+ reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
+ }
+
+ /*! \internal
+
+ Reinterprets the data of this QArrayDataPointer to type X. It's the
+ caller's responsibility to ensure that the data contents are valid and
+ properly aligned, particularly if T and X are not trivial types (i.e,
+ don't do that). The current size is kept and the allocated capacity is
+ updated to account for the difference in the element type's size.
+
+ This is used in QString::fromLatin1 to perform in-place conversion of
+ QString to QByteArray.
+ */
+ template <typename X> QArrayDataPointer<X> reinterpreted() &&
+ {
+ if (sizeof(T) != sizeof(X)) {
+ Q_ASSERT(!d->isShared());
+ d->alloc = d->alloc * sizeof(T) / sizeof(X);
+ }
+ auto od = reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d, nullptr));
+ auto optr = reinterpret_cast<X *>(std::exchange(ptr, nullptr));
+ return { od, optr, std::exchange(size, 0) };
+ }
+
+ /*! \internal
+
+ Detaches this (optionally) and grows to accommodate the free space for
+ \a n elements at the required side. The side is determined from \a pos.
+
+ \a data pointer can be provided when the caller knows that \a data
+ points into range [this->begin(), this->end()). In case it is, *data
+ would be updated so that it continues to point to the element it was
+ pointing to before the data move. if \a data does not point into range,
+ one can/should pass \c nullptr.
+
+ Similarly to \a data, \a old, pointer to a default-constructed QADP, can
+ be provided when the caller expects to e.g. copy the data from this to
+ itself:
+ \code
+ QList<T> list(5);
+ qsizetype pos = getArbitraryPos();
+ list.insert(pos, list.begin(), list.end());
+ \endcode
+
+ The default rule would be: \a data and \a old must either both be valid
+ pointers, or both equal to \c nullptr.
+ */
+ void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, const T **data,
+ QArrayDataPointer *old)
+ {
+ const bool detach = needsDetach();
+ bool readjusted = false;
+ if (!detach) {
+ if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
+ || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
+ return;
+ readjusted = tryReadjustFreeSpace(where, n, data);
+ Q_ASSERT(!readjusted
+ || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
+ || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
+ }
+
+ if (!readjusted)
+ reallocateAndGrow(where, n, old);
+ }
+
+ /*! \internal
+
+ Reallocates to accommodate the free space for \a n elements at the
+ required side. The side is determined from \a pos. Might also shrink
+ when n < 0.
+ */
+ Q_NEVER_INLINE void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
+ QArrayDataPointer *old = nullptr)
+ {
+ if constexpr (QTypeInfo<T>::isRelocatable && alignof(T) <= alignof(std::max_align_t)) {
+ if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
+ (*this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow); // fast path
+ return;
+ }
+ }
+
+ QArrayDataPointer dp(allocateGrow(*this, n, where));
+ if (n > 0)
+ Q_CHECK_PTR(dp.data());
+ if (where == QArrayData::GrowsAtBeginning) {
+ Q_ASSERT(dp.freeSpaceAtBegin() >= n);
+ } else {
+ Q_ASSERT(dp.freeSpaceAtEnd() >= n);
+ }
+ if (size) {
+ qsizetype toCopy = size;
+ if (n < 0)
+ toCopy += n;
+ if (needsDetach() || old)
+ dp->copyAppend(begin(), begin() + toCopy);
+ else
+ dp->moveAppend(begin(), begin() + toCopy);
+ Q_ASSERT(dp.size == toCopy);
+ }
+
+ swap(dp);
+ if (old)
+ old->swap(dp);
+ }
+
+ /*! \internal
+
+ Attempts to relocate [begin(), end()) to accommodate the free space for
+ \a n elements at the required side. The side is determined from \a pos.
+
+ Returns \c true if the internal data is moved. Returns \c false when
+ there is no point in moving the data or the move is impossible. If \c
+ false is returned, it is the responsibility of the caller to figure out
+ how to accommodate the free space for \a n elements at \a pos.
+
+ This function expects that certain preconditions are met, e.g. the
+ detach is not needed, n > 0 and so on. This is intentional to reduce the
+ number of if-statements when the caller knows that preconditions would
+ be satisfied.
+
+ \sa reallocateAndGrow
+ */
+ bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n, const T **data = nullptr)
+ {
+ Q_ASSERT(!this->needsDetach());
+ Q_ASSERT(n > 0);
+ Q_ASSERT((pos == QArrayData::GrowsAtEnd && this->freeSpaceAtEnd() < n)
+ || (pos == QArrayData::GrowsAtBeginning && this->freeSpaceAtBegin() < n));
+
+ const qsizetype capacity = this->constAllocatedCapacity();
+ const qsizetype freeAtBegin = this->freeSpaceAtBegin();
+ const qsizetype freeAtEnd = this->freeSpaceAtEnd();
+
+ qsizetype dataStartOffset = 0;
+ // algorithm:
+ // a. GrowsAtEnd: relocate if space at begin AND size < (capacity * 2) / 3
+ // [all goes to free space at end]:
+ // new free space at begin = 0
+ //
+ // b. GrowsAtBeginning: relocate if space at end AND size < capacity / 3
+ // [balance the free space]:
+ // new free space at begin = n + (total free space - n) / 2
+ if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
+ && ((3 * this->size) < (2 * capacity))) {
+ // dataStartOffset = 0; - done in declaration
+ } else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
+ && ((3 * this->size) < capacity)) {
+ // total free space == capacity - size
+ dataStartOffset = n + qMax(0, (capacity - this->size - n) / 2);
+ } else {
+ // nothing to do otherwise
+ return false;
+ }
+
+ relocate(dataStartOffset - freeAtBegin, data);
+
+ Q_ASSERT((pos == QArrayData::GrowsAtEnd && this->freeSpaceAtEnd() >= n)
+ || (pos == QArrayData::GrowsAtBeginning && this->freeSpaceAtBegin() >= n));
+ return true;
+ }
+
+ /*! \internal
+
+ Relocates [begin(), end()) by \a offset and updates \a data if it is not
+ \c nullptr and points into [begin(), end()).
+ */
+ void relocate(qsizetype offset, const T **data = nullptr)
+ {
+ T *res = this->ptr + offset;
+ QtPrivate::q_relocate_overlap_n(this->ptr, this->size, res);
+ // first update data pointer, then this->ptr
+ if (data && QtPrivate::q_points_into_range(*data, *this))
+ *data += offset;
+ this->ptr = res;
+ }
+
+ template <typename InputIterator, typename Projection = q20::identity>
+ void assign(InputIterator first, InputIterator last, Projection proj = {})
{
- if (needsDetach()) {
- QPair<Data *, T *> copy = clone(detachFlags());
- QArrayDataPointer old(d, ptr, size);
- d = copy.first;
- ptr = copy.second;
- return true;
+ // This function only provides the basic exception guarantee.
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag>;
+ constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
+
+ if constexpr (IsFwdIt) {
+ const qsizetype n = std::distance(first, last);
+ if (needsDetach() || n > constAllocatedCapacity()) {
+ QArrayDataPointer allocated(detachCapacity(n));
+ swap(allocated);
+ }
+ } else if (needsDetach()) {
+ QArrayDataPointer allocated(allocatedCapacity());
+ swap(allocated);
+ // We don't want to copy data that we know we'll overwrite
+ }
+
+ auto offset = freeSpaceAtBegin();
+ const auto capacityBegin = begin() - offset;
+ const auto prependBufferEnd = begin();
+
+ if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ // If construction can throw, and we have freeSpaceAtBegin(),
+ // it's easiest to just clear the container and start fresh.
+ // The alternative would be to keep track of two active, disjoint ranges.
+ if (offset) {
+ (*this)->truncate(0);
+ setBegin(capacityBegin);
+ offset = 0;
+ }
}
- return false;
+ auto dst = capacityBegin;
+ const auto dend = end();
+ if (offset) { // avoids dead stores
+ setBegin(capacityBegin); // undo prepend optimization
+
+ // By construction, the following loop is nothrow!
+ // (otherwise, we can't reach here)
+ // Assumes InputIterator operations don't throw.
+ // (but we can't statically assert that, as these operations
+ // have preconditons, so typically aren't noexcept)
+ while (true) {
+ if (dst == prependBufferEnd) { // ran out of prepend buffer space
+ size += offset;
+ // we now have a contiguous buffer, continue with the main loop:
+ break;
+ }
+ if (first == last) { // ran out of elements to assign
+ std::destroy(prependBufferEnd, dend);
+ size = dst - begin();
+ return;
+ }
+ // construct element in prepend buffer
+ q20::construct_at(dst, std::invoke(proj, *first));
+ ++dst;
+ ++first;
+ }
+ }
+
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt && IsIdentity) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else if constexpr (IsFwdIt && !IsIdentity
+ && std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ for (; first != last; ++dst, ++first) // uninitialized_copy with projection
+ q20::construct_at(dst, std::invoke(proj, *first));
+ break;
+ } else {
+ do {
+ (*this)->emplace(size, std::invoke(proj, *first));
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = std::invoke(proj, *first); // overwrite existing element
+ ++dst;
+ ++first;
+ }
+ size = dst - begin();
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
+ {
+ QArrayDataPointer result(n);
+ std::uninitialized_copy_n(begin() + pos, n, result.begin());
+ result.size = n;
+ return result;
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
+ {
+ if (needsDetach())
+ return sliced(pos, n);
+ T *newBeginning = begin() + pos;
+ std::destroy(begin(), newBeginning);
+ std::destroy(newBeginning + n, end());
+ setBegin(newBeginning);
+ size = n;
+ return std::move(*this);
}
// forwards from QArrayData
- size_t allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
- size_t constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
+ qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
+ qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
void ref() noexcept { if (d) d->ref(); }
bool deref() noexcept { return !d || d->deref(); }
bool isMutable() const noexcept { return d; }
bool isShared() const noexcept { return !d || d->isShared(); }
bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; }
bool needsDetach() const noexcept { return !d || d->needsDetach(); }
- size_t detachCapacity(size_t newSize) const noexcept { return d ? d->detachCapacity(newSize) : newSize; }
- const typename Data::ArrayOptions flags() const noexcept { return d ? typename Data::ArrayOption(d->flags) : Data::DefaultAllocationFlags; }
+ qsizetype detachCapacity(qsizetype newSize) const noexcept { return d ? d->detachCapacity(newSize) : newSize; }
+ const typename Data::ArrayOptions flags() const noexcept { return d ? d->flags : Data::ArrayOptionDefault; }
void setFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags |= f; }
- void clearFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags &= ~f; }
- typename Data::ArrayOptions detachFlags() const noexcept { return d ? d->detachFlags() : Data::DefaultAllocationFlags; }
+ void clearFlag(typename Data::ArrayOptions f) noexcept { if (d) d->flags &= ~f; }
Data *d_ptr() noexcept { return d; }
void setBegin(T *begin) noexcept { ptr = begin; }
@@ -209,75 +463,50 @@ public:
return d->constAllocatedCapacity() - freeSpaceAtBegin() - this->size;
}
- static QArrayDataPointer allocateGrow(const QArrayDataPointer &from,
- qsizetype newSize, QArrayData::ArrayOptions options)
+ // allocate and grow. Ensure that at the minimum requiredSpace is available at the requested end
+ static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
{
- return allocateGrow(from, from.detachCapacity(newSize), newSize, options);
- }
-
- static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype capacity,
- qsizetype newSize, QArrayData::ArrayOptions options)
- {
- auto [header, dataPtr] = Data::allocate(capacity, options);
+ // calculate new capacity. We keep the free capacity at the side that does not have to grow
+ // to avoid quadratic behavior with mixed append/prepend cases
+
+ // use qMax below, because constAllocatedCapacity() can be 0 when using fromRawData()
+ qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
+ // subtract the free space at the side we want to allocate. This ensures that the total size requested is
+ // the existing allocation at the other side + size + n.
+ minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
+ qsizetype capacity = from.detachCapacity(minimalCapacity);
+ const bool grows = capacity > from.constAllocatedCapacity();
+ auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
const bool valid = header != nullptr && dataPtr != nullptr;
- const bool grows = (options & (Data::GrowsForward | Data::GrowsBackwards));
- if (!valid || !grows)
+ if (!valid)
return QArrayDataPointer(header, dataPtr);
- // when growing, special rules apply to memory layout
-
- if (from.needsDetach()) {
- // When detaching: the free space reservation is biased towards
- // append as in Qt5 QList. If we're growing backwards, put the data
- // in the middle instead of at the end - assuming that prepend is
- // uncommon and even initial prepend will eventually be followed by
- // at least some appends.
- if (options & Data::GrowsBackwards)
- dataPtr += (header->alloc - newSize) / 2;
- } else {
- // When not detaching: fake ::realloc() policy - preserve existing
- // free space at beginning.
- dataPtr += from.freeSpaceAtBegin();
- }
+ // Idea: * when growing backwards, adjust pointer to prepare free space at the beginning
+ // * when growing forward, adjust by the previous data pointer offset
+ dataPtr += (position == QArrayData::GrowsAtBeginning)
+ ? n + qMax(0, (header->alloc - from.size - n) / 2)
+ : from.freeSpaceAtBegin();
+ header->flags = from.flags();
return QArrayDataPointer(header, dataPtr);
}
-private:
- Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const
+ friend bool operator==(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
{
- QPair<Data *, T *> pair = Data::allocate(detachCapacity(size), options);
- QArrayDataPointer copy(pair.first, pair.second, 0);
- if (size)
- copy->copyAppend(begin(), end());
-
- pair.first = copy.d;
- copy.d = nullptr;
- copy.ptr = nullptr;
- return pair;
+ return lhs.data() == rhs.data() && lhs.size == rhs.size;
+ }
+
+ friend bool operator!=(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
+ {
+ return lhs.data() != rhs.data() || lhs.size != rhs.size;
}
-protected:
Data *d;
T *ptr;
-
-public:
qsizetype size;
};
template <class T>
-inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) noexcept
-{
- return lhs.data() == rhs.data() && lhs.size == rhs.size;
-}
-
-template <class T>
-inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) noexcept
-{
- return lhs.data() != rhs.data() || lhs.size != rhs.size;
-}
-
-template <class T>
-inline void qSwap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
+inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
{
p1.swap(p2);
}