summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/LICENSE.siphash116
-rw-r--r--src/corelib/tools/qalgorithms.h65
-rw-r--r--src/corelib/tools/qalgorithms.qdoc2
-rw-r--r--src/corelib/tools/qarraydata.cpp111
-rw-r--r--src/corelib/tools/qarraydata.h304
-rw-r--r--src/corelib/tools/qarraydataops.h423
-rw-r--r--src/corelib/tools/qarraydatapointer.h169
-rw-r--r--src/corelib/tools/qbitarray.cpp32
-rw-r--r--src/corelib/tools/qbitarray.h6
-rw-r--r--src/corelib/tools/qcache.h337
-rw-r--r--src/corelib/tools/qcontainerfwd.h7
-rw-r--r--src/corelib/tools/qcontiguouscache.cpp4
-rw-r--r--src/corelib/tools/qcontiguouscache.h314
-rw-r--r--src/corelib/tools/qcryptographichash.cpp100
-rw-r--r--src/corelib/tools/qcryptographichash.h2
-rw-r--r--src/corelib/tools/qeasingcurve.cpp5
-rw-r--r--src/corelib/tools/qeasingcurve.h7
-rw-r--r--src/corelib/tools/qflatmap_p.h983
-rw-r--r--src/corelib/tools/qhash.cpp1963
-rw-r--r--src/corelib/tools/qhash.h2597
-rw-r--r--src/corelib/tools/qhashfunctions.h123
-rw-r--r--src/corelib/tools/qiterator.qdoc163
-rw-r--r--src/corelib/tools/qlinkedlist.cpp1238
-rw-r--r--src/corelib/tools/qlinkedlist.h615
-rw-r--r--src/corelib/tools/qlist.cpp2025
-rw-r--r--src/corelib/tools/qlist.h1154
-rw-r--r--src/corelib/tools/qmap.cpp40
-rw-r--r--src/corelib/tools/qmap.h102
-rw-r--r--src/corelib/tools/qpoint.h1
-rw-r--r--src/corelib/tools/qrefcount.h25
-rw-r--r--src/corelib/tools/qset.h119
-rw-r--r--src/corelib/tools/qset.qdoc2
-rw-r--r--src/corelib/tools/qshareddata.h4
-rw-r--r--src/corelib/tools/qsharedpointer.cpp2
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h2
-rw-r--r--src/corelib/tools/qsimd.cpp718
-rw-r--r--src/corelib/tools/qsimd_p.h396
-rw-r--r--src/corelib/tools/qsimd_x86.cpp116
-rw-r--r--src/corelib/tools/qsimd_x86_p.h222
-rw-r--r--src/corelib/tools/qt_attribution.json15
-rw-r--r--src/corelib/tools/qtaggedpointer.h205
-rw-r--r--src/corelib/tools/qtaggedpointer.qdoc206
-rw-r--r--src/corelib/tools/qvarlengtharray.h177
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc171
-rw-r--r--src/corelib/tools/qvector.h1260
-rw-r--r--src/corelib/tools/qvector.qdoc72
-rw-r--r--src/corelib/tools/qvector_msvc.cpp7
-rw-r--r--src/corelib/tools/qversionnumber.cpp200
-rw-r--r--src/corelib/tools/qversionnumber.h157
-rw-r--r--src/corelib/tools/tools.pri7
50 files changed, 6644 insertions, 10447 deletions
diff --git a/src/corelib/tools/LICENSE.siphash b/src/corelib/tools/LICENSE.siphash
new file mode 100644
index 0000000000..670154e353
--- /dev/null
+++ b/src/corelib/tools/LICENSE.siphash
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+<http://creativecommons.org/publicdomain/zero/1.0/>
diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h
index aa79e0d4a9..838e8472d8 100644
--- a/src/corelib/tools/qalgorithms.h
+++ b/src/corelib/tools/qalgorithms.h
@@ -744,11 +744,9 @@ Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(long un
#endif
#undef QT_POPCOUNT_CONSTEXPR
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint32 v) noexcept
+namespace QtPrivate {
+constexpr inline uint qConstexprCountTrailingZeroBits(quint32 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZ)
- return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 32U;
-#else
// see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
@@ -759,14 +757,17 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint32 v) noexcept
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
-#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint8 v) noexcept
+constexpr inline uint qConstexprCountTrailingZeroBits(quint64 v) noexcept
+{
+ quint32 x = static_cast<quint32>(v);
+ return x ? qConstexprCountTrailingZeroBits(x)
+ : 32 + qConstexprCountTrailingZeroBits(static_cast<quint32>(v >> 32));
+}
+
+constexpr inline uint qConstexprCountTrailingZeroBits(quint8 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZ)
- return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 8U;
-#else
unsigned int c = 8; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
@@ -774,14 +775,10 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint8 v) noexcept
if (v & 0x00000033) c -= 2;
if (v & 0x00000055) c -= 1;
return c;
-#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint16 v) noexcept
+constexpr inline uint qConstexprCountTrailingZeroBits(quint16 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZS)
- return v ? QAlgorithmsPrivate::qt_builtin_ctzs(v) : 16U;
-#else
unsigned int c = 16; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
@@ -790,21 +787,51 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint16 v) noexcept
if (v & 0x00003333) c -= 2;
if (v & 0x00005555) c -= 1;
return c;
+}
+
+constexpr inline uint qConstexprCountTrailingZeroBits(unsigned long v) noexcept
+{
+ return qConstexprCountTrailingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
+}
+}
+
+constexpr inline uint qCountTrailingZeroBits(quint32 v) noexcept
+{
+#if defined(QT_HAS_BUILTIN_CTZ)
+ return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 32U;
+#else
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
+#endif
+}
+
+constexpr inline uint qCountTrailingZeroBits(quint8 v) noexcept
+{
+#if defined(QT_HAS_BUILTIN_CTZ)
+ return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 8U;
+#else
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
+#endif
+}
+
+constexpr inline uint qCountTrailingZeroBits(quint16 v) noexcept
+{
+#if defined(QT_HAS_BUILTIN_CTZS)
+ return v ? QAlgorithmsPrivate::qt_builtin_ctzs(v) : 16U;
+#else
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint64 v) noexcept
+constexpr inline uint qCountTrailingZeroBits(quint64 v) noexcept
{
#if defined(QT_HAS_BUILTIN_CTZLL)
return v ? QAlgorithmsPrivate::qt_builtin_ctzll(v) : 64;
#else
- quint32 x = static_cast<quint32>(v);
- return x ? qCountTrailingZeroBits(x)
- : 32 + qCountTrailingZeroBits(static_cast<quint32>(v >> 32));
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(unsigned long v) noexcept
+constexpr inline uint qCountTrailingZeroBits(unsigned long v) noexcept
{
return qCountTrailingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
}
diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc
index c86e69f9c3..a4a30cc798 100644
--- a/src/corelib/tools/qalgorithms.qdoc
+++ b/src/corelib/tools/qalgorithms.qdoc
@@ -39,7 +39,7 @@
on all items in a given container or in a given range.
You can use these algorithms with any \l {container
class} that provides STL-style iterators, including Qt's QList,
- QLinkedList, QVector, QMap, and QHash classes.
+ QVector, QMap, and QHash classes.
Most algorithms take \l {STL-style iterators} as parameters. The
algorithms are generic in the sense that they aren't bound to a
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 3879b48cbb..497eae1f7f 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -153,18 +153,16 @@ QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
const QArrayData QArrayData::shared_null[2] = {
- { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared null
+ { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }, // shared null
/* zero initialized terminator */};
-static const QArrayData qt_array[3] = {
- { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared empty
- { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, sizeof(QArrayData) }, // unsharable empty
+static const QArrayData emptyNotNullShared[2] = {
+ { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }, // shared empty
/* zero initialized terminator */};
QT_WARNING_POP
-static const QArrayData &qt_array_empty = qt_array[0];
-static const QArrayData &qt_array_unsharable_empty = qt_array[1];
+static const QArrayData &qt_array_empty = emptyNotNullShared[0];
static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
uint options)
@@ -172,7 +170,7 @@ static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, siz
// Calculate the byte size
// allocSize = objectSize * capacity + headerSize, but checked for overflow
// plus padded to grow in size
- if (options & QArrayData::Grow) {
+ if (options & QArrayData::GrowsForward) {
auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
capacity = r.elementCount;
return r.size;
@@ -181,91 +179,104 @@ static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, siz
}
}
+static QArrayData *allocateData(size_t allocSize, uint options)
+{
+ QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
+ if (header) {
+ header->ref_.storeRelaxed(1);
+ header->flags = options;
+ header->alloc = 0;
+ }
+ return header;
+}
+
static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options)
{
header = static_cast<QArrayData *>(::realloc(header, allocSize));
if (header)
- header->capacityReserved = bool(options & QArrayData::CapacityReserved);
+ header->flags = options;
return header;
}
-QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
- size_t capacity, AllocationOptions options) noexcept
+void *QArrayData::allocate(QArrayData **dptr, size_t objectSize, size_t alignment,
+ size_t capacity, ArrayOptions options) noexcept
{
+ Q_ASSERT(dptr);
// Alignment is a power of two
- Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData)
+ Q_ASSERT(alignment >= alignof(QArrayData)
&& !(alignment & (alignment - 1)));
- // Don't allocate empty headers
- if (!(options & RawData) && !capacity) {
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- if (options & Unsharable)
- return const_cast<QArrayData *>(&qt_array_unsharable_empty);
-#endif
- return const_cast<QArrayData *>(&qt_array_empty);
+ if (capacity == 0) {
+ // optimization for empty headers
+ *dptr = const_cast<QArrayData *>(&qt_array_empty);
+ return sharedNullData();
}
size_t headerSize = sizeof(QArrayData);
- // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
- // can properly align the data array. This assumes malloc is able to
- // provide appropriate alignment for the header -- as it should!
- // Padding is skipped when allocating a header for RawData.
- if (!(options & RawData))
- headerSize += (alignment - Q_ALIGNOF(QArrayData));
+ if (alignment > alignof(QArrayData)) {
+ // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
+ // can properly align the data array. This assumes malloc is able to
+ // provide appropriate alignment for the header -- as it should!
+ headerSize += alignment - alignof(QArrayData);
+ }
if (headerSize > size_t(MaxAllocSize))
return nullptr;
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
- QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
+ options |= AllocatedDataType | MutableData;
+ options &= ~ImmutableHeader;
+ QArrayData *header = allocateData(allocSize, options);
+ quintptr data = 0;
if (header) {
- quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
+ // find where offset should point to so that data() is aligned to alignment bytes
+ data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
& ~(alignment - 1);
-
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- header->ref.atomic.storeRelaxed(bool(!(options & Unsharable)));
-#else
- header->ref.atomic.storeRelaxed(1);
-#endif
- header->size = 0;
- header->alloc = capacity;
- header->capacityReserved = bool(options & CapacityReserved);
- header->offset = data - quintptr(header);
+ header->alloc = uint(capacity);
}
+ *dptr = header;
+ return reinterpret_cast<void *>(data);
+}
+
+QArrayData *QArrayData::prepareRawData(ArrayOptions options) Q_DECL_NOTHROW
+{
+ QArrayData *header = allocateData(sizeof(QArrayData), (options & ~DataTypeBits) | RawDataType);
+ if (header)
+ header->alloc = 0;
return header;
}
-QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity,
- AllocationOptions options) noexcept
+QPair<QArrayData *, void *>
+QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
+ size_t objectSize, size_t capacity, ArrayOptions options) noexcept
{
Q_ASSERT(data);
Q_ASSERT(data->isMutable());
- Q_ASSERT(!data->ref.isShared());
+ Q_ASSERT(!data->isShared());
size_t headerSize = sizeof(QArrayData);
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
- QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options));
- if (header)
- header->alloc = capacity;
- return header;
+ qptrdiff offset = reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data);
+ options |= AllocatedDataType | MutableData;
+ QArrayData *header = reallocateData(data, allocSize, options);
+ if (header) {
+ header->alloc = uint(capacity);
+ dataPointer = reinterpret_cast<char *>(header) + offset;
+ }
+ return qMakePair(static_cast<QArrayData *>(header), dataPointer);
}
void QArrayData::deallocate(QArrayData *data, size_t objectSize,
size_t alignment) noexcept
{
// Alignment is a power of two
- Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData)
+ Q_ASSERT(alignment >= alignof(QArrayData)
&& !(alignment & (alignment - 1)));
Q_UNUSED(objectSize) Q_UNUSED(alignment)
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- if (data == &qt_array_unsharable_empty)
- return;
-#endif
-
- Q_ASSERT_X(data == nullptr || !data->ref.isStatic(), "QArrayData::deallocate",
+ Q_ASSERT_X(data == nullptr || !data->isStatic(), "QArrayData::deallocate",
"Static data cannot be deleted");
::free(data);
}
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index dcd95924c1..d996b9c56b 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -40,32 +41,64 @@
#ifndef QARRAYDATA_H
#define QARRAYDATA_H
-#include <QtCore/qrefcount.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qatomic.h>
#include <string.h>
QT_BEGIN_NAMESPACE
+template <class T> struct QTypedArrayData;
+
struct Q_CORE_EXPORT QArrayData
{
- QtPrivate::RefCount ref;
- int size;
- uint alloc : 31;
- uint capacityReserved : 1;
+ enum ArrayOption {
+ RawDataType = 0x0001, //!< this class is really a QArrayData
+ AllocatedDataType = 0x0002, //!< this class is really a QArrayAllocatedData
+ DataTypeBits = 0x000f,
+
+ CapacityReserved = 0x0010, //!< the capacity was reserved by the user, try to keep it
+ GrowsForward = 0x0020, //!< allocate with eyes towards growing through append()
+ GrowsBackwards = 0x0040, //!< allocate with eyes towards growing through prepend()
+ MutableData = 0x0080, //!< the data can be changed; doesn't say anything about the header
+ ImmutableHeader = 0x0100, //!< the header is static, it can't be changed
+
+ /// this option is used by the Q_ARRAY_LITERAL and similar macros
+ StaticDataFlags = RawDataType | ImmutableHeader,
+ /// this option is used by the allocate() function
+ DefaultAllocationFlags = MutableData,
+ /// this option is used by the prepareRawData() function
+ DefaultRawFlags = 0
+ };
+ Q_DECLARE_FLAGS(ArrayOptions, ArrayOption)
+
+ QBasicAtomicInt ref_;
+ uint flags;
+ uint alloc;
+
+ inline size_t allocatedCapacity()
+ {
+ return alloc;
+ }
- qptrdiff offset; // in bytes from beginning of header
+ inline size_t constAllocatedCapacity() const
+ {
+ return alloc;
+ }
- void *data()
+ /// Returns true if sharing took place
+ bool ref()
{
- Q_ASSERT(size == 0
- || offset < 0 || size_t(offset) >= sizeof(QArrayData));
- return reinterpret_cast<char *>(this) + offset;
+ if (!isStatic())
+ ref_.ref();
+ return true;
}
- const void *data() const
+ /// Returns false if deallocation is necessary
+ bool deref()
{
- Q_ASSERT(size == 0
- || offset < 0 || size_t(offset) >= sizeof(QArrayData));
- return reinterpret_cast<const char *>(this) + offset;
+ if (isStatic())
+ return true;
+ return ref_.deref();
}
// This refers to array data mutability, not "header data" represented by
@@ -73,183 +106,140 @@ struct Q_CORE_EXPORT QArrayData
// follow COW principles.
bool isMutable() const
{
- return alloc != 0;
+ return flags & MutableData;
}
- enum AllocationOption {
- CapacityReserved = 0x1,
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- Unsharable = 0x2,
-#endif
- RawData = 0x4,
- Grow = 0x8,
+ bool isStatic() const
+ {
+ return flags & ImmutableHeader;
+ }
- Default = 0
- };
+ bool isShared() const
+ {
+ return ref_.loadRelaxed() != 1;
+ }
- Q_DECLARE_FLAGS(AllocationOptions, AllocationOption)
+ // Returns true if a detach is necessary before modifying the data
+ // This method is intentionally not const: if you want to know whether
+ // detaching is necessary, you should be in a non-const function already
+ bool needsDetach()
+ {
+ // requires two conditionals
+ return !isMutable() || isShared();
+ }
size_t detachCapacity(size_t newSize) const
{
- if (capacityReserved && newSize < alloc)
- return alloc;
+ if (flags & CapacityReserved && newSize < constAllocatedCapacity())
+ return constAllocatedCapacity();
return newSize;
}
- AllocationOptions detachFlags() const
+ ArrayOptions detachFlags() const
{
- AllocationOptions result;
- if (capacityReserved)
+ ArrayOptions result = DefaultAllocationFlags;
+ if (flags & CapacityReserved)
result |= CapacityReserved;
return result;
}
- AllocationOptions cloneFlags() const
+ ArrayOptions cloneFlags() const
{
- AllocationOptions result;
- if (capacityReserved)
+ ArrayOptions result = DefaultAllocationFlags;
+ if (flags & CapacityReserved)
result |= CapacityReserved;
return result;
}
- Q_REQUIRED_RESULT static QArrayData *allocate(size_t objectSize, size_t alignment,
- size_t capacity, AllocationOptions options = Default) noexcept;
+ Q_REQUIRED_RESULT
+#if defined(Q_CC_GNU)
+ __attribute__((__malloc__))
+#endif
+ static void *allocate(QArrayData **pdata, size_t objectSize, size_t alignment,
+ size_t capacity, ArrayOptions options = DefaultAllocationFlags) noexcept;
Q_REQUIRED_RESULT static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,
- size_t newCapacity, AllocationOptions newOptions = Default) noexcept;
+ size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept;
+ Q_REQUIRED_RESULT static QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
+ size_t objectSize, size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) Q_DECL_NOTHROW;
+ Q_REQUIRED_RESULT static QArrayData *prepareRawData(ArrayOptions options = ArrayOptions(RawDataType))
+ Q_DECL_NOTHROW;
static void deallocate(QArrayData *data, size_t objectSize,
size_t alignment) noexcept;
static const QArrayData shared_null[2];
static QArrayData *sharedNull() noexcept { return const_cast<QArrayData*>(shared_null); }
+ static void *sharedNullData()
+ {
+ QArrayData *const null = const_cast<QArrayData *>(&shared_null[1]);
+ return null;
+ }
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocationOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions)
+
+template <class T, size_t N>
+struct QStaticArrayData
+{
+ // static arrays are of type RawDataType
+ QArrayData header;
+ T data[N];
+};
+
+// Support for returning QArrayDataPointer<T> from functions
+template <class T>
+struct QArrayDataPointerRef
+{
+ QTypedArrayData<T> *ptr;
+ T *data;
+ uint size;
+};
template <class T>
struct QTypedArrayData
: QArrayData
{
-#ifdef QT_STRICT_ITERATORS
- class iterator {
- public:
- T *i;
- typedef std::random_access_iterator_tag iterator_category;
- typedef int difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
-
- inline iterator() : i(nullptr) {}
- inline iterator(T *n) : i(n) {}
- inline iterator(const iterator &o): i(o.i){} // #### Qt 6: remove, the implicit version is fine
- inline T &operator*() const { return *i; }
- inline T *operator->() const { return i; }
- inline T &operator[](int j) const { return *(i + j); }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
- inline bool operator<(const iterator& other) const { return i < other.i; }
- inline bool operator<=(const iterator& other) const { return i <= other.i; }
- inline bool operator>(const iterator& other) const { return i > other.i; }
- inline bool operator>=(const iterator& other) const { return i >= other.i; }
- inline iterator &operator++() { ++i; return *this; }
- inline iterator operator++(int) { T *n = i; ++i; return n; }
- inline iterator &operator--() { i--; return *this; }
- inline iterator operator--(int) { T *n = i; i--; return n; }
- inline iterator &operator+=(int j) { i+=j; return *this; }
- inline iterator &operator-=(int j) { i-=j; return *this; }
- inline iterator operator+(int j) const { return iterator(i+j); }
- inline iterator operator-(int j) const { return iterator(i-j); }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
- inline int operator-(iterator j) const { return i - j.i; }
- inline operator T*() const { return i; }
- };
- friend class iterator;
-
- class const_iterator {
- public:
- const T *i;
- typedef std::random_access_iterator_tag iterator_category;
- typedef int difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
-
- inline const_iterator() : i(nullptr) {}
- inline const_iterator(const T *n) : i(n) {}
- inline const_iterator(const const_iterator &o): i(o.i) {} // #### Qt 6: remove, the default version is fine
- inline explicit const_iterator(const iterator &o): i(o.i) {}
- inline const T &operator*() const { return *i; }
- inline const T *operator->() const { return i; }
- inline const T &operator[](int j) const { return *(i + j); }
- inline bool operator==(const const_iterator &o) const { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const { return i != o.i; }
- inline bool operator<(const const_iterator& other) const { return i < other.i; }
- inline bool operator<=(const const_iterator& other) const { return i <= other.i; }
- inline bool operator>(const const_iterator& other) const { return i > other.i; }
- inline bool operator>=(const const_iterator& other) const { return i >= other.i; }
- inline const_iterator &operator++() { ++i; return *this; }
- inline const_iterator operator++(int) { const T *n = i; ++i; return n; }
- inline const_iterator &operator--() { i--; return *this; }
- inline const_iterator operator--(int) { const T *n = i; i--; return n; }
- inline const_iterator &operator+=(int j) { i+=j; return *this; }
- inline const_iterator &operator-=(int j) { i-=j; return *this; }
- inline const_iterator operator+(int j) const { return const_iterator(i+j); }
- inline const_iterator operator-(int j) const { return const_iterator(i-j); }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
- inline int operator-(const_iterator j) const { return i - j.i; }
- inline operator const T*() const { return i; }
- };
- friend class const_iterator;
-#else
typedef T* iterator;
typedef const T* const_iterator;
-#endif
-
- T *data() { return static_cast<T *>(QArrayData::data()); }
- const T *data() const { return static_cast<const T *>(QArrayData::data()); }
-
- iterator begin(iterator = iterator()) { return data(); }
- iterator end(iterator = iterator()) { return data() + size; }
- const_iterator begin(const_iterator = const_iterator()) const { return data(); }
- const_iterator end(const_iterator = const_iterator()) const { return data() + size; }
- const_iterator constBegin(const_iterator = const_iterator()) const { return data(); }
- const_iterator constEnd(const_iterator = const_iterator()) const { return data() + size; }
class AlignmentDummy { QArrayData header; T data; };
- Q_REQUIRED_RESULT static QTypedArrayData *allocate(size_t capacity,
- AllocationOptions options = Default)
+ Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(size_t capacity,
+ ArrayOptions options = DefaultAllocationFlags)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T),
- Q_ALIGNOF(AlignmentDummy), capacity, options));
+ QArrayData *d;
+ void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, options);
+#if (defined(Q_CC_GNU) && Q_CC_GNU >= 407) || QT_HAS_BUILTIN(__builtin_assume_aligned)
+ result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy));
+#endif
+ return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result));
}
- static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,
- AllocationOptions options = Default)
+ static QPair<QTypedArrayData *, T *>
+ reallocateUnaligned(QTypedArrayData *data, T *dataPointer, size_t capacity,
+ ArrayOptions options = DefaultAllocationFlags)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),
- capacity, options));
+ QPair<QArrayData *, void *> pair =
+ QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, options);
+ return qMakePair(static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second));
}
static void deallocate(QArrayData *data)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy));
+ QArrayData::deallocate(data, sizeof(T), alignof(AlignmentDummy));
}
- static QTypedArrayData *fromRawData(const T *data, size_t n,
- AllocationOptions options = Default)
+ static QArrayDataPointerRef<T> fromRawData(const T *data, size_t n,
+ ArrayOptions options = DefaultRawFlags)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- QTypedArrayData *result = allocate(0, options | RawData);
- if (result) {
- Q_ASSERT(!result->ref.isShared()); // No shared empty, please!
-
- result->offset = reinterpret_cast<const char *>(data)
- - reinterpret_cast<const char *>(result);
- result->size = int(n);
+ QArrayDataPointerRef<T> result = {
+ static_cast<QTypedArrayData *>(prepareRawData(options)), const_cast<T *>(data), uint(n)
+ };
+ if (result.ptr) {
+ Q_ASSERT(!result.ptr->isShared()); // No shared empty, please!
}
return result;
}
@@ -266,38 +256,13 @@ struct QTypedArrayData
return allocate(/* capacity */ 0);
}
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- static QTypedArrayData *unsharableEmpty()
+ static T *sharedNullData()
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return allocate(/* capacity */ 0, Unsharable);
+ return static_cast<T *>(QArrayData::sharedNullData());
}
-#endif
-};
-
-template <class T, size_t N>
-struct QStaticArrayData
-{
- QArrayData header;
- T data[N];
};
-// Support for returning QArrayDataPointer<T> from functions
-template <class T>
-struct QArrayDataPointerRef
-{
- QTypedArrayData<T> *ptr;
-};
-
-#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
- { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
- /**/
-
-#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) \
- Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size,\
- ((sizeof(QArrayData) + (Q_ALIGNOF(type) - 1)) & ~(Q_ALIGNOF(type) - 1) )) \
- /**/
-
////////////////////////////////////////////////////////////////////////////////
// Q_ARRAY_LITERAL
@@ -333,15 +298,16 @@ struct QArrayDataPointerRef
Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type); \
\
/* Portable compile-time array size computation */ \
- Q_CONSTEXPR Type data[] = { __VA_ARGS__ }; Q_UNUSED(data); \
+ static Type const data[] = { __VA_ARGS__ }; \
enum { Size = sizeof(data) / sizeof(data[0]) }; \
\
- static const QStaticArrayData<Type, Size> literal = { \
- Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } }; \
+ static const QArrayData literal = { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }; \
\
QArrayDataPointerRef<Type> ref = \
{ static_cast<QTypedArrayData<Type> *>( \
- const_cast<QArrayData *>(&literal.header)) }; \
+ const_cast<QArrayData *>(&literal)), \
+ const_cast<Type *>(data), \
+ Size }; \
/**/
namespace QtPrivate {
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 8e19525f07..1d74f49993 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -41,12 +42,15 @@
#define QARRAYDATAOPS_H
#include <QtCore/qarraydata.h>
+#include <QtCore/qcontainertools_impl.h>
#include <new>
#include <string.h>
QT_BEGIN_NAMESPACE
+template <class T> struct QArrayDataPointer;
+
namespace QtPrivate {
QT_WARNING_PUSH
@@ -56,48 +60,70 @@ QT_WARNING_DISABLE_GCC("-Wstringop-overflow")
template <class T>
struct QPodArrayOps
- : QTypedArrayData<T>
+ : public QArrayDataPointer<T>
{
+ typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
+
void appendInitialize(size_t newSize)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(newSize > uint(this->size));
- Q_ASSERT(newSize <= this->alloc);
+ Q_ASSERT(newSize <= this->allocatedCapacity());
::memset(static_cast<void *>(this->end()), 0, (newSize - this->size) * sizeof(T));
this->size = int(newSize);
}
+ template<typename iterator>
+ void copyAppend(iterator b, iterator e, QtPrivate::IfIsForwardIterator<iterator> = true)
+ {
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(std::distance(b, e) >= 0 && size_t(std::distance(b, e)) <= this->allocatedCapacity() - this->size);
+
+ T *iter = this->end();
+ for (; b != e; ++iter, ++b) {
+ new (iter) T(*b);
+ ++this->size;
+ }
+ }
+
void copyAppend(const T *b, const T *e)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(b < e);
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(b <= e);
+ Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
::memcpy(static_cast<void *>(this->end()), static_cast<const void *>(b),
(e - b) * sizeof(T));
this->size += e - b;
}
- void copyAppend(size_t n, const T &t)
+ void moveAppend(T *b, T *e)
+ { copyAppend(b, e); }
+
+ void copyAppend(size_t n, parameter_type t)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(n <= this->alloc - uint(this->size));
+ Q_ASSERT(this->isMutable() || n == 0);
+ Q_ASSERT(!this->isShared() || n == 0);
+ Q_ASSERT(n <= uint(this->allocatedCapacity() - this->size));
T *iter = this->end();
const T *const end = iter + n;
for (; iter != end; ++iter)
- ::memcpy(iter, &t, sizeof(T));
+ *iter = t;
this->size += int(n);
}
+ template <typename ...Args>
+ void emplaceBack(Args&&... args) { this->emplace(this->end(), T(std::forward<Args>(args)...)); }
+
void truncate(size_t newSize)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(newSize < size_t(this->size));
this->size = int(newSize);
@@ -106,7 +132,7 @@ struct QPodArrayOps
void destroyAll() // Call from destructors, ONLY!
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(this->ref.atomic.loadRelaxed() == 0);
+ Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
// As this is to be called only from destructor, it doesn't need to be
// exception safe; size not updated.
@@ -115,11 +141,11 @@ struct QPodArrayOps
void insert(T *where, const T *b, const T *e)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
- Q_ASSERT(b < e);
+ Q_ASSERT(b <= e);
Q_ASSERT(e <= where || b > this->end()); // No overlap
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
::memmove(static_cast<void *>(where + (e - b)), static_cast<void *>(where),
(static_cast<const T*>(this->end()) - where) * sizeof(T));
@@ -127,43 +153,109 @@ struct QPodArrayOps
this->size += (e - b);
}
+ void insert(T *where, size_t n, parameter_type t)
+ {
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
+ Q_ASSERT(this->allocatedCapacity() - this->size >= n);
+
+ ::memmove(static_cast<void *>(where + n), static_cast<void *>(where),
+ (static_cast<const T*>(this->end()) - where) * sizeof(T));
+ this->size += int(n); // PODs can't throw on copy
+ while (n--)
+ *where++ = t;
+ }
+
+ template <typename ...Args>
+ void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); }
+
+ template <typename ...Args>
+ void emplace(T *where, Args&&... args)
+ {
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(where >= this->begin() && where <= this->end());
+ Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
+
+ if (where == this->end()) {
+ new (this->end()) T(std::forward<Args>(args)...);
+ } else {
+ // Preserve the value, because it might be a reference to some part of the moved chunk
+ T t(std::forward<Args>(args)...);
+
+ ::memmove(static_cast<void *>(where + 1), static_cast<void *>(where),
+ (static_cast<const T*>(this->end()) - where) * sizeof(T));
+ *where = t;
+ }
+
+ ++this->size;
+ }
+
+
void erase(T *b, T *e)
{
Q_ASSERT(this->isMutable());
Q_ASSERT(b < e);
Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e < this->end());
+ Q_ASSERT(e > this->begin() && e <= this->end());
::memmove(static_cast<void *>(b), static_cast<void *>(e),
(static_cast<T *>(this->end()) - e) * sizeof(T));
this->size -= (e - b);
}
+
+ void assign(T *b, T *e, parameter_type t)
+ {
+ Q_ASSERT(b <= e);
+ Q_ASSERT(b >= this->begin() && e <= this->end());
+
+ while (b != e)
+ ::memcpy(static_cast<void *>(b++), static_cast<const void *>(&t), sizeof(T));
+ }
+
+ bool compare(const T *begin1, const T *begin2, size_t n) const
+ {
+ // only use memcmp for fundamental types or pointers.
+ // Other types could have padding in the data structure or custom comparison
+ // operators that would break the comparison using memcmp
+ if (QArrayDataPointer<T>::pass_parameter_by_value)
+ return ::memcmp(begin1, begin2, n * sizeof(T)) == 0;
+ const T *end1 = begin1 + n;
+ while (begin1 != end1) {
+ if (*begin1 == *begin2)
+ ++begin1, ++begin2;
+ else
+ return false;
+ }
+ return true;
+ }
};
QT_WARNING_POP
template <class T>
struct QGenericArrayOps
- : QTypedArrayData<T>
+ : public QArrayDataPointer<T>
{
+ typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
+
void appendInitialize(size_t newSize)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(newSize > uint(this->size));
- Q_ASSERT(newSize <= this->alloc);
+ Q_ASSERT(newSize <= this->allocatedCapacity());
- T *const begin = this->begin();
+ T *const b = this->begin();
do {
- new (begin + this->size) T;
+ new (b + this->size) T;
} while (uint(++this->size) != newSize);
}
- void copyAppend(const T *b, const T *e)
+ template<typename iterator>
+ void copyAppend(iterator b, iterator e, QtPrivate::IfIsForwardIterator<iterator> = true)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(b < e);
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(std::distance(b, e) >= 0 && size_t(std::distance(b, e)) <= this->allocatedCapacity() - this->size);
T *iter = this->end();
for (; b != e; ++iter, ++b) {
@@ -172,11 +264,37 @@ struct QGenericArrayOps
}
}
- void copyAppend(size_t n, const T &t)
+ void copyAppend(const T *b, const T *e)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(n <= this->alloc - uint(this->size));
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(std::distance(b, e) >= 0 && size_t(std::distance(b, e)) <= this->allocatedCapacity() - this->size);
+
+ T *iter = this->end();
+ this->size += e - b;
+ for (; b != e; ++iter, ++b)
+ new (iter) T(*b);
+ }
+
+ void moveAppend(T *b, T *e)
+ {
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(b <= e);
+ Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
+
+ T *iter = this->end();
+ for (; b != e; ++iter, ++b) {
+ new (iter) T(std::move(*b));
+ ++this->size;
+ }
+ }
+
+ void copyAppend(size_t n, parameter_type t)
+ {
+ Q_ASSERT(this->isMutable() || n == 0);
+ Q_ASSERT(!this->isShared() || n == 0);
+ Q_ASSERT(n <= size_t(this->allocatedCapacity() - this->size));
T *iter = this->end();
const T *const end = iter + n;
@@ -186,10 +304,16 @@ struct QGenericArrayOps
}
}
+ template <typename ...Args>
+ void emplaceBack(Args&&... args)
+ {
+ this->emplace(this->end(), std::forward<Args>(args)...);
+ }
+
void truncate(size_t newSize)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(newSize < size_t(this->size));
const T *const b = this->begin();
@@ -204,7 +328,7 @@ struct QGenericArrayOps
// As this is to be called only from destructor, it doesn't need to be
// exception safe; size not updated.
- Q_ASSERT(this->ref.atomic.loadRelaxed() == 0);
+ Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
const T *const b = this->begin();
const T *i = this->end();
@@ -216,11 +340,11 @@ struct QGenericArrayOps
void insert(T *where, const T *b, const T *e)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
- Q_ASSERT(b < e);
+ Q_ASSERT(b <= e);
Q_ASSERT(e <= where || b > this->end()); // No overlap
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
// Array may be truncated at where in case of exceptions
@@ -279,25 +403,128 @@ struct QGenericArrayOps
}
}
+ void insert(T *where, size_t n, parameter_type t)
+ {
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(where >= this->begin() && where <= this->end());
+ Q_ASSERT(this->allocatedCapacity() - this->size >= n);
+
+ // Array may be truncated at where in case of exceptions
+ T *const end = this->end();
+ const T *readIter = end;
+ T *writeIter = end + n;
+
+ const T *const step1End = where + qMax<size_t>(n, end - where);
+
+ struct Destructor
+ {
+ Destructor(T *&it)
+ : iter(&it)
+ , end(it)
+ {
+ }
+
+ void commit()
+ {
+ iter = &end;
+ }
+
+ ~Destructor()
+ {
+ for (; *iter != end; --*iter)
+ (*iter)->~T();
+ }
+
+ T **iter;
+ T *end;
+ } destroyer(writeIter);
+
+ // Construct new elements in array
+ do {
+ --readIter, --writeIter;
+ new (writeIter) T(*readIter);
+ } while (writeIter != step1End);
+
+ while (writeIter != end) {
+ --n, --writeIter;
+ new (writeIter) T(t);
+ }
+
+ destroyer.commit();
+ this->size += destroyer.end - end;
+
+ // Copy assign over existing elements
+ while (readIter != where) {
+ --readIter, --writeIter;
+ *writeIter = *readIter;
+ }
+
+ while (writeIter != where) {
+ --n, --writeIter;
+ *writeIter = t;
+ }
+ }
+
+ template <typename ...Args>
+ void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); }
+
+ template <typename iterator, typename ...Args>
+ void emplace(iterator where, Args&&... args)
+ {
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(where >= this->begin() && where <= this->end());
+ Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
+
+ createInPlace(this->end(), std::forward<Args>(args)...);
+ ++this->size;
+
+ std::rotate(where, this->end() - 1, this->end());
+ }
+
void erase(T *b, T *e)
{
Q_ASSERT(this->isMutable());
Q_ASSERT(b < e);
Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e < this->end());
+ Q_ASSERT(e > this->begin() && e <= this->end());
const T *const end = this->end();
- do {
+ // move (by assignment) the elements from e to end
+ // onto b to the new end
+ while (e != end) {
*b = *e;
++b, ++e;
- } while (e != end);
+ }
+ // destroy the final elements at the end
+ // here, b points to the new end and e to the actual end
do {
(--e)->~T();
--this->size;
} while (e != b);
}
+
+ void assign(T *b, T *e, parameter_type t)
+ {
+ Q_ASSERT(b <= e);
+ Q_ASSERT(b >= this->begin() && e <= this->end());
+
+ while (b != e)
+ *b++ = t;
+ }
+
+ bool compare(const T *begin1, const T *begin2, size_t n) const
+ {
+ const T *end1 = begin1 + n;
+ while (begin1 != end1) {
+ if (*begin1 == *begin2)
+ ++begin1, ++begin2;
+ else
+ return false;
+ }
+ return true;
+ }
};
template <class T>
@@ -308,15 +535,16 @@ struct QMovableArrayOps
// using QGenericArrayOps<T>::copyAppend;
// using QGenericArrayOps<T>::truncate;
// using QGenericArrayOps<T>::destroyAll;
+ typedef typename QGenericArrayOps<T>::parameter_type parameter_type;
void insert(T *where, const T *b, const T *e)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
- Q_ASSERT(b < e);
+ Q_ASSERT(b <= e);
Q_ASSERT(e <= where || b > this->end()); // No overlap
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
// Provides strong exception safety guarantee,
// provided T::~T() nothrow
@@ -376,12 +604,79 @@ struct QMovableArrayOps
this->size += (e - b);
}
+ void insert(T *where, size_t n, parameter_type t)
+ {
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(where >= this->begin() && where <= this->end());
+ Q_ASSERT(this->allocatedCapacity() - this->size >= n);
+
+ // Provides strong exception safety guarantee,
+ // provided T::~T() nothrow
+
+ struct ReversibleDisplace
+ {
+ ReversibleDisplace(T *start, T *finish, size_t diff)
+ : begin(start)
+ , end(finish)
+ , displace(diff)
+ {
+ ::memmove(static_cast<void *>(begin + displace), static_cast<void *>(begin),
+ (end - begin) * sizeof(T));
+ }
+
+ void commit() { displace = 0; }
+
+ ~ReversibleDisplace()
+ {
+ if (displace)
+ ::memmove(static_cast<void *>(begin), static_cast<void *>(begin + displace),
+ (end - begin) * sizeof(T));
+ }
+
+ T *const begin;
+ T *const end;
+ size_t displace;
+
+ } displace(where, this->end(), n);
+
+ struct CopyConstructor
+ {
+ CopyConstructor(T *w) : where(w) {}
+
+ void copy(size_t count, parameter_type proto)
+ {
+ n = 0;
+ while (count--) {
+ new (where + n) T(proto);
+ ++n;
+ }
+ n = 0;
+ }
+
+ ~CopyConstructor()
+ {
+ while (n)
+ where[--n].~T();
+ }
+
+ T *const where;
+ size_t n;
+ } copier(where);
+
+ copier.copy(n, t);
+ displace.commit();
+ this->size += int(n);
+ }
+
+ // use moving insert
+ using QGenericArrayOps<T>::insert;
+
void erase(T *b, T *e)
{
Q_ASSERT(this->isMutable());
Q_ASSERT(b < e);
Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e < this->end());
+ Q_ASSERT(e > this->begin() && e <= this->end());
struct Mover
{
@@ -405,11 +700,51 @@ struct QMovableArrayOps
int &size;
} mover(e, this->end(), this->size);
+ // destroy the elements we're erasing
do {
// Exceptions or not, dtor called once per instance
(--e)->~T();
} while (e != b);
}
+
+ void moveAppend(T *b, T *e)
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(b <= e);
+ Q_ASSERT(e <= this->begin() || b > this->end()); // No overlap
+ Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
+
+ // Provides strong exception safety guarantee,
+ // provided T::~T() nothrow
+
+ struct CopyConstructor
+ {
+ CopyConstructor(T *w) : where(w) {}
+
+ void copy(T *src, const T *const srcEnd)
+ {
+ n = 0;
+ for (; src != srcEnd; ++src) {
+ new (where + n) T(std::move(*src));
+ ++n;
+ }
+ n = 0;
+ }
+
+ ~CopyConstructor()
+ {
+ while (n)
+ where[--n].~T();
+ }
+
+ T *const where;
+ size_t n;
+ } copier(this->end());
+
+ copier.copy(b, e);
+ this->size += (e - b);
+ }
};
template <class T, class = void>
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index af5173c9ad..a17cf4a101 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -41,6 +41,7 @@
#define QARRAYDATAPOINTER_H
#include <QtCore/qarraydataops.h>
+#include <QtCore/qcontainertools_impl.h>
QT_BEGIN_NAMESPACE
@@ -52,30 +53,40 @@ 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 };
+
+ typedef typename std::conditional<pass_parameter_by_value, T, const T &>::type parameter_type;
+
QArrayDataPointer() noexcept
- : d(Data::sharedNull())
+ : d(Data::sharedNull()), ptr(Data::sharedNullData()), size(0)
{
}
- QArrayDataPointer(const QArrayDataPointer &other)
- : d(other.d->ref.ref()
- ? other.d
- : other.clone(other.d->cloneFlags()))
+ QArrayDataPointer(const QArrayDataPointer &other) noexcept
+ : d(other.d), ptr(other.ptr), size(other.size)
{
+ other.d->ref();
}
- explicit QArrayDataPointer(QTypedArrayData<T> *ptr)
- : d(ptr)
+ QArrayDataPointer(Data *header, T *adata, size_t n = 0) noexcept
+ : d(header), ptr(adata), size(int(n))
{
- Q_CHECK_PTR(ptr);
}
- QArrayDataPointer(QArrayDataPointerRef<T> ref)
- : d(ref.ptr)
+ explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> adata, size_t n = 0)
+ : d(adata.first), ptr(adata.second), size(int(n))
{
+ Q_CHECK_PTR(d);
}
- QArrayDataPointer &operator=(const QArrayDataPointer &other)
+ QArrayDataPointer(QArrayDataPointerRef<T> dd) noexcept
+ : d(dd.ptr), ptr(dd.data), size(dd.size)
+ {
+ }
+
+ QArrayDataPointer &operator=(const QArrayDataPointer &other) noexcept
{
QArrayDataPointer tmp(other);
this->swap(tmp);
@@ -83,9 +94,11 @@ public:
}
QArrayDataPointer(QArrayDataPointer &&other) noexcept
- : d(other.d)
+ : d(other.d), ptr(other.ptr), size(other.size)
{
other.d = Data::sharedNull();
+ other.ptr = Data::sharedNullData();
+ other.size = 0;
}
QArrayDataPointer &operator=(QArrayDataPointer &&other) noexcept
@@ -95,114 +108,142 @@ public:
return *this;
}
- DataOps &operator*() const
+ DataOps &operator*() noexcept
{
Q_ASSERT(d);
- return *static_cast<DataOps *>(d);
+ return *static_cast<DataOps *>(this);
}
- DataOps *operator->() const
+ DataOps *operator->() noexcept
{
Q_ASSERT(d);
- return static_cast<DataOps *>(d);
+ return static_cast<DataOps *>(this);
}
- ~QArrayDataPointer()
+ const DataOps &operator*() const noexcept
{
- if (!d->ref.deref()) {
- if (d->isMutable())
- (*this)->destroyAll();
- Data::deallocate(d);
- }
+ Q_ASSERT(d);
+ return *static_cast<const DataOps *>(this);
}
- bool isNull() const
+ const DataOps *operator->() const noexcept
{
- return d == Data::sharedNull();
+ Q_ASSERT(d);
+ return static_cast<const DataOps *>(this);
}
- Data *data() const
+ ~QArrayDataPointer()
{
- return d;
+ if (!deref()) {
+ if (isMutable())
+ (*this)->destroyAll();
+ Data::deallocate(d);
+ }
}
- bool needsDetach() const
+ bool isNull() const noexcept
{
- return (!d->isMutable() || d->ref.isShared());
+ return d == Data::sharedNull();
}
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- void setSharable(bool sharable)
- {
- if (needsDetach()) {
- Data *detached = clone(sharable
- ? d->detachFlags() & ~QArrayData::Unsharable
- : d->detachFlags() | QArrayData::Unsharable);
- QArrayDataPointer old(d);
- d = detached;
- } else {
- d->ref.setSharable(sharable);
- }
- }
+ T *data() noexcept { return ptr; }
+ const T *data() const noexcept { return ptr; }
- bool isSharable() const { return d->isSharable(); }
-#endif
+ 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; }
void swap(QArrayDataPointer &other) noexcept
{
qSwap(d, other.d);
+ qSwap(ptr, other.ptr);
+ qSwap(size, other.size);
}
- void clear()
+ void clear() Q_DECL_NOEXCEPT_EXPR(std::is_nothrow_destructible<T>::value)
{
- QArrayDataPointer tmp(d);
- d = Data::sharedNull();
+ QArrayDataPointer tmp;
+ swap(tmp);
}
bool detach()
{
- if (needsDetach()) {
- Data *copy = clone(d->detachFlags());
- QArrayDataPointer old(d);
- d = copy;
+ if (d->needsDetach()) {
+ QPair<Data *, T *> copy = clone(d->detachFlags());
+ QArrayDataPointer old(d, ptr, size);
+ d = copy.first;
+ ptr = copy.second;
return true;
}
return false;
}
-private:
- Q_REQUIRED_RESULT Data *clone(QArrayData::AllocationOptions options) const
+ // forwards from QArrayData
+ size_t allocatedCapacity() noexcept { return d->allocatedCapacity(); }
+ size_t constAllocatedCapacity() const noexcept { return d->constAllocatedCapacity(); }
+ int refCounterValue() const noexcept { return d->refCounterValue(); }
+ bool ref() noexcept { return d->ref(); }
+ bool deref() noexcept { return d->deref(); }
+ bool isMutable() const noexcept { return d->isMutable(); }
+ bool isStatic() const noexcept { return d->isStatic(); }
+ bool isShared() const noexcept { return d->isShared(); }
+ bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; }
+ bool needsDetach() const noexcept { return d->needsDetach(); }
+ size_t detachCapacity(size_t newSize) const noexcept { return d->detachCapacity(newSize); }
+ typename Data::ArrayOptions &flags() noexcept { return reinterpret_cast<typename Data::ArrayOptions &>(d->flags); }
+ typename Data::ArrayOptions flags() const noexcept { return typename Data::ArrayOption(d->flags); }
+ typename Data::ArrayOptions detachFlags() const noexcept { return d->detachFlags(); }
+ typename Data::ArrayOptions cloneFlags() const noexcept { return d->cloneFlags(); }
+
+ void reallocate(uint alloc, typename Data::ArrayOptions options)
{
- Data *x = Data::allocate(d->detachCapacity(d->size), options);
- Q_CHECK_PTR(x);
- QArrayDataPointer copy(x);
+ auto pair = Data::reallocateUnaligned(d, ptr, alloc, options);
+ d = pair.first;
+ ptr = pair.second;
+ }
+ Data *d_ptr() { return d; }
- if (d->size)
- copy->copyAppend(d->begin(), d->end());
+private:
+ Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const
+ {
+ QPair<Data *, T *> pair = Data::allocate(d->detachCapacity(size),
+ options);
+ Q_CHECK_PTR(pair.first);
+ QArrayDataPointer copy(pair.first, pair.second, 0);
+ if (size)
+ copy->copyAppend(begin(), end());
- Data *result = copy.d;
+ pair.first = copy.d;
copy.d = Data::sharedNull();
- return result;
+ return pair;
}
+protected:
Data *d;
+ T *ptr;
+
+public:
+ int size;
};
template <class T>
-inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs)
+inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) noexcept
{
- return lhs.data() == rhs.data();
+ return lhs.data() == rhs.data() && lhs.size == rhs.size;
}
template <class T>
-inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs)
+inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) noexcept
{
- return lhs.data() != rhs.data();
+ return lhs.data() != rhs.data() || lhs.size != rhs.size;
}
template <class T>
-inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2)
+inline void qSwap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
{
p1.swap(p2);
}
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index ab3054d5be..12ad6f4573 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -342,6 +342,38 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
return result;
}
+/*!
+ \since 6.0
+
+ Returns the array of bit converted to an int. The conversion is based on \a endianness.
+ Converts up to the first 32 bits of the array to \c quint32 and returns it,
+ obeying \a endianness. If \a ok is not a null pointer, and the array has more
+ than 32 bits, \a ok is set to false and this function returns zero; otherwise,
+ it's set to true.
+*/
+quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcept
+{
+ const qsizetype _size = size();
+ if (_size > 32) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ if (ok)
+ *ok = true;
+
+ quint32 factor = 1;
+ quint32 total = 0;
+ for (qsizetype i = 0; i < _size; ++i, factor *= 2) {
+ const auto index = endianness == QSysInfo::Endian::LittleEndian ? i : (_size - i - 1);
+ if (testBit(index))
+ total += factor;
+ }
+
+ return total;
+}
+
/*! \fn bool QBitArray::isDetached() const
\internal
diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h
index 9b0e931aca..e8ef032c24 100644
--- a/src/corelib/tools/qbitarray.h
+++ b/src/corelib/tools/qbitarray.h
@@ -50,7 +50,7 @@ class Q_CORE_EXPORT QBitArray
{
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QBitArray &);
- friend Q_CORE_EXPORT uint qHash(const QBitArray &key, uint seed) noexcept;
+ friend Q_CORE_EXPORT size_t qHash(const QBitArray &key, size_t seed) noexcept;
QByteArray d;
public:
@@ -105,8 +105,10 @@ public:
const char *bits() const { return isEmpty() ? nullptr : d.constData() + 1; }
static QBitArray fromBits(const char *data, qsizetype len);
+ quint32 toUInt32(QSysInfo::Endian endianness, bool *ok = nullptr) const noexcept;
+
public:
- typedef QByteArray::DataPtr DataPtr;
+ typedef QByteArray::DataPointer DataPtr;
inline DataPtr &data_ptr() { return d.data_ptr(); }
};
diff --git a/src/corelib/tools/qcache.h b/src/corelib/tools/qcache.h
index 4fcde46fbc..3582a44e32 100644
--- a/src/corelib/tools/qcache.h
+++ b/src/corelib/tools/qcache.h
@@ -48,151 +48,244 @@ QT_BEGIN_NAMESPACE
template <class Key, class T>
class QCache
{
- struct Node {
- inline Node() : keyPtr(0) {}
- inline Node(T *data, int cost)
- : keyPtr(nullptr), t(data), c(cost), p(nullptr), n(nullptr) {}
- const Key *keyPtr; T *t; int c; Node *p,*n;
+ struct Value {
+ T *t = nullptr;
+ int cost = 0;
+ Value() noexcept = default;
+ Value(T *tt, int c) noexcept
+ : t(tt), cost(c)
+ {}
+ Value(Value &&other) noexcept
+ : t(other.t),
+ cost(other.cost)
+ {
+ other.t = nullptr;
+ }
+ Value &operator=(Value &&other) noexcept
+ {
+ qSwap(t, other.t);
+ qSwap(cost, other.cost);
+ return *this;
+ }
+ ~Value() { delete t; }
+ private:
+ Q_DISABLE_COPY(Value)
};
- Node *f, *l;
- QHash<Key, Node> hash;
- int mx, total;
-
- inline void unlink(Node &n) {
- if (n.p) n.p->n = n.n;
- if (n.n) n.n->p = n.p;
- if (l == &n) l = n.p;
- if (f == &n) f = n.n;
- total -= n.c;
- T *obj = n.t;
- hash.remove(*n.keyPtr);
- delete obj;
- }
- inline T *relink(const Key &key) {
- typename QHash<Key, Node>::iterator i = hash.find(key);
- if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd())
- return nullptr;
- Node &n = *i;
- if (f != &n) {
- if (n.p) n.p->n = n.n;
- if (n.n) n.n->p = n.p;
- if (l == &n) l = n.p;
- n.p = nullptr;
- n.n = f;
- f->p = &n;
- f = &n;
- }
- return n.t;
- }
+ struct Chain {
+ Chain() noexcept
+ : prev(this), next(this)
+ {}
+ Chain *prev;
+ Chain *next;
+ };
- Q_DISABLE_COPY(QCache)
+ struct Node : public Chain {
+ using KeyType = Key;
+ using ValueType = Value;
-public:
- inline explicit QCache(int maxCost = 100) noexcept;
- inline ~QCache() { clear(); }
+ Key key;
+ Value value;
- inline int maxCost() const { return mx; }
- void setMaxCost(int m);
- inline int totalCost() const { return total; }
+ Node(const Key &k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key>)
+ : Chain(),
+ key(k),
+ value(std::move(t))
+ {
+ }
+ Node(Key &&k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key>)
+ : Chain(),
+ key(std::move(k)),
+ value(std::move(t))
+ {
+ }
+ static void createInPlace(Node *n, const Key &k, T *o, int cost)
+ {
+ new (n) Node{ Key(k), Value(o, cost) };
+ }
+ void emplace(T *o, int cost)
+ {
+ value = Value(o, cost);
+ }
+ static Node create(const Key &k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key> && std::is_nothrow_move_assignable_v<T>)
+ {
+ return Node(k, std::move(t));
+ }
+ void replace(const Value &t) noexcept(std::is_nothrow_assignable_v<T>)
+ {
+ value = t;
+ }
+ void replace(Value &&t) noexcept(std::is_nothrow_move_assignable_v<T>)
+ {
+ value = std::move(t);
+ }
+ Value takeValue() noexcept(std::is_nothrow_move_constructible_v<T>)
+ {
+ return std::move(value);
+ }
+ bool valuesEqual(const Node *other) const { return value == other->value; }
- inline int size() const { return hash.size(); }
- inline int count() const { return hash.size(); }
- inline bool isEmpty() const { return hash.isEmpty(); }
- inline QList<Key> keys() const { return hash.keys(); }
+ Node(Node &&other)
+ : Chain(other),
+ key(std::move(other.key)),
+ value(std::move(other.value))
+ {
+ Q_ASSERT(this->prev);
+ Q_ASSERT(this->next);
+ this->prev->next = this;
+ this->next->prev = this;
+ }
+ private:
+ Q_DISABLE_COPY(Node)
+ };
- void clear();
+ using Data = QHashPrivate::Data<Node>;
- bool insert(const Key &key, T *object, int cost = 1);
- T *object(const Key &key) const;
- inline bool contains(const Key &key) const { return hash.contains(key); }
- T *operator[](const Key &key) const;
+ mutable Chain chain;
+ Data d;
+ int mx = 0;
+ int total = 0;
- bool remove(const Key &key);
- T *take(const Key &key);
+ void unlink(Node *n) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ Q_ASSERT(n->prev);
+ Q_ASSERT(n->next);
+ n->prev->next = n->next;
+ n->next->prev = n->prev;
+ total -= n->value.cost;
+ auto it = d.find(n->key);
+ d.erase(it);
+ }
+ T *relink(const Key &key) const noexcept
+ {
+ Node *n = d.findNode(key);
+ if (!n)
+ return nullptr;
-private:
- void trim(int m);
-};
+ if (chain.next != n) {
+ Q_ASSERT(n->prev);
+ Q_ASSERT(n->next);
+ n->prev->next = n->next;
+ n->next->prev = n->prev;
+ n->next = chain.next;
+ chain.next->prev = n;
+ n->prev = &chain;
+ chain.next = n;
+ }
+ return n->value.t;
+ }
-template <class Key, class T>
-inline QCache<Key, T>::QCache(int amaxCost) noexcept
- : f(nullptr), l(nullptr), mx(amaxCost), total(0) {}
+ void trim(int m) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ Chain *n = chain.prev;
+ while (n != &chain && total > m) {
+ Node *u = static_cast<Node *>(n);
+ n = n->prev;
+ unlink(u);
+ }
+ }
-template <class Key, class T>
-inline void QCache<Key,T>::clear()
-{ while (f) { delete f->t; f = f->n; }
- hash.clear(); l = nullptr; total = 0; }
-template <class Key, class T>
-inline void QCache<Key,T>::setMaxCost(int m)
-{ mx = m; trim(mx); }
+ Q_DISABLE_COPY(QCache)
-template <class Key, class T>
-inline T *QCache<Key,T>::object(const Key &key) const
-{ return const_cast<QCache<Key,T>*>(this)->relink(key); }
+public:
+ inline explicit QCache(int maxCost = 100) noexcept
+ : mx(maxCost)
+ {}
+ inline ~QCache() { clear(); }
-template <class Key, class T>
-inline T *QCache<Key,T>::operator[](const Key &key) const
-{ return object(key); }
+ inline int maxCost() const noexcept { return mx; }
+ void setMaxCost(int m) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ mx = m;
+ trim(mx);
+ }
+ inline int totalCost() const noexcept { return total; }
-template <class Key, class T>
-inline bool QCache<Key,T>::remove(const Key &key)
-{
- typename QHash<Key, Node>::iterator i = hash.find(key);
- if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd()) {
- return false;
- } else {
- unlink(*i);
- return true;
+ inline int size() const noexcept { return d.size; }
+ inline int count() const noexcept { return d.size; }
+ inline bool isEmpty() const noexcept { return !d.size; }
+ inline QVector<Key> keys() const
+ {
+ QVector<Key> k;
+ if (d.size) {
+ k.reserve(d.size);
+ for (auto it = d.begin(); it != d.end(); ++it)
+ k << it.node()->key;
+ }
+ Q_ASSERT(k.size() == qsizetype(d.size));
+ return k;
}
-}
-template <class Key, class T>
-inline T *QCache<Key,T>::take(const Key &key)
-{
- typename QHash<Key, Node>::iterator i = hash.find(key);
- if (i == hash.end())
- return nullptr;
+ void clear() noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ d.clear();
+ total = 0;
+ chain.next = &chain;
+ chain.prev = &chain;
+ }
- Node &n = *i;
- T *t = n.t;
- n.t = nullptr;
- unlink(n);
- return t;
-}
+ bool insert(const Key &key, T *object, int cost = 1)
+ {
+ remove(key);
-template <class Key, class T>
-bool QCache<Key,T>::insert(const Key &akey, T *aobject, int acost)
-{
- remove(akey);
- if (acost > mx) {
- delete aobject;
- return false;
+ if (cost > mx) {
+ delete object;
+ return false;
+ }
+ trim(mx - cost);
+ auto result = d.findOrInsert(key);
+ Node *n = result.it.node();
+ if (result.initialized) {
+ cost -= n->value.cost;
+ result.it.node()->emplace(object, cost);
+ } else {
+ Node::createInPlace(n, key, object, cost);
+ }
+ total += cost;
+ n->prev = &chain;
+ n->next = chain.next;
+ chain.next->prev = n;
+ chain.next = n;
+ return true;
+ }
+ T *object(const Key &key) const noexcept
+ {
+ return relink(key);
+ }
+ T *operator[](const Key &key) const noexcept
+ {
+ return relink(key);
+ }
+ inline bool contains(const Key &key) const noexcept
+ {
+ return d.findNode(key) != nullptr;
}
- trim(mx - acost);
- Node sn(aobject, acost);
- typename QHash<Key, Node>::iterator i = hash.insert(akey, sn);
- total += acost;
- Node *n = &i.value();
- n->keyPtr = &i.key();
- if (f) f->p = n;
- n->n = f;
- f = n;
- if (!l) l = f;
- return true;
-}
-template <class Key, class T>
-void QCache<Key,T>::trim(int m)
-{
- Node *n = l;
- while (n && total > m) {
- Node *u = n;
- n = n->p;
- unlink(*u);
+ bool remove(const Key &key) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ Node *n = d.findNode(key);
+ if (!n) {
+ return false;
+ } else {
+ unlink(n);
+ return true;
+ }
}
-}
+
+ T *take(const Key &key) noexcept(std::is_nothrow_destructible_v<Key>)
+ {
+ Node *n = d.findNode(key);
+ if (!n)
+ return nullptr;
+
+ T *t = n->value.t;
+ n->value.t = nullptr;
+ unlink(n);
+ return t;
+ }
+
+};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcontainerfwd.h b/src/corelib/tools/qcontainerfwd.h
index 00a8c85b66..bdf9e0dcc0 100644
--- a/src/corelib/tools/qcontainerfwd.h
+++ b/src/corelib/tools/qcontainerfwd.h
@@ -47,10 +47,6 @@ QT_BEGIN_NAMESPACE
template <class Key, class T> class QCache;
template <class Key, class T> class QHash;
-#if !defined(QT_NO_LINKED_LIST) && QT_DEPRECATED_SINCE(5, 15)
-template <class T> class QLinkedList;
-#endif
-template <class T> class QList;
template <class Key, class T> class QMap;
template <class Key, class T> class QMultiHash;
template <class Key, class T> class QMultiMap;
@@ -58,8 +54,9 @@ template <class T1, class T2> struct QPair;
template <class T> class QQueue;
template <class T> class QSet;
template <class T> class QStack;
-template<class T, int Prealloc = 256> class QVarLengthArray;
+template<class T, qsizetype Prealloc = 256> class QVarLengthArray;
template <class T> class QVector;
+template<typename T> using QList = QVector<T>;
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp
index 64cbd7df4b..cc3510ef88 100644
--- a/src/corelib/tools/qcontiguouscache.cpp
+++ b/src/corelib/tools/qcontiguouscache.cpp
@@ -54,9 +54,9 @@ void QContiguousCacheData::dump() const
}
#endif
-QContiguousCacheData *QContiguousCacheData::allocateData(int size, int alignment)
+QContiguousCacheData *QContiguousCacheData::allocateData(qsizetype size, qsizetype alignment)
{
- return static_cast<QContiguousCacheData *>(qMallocAligned(size, alignment));
+ return static_cast<QContiguousCacheData *>(qMallocAligned(size_t(size), size_t(alignment)));
}
void QContiguousCacheData::freeData(QContiguousCacheData *data)
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 7b74b4f526..81361f219a 100644
--- a/src/corelib/tools/qcontiguouscache.h
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -52,19 +52,12 @@ QT_BEGIN_NAMESPACE
struct Q_CORE_EXPORT QContiguousCacheData
{
QBasicAtomicInt ref;
- int alloc;
- int count;
- int start;
- int offset;
- uint sharable : 1;
- uint reserved : 31;
-
- // total is 24 bytes (HP-UX aCC: 40 bytes)
- // the next entry is already aligned to 8 bytes
- // there will be an 8 byte gap here if T requires 16-byte alignment
- // (such as long double on 64-bit platforms, __int128, __float128)
-
- static QContiguousCacheData *allocateData(int size, int alignment);
+ qsizetype alloc;
+ qsizetype count;
+ qsizetype start;
+ qsizetype offset;
+
+ static QContiguousCacheData *allocateData(qsizetype size, qsizetype alignment);
static void freeData(QContiguousCacheData *data);
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
@@ -73,18 +66,15 @@ struct Q_CORE_EXPORT QContiguousCacheData
};
template <typename T>
-struct QContiguousCacheTypedData: private QContiguousCacheData
+struct QContiguousCacheTypedData : public QContiguousCacheData
{
- // private inheritance to avoid aliasing warningss
T array[1];
-
- static inline void freeData(QContiguousCacheTypedData *data) { QContiguousCacheData::freeData(data); }
};
template<typename T>
class QContiguousCache {
typedef QContiguousCacheTypedData<T> Data;
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; };
+ Data *d;
public:
// STL compatibility
typedef T value_type;
@@ -93,18 +83,15 @@ public:
typedef value_type& reference;
typedef const value_type& const_reference;
typedef qptrdiff difference_type;
- typedef int size_type;
+ typedef qsizetype size_type;
- explicit QContiguousCache(int capacity = 0);
- QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
+ explicit QContiguousCache(qsizetype capacity = 0);
+ QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); }
- inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(p); }
+ inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(d); }
inline void detach() { if (d->ref.loadRelaxed() != 1) detach_helper(); }
inline bool isDetached() const { return d->ref.loadRelaxed() == 1; }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
-#endif
QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
inline QContiguousCache<T> &operator=(QContiguousCache<T> &&other) noexcept
@@ -113,139 +100,122 @@ public:
bool operator==(const QContiguousCache<T> &other) const;
inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); }
- inline int capacity() const {return d->alloc; }
- inline int count() const { return d->count; }
- inline int size() const { return d->count; }
+ inline qsizetype capacity() const {return d->alloc; }
+ inline qsizetype count() const { return d->count; }
+ inline qsizetype size() const { return d->count; }
inline bool isEmpty() const { return d->count == 0; }
inline bool isFull() const { return d->count == d->alloc; }
- inline int available() const { return d->alloc - d->count; }
+ inline qsizetype available() const { return d->alloc - d->count; }
void clear();
- void setCapacity(int size);
+ void setCapacity(qsizetype size);
- const T &at(int pos) const;
- T &operator[](int i);
- const T &operator[](int i) const;
+ const T &at(qsizetype pos) const;
+ T &operator[](qsizetype i);
+ const T &operator[](qsizetype i) const;
+ void append(T &&value);
void append(const T &value);
+ void prepend(T &&value);
void prepend(const T &value);
- void insert(int pos, const T &value);
+ void insert(qsizetype pos, T &&value);
+ void insert(qsizetype pos, const T &value);
+
- inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; }
- inline int firstIndex() const { return d->offset; }
- inline int lastIndex() const { return d->offset + d->count - 1; }
+ inline bool containsIndex(qsizetype pos) const { return pos >= d->offset && pos - d->offset < d->count; }
+ inline qsizetype firstIndex() const { return d->offset; }
+ inline qsizetype lastIndex() const { return d->offset + d->count - 1; }
- inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; }
- inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; }
- inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; }
- inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; }
+ inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; }
+ inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; }
+ inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; }
+ inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; }
void removeFirst();
T takeFirst();
void removeLast();
T takeLast();
+ // Use extra parentheses around max to avoid expanding it if it is a macro.
inline bool areIndexesValid() const
- { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; }
+ { return d->offset >= 0 && d->offset < (std::numeric_limits<qsizetype>::max)() - d->count && (d->offset % d->alloc) == d->start; }
inline void normalizeIndexes() { d->offset = d->start; }
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
- void dump() const { p->dump(); }
+ void dump() const { d->dump(); }
#endif
private:
void detach_helper();
- QContiguousCacheData *allocateData(int aalloc);
+ Data *allocateData(qsizetype aalloc);
void freeData(Data *x);
- int sizeOfTypedData() {
- // this is more or less the same as sizeof(Data), except that it doesn't
- // count the padding at the end
- return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this);
- }
- int alignOfTypedData() const
- {
- return qMax<int>(sizeof(void*), Q_ALIGNOF(Data));
- }
};
template <typename T>
void QContiguousCache<T>::detach_helper()
{
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
-
- x.d = allocateData(d->alloc);
- x.d->ref.storeRelaxed(1);
- x.d->count = d->count;
- x.d->start = d->start;
- x.d->offset = d->offset;
- x.d->alloc = d->alloc;
- x.d->sharable = true;
- x.d->reserved = 0;
-
- T *dest = x.p->array + x.d->start;
- T *src = p->array + d->start;
- int oldcount = x.d->count;
+ Data *x = allocateData(d->alloc);
+ x->ref.storeRelaxed(1);
+ x->count = d->count;
+ x->start = d->start;
+ x->offset = d->offset;
+ x->alloc = d->alloc;
+
+ T *dest = x->array + x->start;
+ T *src = d->array + d->start;
+ qsizetype oldcount = x->count;
while (oldcount--) {
- if (QTypeInfo<T>::isComplex) {
- new (dest) T(*src);
- } else {
- *dest = *src;
- }
+ new (dest) T(*src);
dest++;
- if (dest == x.p->array + x.d->alloc)
- dest = x.p->array;
+ if (dest == x->array + x->alloc)
+ dest = x->array;
src++;
- if (src == p->array + d->alloc)
- src = p->array;
+ if (src == d->array + d->alloc)
+ src = d->array;
}
if (!d->ref.deref())
- freeData(p);
- d = x.d;
+ freeData(d);
+ d = x;
}
template <typename T>
-void QContiguousCache<T>::setCapacity(int asize)
+void QContiguousCache<T>::setCapacity(qsizetype asize)
{
Q_ASSERT(asize >= 0);
if (asize == d->alloc)
return;
detach();
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
- x.d = allocateData(asize);
- x.d->ref.storeRelaxed(1);
- x.d->alloc = asize;
- x.d->count = qMin(d->count, asize);
- x.d->offset = d->offset + d->count - x.d->count;
+ Data *x = allocateData(asize);
+ x->ref.storeRelaxed(1);
+ x->alloc = asize;
+ x->count = qMin(d->count, asize);
+ x->offset = d->offset + d->count - x->count;
if(asize)
- x.d->start = x.d->offset % x.d->alloc;
+ x->start = x->offset % x->alloc;
else
- x.d->start = 0;
+ x->start = 0;
- int oldcount = x.d->count;
+ qsizetype oldcount = x->count;
if(oldcount)
{
- T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc;
- T *src = p->array + (d->start + d->count-1) % d->alloc;
+ T *dest = x->array + (x->start + x->count-1) % x->alloc;
+ T *src = d->array + (d->start + d->count-1) % d->alloc;
while (oldcount--) {
- if (QTypeInfo<T>::isComplex) {
- new (dest) T(*src);
- } else {
- *dest = *src;
- }
- if (dest == x.p->array)
- dest = x.p->array + x.d->alloc;
+ new (dest) T(*src);
+ if (dest == x->array)
+ dest = x->array + x->alloc;
dest--;
- if (src == p->array)
- src = p->array + d->alloc;
+ if (src == d->array)
+ src = d->array + d->alloc;
src--;
}
}
/* free old */
- freeData(p);
- d = x.d;
+ freeData(d);
+ d = x;
}
template <typename T>
@@ -253,44 +223,42 @@ void QContiguousCache<T>::clear()
{
if (d->ref.loadRelaxed() == 1) {
if (QTypeInfo<T>::isComplex) {
- int oldcount = d->count;
- T * i = p->array + d->start;
- T * e = p->array + d->alloc;
+ qsizetype oldcount = d->count;
+ T * i = d->array + d->start;
+ T * e = d->array + d->alloc;
while (oldcount--) {
i->~T();
i++;
if (i == e)
- i = p->array;
+ i = d->array;
}
}
d->count = d->start = d->offset = 0;
} else {
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
- x.d = allocateData(d->alloc);
- x.d->ref.storeRelaxed(1);
- x.d->alloc = d->alloc;
- x.d->count = x.d->start = x.d->offset = 0;
- x.d->sharable = true;
- if (!d->ref.deref()) freeData(p);
- d = x.d;
+ Data *x = allocateData(d->alloc);
+ x->ref.storeRelaxed(1);
+ x->alloc = d->alloc;
+ x->count = x->start = x->offset = 0;
+ if (!d->ref.deref())
+ freeData(d);
+ d = x;
}
}
template <typename T>
-inline QContiguousCacheData *QContiguousCache<T>::allocateData(int aalloc)
+inline typename QContiguousCache<T>::Data *QContiguousCache<T>::allocateData(qsizetype aalloc)
{
- return QContiguousCacheData::allocateData(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData());
+ return static_cast<Data *>(QContiguousCacheData::allocateData(sizeof(Data) + (aalloc - 1) * sizeof(T), alignof(Data)));
}
template <typename T>
-QContiguousCache<T>::QContiguousCache(int cap)
+QContiguousCache<T>::QContiguousCache(qsizetype cap)
{
Q_ASSERT(cap >= 0);
d = allocateData(cap);
d->ref.storeRelaxed(1);
d->alloc = cap;
d->count = d->start = d->offset = 0;
- d->sharable = true;
}
template <typename T>
@@ -298,10 +266,8 @@ QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &o
{
other.d->ref.ref();
if (!d->ref.deref())
- freeData(p);
+ freeData(d);
d = other.d;
- if (!d->sharable)
- detach_helper();
return *this;
}
@@ -315,7 +281,7 @@ bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const
|| other.d->offset != d->offset
|| other.d->alloc != d->alloc)
return false;
- for (int i = firstIndex(); i <= lastIndex(); ++i)
+ for (qsizetype i = firstIndex(); i <= lastIndex(); ++i)
if (!(at(i) == other.at(i)))
return false;
return true;
@@ -325,31 +291,46 @@ template <typename T>
void QContiguousCache<T>::freeData(Data *x)
{
if (QTypeInfo<T>::isComplex) {
- int oldcount = d->count;
- T * i = p->array + d->start;
- T * e = p->array + d->alloc;
+ qsizetype oldcount = d->count;
+ T * i = d->array + d->start;
+ T * e = d->array + d->alloc;
while (oldcount--) {
i->~T();
i++;
if (i == e)
- i = p->array;
+ i = d->array;
}
}
- x->freeData(x);
+ Data::freeData(x);
}
template <typename T>
-void QContiguousCache<T>::append(const T &value)
+void QContiguousCache<T>::append(T &&value)
{
if (!d->alloc)
return; // zero capacity
detach();
- if (QTypeInfo<T>::isComplex) {
- if (d->count == d->alloc)
- (p->array + (d->start+d->count) % d->alloc)->~T();
- new (p->array + (d->start+d->count) % d->alloc) T(value);
+ if (d->count == d->alloc)
+ (d->array + (d->start+d->count) % d->alloc)->~T();
+ new (d->array + (d->start+d->count) % d->alloc) T(std::move(value));
+
+ if (d->count == d->alloc) {
+ d->start++;
+ d->start %= d->alloc;
+ d->offset++;
} else {
- p->array[(d->start+d->count) % d->alloc] = value;
+ d->count++;
}
+}
+
+template <typename T>
+void QContiguousCache<T>::append(const T &value)
+{
+ if (!d->alloc)
+ return; // zero capacity
+ detach();
+ if (d->count == d->alloc)
+ (d->array + (d->start+d->count) % d->alloc)->~T();
+ new (d->array + (d->start+d->count) % d->alloc) T(value);
if (d->count == d->alloc) {
d->start++;
@@ -361,7 +342,7 @@ void QContiguousCache<T>::append(const T &value)
}
template<typename T>
-void QContiguousCache<T>::prepend(const T &value)
+void QContiguousCache<T>::prepend(T &&value)
{
if (!d->alloc)
return; // zero capacity
@@ -376,28 +357,41 @@ void QContiguousCache<T>::prepend(const T &value)
d->count++;
else
if (d->count == d->alloc)
- (p->array + d->start)->~T();
+ (d->array + d->start)->~T();
- if (QTypeInfo<T>::isComplex)
- new (p->array + d->start) T(value);
+ new (d->array + d->start) T(std::move(value));
+}
+
+template<typename T>
+void QContiguousCache<T>::prepend(const T &value)
+{
+ if (!d->alloc)
+ return; // zero capacity
+ detach();
+ if (d->start)
+ d->start--;
+ else
+ d->start = d->alloc-1;
+ d->offset--;
+
+ if (d->count != d->alloc)
+ d->count++;
else
- p->array[d->start] = value;
+ if (d->count == d->alloc)
+ (d->array + d->start)->~T();
+
+ new (d->array + d->start) T(value);
}
template<typename T>
-void QContiguousCache<T>::insert(int pos, const T &value)
+void QContiguousCache<T>::insert(qsizetype pos, T &&value)
{
- Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range");
+ Q_ASSERT_X(pos >= 0, "QContiguousCache<T>::insert", "index out of range");
if (!d->alloc)
return; // zero capacity
detach();
if (containsIndex(pos)) {
- if (QTypeInfo<T>::isComplex) {
- (p->array + pos % d->alloc)->~T();
- new (p->array + pos % d->alloc) T(value);
- } else {
- p->array[pos % d->alloc] = value;
- }
+ d->array[pos % d->alloc] = std::move(value);
} else if (pos == d->offset-1)
prepend(value);
else if (pos == d->offset+d->count)
@@ -408,27 +402,29 @@ void QContiguousCache<T>::insert(int pos, const T &value)
d->offset = pos;
d->start = pos % d->alloc;
d->count = 1;
- if (QTypeInfo<T>::isComplex)
- new (p->array + d->start) T(value);
- else
- p->array[d->start] = value;
+ new (d->array + d->start) T(std::move(value));
}
}
+template<typename T>
+void QContiguousCache<T>::insert(qsizetype pos, const T &value)
+{
+ return insert(pos, T(value));
+}
template <typename T>
-inline const T &QContiguousCache<T>::at(int pos) const
-{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
+inline const T &QContiguousCache<T>::at(qsizetype pos) const
+{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; }
template <typename T>
-inline const T &QContiguousCache<T>::operator[](int pos) const
-{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
+inline const T &QContiguousCache<T>::operator[](qsizetype pos) const
+{ return at(pos); }
template <typename T>
-inline T &QContiguousCache<T>::operator[](int pos)
+inline T &QContiguousCache<T>::operator[](qsizetype pos)
{
detach();
if (!containsIndex(pos))
insert(pos, T());
- return p->array[pos % d->alloc];
+ return d->array[pos % d->alloc];
}
template <typename T>
@@ -438,7 +434,7 @@ inline void QContiguousCache<T>::removeFirst()
detach();
d->count--;
if (QTypeInfo<T>::isComplex)
- (p->array + d->start)->~T();
+ (d->array + d->start)->~T();
d->start = (d->start + 1) % d->alloc;
d->offset++;
}
@@ -450,16 +446,16 @@ inline void QContiguousCache<T>::removeLast()
detach();
d->count--;
if (QTypeInfo<T>::isComplex)
- (p->array + (d->start + d->count) % d->alloc)->~T();
+ (d->array + (d->start + d->count) % d->alloc)->~T();
}
template <typename T>
inline T QContiguousCache<T>::takeFirst()
-{ T t = first(); removeFirst(); return t; }
+{ T t = std::move(first()); removeFirst(); return t; }
template <typename T>
inline T QContiguousCache<T>::takeLast()
-{ T t = last(); removeLast(); return t; }
+{ T t = std::move(last()); removeLast(); return t; }
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index fa8d21e07a..1d4afabedd 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -359,53 +359,67 @@ void QCryptographicHash::reset()
Adds the first \a length chars of \a data to the cryptographic
hash.
*/
-void QCryptographicHash::addData(const char *data, int length)
+void QCryptographicHash::addData(const char *data, qsizetype length)
{
- switch (d->method) {
- case Sha1:
- sha1Update(&d->sha1Context, (const unsigned char *)data, length);
- break;
+ Q_ASSERT(length >= 0);
+
+#if QT_POINTER_SIZE == 8
+ // feed the data UINT_MAX bytes at a time, as some of the methods below
+ // take a uint (of course, feeding more than 4G of data into the hashing
+ // functions will be pretty slow anyway)
+ qsizetype remaining = length;
+ while (remaining) {
+ length = qMin(qsizetype(std::numeric_limits<uint>::max()), remaining);
+ remaining -= length;
+#else
+ {
+#endif
+ switch (d->method) {
+ case Sha1:
+ sha1Update(&d->sha1Context, (const unsigned char *)data, length);
+ break;
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- default:
- Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
- Q_UNREACHABLE();
- break;
+ default:
+ Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
+ Q_UNREACHABLE();
+ break;
#else
- case Md4:
- md4_update(&d->md4Context, (const unsigned char *)data, length);
- break;
- case Md5:
- MD5Update(&d->md5Context, (const unsigned char *)data, length);
- break;
- case Sha224:
- SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length);
- break;
- case Sha256:
- SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length);
- break;
- case Sha384:
- SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length);
- break;
- case Sha512:
- SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length);
- break;
- case RealSha3_224:
- case Keccak_224:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
- break;
- case RealSha3_256:
- case Keccak_256:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
- break;
- case RealSha3_384:
- case Keccak_384:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
- break;
- case RealSha3_512:
- case Keccak_512:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
- break;
+ case Md4:
+ md4_update(&d->md4Context, (const unsigned char *)data, length);
+ break;
+ case Md5:
+ MD5Update(&d->md5Context, (const unsigned char *)data, length);
+ break;
+ case Sha224:
+ SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case Sha256:
+ SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case Sha384:
+ SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case Sha512:
+ SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case RealSha3_224:
+ case Keccak_224:
+ sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ break;
+ case RealSha3_256:
+ case Keccak_256:
+ sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ break;
+ case RealSha3_384:
+ case Keccak_384:
+ sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ break;
+ case RealSha3_512:
+ case Keccak_512:
+ sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ break;
#endif
+ }
}
d->result.clear();
}
diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h
index ad1de7c756..f76fe2d013 100644
--- a/src/corelib/tools/qcryptographichash.h
+++ b/src/corelib/tools/qcryptographichash.h
@@ -94,7 +94,7 @@ public:
void reset();
- void addData(const char *data, int length);
+ void addData(const char *data, qsizetype length);
void addData(const QByteArray &data);
bool addData(QIODevice* device);
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index 84430ae49a..1207ce0659 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -1382,11 +1382,6 @@ void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qre
}
/*!
- \fn QList<QPointF> QEasingCurve::cubicBezierSpline() const
- \obsolete Use toCubicSpline() instead.
- */
-
-/*!
\since 5.0
Returns the cubicBezierSpline that defines a custom easing curve.
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index d3a468bb22..81833a758f 100644
--- a/src/corelib/tools/qeasingcurve.h
+++ b/src/corelib/tools/qeasingcurve.h
@@ -46,10 +46,6 @@ QT_REQUIRE_CONFIG(easingcurve);
#include <QtCore/qobjectdefs.h>
#include <QtCore/qvector.h>
-#if QT_DEPRECATED_SINCE(5, 0)
-# include <QtCore/qlist.h>
-# include <QtCore/qpoint.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -105,9 +101,6 @@ public:
void addCubicBezierSegment(const QPointF & c1, const QPointF & c2, const QPointF & endPoint);
void addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qreal b);
QVector<QPointF> toCubicSpline() const;
-#if QT_DEPRECATED_SINCE(5, 0)
- QT_DEPRECATED QList<QPointF> cubicBezierSpline() const { return toCubicSpline().toList(); }
-#endif
Type type() const;
void setType(Type type);
diff --git a/src/corelib/tools/qflatmap_p.h b/src/corelib/tools/qflatmap_p.h
new file mode 100644
index 0000000000..82a1068d34
--- /dev/null
+++ b/src/corelib/tools/qflatmap_p.h
@@ -0,0 +1,983 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QFLATMAP_P_H
+#define QFLATMAP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qvector.h"
+
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <numeric>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QFlatMap provides an associative container backed by sorted sequential
+ containers. By default, QVector is used.
+
+ Keys and values are stored in two separate containers. This provides improved
+ cache locality for key iteration and makes keys() and values() fast
+ operations.
+
+ One can customize the underlying container type by passing the KeyContainer
+ and MappedContainer template arguments:
+ QFlatMap<float, int, std::less<float>, std::vector<float>, std::vector<int>>
+*/
+
+namespace Qt {
+
+struct OrderedUniqueRange_t {};
+constexpr OrderedUniqueRange_t OrderedUniqueRange = {};
+
+} // namespace Qt
+
+template <class Key, class T, class Compare>
+class QFlatMapValueCompare : protected Compare
+{
+public:
+ QFlatMapValueCompare() = default;
+ QFlatMapValueCompare(const Compare &key_compare)
+ : Compare(key_compare)
+ {
+ }
+
+ using value_type = std::pair<const Key, T>;
+ static constexpr bool is_comparator_noexcept = noexcept(
+ std::declval<Compare>()(std::declval<Key>(), std::declval<Key>()));
+
+ bool operator()(const value_type &lhs, const value_type &rhs) const
+ noexcept(is_comparator_noexcept)
+ {
+ return Compare::operator()(lhs.first, rhs.first);
+ }
+};
+
+template <class Key, class T,
+ class Compare = std::less<Key>,
+ class KeyContainer = QVector<Key>,
+ class MappedContainer = QVector<T>>
+class QFlatMap : private QFlatMapValueCompare<Key, T, Compare>
+{
+ using full_map_t = QFlatMap<Key, T, Compare, KeyContainer, MappedContainer>;
+
+ template <class U>
+ class mock_pointer
+ {
+ U ref;
+ public:
+ mock_pointer(U r)
+ : ref(r)
+ {
+ }
+
+ U *operator->()
+ {
+ return &ref;
+ }
+ };
+
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using value_compare = QFlatMapValueCompare<Key, T, Compare>;
+ using value_type = typename value_compare::value_type;
+ using key_container_type = KeyContainer;
+ using mapped_container_type = MappedContainer;
+ using size_type = typename key_container_type::size_type;
+ using key_compare = Compare;
+
+ struct containers
+ {
+ key_container_type keys;
+ mapped_container_type values;
+ };
+
+ class iterator
+ {
+ public:
+ using difference_type = ptrdiff_t;
+ using value_type = std::pair<const Key, T>;
+ using reference = std::pair<const Key &, T &>;
+ using pointer = mock_pointer<reference>;
+ using iterator_category = std::random_access_iterator_tag;
+
+ iterator() = default;
+
+ iterator(containers *ac, size_type ai)
+ : c(ac), i(ai)
+ {
+ }
+
+ reference operator*()
+ {
+ return { c->keys[i], c->values[i] };
+ }
+
+ pointer operator->()
+ {
+ return { operator*() };
+ }
+
+ bool operator==(const iterator &o) const
+ {
+ return c == o.c && i == o.i;
+ }
+
+ bool operator!=(const iterator &o) const
+ {
+ return !operator==(o);
+ }
+
+ iterator &operator++()
+ {
+ ++i;
+ return *this;
+ }
+
+ iterator operator++(int)
+ {
+
+ iterator r = *this;
+ i++;
+ return r;
+ }
+
+ iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+
+ iterator operator--(int)
+ {
+ iterator r = *this;
+ i--;
+ return r;
+ }
+
+ iterator &operator+=(size_type n)
+ {
+ i += n;
+ return *this;
+ }
+
+ friend iterator operator+(size_type n, const iterator a)
+ {
+ iterator ret = a;
+ return ret += n;
+ }
+
+ friend iterator operator+(const iterator a, size_type n)
+ {
+ return n + a;
+ }
+
+ iterator &operator-=(size_type n)
+ {
+ i -= n;
+ return *this;
+ }
+
+ friend iterator operator-(const iterator a, size_type n)
+ {
+ iterator ret = a;
+ return ret -= n;
+ }
+
+ friend difference_type operator-(const iterator b, const iterator a)
+ {
+ return b.i - a.i;
+ }
+
+ reference operator[](size_type n)
+ {
+ size_type k = i + n;
+ return { c->keys[k], c->values[k] };
+ }
+
+ bool operator<(const iterator &other) const
+ {
+ return i < other.i;
+ }
+
+ bool operator>(const iterator &other) const
+ {
+ return i > other.i;
+ }
+
+ bool operator<=(const iterator &other) const
+ {
+ return i <= other.i;
+ }
+
+ bool operator>=(const iterator &other) const
+ {
+ return i >= other.i;
+ }
+
+ const Key &key() const { return c->keys[i]; }
+ T &value() { return c->values[i]; }
+
+ private:
+ containers *c = nullptr;
+ size_type i = 0;
+ friend full_map_t;
+ };
+
+ class const_iterator
+ {
+ public:
+ using difference_type = ptrdiff_t;
+ using value_type = std::pair<const Key, const T>;
+ using reference = std::pair<const Key &, const T &>;
+ using pointer = mock_pointer<reference>;
+ using iterator_category = std::random_access_iterator_tag;
+
+ const_iterator() = default;
+
+ const_iterator(const containers *ac, size_type ai)
+ : c(ac), i(ai)
+ {
+ }
+
+ const_iterator(iterator o)
+ : c(o.c), i(o.i)
+ {
+ }
+
+ reference operator*()
+ {
+ return { c->keys[i], c->values[i] };
+ }
+
+ pointer operator->()
+ {
+ return { operator*() };
+ }
+
+ bool operator==(const const_iterator &o) const
+ {
+ return c == o.c && i == o.i;
+ }
+
+ bool operator!=(const const_iterator &o) const
+ {
+ return !operator==(o);
+ }
+
+ const_iterator &operator++()
+ {
+ ++i;
+ return *this;
+ }
+
+ const_iterator operator++(int)
+ {
+
+ const_iterator r = *this;
+ i++;
+ return r;
+ }
+
+ const_iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+
+ const_iterator operator--(int)
+ {
+ const_iterator r = *this;
+ i--;
+ return r;
+ }
+
+ const_iterator &operator+=(size_type n)
+ {
+ i += n;
+ return *this;
+ }
+
+ friend const_iterator operator+(size_type n, const const_iterator a)
+ {
+ const_iterator ret = a;
+ return ret += n;
+ }
+
+ friend const_iterator operator+(const const_iterator a, size_type n)
+ {
+ return n + a;
+ }
+
+ const_iterator &operator-=(size_type n)
+ {
+ i -= n;
+ return *this;
+ }
+
+ friend const_iterator operator-(const const_iterator a, size_type n)
+ {
+ const_iterator ret = a;
+ return ret -= n;
+ }
+
+ friend difference_type operator-(const const_iterator b, const const_iterator a)
+ {
+ return b.i - a.i;
+ }
+
+ reference operator[](size_type n)
+ {
+ size_type k = i + n;
+ return { c->keys[k], c->values[k] };
+ }
+
+ bool operator<(const const_iterator &other) const
+ {
+ return i < other.i;
+ }
+
+ bool operator>(const const_iterator &other) const
+ {
+ return i > other.i;
+ }
+
+ bool operator<=(const const_iterator &other) const
+ {
+ return i <= other.i;
+ }
+
+ bool operator>=(const const_iterator &other) const
+ {
+ return i >= other.i;
+ }
+
+ const Key &key() const { return c->keys[i]; }
+ const T &value() { return c->values[i]; }
+
+ private:
+ const containers *c = nullptr;
+ size_type i = 0;
+ friend full_map_t;
+ };
+
+private:
+ template <class, class = void>
+ struct is_marked_transparent_type : std::false_type { };
+
+ template <class X>
+ struct is_marked_transparent_type<X, typename X::is_transparent> : std::true_type { };
+
+ template <class X>
+ using is_marked_transparent = typename std::enable_if<
+ is_marked_transparent_type<X>::value>::type *;
+
+ template <typename It>
+ using is_compatible_iterator = typename std::enable_if<
+ std::is_same<value_type, typename std::iterator_traits<It>::value_type>::value>::type *;
+
+public:
+ QFlatMap() = default;
+
+ explicit QFlatMap(const key_container_type &keys, const mapped_container_type &values)
+ : c{keys, values}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, const mapped_container_type &values)
+ {
+ c.keys = std::move(keys);
+ c.values = values;
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(const key_container_type &keys, mapped_container_type &&values)
+ {
+ c.keys = keys;
+ c.values = std::move(values);
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, mapped_container_type &&values)
+ {
+ c.keys = std::move(keys);
+ c.values = std::move(values);
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(std::initializer_list<value_type> lst)
+ : QFlatMap(lst.begin(), lst.end())
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(InputIt first, InputIt last)
+ {
+ initWithRange(first, last);
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ const mapped_container_type &values)
+ {
+ c.keys = keys;
+ c.values = values;
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ const mapped_container_type &values)
+ {
+ c.keys = std::move(keys);
+ c.values = values;
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ mapped_container_type &&values)
+ {
+ c.keys = keys;
+ c.values = std::move(values);
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ mapped_container_type &&values)
+ {
+ c.keys = std::move(keys);
+ c.values = std::move(values);
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, std::initializer_list<value_type> lst)
+ : QFlatMap(lst.begin(), lst.end())
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, InputIt first, InputIt last)
+ {
+ initWithRange(first, last);
+ }
+
+ explicit QFlatMap(const Compare &compare)
+ : value_compare(compare)
+ {
+ }
+
+ explicit QFlatMap(const key_container_type &keys, const mapped_container_type &values,
+ const Compare &compare)
+ : value_compare(compare), c{keys, values}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, const mapped_container_type &values,
+ const Compare &compare)
+ : value_compare(compare), c{std::move(keys), values}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(const key_container_type &keys, mapped_container_type &&values,
+ const Compare &compare)
+ : value_compare(compare), c{keys, std::move(values)}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, mapped_container_type &&values,
+ const Compare &compare)
+ : value_compare(compare), c{std::move(keys), std::move(values)}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(std::initializer_list<value_type> lst, const Compare &compare)
+ : QFlatMap(lst.begin(), lst.end(), compare)
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(InputIt first, InputIt last, const Compare &compare)
+ : value_compare(compare)
+ {
+ initWithRange(first, last);
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ const mapped_container_type &values, const Compare &compare)
+ : value_compare(compare), c{keys, values}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ const mapped_container_type &values, const Compare &compare)
+ : value_compare(compare), c{std::move(keys), values}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ mapped_container_type &&values, const Compare &compare)
+ : value_compare(compare), c{keys, std::move(values)}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ mapped_container_type &&values, const Compare &compare)
+ : value_compare(compare), c{std::move(keys), std::move(values)}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, std::initializer_list<value_type> lst,
+ const Compare &compare)
+ : QFlatMap(Qt::OrderedUniqueRange, lst.begin(), lst.end(), compare)
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, InputIt first, InputIt last, const Compare &compare)
+ : value_compare(compare)
+ {
+ initWithRange(first, last);
+ }
+
+ size_type count() const noexcept { return c.keys.size(); }
+ size_type size() const noexcept { return c.keys.size(); }
+ size_type capacity() const noexcept { return c.keys.capacity(); }
+ bool isEmpty() const noexcept { return c.keys.empty(); }
+ bool empty() const noexcept { return c.keys.empty(); }
+ containers extract() && { return std::move(c); }
+ const key_container_type &keys() const noexcept { return c.keys; }
+ const mapped_container_type &values() const noexcept { return c.values; }
+
+ void reserve(size_type s)
+ {
+ c.keys.reserve(s);
+ c.values.reserve(s);
+ }
+
+ void clear()
+ {
+ c.keys.clear();
+ c.values.clear();
+ }
+
+ bool remove(const Key &key)
+ {
+ auto it = binary_find(key);
+ if (it != end()) {
+ c.keys.erase(toKeysIterator(it));
+ c.values.erase(toValuesIterator(it));
+ return true;
+ }
+ return false;
+ }
+
+ iterator erase(iterator it)
+ {
+ c.values.erase(toValuesIterator(it));
+ return fromKeysIterator(c.keys.erase(toKeysIterator(it)));
+ }
+
+ T take(const Key &key)
+ {
+ auto it = binary_find(key);
+ if (it != end()) {
+ T result = std::move(it.value());
+ erase(it);
+ return result;
+ }
+ return {};
+ }
+
+ bool contains(const Key &key) const
+ {
+ return binary_find(key) != end();
+ }
+
+ T value(const Key &key, const T &defaultValue) const
+ {
+ auto it = binary_find(key);
+ return it == end() ? defaultValue : it.value();
+ }
+
+ T value(const Key &key) const
+ {
+ auto it = binary_find(key);
+ return it == end() ? T() : it.value();
+ }
+
+ T &operator[](const Key &key)
+ {
+ auto it = lower_bound(key);
+ if (it == end() || key_compare::operator()(key, it.key())) {
+ c.keys.insert(toKeysIterator(it), key);
+ return *c.values.insert(toValuesIterator(it), T());
+ }
+ return it.value();
+ }
+
+ T &operator[](Key &&key)
+ {
+ auto it = lower_bound(key);
+ if (it == end() || key_compare::operator()(key, it.key())) {
+ c.keys.insert(toKeysIterator(it), key);
+ return *c.values.insert(toValuesIterator(it), T());
+ }
+ return it.value();
+ }
+
+ T operator[](const Key &key) const
+ {
+ return value(key);
+ }
+
+ std::pair<iterator, bool> insert(const Key &key, const T &value)
+ {
+ auto it = lower_bound(key);
+ if (it == end() || key_compare::operator()(key, it.key())) {
+ c.values.insert(toValuesIterator(it), value);
+ auto k = c.keys.insert(toKeysIterator(it), key);
+ return { fromKeysIterator(k), true };
+ } else {
+ it.value() = value;
+ return {it, false};
+ }
+ }
+
+ std::pair<iterator, bool> insert(Key &&key, const T &value)
+ {
+ auto it = lower_bound(key);
+ if (it == end() || key_compare::operator()(key, it.key())) {
+ c.values.insert(toValuesIterator(it), value);
+ return { c.keys.insert(it, std::move(key)), true };
+ } else {
+ *toValuesIterator(it) = value;
+ return {it, false};
+ }
+ }
+
+ std::pair<iterator, bool> insert(const Key &key, T &&value)
+ {
+ auto it = lower_bound(key);
+ if (it == end() || key_compare::operator()(key, it.key())) {
+ c.values.insert(toValuesIterator(it), std::move(value));
+ return { c.keys.insert(it, key), true };
+ } else {
+ *toValuesIterator(it) = std::move(value);
+ return {it, false};
+ }
+ }
+
+ std::pair<iterator, bool> insert(Key &&key, T &&value)
+ {
+ auto it = lower_bound(key);
+ if (it == end() || key_compare::operator()(key, it.key())) {
+ c.values.insert(toValuesIterator(it), std::move(value));
+ return { fromKeysIterator(c.keys.insert(toKeysIterator(it), std::move(key))), true };
+ } else {
+ *toValuesIterator(it) = std::move(value);
+ return {it, false};
+ }
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ void insert(InputIt first, InputIt last)
+ {
+ insertRange(first, last);
+ }
+
+ // ### Merge with the templated version above
+ // once we can use std::disjunction in is_compatible_iterator.
+ void insert(const value_type *first, const value_type *last)
+ {
+ insertRange(first, last);
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ void insert(Qt::OrderedUniqueRange_t, InputIt first, InputIt last)
+ {
+ insertOrderedUniqueRange(first, last);
+ }
+
+ // ### Merge with the templated version above
+ // once we can use std::disjunction in is_compatible_iterator.
+ void insert(Qt::OrderedUniqueRange_t, const value_type *first, const value_type *last)
+ {
+ insertOrderedUniqueRange(first, last);
+ }
+
+ iterator begin() { return { &c, 0 }; }
+ const_iterator begin() const { return { &c, 0 }; }
+ const_iterator cbegin() const { return begin(); }
+ const_iterator constBegin() const { return cbegin(); }
+ iterator end() { return { &c, c.keys.size() }; }
+ const_iterator end() const { return { &c, c.keys.size() }; }
+ const_iterator cend() const { return end(); }
+ const_iterator constEnd() const { return cend(); }
+ std::reverse_iterator<iterator> rbegin() { return std::reverse_iterator<iterator>(end()); }
+ std::reverse_iterator<const_iterator> rbegin() const
+ {
+ return std::reverse_iterator<const_iterator>(end());
+ }
+ std::reverse_iterator<const_iterator> crbegin() const { return rbegin(); }
+ std::reverse_iterator<iterator> rend() {
+ return std::reverse_iterator<iterator>(begin());
+ }
+ std::reverse_iterator<const_iterator> rend() const
+ {
+ return std::reverse_iterator<const_iterator>(begin());
+ }
+ std::reverse_iterator<const_iterator> crend() const { return rend(); }
+
+ iterator lower_bound(const Key &key)
+ {
+ auto cit = const_cast<const full_map_t *>(this)->lower_bound(key);
+ return { &c, cit.i };
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ iterator lower_bound(const X &key)
+ {
+ auto cit = const_cast<const full_map_t *>(this)->lower_bound(key);
+ return { &c, cit.i };
+ }
+
+ const_iterator lower_bound(const Key &key) const
+ {
+ return fromKeysIterator(std::lower_bound(c.keys.begin(), c.keys.end(), key, key_comp()));
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ const_iterator lower_bound(const X &key) const
+ {
+ return fromKeysIterator(std::lower_bound(c.keys.begin(), c.keys.end(), key, key_comp()));
+ }
+
+ iterator find(const key_type &k)
+ {
+ return binary_find(k);
+ }
+
+ const_iterator find(const key_type &k) const
+ {
+ return binary_find(k);
+ }
+
+ key_compare key_comp() const noexcept
+ {
+ return static_cast<key_compare>(*this);
+ }
+
+ value_compare value_comp() const noexcept
+ {
+ return static_cast<value_compare>(*this);
+ }
+
+private:
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ void initWithRange(InputIt first, InputIt last)
+ {
+ QtPrivate::reserveIfForwardIterator(this, first, last);
+ while (first != last) {
+ c.keys.push_back(first->first);
+ c.values.push_back(first->second);
+ ++first;
+ }
+ }
+
+ iterator fromKeysIterator(typename key_container_type::iterator kit)
+ {
+ return { &c, static_cast<size_type>(std::distance(c.keys.begin(), kit)) };
+ }
+
+ const_iterator fromKeysIterator(typename key_container_type::const_iterator kit) const
+ {
+ return { &c, static_cast<size_type>(std::distance(c.keys.begin(), kit)) };
+ }
+
+ typename key_container_type::iterator toKeysIterator(iterator it)
+ {
+ return c.keys.begin() + it.i;
+ }
+
+ typename mapped_container_type::iterator toValuesIterator(iterator it)
+ {
+ return c.values.begin() + it.i;
+ }
+
+ template <class InputIt>
+ void insertRange(InputIt first, InputIt last)
+ {
+ size_type i = c.keys.size();
+ c.keys.resize(i + std::distance(first, last));
+ c.values.resize(c.keys.size());
+ for (; first != last; ++first, ++i) {
+ c.keys[i] = first->first;
+ c.values[i] = first->second;
+ }
+ ensureOrderedUnique();
+ }
+
+ class IndexedKeyComparator
+ {
+ public:
+ IndexedKeyComparator(const full_map_t *am)
+ : m(am)
+ {
+ }
+
+ bool operator()(size_type i, size_type k) const
+ {
+ return m->key_comp()(m->c.keys[i], m->c.keys[k]);
+ }
+
+ private:
+ const full_map_t *m;
+ };
+
+ template <class InputIt>
+ void insertOrderedUniqueRange(InputIt first, InputIt last)
+ {
+ const size_type s = c.keys.size();
+ c.keys.resize(s + std::distance(first, last));
+ c.values.resize(c.keys.size());
+ for (size_type i = s; first != last; ++first, ++i) {
+ c.keys[i] = first->first;
+ c.values[i] = first->second;
+ }
+
+ std::vector<size_type> p(size_t(c.keys.size()));
+ std::iota(p.begin(), p.end(), 0);
+ std::inplace_merge(p.begin(), p.begin() + s, p.end(), IndexedKeyComparator(this));
+ applyPermutation(p);
+ makeUnique();
+ }
+
+ iterator binary_find(const Key &key)
+ {
+ return { &c, const_cast<const full_map_t *>(this)->binary_find(key).i };
+ }
+
+ const_iterator binary_find(const Key &key) const
+ {
+ auto it = lower_bound(key);
+ if (it != end()) {
+ if (!key_compare::operator()(key, it.key()))
+ return it;
+ it = end();
+ }
+ return it;
+ }
+
+ void ensureOrderedUnique()
+ {
+ std::vector<size_type> p(size_t(c.keys.size()));
+ std::iota(p.begin(), p.end(), 0);
+ std::stable_sort(p.begin(), p.end(), IndexedKeyComparator(this));
+ applyPermutation(p);
+ makeUnique();
+ }
+
+ void applyPermutation(const std::vector<size_type> &p)
+ {
+ const size_type s = c.keys.size();
+ std::vector<bool> done(s);
+ for (size_type i = 0; i < s; ++i) {
+ if (done[i])
+ continue;
+ done[i] = true;
+ size_type j = i;
+ size_type k = p[i];
+ while (i != k) {
+ qSwap(c.keys[j], c.keys[k]);
+ qSwap(c.values[j], c.values[k]);
+ done[k] = true;
+ j = k;
+ k = p[j];
+ }
+ }
+ }
+
+ void makeUnique()
+ {
+ if (c.keys.size() < 2)
+ return;
+ auto k = std::end(c.keys) - 1;
+ auto i = k - 1;
+ for (;;) {
+ if (key_compare::operator()(*i, *k) || key_compare::operator()(*k, *i)) {
+ if (i == std::begin(c.keys))
+ break;
+ --i;
+ --k;
+ } else {
+ c.values.erase(std::begin(c.values) + std::distance(std::begin(c.keys), i));
+ i = c.keys.erase(i);
+ if (i == std::begin(c.keys))
+ break;
+ k = i + 1;
+ }
+ }
+ c.keys.shrink_to_fit();
+ c.values.shrink_to_fit();
+ }
+
+ containers c;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFLATMAP_P_H
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 025c6e9dc0..97dda58748 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -45,6 +45,7 @@
#define _CRT_RAND_S
#endif
#include <stdlib.h>
+#include <stdint.h>
#include "qhash.h"
@@ -70,191 +71,356 @@
QT_BEGIN_NAMESPACE
+// We assume that pointers and size_t have the same size. If that assumption should fail
+// on a platform the code selecting the different methods below needs to be fixed.
+static_assert(sizeof(size_t) == QT_POINTER_SIZE, "size_t and pointers have different size.");
+
/*
- The Java's hashing algorithm for strings is a variation of D. J. Bernstein
- hashing algorithm appeared here http://cr.yp.to/cdb/cdb.txt
- and informally known as DJB33XX - DJB's 33 Times Xor.
- Java uses DJB31XA, that is, 31 Times Add.
-
- The original algorithm was a loop around
- (h << 5) + h ^ c
- (which is indeed h*33 ^ c); it was then changed to
- (h << 5) - h ^ c
- (so h*31^c: DJB31XX), and the XOR changed to a sum:
- (h << 5) - h + c
- (DJB31XA), which can save some assembly instructions.
-
- Still, we can avoid writing the multiplication as "(h << 5) - h"
- -- the compiler will turn it into a shift and an addition anyway
- (for instance, gcc 4.4 does that even at -O0).
-*/
-
-#if QT_COMPILER_SUPPORTS_HERE(SSE4_2)
-static inline bool hasFastCrc32()
-{
- return qCpuHasFeature(SSE4_2);
-}
+ * Hashing for memory segments is based on the public domain MurmurHash2 by
+ * Austin Appleby. See http://murmurhash.googlepages.com/
+ */
+#if QT_POINTER_SIZE == 4
-template <typename Char>
-QT_FUNCTION_TARGET(SSE4_2)
-static uint crc32(const Char *ptr, size_t len, uint h)
+static inline uint murmurhash(const void *key, uint len, uint seed) noexcept
{
- // The CRC32 instructions from Nehalem calculate a 32-bit CRC32 checksum
- const uchar *p = reinterpret_cast<const uchar *>(ptr);
- const uchar *const e = p + (len * sizeof(Char));
-# ifdef Q_PROCESSOR_X86_64
- // The 64-bit instruction still calculates only 32-bit, but without this
- // variable GCC 4.9 still tries to clear the high bits on every loop
- qulonglong h2 = h;
-
- p += 8;
- for ( ; p <= e; p += 8)
- h2 = _mm_crc32_u64(h2, qFromUnaligned<qlonglong>(p - 8));
- h = h2;
- p -= 8;
-
- len = e - p;
- if (len & 4) {
- h = _mm_crc32_u32(h, qFromUnaligned<uint>(p));
- p += 4;
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+
+ unsigned int h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
+ const unsigned char *end = data + (len & ~3);
+
+ while (data != end) {
+ size_t k;
+ memcpy(&k, data, sizeof(uint));
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
}
-# else
- p += 4;
- for ( ; p <= e; p += 4)
- h = _mm_crc32_u32(h, qFromUnaligned<uint>(p - 4));
- p -= 4;
- len = e - p;
-# endif
- if (len & 2) {
- h = _mm_crc32_u16(h, qFromUnaligned<ushort>(p));
- p += 2;
+
+ // Handle the last few bytes of the input array
+ len &= 3;
+ if (len) {
+ unsigned int k = 0;
+ end += len;
+
+ while (data != end) {
+ k <<= 8;
+ k |= *data;
+ ++data;
+ }
+ h ^= k;
+ h *= m;
}
- if (sizeof(Char) == 1 && len & 1)
- h = _mm_crc32_u8(h, *p);
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
return h;
}
-#elif defined(__ARM_FEATURE_CRC32)
-static inline bool hasFastCrc32()
+
+#else
+
+static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed) noexcept
{
- return qCpuHasFeature(CRC32);
+ const uint64_t m = 0xc6a4a7935bd1e995ULL;
+ const int r = 47;
+
+ uint64_t h = seed ^ (len * m);
+
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
+ const unsigned char *end = data + (len & ~7ul);
+
+ while (data != end) {
+ uint64_t k;
+ memcpy(&k, data, sizeof(uint64_t));
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h ^= k;
+ h *= m;
+
+ data += 8;
+ }
+
+ len &= 7;
+ if (len) {
+ // handle the last few bytes of input
+ size_t k = 0;
+ end += len;
+
+ while (data != end) {
+ k <<= 8;
+ k |= *data;
+ ++data;
+ }
+ h ^= k;
+ h *= m;
+ }
+
+ h ^= h >> r;
+ h *= m;
+ h ^= h >> r;
+
+ return h;
}
-template <typename Char>
-#if defined(Q_PROCESSOR_ARM_64)
-QT_FUNCTION_TARGET(CRC32)
#endif
-static uint crc32(const Char *ptr, size_t len, uint h)
+
+#if QT_POINTER_SIZE == 8
+// This is an inlined version of the SipHash implementation that is
+// trying to avoid some memcpy's from uint64 to uint8[] and back.
+//
+// The original algorithm uses a 128bit seed. Our public API only allows
+// for a 64bit seed, so we mix in the length of the string to get some more
+// bits for the seed.
+//
+// Use SipHash-1-2, which has similar performance characteristics as
+// stablehash() above, instead of the SipHash-2-4 default
+#define cROUNDS 1
+#define dROUNDS 2
+
+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#define SIPROUND \
+ do { \
+ v0 += v1; \
+ v1 = ROTL(v1, 13); \
+ v1 ^= v0; \
+ v0 = ROTL(v0, 32); \
+ v2 += v3; \
+ v3 = ROTL(v3, 16); \
+ v3 ^= v2; \
+ v0 += v3; \
+ v3 = ROTL(v3, 21); \
+ v3 ^= v0; \
+ v2 += v1; \
+ v1 = ROTL(v1, 17); \
+ v1 ^= v2; \
+ v2 = ROTL(v2, 32); \
+ } while (0)
+
+
+static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
{
- // The crc32[whbd] instructions on Aarch64/Aarch32 calculate a 32-bit CRC32 checksum
- const uchar *p = reinterpret_cast<const uchar *>(ptr);
- const uchar *const e = p + (len * sizeof(Char));
-
-#ifndef __ARM_FEATURE_UNALIGNED
- if (Q_UNLIKELY(reinterpret_cast<quintptr>(p) & 7)) {
- if ((sizeof(Char) == 1) && (reinterpret_cast<quintptr>(p) & 1) && (e - p > 0)) {
- h = __crc32b(h, *p);
- ++p;
- }
- if ((reinterpret_cast<quintptr>(p) & 2) && (e >= p + 2)) {
- h = __crc32h(h, *reinterpret_cast<const uint16_t *>(p));
- p += 2;
- }
- if ((reinterpret_cast<quintptr>(p) & 4) && (e >= p + 4)) {
- h = __crc32w(h, *reinterpret_cast<const uint32_t *>(p));
- p += 4;
- }
+ /* "somepseudorandomlygeneratedbytes" */
+ uint64_t v0 = 0x736f6d6570736575ULL;
+ uint64_t v1 = 0x646f72616e646f6dULL;
+ uint64_t v2 = 0x6c7967656e657261ULL;
+ uint64_t v3 = 0x7465646279746573ULL;
+ uint64_t b;
+ uint64_t k0 = seed;
+ uint64_t k1 = seed ^ inlen;
+ int i;
+ const uint8_t *end = in + (inlen & ~7ULL);
+ const int left = inlen & 7;
+ b = inlen << 56;
+ v3 ^= k1;
+ v2 ^= k0;
+ v1 ^= k1;
+ v0 ^= k0;
+
+ for (; in != end; in += 8) {
+ uint64_t m = qFromUnaligned<uint64_t>(in);
+ v3 ^= m;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
+
+ v0 ^= m;
}
-#endif
- for ( ; p + 8 <= e; p += 8)
- h = __crc32d(h, *reinterpret_cast<const uint64_t *>(p));
- len = e - p;
- if (len == 0)
- return h;
- if (len & 4) {
- h = __crc32w(h, *reinterpret_cast<const uint32_t *>(p));
- p += 4;
- }
- if (len & 2) {
- h = __crc32h(h, *reinterpret_cast<const uint16_t *>(p));
- p += 2;
+#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
+ QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
+#endif
+ switch (left) {
+ case 7:
+ b |= ((uint64_t)in[6]) << 48;
+ case 6:
+ b |= ((uint64_t)in[5]) << 40;
+ case 5:
+ b |= ((uint64_t)in[4]) << 32;
+ case 4:
+ b |= ((uint64_t)in[3]) << 24;
+ case 3:
+ b |= ((uint64_t)in[2]) << 16;
+ case 2:
+ b |= ((uint64_t)in[1]) << 8;
+ case 1:
+ b |= ((uint64_t)in[0]);
+ break;
+ case 0:
+ break;
}
- if (sizeof(Char) == 1 && len & 1)
- h = __crc32b(h, *p);
- return h;
+
+ v3 ^= b;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
+
+ v0 ^= b;
+
+ v2 ^= 0xff;
+
+ for (i = 0; i < dROUNDS; ++i)
+ SIPROUND;
+
+ b = v0 ^ v1 ^ v2 ^ v3;
+ return b;
}
#else
-static inline bool hasFastCrc32()
+// This is a "SipHash" implementation adopted for 32bit platforms. It performs
+// basically the same operations as the 64bit version using 4 byte at a time
+// instead of 8.
+//
+// To make this work, we also need to change the constants for the mixing
+// rotations in ROTL. We're simply using half of the 64bit constants, rounded up
+// for odd numbers.
+//
+// For the v0-v4 constants, simply use the first four bytes of the 64 bit versions.
+//
+// Use SipHash-1-2, which has similar performance characteristics as
+// stablehash() above, instead of the SipHash-2-4 default
+#define cROUNDS 1
+#define dROUNDS 2
+
+#define ROTL(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
+
+#define SIPROUND \
+ do { \
+ v0 += v1; \
+ v1 = ROTL(v1, 7); \
+ v1 ^= v0; \
+ v0 = ROTL(v0, 16); \
+ v2 += v3; \
+ v3 = ROTL(v3, 8); \
+ v3 ^= v2; \
+ v0 += v3; \
+ v3 = ROTL(v3, 11); \
+ v3 ^= v0; \
+ v2 += v1; \
+ v1 = ROTL(v1, 9); \
+ v1 ^= v2; \
+ v2 = ROTL(v2, 16); \
+ } while (0)
+
+
+static uint siphash(const uint8_t *in, uint inlen, const uint seed)
{
- return false;
-}
+ /* "somepseudorandomlygeneratedbytes" */
+ uint v0 = 0x736f6d65U;
+ uint v1 = 0x646f7261U;
+ uint v2 = 0x6c796765U;
+ uint v3 = 0x74656462U;
+ uint b;
+ uint k0 = seed;
+ uint k1 = seed ^ inlen;
+ int i;
+ const uint8_t *end = in + (inlen & ~3ULL);
+ const int left = inlen & 3;
+ b = inlen << 24;
+ v3 ^= k1;
+ v2 ^= k0;
+ v1 ^= k1;
+ v0 ^= k0;
+
+ for (; in != end; in += 4) {
+ uint m = qFromUnaligned<uint>(in);
+ v3 ^= m;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
+
+ v0 ^= m;
+ }
-static uint crc32(...)
-{
- Q_UNREACHABLE();
- return 0;
-}
+#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
+ QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
#endif
+ switch (left) {
+ case 3:
+ b |= ((uint)in[2]) << 16;
+ case 2:
+ b |= ((uint)in[1]) << 8;
+ case 1:
+ b |= ((uint)in[0]);
+ break;
+ case 0:
+ break;
+ }
-static inline uint hash(const uchar *p, size_t len, uint seed) noexcept
-{
- uint h = seed;
+ v3 ^= b;
- if (seed && hasFastCrc32())
- return crc32(p, len, h);
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
- for (size_t i = 0; i < len; ++i)
- h = 31 * h + p[i];
+ v0 ^= b;
- return h;
-}
+ v2 ^= 0xff;
-uint qHashBits(const void *p, size_t len, uint seed) noexcept
-{
- return hash(static_cast<const uchar*>(p), int(len), seed);
+ for (i = 0; i < dROUNDS; ++i)
+ SIPROUND;
+
+ b = v0 ^ v1 ^ v2 ^ v3;
+ return b;
}
+#endif
-static inline uint hash(const QChar *p, size_t len, uint seed) noexcept
+size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
{
- uint h = seed;
+ if (size <= QT_POINTER_SIZE)
+ return murmurhash(p, size, seed);
- if (seed && hasFastCrc32())
- return crc32(p, len, h);
-
- for (size_t i = 0; i < len; ++i)
- h = 31 * h + p[i].unicode();
-
- return h;
+ return siphash(reinterpret_cast<const uchar *>(p), size, seed);
}
-uint qHash(const QByteArray &key, uint seed) noexcept
+size_t qHash(const QByteArray &key, size_t seed) noexcept
{
- return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed);
+ return qHashBits(key.constData(), size_t(key.size()), seed);
}
#if QT_STRINGVIEW_LEVEL < 2
-uint qHash(const QString &key, uint seed) noexcept
+size_t qHash(const QString &key, size_t seed) noexcept
{
- return hash(key.unicode(), size_t(key.size()), seed);
+ return qHashBits(key.unicode(), size_t(key.size())*sizeof(QChar), seed);
}
-uint qHash(const QStringRef &key, uint seed) noexcept
+size_t qHash(const QStringRef &key, size_t seed) noexcept
{
- return hash(key.unicode(), size_t(key.size()), seed);
+ return qHashBits(key.unicode(), size_t(key.size())*sizeof(QChar), seed);
}
#endif
-uint qHash(QStringView key, uint seed) noexcept
+size_t qHash(QStringView key, size_t seed) noexcept
{
- return hash(key.data(), key.size(), seed);
+ return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
}
-uint qHash(const QBitArray &bitArray, uint seed) noexcept
+size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
{
int m = bitArray.d.size() - 1;
- uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()),
- size_t(qMax(0, m)), seed);
+ size_t result = qHashBits(reinterpret_cast<const uchar *>(bitArray.d.constData()), size_t(qMax(0, m)), seed);
// deal with the last 0 to 7 bits manually, because we can't trust that
// the padding is initialized to 0 in bitArray.d
@@ -264,21 +430,13 @@ uint qHash(const QBitArray &bitArray, uint seed) noexcept
return result;
}
-uint qHash(QLatin1String key, uint seed) noexcept
+size_t qHash(QLatin1String key, size_t seed) noexcept
{
- return hash(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
+ return qHashBits(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
}
/*!
\internal
-
- Creates the QHash random seed from various sources.
- In order of decreasing precedence:
- - under Unix, it attemps to read from /dev/urandom;
- - under Unix, it attemps to read from /dev/random;
- - under Windows, it attempts to use rand_s;
- - as a general fallback, the application's PID, a timestamp and the
- address of a stack-local variable are used.
*/
static uint qt_create_qhash_seed()
{
@@ -413,330 +571,8 @@ uint qt_hash(QStringView key, uint chained) noexcept
return h;
}
-/*
- The prime_deltas array contains the difference between a power
- of two and the next prime number:
-
- prime_deltas[i] = nextprime(2^i) - 2^i
-
- Basically, it's sequence A092131 from OEIS, assuming:
- - nextprime(1) = 1
- - nextprime(2) = 2
- and
- - left-extending it for the offset 0 (A092131 starts at i=1)
- - stopping the sequence at i = 28 (the table is big enough...)
-*/
-
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 17, 27, 3,
- 1, 29, 3, 21, 7, 17, 15, 9, 43, 35, 15, 0, 0, 0, 0, 0
-};
-
-/*
- The primeForNumBits() function returns the prime associated to a
- power of two. For example, primeForNumBits(8) returns 257.
-*/
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-/*
- Returns the smallest integer n such that
- primeForNumBits(n) >= hint.
-*/
-static int countBits(int hint)
-{
- int numBits = 0;
- int bits = hint;
-
- while (bits > 1) {
- bits >>= 1;
- numBits++;
- }
-
- if (numBits >= (int)sizeof(prime_deltas)) {
- numBits = sizeof(prime_deltas) - 1;
- } else if (primeForNumBits(numBits) < hint) {
- ++numBits;
- }
- return numBits;
-}
-
-/*
- A QHash has initially around pow(2, MinNumBits) buckets. For
- example, if MinNumBits is 4, it has 17 buckets.
-*/
-const int MinNumBits = 4;
-
-const QHashData QHashData::shared_null = {
- nullptr, nullptr, Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, MinNumBits, 0, 0, 0, true, false, 0
-};
-
-void *QHashData::allocateNode(int nodeAlign)
-{
- void *ptr = strictAlignment ? qMallocAligned(nodeSize, nodeAlign) : malloc(nodeSize);
- Q_CHECK_PTR(ptr);
- return ptr;
-}
-
-void QHashData::freeNode(void *node)
-{
- if (strictAlignment)
- qFreeAligned(node);
- else
- free(node);
-}
-
-QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *),
- void (*node_delete)(Node *),
- int nodeSize,
- int nodeAlign)
-{
- union {
- QHashData *d;
- Node *e;
- };
- if (this == &shared_null)
- qt_initialize_qhash_seed(); // may throw
- d = new QHashData;
- d->fakeNext = nullptr;
- d->buckets = nullptr;
- d->ref.initializeOwned();
- d->size = size;
- d->nodeSize = nodeSize;
- d->userNumBits = userNumBits;
- d->numBits = numBits;
- d->numBuckets = numBuckets;
- d->seed = (this == &shared_null) ? uint(qt_qhash_seed.loadRelaxed()) : seed;
- d->sharable = true;
- d->strictAlignment = nodeAlign > 8;
- d->reserved = 0;
-
- if (numBuckets) {
- QT_TRY {
- d->buckets = new Node *[numBuckets];
- } QT_CATCH(...) {
- // restore a consistent state for d
- d->numBuckets = 0;
- // roll back
- d->free_helper(node_delete);
- QT_RETHROW;
- }
-
- Node *this_e = reinterpret_cast<Node *>(this);
- for (int i = 0; i < numBuckets; ++i) {
- Node **nextNode = &d->buckets[i];
- Node *oldNode = buckets[i];
- while (oldNode != this_e) {
- QT_TRY {
- Node *dup = static_cast<Node *>(allocateNode(nodeAlign));
-
- QT_TRY {
- node_duplicate(oldNode, dup);
- } QT_CATCH(...) {
- freeNode( dup );
- QT_RETHROW;
- }
-
- *nextNode = dup;
- nextNode = &dup->next;
- oldNode = oldNode->next;
- } QT_CATCH(...) {
- // restore a consistent state for d
- *nextNode = e;
- d->numBuckets = i+1;
- // roll back
- d->free_helper(node_delete);
- QT_RETHROW;
- }
- }
- *nextNode = e;
- }
- }
- return d;
-}
-
-void QHashData::free_helper(void (*node_delete)(Node *))
-{
- if (node_delete) {
- Node *this_e = reinterpret_cast<Node *>(this);
- Node **bucket = reinterpret_cast<Node **>(this->buckets);
-
- int n = numBuckets;
- while (n--) {
- Node *cur = *bucket++;
- while (cur != this_e) {
- Node *next = cur->next;
- node_delete(cur);
- freeNode(cur);
- cur = next;
- }
- }
- }
- delete [] buckets;
- delete this;
-}
-
-QHashData::Node *QHashData::nextNode(Node *node)
-{
- union {
- Node *next;
- Node *e;
- QHashData *d;
- };
- next = node->next;
- Q_ASSERT_X(next, "QHash", "Iterating beyond end()");
- if (next->next)
- return next;
-
- int start = (node->h % d->numBuckets) + 1;
- Node **bucket = d->buckets + start;
- int n = d->numBuckets - start;
- while (n--) {
- if (*bucket != e)
- return *bucket;
- ++bucket;
- }
- return e;
-}
-
-QHashData::Node *QHashData::previousNode(Node *node)
-{
- union {
- Node *e;
- QHashData *d;
- };
-
- e = node;
- while (e->next)
- e = e->next;
-
- int start;
- if (node == e)
- start = d->numBuckets - 1;
- else
- start = node->h % d->numBuckets;
-
- Node *sentinel = node;
- Node **bucket = d->buckets + start;
- while (start >= 0) {
- if (*bucket != sentinel) {
- Node *prev = *bucket;
- while (prev->next != sentinel)
- prev = prev->next;
- return prev;
- }
-
- sentinel = e;
- --bucket;
- --start;
- }
- Q_ASSERT_X(start >= 0, "QHash", "Iterating backward beyond begin()");
- return e;
-}
-
-/*
- If hint is negative, -hint gives the approximate number of
- buckets that should be used for the hash table. If hint is
- nonnegative, (1 << hint) gives the approximate number
- of buckets that should be used.
-*/
-void QHashData::rehash(int hint)
-{
- if (hint < 0) {
- hint = countBits(-hint);
- if (hint < MinNumBits)
- hint = MinNumBits;
- userNumBits = hint;
- while (primeForNumBits(hint) < (size >> 1))
- ++hint;
- } else if (hint < MinNumBits) {
- hint = MinNumBits;
- }
-
- if (numBits != hint) {
- Node *e = reinterpret_cast<Node *>(this);
- Node **oldBuckets = buckets;
- int oldNumBuckets = numBuckets;
-
- int nb = primeForNumBits(hint);
- buckets = new Node *[nb];
- numBits = hint;
- numBuckets = nb;
- for (int i = 0; i < numBuckets; ++i)
- buckets[i] = e;
-
- for (int i = 0; i < oldNumBuckets; ++i) {
- Node *firstNode = oldBuckets[i];
- while (firstNode != e) {
- uint h = firstNode->h;
- Node *lastNode = firstNode;
- while (lastNode->next != e && lastNode->next->h == h)
- lastNode = lastNode->next;
-
- Node *afterLastNode = lastNode->next;
- Node **beforeFirstNode = &buckets[h % numBuckets];
- while (*beforeFirstNode != e)
- beforeFirstNode = &(*beforeFirstNode)->next;
- lastNode->next = *beforeFirstNode;
- *beforeFirstNode = firstNode;
- firstNode = afterLastNode;
- }
- }
- delete [] oldBuckets;
- }
-}
-
-#ifdef QT_QHASH_DEBUG
-
-void QHashData::dump()
-{
- qDebug("Hash data (ref = %d, size = %d, nodeSize = %d, userNumBits = %d, numBits = %d, numBuckets = %d)",
- int(ref), size, nodeSize, userNumBits, numBits,
- numBuckets);
- qDebug(" %p (fakeNode = %p)", this, fakeNext);
- for (int i = 0; i < numBuckets; ++i) {
- Node *n = buckets[i];
- if (n != reinterpret_cast<Node *>(this)) {
- QString line = QString::asprintf("%d:", i);
- while (n != reinterpret_cast<Node *>(this)) {
- line += QString::asprintf(" -> [%p]", n);
- if (!n) {
- line += " (CORRUPT)";
- break;
- }
- n = n->next;
- }
- qDebug("%ls", qUtf16Printable(line));
- }
- }
-}
-
-void QHashData::checkSanity()
-{
- if (Q_UNLIKELY(fakeNext))
- qFatal("Fake next isn't 0");
-
- for (int i = 0; i < numBuckets; ++i) {
- Node *n = buckets[i];
- Node *p = n;
- if (Q_UNLIKELY(!n))
- qFatal("%d: Bucket entry is 0", i);
- if (n != reinterpret_cast<Node *>(this)) {
- while (n != reinterpret_cast<Node *>(this)) {
- if (Q_UNLIKELY(!n->next))
- qFatal("%d: Next of %p is 0, should be %p", i, n, this);
- n = n->next;
- }
- }
- }
-}
-#endif
-
/*!
- \fn template <typename T1, typename T2> uint qHash(const QPair<T1, T2> &key, uint seed = 0)
+ \fn template <typename T1, typename T2> size_t qHash(const QPair<T1, T2> &key, size_t seed = 0)
\since 5.0
\relates QHash
@@ -746,7 +582,7 @@ void QHashData::checkSanity()
*/
/*!
- \fn template <typename T1, typename T2> uint qHash(const std::pair<T1, T2> &key, uint seed = 0)
+ \fn template <typename T1, typename T2> size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
\since 5.7
\relates QHash
@@ -760,7 +596,7 @@ void QHashData::checkSanity()
constraints, we cannot change the QPair algorithm to match the std::pair one before Qt 6.
*/
-/*! \fn template <typename InputIterator> uint qHashRange(InputIterator first, InputIterator last, uint seed = 0)
+/*! \fn template <typename InputIterator> size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
\relates QHash
\since 5.5
@@ -795,7 +631,7 @@ void QHashData::checkSanity()
\sa qHashBits(), qHashRangeCommutative()
*/
-/*! \fn template <typename InputIterator> uint qHashRangeCommutative(InputIterator first, InputIterator last, uint seed = 0)
+/*! \fn template <typename InputIterator> size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
\relates QHash
\since 5.5
@@ -831,7 +667,7 @@ void QHashData::checkSanity()
\sa qHashBits(), qHashRange()
*/
-/*! \fn uint qHashBits(const void *p, size_t len, uint seed = 0)
+/*! \fn size_t qHashBits(const void *p, size_t len, size_t seed = 0)
\relates QHash
\since 5.4
@@ -856,101 +692,106 @@ void QHashData::checkSanity()
\sa qHashRange(), qHashRangeCommutative()
*/
-/*! \fn uint qHash(char key, uint seed = 0)
+/*! \fn size_t qHash(char key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(uchar key, uint seed = 0)
+/*! \fn size_t qHash(uchar key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(signed char key, uint seed = 0)
+/*! \fn size_t qHash(signed char key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(ushort key, uint seed = 0)
+/*! \fn size_t qHash(ushort key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(short key, uint seed = 0)
+/*! \fn size_t qHash(short key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(uint key, uint seed = 0)
+/*! \fn size_t qHash(uint key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(int key, uint seed = 0)
+/*! \fn size_t qHash(int key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(ulong key, uint seed = 0)
+/*! \fn size_t qHash(ulong key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(long key, uint seed = 0)
+/*! \fn size_t qHash(long key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(quint64 key, uint seed = 0)
+/*! \fn size_t qHash(quint64 key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(qint64 key, uint seed = 0)
+/*! \fn size_t qHash(qint64 key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \relates QHash
+/*! \fn size_t qHash(float key, size_t seed) noexcept
+ \relates QHash
\since 5.3
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(float key, uint seed) noexcept
-{
- return key != 0.0f ? hash(reinterpret_cast<const uchar *>(&key), sizeof(key), seed) : seed ;
-}
/*! \relates QHash
\since 5.3
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(double key, uint seed) noexcept
+size_t qHash(double key, size_t seed) noexcept
{
- return key != 0.0 ? hash(reinterpret_cast<const uchar *>(&key), sizeof(key), seed) : seed ;
+ // ensure -0 gets mapped to 0
+ key += 0.0;
+ if constexpr (sizeof(double) == sizeof(size_t)) {
+ size_t k;
+ memcpy(&k, &key, sizeof(double));
+ return QHashPrivate::hash(k, seed);
+ } else {
+ return murmurhash(&key, sizeof(key), seed);
+ }
}
#if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
@@ -959,62 +800,70 @@ uint qHash(double key, uint seed) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(long double key, uint seed) noexcept
+size_t qHash(long double key, size_t seed) noexcept
{
- return key != 0.0L ? hash(reinterpret_cast<const uchar *>(&key), sizeof(key), seed) : seed ;
+ // ensure -0 gets mapped to 0
+ key += static_cast<long double>(0.0);
+ if constexpr (sizeof(long double) == sizeof(size_t)) {
+ size_t k;
+ memcpy(&k, &key, sizeof(long double));
+ return QHashPrivate::hash(k, seed);
+ } else {
+ return murmurhash(&key, sizeof(key), seed);
+ }
}
#endif
-/*! \fn uint qHash(const QChar key, uint seed = 0)
+/*! \fn size_t qHash(const QChar key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QByteArray &key, uint seed = 0)
+/*! \fn size_t qHash(const QByteArray &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QBitArray &key, uint seed = 0)
+/*! \fn size_t qHash(const QBitArray &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QString &key, uint seed = 0)
+/*! \fn size_t qHash(const QString &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QStringRef &key, uint seed = 0)
+/*! \fn size_t qHash(const QStringRef &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(QStringView key, uint seed = 0)
+/*! \fn size_t qHash(QStringView key, size_t seed = 0)
\relates QStringView
\since 5.10
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(QLatin1String key, uint seed = 0)
+/*! \fn size_t qHash(QLatin1String key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn template <class T> uint qHash(const T *key, uint seed = 0)
+/*! \fn template <class T> size_t qHash(const T *key, size_t seed = 0)
\relates QHash
\since 5.0
@@ -1091,13 +940,16 @@ uint qHash(long double key, uint seed) noexcept
in the code above.
Internally, QHash uses a hash table to perform lookups. This
- hash table automatically grows and shrinks to
+ hash table automatically grows to
provide fast lookups without wasting too much memory. You can
still control the size of the hash table by calling reserve() if
you already know approximately how many items the QHash will
contain, but this isn't necessary to obtain good performance. You
can also call capacity() to retrieve the hash table's size.
+ QHash will not shrink automatically if items are removed from the
+ table. To minimize the memory used by the hash, call squeeze().
+
If you want to navigate through all the (key, value) pairs stored
in a QHash, you can use an iterator. QHash provides both
\l{Java-style iterators} (QHashIterator and QMutableHashIterator)
@@ -1114,12 +966,15 @@ uint qHash(long double key, uint seed) noexcept
QHash is unordered, so an iterator's sequence cannot be assumed
to be predictable. If ordering by key is required, use a QMap.
- Normally, a QHash allows only one value per key. If you call
+ A QHash allows only one value per key. If you call
insert() with a key that already exists in the QHash, the
previous value is erased. For example:
\snippet code/src_corelib_tools_qhash.cpp 9
+ If you need to store multiple entries for the same key in the
+ hash table, use \l{QMultiHash}.
+
If you only need to extract the values from a hash (not the keys),
you can also use \l{foreach}:
@@ -1231,9 +1086,6 @@ uint qHash(long double key, uint seed) noexcept
Constructs a hash with a copy of each of the elements in the
initializer list \a list.
-
- This function is only available if the program is being
- compiled in C++11 mode.
*/
/*! \fn template <class Key, class T> template <class InputIterator> QHash<Key, T>::QHash(InputIterator begin, InputIterator end)
@@ -1345,24 +1197,45 @@ uint qHash(long double key, uint seed) noexcept
\sa reserve(), squeeze()
*/
+/*! \fn template <class Key, class T> float QHash<Key, T>::load_factor() const noexcept
+
+ Returns the current load factor of the QHash's internal hash table.
+ This is the same as capacity()/size(). The implementation used
+ will aim to keep the load factor between 0.25 and 0.5. This avoids
+ having too many hash table collisions that would degrade performance.
+
+ Even with a low load factor, the implementation of the hash table has a
+ very low memory overhead.
+
+ This method purely exists for diagnostic purposes and you should rarely
+ need to call it yourself.
+
+ \sa reserve(), squeeze()
+*/
+
+
/*! \fn template <class Key, class T> void QHash<Key, T>::reserve(int size)
- Ensures that the QHash's internal hash table consists of at least
- \a size buckets.
+ Ensures that the QHash's internal hash table has space to store at
+ least \a size items without having to grow the hash table.
+
+ This implies that the hash table will contain at least 2 * \a size buckets
+ to ensure good performance
This function is useful for code that needs to build a huge hash
and wants to avoid repeated reallocation. For example:
\snippet code/src_corelib_tools_qhash.cpp 14
- Ideally, \a size should be slightly more than the maximum number
- of items expected in the hash. \a size doesn't have to be prime,
- because QHash will use a prime number internally anyway. If \a size
+ Ideally, \a size should be the maximum number of items expected
+ in the hash. QHash will then choose the smallest possible
+ number of buckets that will allow storing \a size items in the table
+ without having to grow the internal hash table. If \a size
is an underestimate, the worst that will happen is that the QHash
will be a bit slower.
In general, you will rarely ever need to call this function.
- QHash's internal hash table automatically shrinks or grows to
+ QHash's internal hash table automatically grows to
provide good performance without wasting too much memory.
\sa squeeze(), capacity()
@@ -1400,30 +1273,27 @@ uint qHash(long double key, uint seed) noexcept
\sa detach()
*/
-/*! \fn template <class Key, class T> void QHash<Key, T>::setSharable(bool sharable)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> bool QHash<Key, T>::isSharedWith(const QHash &other) const
\internal
+
+ Returns true if the internal hash table of this QHash is shared with \a other, otherwise false.
*/
/*! \fn template <class Key, class T> void QHash<Key, T>::clear()
- Removes all items from the hash.
+ Removes all items from the hash and frees up all memory used by it.
\sa remove()
*/
-/*! \fn template <class Key, class T> int QHash<Key, T>::remove(const Key &key)
+/*! \fn template <class Key, class T> bool QHash<Key, T>::remove(const Key &key)
- Removes all the items that have the \a key from the hash.
- Returns the number of items removed which is 1 if the key exists in the hash,
- and 0 otherwise.
+ Removes the item that has the \a key from the hash.
+ Returns true if the key exists in the hash and the item has been removed,
+ and false otherwise.
- \sa clear(), take(), QMultiHash::remove()
+ \sa clear(), take()
*/
/*! \fn template <class Key, class T> T QHash<Key, T>::take(const Key &key)
@@ -1432,9 +1302,7 @@ uint qHash(long double key, uint seed) noexcept
the value associated with it.
If the item does not exist in the hash, the function simply
- returns a \l{default-constructed value}. If there are multiple
- items for \a key in the hash, only the most recently inserted one
- is removed.
+ returns a \l{default-constructed value}.
If you don't use the return value, remove() is more efficient.
@@ -1449,23 +1317,14 @@ uint qHash(long double key, uint seed) noexcept
\sa count(), QMultiHash::contains()
*/
-/*! \fn template <class Key, class T> const T QHash<Key, T>::value(const Key &key) const
+/*! \fn template <class Key, class T> T QHash<Key, T>::value(const Key &key, const T &defaultValue = T()) const
+ \overload
Returns the value associated with the \a key.
If the hash contains no item with the \a key, the function
- returns a \l{default-constructed value}. If there are multiple
- items for the \a key in the hash, the value of the most recently
- inserted one is returned.
-
- \sa key(), values(), contains(), operator[]()
-*/
-
-/*! \fn template <class Key, class T> const T QHash<Key, T>::value(const Key &key, const T &defaultValue) const
- \overload
-
- If the hash contains no item with the given \a key, the function returns
- \a defaultValue.
+ returns \a defaultValue, which is a \l{default-constructed value} if the
+ parameter has not been specified.
*/
/*! \fn template <class Key, class T> T &QHash<Key, T>::operator[](const Key &key)
@@ -1475,9 +1334,7 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains no item with the \a key, the function inserts
a \l{default-constructed value} into the hash with the \a key, and
- returns a reference to it. If the hash contains multiple items
- with the \a key, this function returns a reference to the most
- recently inserted value.
+ returns a reference to it.
\sa insert(), value()
*/
@@ -1489,27 +1346,14 @@ uint qHash(long double key, uint seed) noexcept
Same as value().
*/
-/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::uniqueKeys() const
- \since 4.2
- \obsolete Use QMultiHash for storing multiple values with the same key.
-
- Returns a list containing all the keys in the map. Keys that occur multiple
- times in the map (because items were inserted with insertMulti(), or
- unite() was used) occur only once in the returned list.
-
- \sa QMultiHash::uniqueKeys()
-*/
-
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::keys() const
Returns a list containing all the keys in the hash, in an
- arbitrary order. Keys that occur multiple times in the hash
- (because the method is operating on a QMultiHash) also occur
- multiple times in the list.
+ arbitrary order.
The order is guaranteed to be the same as that used by values().
- \sa QMultiMap::uniqueKeys(), values(), key()
+ \sa values(), key()
*/
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::keys(const T &value) const
@@ -1527,43 +1371,16 @@ uint qHash(long double key, uint seed) noexcept
/*! \fn template <class Key, class T> QList<T> QHash<Key, T>::values() const
Returns a list containing all the values in the hash, in an
- arbitrary order. If a key is associated with multiple values, all of
- its values will be in the list, and not just the most recently
- inserted one.
+ arbitrary order.
The order is guaranteed to be the same as that used by keys().
\sa keys(), value()
*/
-/*! \fn template <class Key, class T> QList<T> QHash<Key, T>::values(const Key &key) const
- \overload
- \obsolete Use QMultiHash for storing multiple values with the same key.
-
- Returns a list of all the values associated with the \a key,
- from the most recently inserted to the least recently inserted.
-
- \sa count(), insertMulti()
-*/
-
-/*! \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value) const
-
- Returns the first key mapped to \a value.
-
- If the hash contains no item with the \a value, the function
- returns a \l{default-constructed value}{default-constructed key}.
-
- This function can be slow (\l{linear time}), because QHash's
- internal data structure is optimized for fast lookup by key, not
- by value.
-
- \sa value(), keys()
-*/
-
/*!
- \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value, const Key &defaultKey) const
+ \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value, const Key &defaultKey = Key()) const
\since 4.3
- \overload
Returns the first key mapped to \a value, or \a defaultKey if the
hash contains no item mapped to \a value.
@@ -1577,7 +1394,7 @@ uint qHash(long double key, uint seed) noexcept
Returns the number of items associated with the \a key.
- \sa contains(), insertMulti()
+ \sa contains()
*/
/*! \fn template <class Key, class T> int QHash<Key, T>::count() const
@@ -1726,7 +1543,7 @@ uint qHash(long double key, uint seed) noexcept
from the hash, and returns an iterator to the next item in the
hash.
- Unlike remove() and take(), this function never causes QHash to
+ This function never causes QHash to
rehash its internal data structure. This means that it can safely
be called while iterating, and won't affect the order of items in
the hash. For example:
@@ -1756,7 +1573,7 @@ uint qHash(long double key, uint seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 16
- \sa value(), values(), QMultiHash::find()
+ \sa value(), values()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &key) const
@@ -1773,7 +1590,7 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains no item with the \a key, the function
returns constEnd().
- \sa find(), QMultiHash::constFind()
+ \sa find()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::insert(const Key &key, const T &value)
@@ -1782,11 +1599,20 @@ uint qHash(long double key, uint seed) noexcept
If there is already an item with the \a key, that item's value
is replaced with \a value.
+*/
- If there are multiple items with the \a key, the most
- recently inserted item's value is replaced with \a value.
+/*!
+ \fn template <typename T> template <typename ...Args> QHash<Key, T>::iterator QHash<Key, T>::emplace(const Key &key, Args&&... args)
+ \fn template <typename T> template <typename ...Args> QHash<Key, T>::iterator QHash<Key, T>::emplace(Key &&key, Args&&... args)
+
+ Inserts a new element into the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
+
+ Returns an iterator pointing to the new element.
*/
+
/*! \fn template <class Key, class T> void QHash<Key, T>::insert(const QHash &other)
\since 5.15
@@ -1799,29 +1625,6 @@ uint qHash(long double key, uint seed) noexcept
final value of the key is undefined.
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &key, const T &value)
- \obsolete
-
- Inserts a new item with the \a key and a value of \a value.
-
- If there is already an item with the same key in the hash, this
- function will simply create a new one. (This behavior is
- different from insert(), which overwrites the value of an
- existing item.)
-
- This function is obsolete. Use QMultiHash or QMultiMap instead.
-
- \sa insert(), values()
-*/
-
-/*! \fn template <class Key, class T> QHash &QHash<Key, T>::unite(const QHash &other)
- \obsolete
-
- Inserts all the items in the \a other hash into this hash. If a
- key is common to both hashes, the resulting hash will contain the
- key multiple times.
-*/
-
/*! \fn template <class Key, class T> bool QHash<Key, T>::empty() const
This function is provided for STL compatibility. It is equivalent
@@ -1829,7 +1632,7 @@ uint qHash(long double key, uint seed) noexcept
returns \c false.
*/
-/*! \fn template <class Key, class T> QPair<iterator, iterator> QHash<Key, T>::equal_range(const Key &key)
+/*! \fn template <class Key, class T> QPair<iterator, iterator> QMultiHash<Key, T>::equal_range(const Key &key)
\since 5.7
Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
@@ -1837,7 +1640,7 @@ uint qHash(long double key, uint seed) noexcept
*/
/*!
- \fn template <class Key, class T> QPair<const_iterator, const_iterator> QHash<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> QPair<const_iterator, const_iterator> QMultiHash<Key, T>::equal_range(const Key &key) const
\overload
\since 5.7
*/
@@ -1934,7 +1737,7 @@ uint qHash(long double key, uint seed) noexcept
/*! \class QHash::iterator
\inmodule QtCore
- \brief The QHash::iterator class provides an STL-style non-const iterator for QHash and QMultiHash.
+ \brief The QHash::iterator class provides an STL-style non-const iterator for QHash.
QHash features both \l{STL-style iterators} and \l{Java-style
iterators}. The STL-style iterators are more low-level and more
@@ -1942,8 +1745,8 @@ uint qHash(long double key, uint seed) noexcept
and, for developers who already know STL, have the advantage of
familiarity.
- QHash\<Key, T\>::iterator allows you to iterate over a QHash (or
- QMultiHash) and to modify the value (but not the key) associated
+ QHash\<Key, T\>::iterator allows you to iterate over a QHash
+ and to modify the value (but not the key) associated
with a particular key. If you want to iterate over a const QHash,
you should use QHash::const_iterator. It is generally good
practice to use QHash::const_iterator on a non-const QHash as
@@ -1987,14 +1790,21 @@ uint qHash(long double key, uint seed) noexcept
However, this will potentially crash in \c{++i}, because \c i is
a dangling iterator after the call to erase().
- Multiple iterators can be used on the same hash. However, be
- aware that any modification performed directly on the QHash has
- the potential of dramatically changing the order in which the
- items are stored in the hash, as they might cause QHash to rehash
- its internal data structure. There is one notable exception:
- QHash::erase(). This function can safely be called while
- iterating, and won't affect the order of items in the hash. If you
- need to keep iterators over a long period of time, we recommend
+ Multiple iterators can be used on the same hash. However, be aware
+ that any modification performed directly on the QHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink its internal hash table.
+ Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
+
+ You can however safely use iterators to remove entries from the hash
+ using the QHash::erase() method. This function can safely be called while
+ iterating, and won't affect the order of items in the hash.
+
+ If you need to keep iterators over a long period of time, we recommend
that you use QMap rather than QHash.
\warning Iterators on implicitly shared containers do not work
@@ -2016,11 +1826,6 @@ uint qHash(long double key, uint seed) noexcept
\sa QHash::begin(), QHash::end()
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator::iterator(void *node)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> const Key &QHash<Key, T>::iterator::key() const
Returns the current item's key as a const reference.
@@ -2088,8 +1893,6 @@ uint qHash(long double key, uint seed) noexcept
item.
Calling this function on QHash::end() leads to undefined results.
-
- \sa operator--()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator++(int)
@@ -2101,74 +1904,9 @@ uint qHash(long double key, uint seed) noexcept
current item.
*/
-/*!
- \fn template <class Key, class T> QHash<Key, T>::iterator &QHash<Key, T>::iterator::operator--()
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- The prefix -- operator (\c{--i}) makes the preceding item
- current and returns an iterator pointing to the new current item.
-
- Calling this function on QHash::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*!
- \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator--(int)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- \overload
-
- The postfix -- operator (\c{i--}) makes the preceding item
- current and returns an iterator pointing to the previously
- current item.
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator+(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator-(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator &QHash<Key, T>::iterator::operator+=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator &QHash<Key, T>::iterator::operator-=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
-*/
-
/*! \class QHash::const_iterator
\inmodule QtCore
- \brief The QHash::const_iterator class provides an STL-style const iterator for QHash and QMultiHash.
+ \brief The QHash::const_iterator class provides an STL-style const iterator for QHash.
QHash features both \l{STL-style iterators} and \l{Java-style
iterators}. The STL-style iterators are more low-level and more
@@ -2177,7 +1915,7 @@ uint qHash(long double key, uint seed) noexcept
familiarity.
QHash\<Key, T\>::const_iterator allows you to iterate over a
- QHash (or a QMultiHash). If you want to modify the QHash as you
+ QHash. If you want to modify the QHash as you
iterate over it, you must use QHash::iterator instead. It is
generally good practice to use QHash::const_iterator on a
non-const QHash as well, unless you need to change the QHash
@@ -2199,11 +1937,14 @@ uint qHash(long double key, uint seed) noexcept
recently to the least recently inserted value.
Multiple iterators can be used on the same hash. However, be aware
- that any modification performed directly on the QHash has the
- potential of dramatically changing the order in which the items
- are stored in the hash, as they might cause QHash to rehash its
- internal data structure. If you need to keep iterators over a long
- period of time, we recommend that you use QMap rather than QHash.
+ that any modification performed directly on the QHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink its internal hash table.
+ Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
\warning Iterators on implicitly shared containers do not work
exactly like STL-iterators. You should avoid copying a container
@@ -2224,11 +1965,6 @@ uint qHash(long double key, uint seed) noexcept
\sa QHash::constBegin(), QHash::constEnd()
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator::const_iterator(void *node)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator::const_iterator(const iterator &other)
Constructs a copy of \a other.
@@ -2301,76 +2037,10 @@ uint qHash(long double key, uint seed) noexcept
current item.
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator &QHash<Key, T>::const_iterator::operator--()
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- The prefix -- operator (\c{--i}) makes the preceding item
- current and returns an iterator pointing to the new current item.
-
- Calling this function on QHash::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator--(int)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- \overload
-
- The postfix -- operator (\c{i--}) makes the preceding item
- current and returns an iterator pointing to the previously
- current item.
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator+(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator-(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator &QHash<Key, T>::const_iterator::operator+=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator &QHash<Key, T>::const_iterator::operator-=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
-*/
-
/*! \class QHash::key_iterator
\inmodule QtCore
\since 5.6
- \brief The QHash::key_iterator class provides an STL-style const iterator for QHash and QMultiHash keys.
+ \brief The QHash::key_iterator class provides an STL-style const iterator for QHash keys.
QHash::key_iterator is essentially the same as QHash::const_iterator
with the difference that operator*() and operator->() return a key
@@ -2451,28 +2121,6 @@ uint qHash(long double key, uint seed) noexcept
item.
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::key_iterator &QHash<Key, T>::key_iterator::operator--()
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- The prefix -- operator (\c{--i}) makes the preceding item
- current and returns an iterator pointing to the new current item.
-
- Calling this function on QHash::keyBegin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::key_iterator QHash<Key, T>::key_iterator::operator--(int)
- \obsolete This operator is deprecated in order to align with std::unordered_map functionality.
-
- \overload
-
- The postfix -- operator (\c{i--}) makes the preceding item
- current and returns an iterator pointing to the previous
- item.
-*/
-
/*! \fn template <class Key, class T> const_iterator QHash<Key, T>::key_iterator::base() const
Returns the underlying const_iterator this key_iterator is based on.
*/
@@ -2480,7 +2128,7 @@ uint qHash(long double key, uint seed) noexcept
/*! \typedef QHash::const_key_value_iterator
\inmodule QtCore
\since 5.10
- \brief The QMap::const_key_value_iterator typedef provides an STL-style const iterator for QHash and QMultiHash.
+ \brief The QHash::const_key_value_iterator typedef provides an STL-style const iterator for QHash.
QHash::const_key_value_iterator is essentially the same as QHash::const_iterator
with the difference that operator*() returns a key/value pair instead of a
@@ -2492,7 +2140,7 @@ uint qHash(long double key, uint seed) noexcept
/*! \typedef QHash::key_value_iterator
\inmodule QtCore
\since 5.10
- \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QHash and QMultiHash.
+ \brief The QHash::key_value_iterator typedef provides an STL-style iterator for QHash.
QHash::key_value_iterator is essentially the same as QHash::iterator
with the difference that operator*() returns a key/value pair instead of a
@@ -2642,6 +2290,41 @@ uint qHash(long double key, uint seed) noexcept
\sa replace()
*/
+/*!
+ \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplace(const Key &key, Args&&... args)
+ \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplace(Key &&key, Args&&... args)
+
+ Inserts a new element into the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
+
+ If there is already an item with the same key in the hash, this
+ function will simply create a new one. (This behavior is
+ different from replace(), which overwrites the value of an
+ existing item.)
+
+ Returns an iterator pointing to the new element.
+
+ \sa insert
+*/
+
+/*!
+ \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplaceReplace(const Key &key, Args&&... args)
+ \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplaceReplace(Key &&key, Args&&... args)
+
+ Inserts a new element into the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
+
+ If there is already an item with the same key in the hash, that item's
+ value is replaced with a value constructed from \a args.
+
+ Returns an iterator pointing to the new element.
+
+ \sa replace, emplace
+*/
+
+
/*! \fn template <class Key, class T> QMultiHash &QMultiHash<Key, T>::unite(const QMultiHash &other)
\since 5.13
@@ -2660,6 +2343,20 @@ uint qHash(long double key, uint seed) noexcept
\sa keys(), values()
*/
+/*! \fn template <class Key, class T> T QMultiHash<Key, T>::value(const Key &key, const T &defaultValue = T()) const
+ \overload
+
+ Returns the value associated with the \a key.
+
+ If the hash contains no item with the \a key, the function
+ returns \a defaultValue, which is a \l{default-constructed value} if the
+ parameter has not been specified.
+
+ If there are multiple
+ items for the \a key in the hash, the value of the most recently
+ inserted one is returned.
+*/
+
/*! \fn template <class Key, class T> QList<T> QMultiHash<Key, T>::values(const Key &key) const
\overload
@@ -2669,6 +2366,20 @@ uint qHash(long double key, uint seed) noexcept
\sa count(), insert()
*/
+/*! \fn template <class Key, class T> T &QMultiHash<Key, T>::operator[](const Key &key)
+
+ Returns the value associated with the \a key as a modifiable reference.
+
+ If the hash contains no item with the \a key, the function inserts
+ a \l{default-constructed value} into the hash with the \a key, and
+ returns a reference to it.
+
+ If the hash contains multiple items with the \a key, this function returns
+ a reference to the most recently inserted value.
+
+ \sa insert(), value()
+*/
+
/*! \fn template <class Key, class T> QMultiHash &QMultiHash<Key, T>::operator+=(const QMultiHash &other)
Inserts all the items in the \a other hash into this hash
@@ -2693,7 +2404,7 @@ uint qHash(long double key, uint seed) noexcept
Returns \c true if the hash contains an item with the \a key and
\a value; otherwise returns \c false.
- \sa QHash::contains()
+ \sa contains()
*/
/*!
@@ -2703,7 +2414,57 @@ uint qHash(long double key, uint seed) noexcept
Removes all the items that have the \a key and the value \a
value from the hash. Returns the number of items removed.
- \sa QHash::remove()
+ \sa remove()
+*/
+
+/*! \fn template <class Key, class T> T QMultiHash<Key, T>::take(const Key &key)
+
+ Removes the item with the \a key from the hash and returns
+ the value associated with it.
+
+ If the item does not exist in the hash, the function simply
+ returns a \l{default-constructed value}. If there are multiple
+ items for \a key in the hash, only the most recently inserted one
+ is removed.
+
+ If you don't use the return value, remove() is more efficient.
+
+ \sa remove()
+*/
+
+/*! \fn template <class Key, class T> QList<Key> QMultiHash<Key, T>::keys() const
+
+ Returns a list containing all the keys in the hash, in an
+ arbitrary order. Keys that occur multiple times in the hash
+ also occur multiple times in the list.
+
+ The order is guaranteed to be the same as that used by values().
+
+ \sa values(), key()
+*/
+
+/*! \fn template <class Key, class T> QList<T> QMultiHash<Key, T>::values() const
+
+ Returns a list containing all the values in the hash, in an
+ arbitrary order. If a key is associated with multiple values, all of
+ its values will be in the list, and not just the most recently
+ inserted one.
+
+ The order is guaranteed to be the same as that used by keys().
+
+ \sa keys(), value()
+*/
+
+/*!
+ \fn template <class Key, class T> Key QMultiHash<Key, T>::key(const T &value, const Key &defaultKey = Key()) const
+ \since 4.3
+
+ Returns the first key mapped to \a value, or \a defaultKey if the
+ hash contains no item mapped to \a value.
+
+ This function can be slow (\l{linear time}), because QMultiHash's
+ internal data structure is optimized for fast lookup by key, not
+ by value.
*/
/*!
@@ -2712,11 +2473,11 @@ uint qHash(long double key, uint seed) noexcept
Returns the number of items with the \a key and \a value.
- \sa QHash::count()
+ \sa count()
*/
/*!
- \fn template <class Key, class T> typename QHash<Key, T>::iterator QMultiHash<Key, T>::find(const Key &key, const T &value)
+ \fn template <class Key, class T> typename QMultiHash<Key, T>::iterator QMultiHash<Key, T>::find(const Key &key, const T &value)
\since 4.3
Returns an iterator pointing to the item with the \a key and \a value.
@@ -2724,18 +2485,16 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains multiple items with the \a key and \a value, the
iterator returned points to the most recently inserted item.
-
- \sa QHash::find()
*/
/*!
- \fn template <class Key, class T> typename QHash<Key, T>::const_iterator QMultiHash<Key, T>::find(const Key &key, const T &value) const
+ \fn template <class Key, class T> typename QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::find(const Key &key, const T &value) const
\since 4.3
\overload
*/
/*!
- \fn template <class Key, class T> typename QHash<Key, T>::const_iterator QMultiHash<Key, T>::constFind(const Key &key, const T &value) const
+ \fn template <class Key, class T> typename QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::constFind(const Key &key, const T &value) const
\since 4.3
Returns an iterator pointing to the item with the \a key and the
@@ -2743,12 +2502,586 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains no such item, the function returns
constEnd().
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::begin()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
+ the hash.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::begin() const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::cbegin() const
+ \since 5.0
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
+ in the hash.
+
+ \sa begin(), cend()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::constBegin() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
+ in the hash.
- \sa QHash::constFind()
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::keyBegin() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
+ in the hash.
+
+ \sa keyEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::end()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
+ after the last item in the hash.
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::end() const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::constEnd() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the hash.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::cend() const
+ \since 5.0
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the hash.
+
+ \sa cbegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::keyEnd() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last key in the hash.
+
+ \sa keyBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_value_iterator QMultiHash<Key, T>::keyValueBegin()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_value_iterator QMultiHash<Key, T>::keyValueEnd()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::keyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::constKeyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::keyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::constKeyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \sa constKeyValueBegin()
+*/
+
+
+/*! \class QMultiHash::iterator
+ \inmodule QtCore
+ \brief The QMultiHash::iterator class provides an STL-style non-const iterator for QMultiHash.
+
+ QMultiHash features both \l{STL-style iterators} and \l{Java-style
+ iterators}. The STL-style iterators are more low-level and more
+ cumbersome to use; on the other hand, they are slightly faster
+ and, for developers who already know STL, have the advantage of
+ familiarity.
+
+ QMultiHash\<Key, T\>::iterator allows you to iterate over a QMultiHash
+ and to modify the value (but not the key) associated
+ with a particular key. If you want to iterate over a const QMultiHash,
+ you should use QMultiHash::const_iterator. It is generally good
+ practice to use QMultiHash::const_iterator on a non-const QMultiHash as
+ well, unless you need to change the QMultiHash through the iterator.
+ Const iterators are slightly faster, and can improve code
+ readability.
+
+ The default QMultiHash::iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QMultiHash function like
+ QMultiHash::begin(), QMultiHash::end(), or QMultiHash::find() before you can
+ start iterating. Here's a typical loop that prints all the (key,
+ value) pairs stored in a hash:
+
+ \snippet code/src_corelib_tools_qhash.cpp 17
+
+ Unlike QMap, which orders its items by key, QMultiHash stores its
+ items in an arbitrary order.
+
+ Let's see a few examples of things we can do with a
+ QMultiHash::iterator that we cannot do with a QMultiHash::const_iterator.
+ Here's an example that increments every value stored in the QMultiHash
+ by 2:
+
+ \snippet code/src_corelib_tools_qhash.cpp 18
+
+ Here's an example that removes all the items whose key is a
+ string that starts with an underscore character:
+
+ \snippet code/src_corelib_tools_qhash.cpp 19
+
+ The call to QMultiHash::erase() removes the item pointed to by the
+ iterator from the hash, and returns an iterator to the next item.
+ Here's another way of removing an item while iterating:
+
+ \snippet code/src_corelib_tools_qhash.cpp 20
+
+ It might be tempting to write code like this:
+
+ \snippet code/src_corelib_tools_qhash.cpp 21
+
+ However, this will potentially crash in \c{++i}, because \c i is
+ a dangling iterator after the call to erase().
+
+ Multiple iterators can be used on the same hash. However, be aware
+ that any modification performed directly on the QHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink its internal hash table.
+ Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
+
+ You can however safely use iterators to remove entries from the hash
+ using the QHash::erase() method. This function can safely be called while
+ iterating, and won't affect the order of items in the hash.
+
+ If you need to keep iterators over a long period of time, we recommend
+ that you use QMultiMap rather than QHash.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiHash::const_iterator, QMultiHash::key_iterator, QMutableHashIterator
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator::iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QMultiHash::begin(), QMultiHash::end()
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiHash<Key, T>::iterator::key() const
+
+ Returns the current item's key as a const reference.
+
+ There is no direct way of changing an item's key through an
+ iterator, although it can be done by calling QMultiHash::erase()
+ followed by QMultiHash::insert().
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiHash<Key, T>::iterator::value() const
+
+ Returns a modifiable reference to the current item's value.
+
+ You can change the value of an item by using value() on
+ the left side of an assignment, for example:
+
+ \snippet code/src_corelib_tools_qhash.cpp 22
+
+ \sa key(), operator*()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiHash<Key, T>::iterator::operator*() const
+
+ Returns a modifiable reference to the current item's value.
+
+ Same as value().
+
+ \sa key()
+*/
+
+/*! \fn template <class Key, class T> T *QMultiHash<Key, T>::iterator::operator->() const
+
+ Returns a pointer to the current item's value.
+
+ \sa value()
+*/
+
+/*!
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator==(const iterator &other) const
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator==(const const_iterator &other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator!=(const iterator &other) const
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator!=(const const_iterator &other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiHash<Key, T>::iterator &QMultiHash<Key, T>::iterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the hash and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiHash::end() leads to undefined results.
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the hash and returns an iterator to the previously
+ current item.
+*/
+
+/*! \class QMultiHash::const_iterator
+ \inmodule QtCore
+ \brief The QMultiHash::const_iterator class provides an STL-style const iterator for QMultiHash.
+
+ QMultiHash features both \l{STL-style iterators} and \l{Java-style
+ iterators}. The STL-style iterators are more low-level and more
+ cumbersome to use; on the other hand, they are slightly faster
+ and, for developers who already know STL, have the advantage of
+ familiarity.
+
+ QMultiHash\<Key, T\>::const_iterator allows you to iterate over a
+ QMultiHash. If you want to modify the QMultiHash as you
+ iterate over it, you must use QMultiHash::iterator instead. It is
+ generally good practice to use QMultiHash::const_iterator on a
+ non-const QMultiHash as well, unless you need to change the QMultiHash
+ through the iterator. Const iterators are slightly faster, and
+ can improve code readability.
+
+ The default QMultiHash::const_iterator constructor creates an
+ uninitialized iterator. You must initialize it using a QMultiHash
+ function like QMultiHash::constBegin(), QMultiHash::constEnd(), or
+ QMultiHash::find() before you can start iterating. Here's a typical
+ loop that prints all the (key, value) pairs stored in a hash:
+
+ \snippet code/src_corelib_tools_qhash.cpp 23
+
+ Unlike QMap, which orders its items by key, QMultiHash stores its
+ items in an arbitrary order. The only guarantee is that items that
+ share the same key (because they were inserted using
+ a QMultiHash) will appear consecutively, from the most
+ recently to the least recently inserted value.
+
+ Multiple iterators can be used on the same hash. However, be aware
+ that any modification performed directly on the QHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink it's internal hash table.
+ Using any iterator after a rehashing operation ahs occurred will lead to undefined behavior.
+
+ You can however safely use iterators to remove entries from the hash
+ using the QHash::erase() method. This function can safely be called while
+ iterating, and won't affect the order of items in the hash.
+
+ If you need to keep iterators over a long period of time, we recommend
+ that you use QMap rather than QHash.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiHash::iterator, QMultiHashIterator
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QMultiHash::constBegin(), QMultiHash::constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator(const iterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiHash<Key, T>::const_iterator::key() const
+
+ Returns the current item's key.
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiHash<Key, T>::const_iterator::value() const
+
+ Returns the current item's value.
+
+ \sa key(), operator*()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiHash<Key, T>::const_iterator::operator*() const
+
+ Returns the current item's value.
+
+ Same as value().
+
+ \sa key()
+*/
+
+/*! \fn template <class Key, class T> const T *QMultiHash<Key, T>::const_iterator::operator->() const
+
+ Returns a pointer to the current item's value.
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::const_iterator::operator==(const const_iterator &other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::const_iterator::operator!=(const const_iterator &other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator &QMultiHash<Key, T>::const_iterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the hash and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiHash::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::const_iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the hash and returns an iterator to the previously
+ current item.
+*/
+
+/*! \class QMultiHash::key_iterator
+ \inmodule QtCore
+ \since 5.6
+ \brief The QMultiHash::key_iterator class provides an STL-style const iterator for QMultiHash keys.
+
+ QMultiHash::key_iterator is essentially the same as QMultiHash::const_iterator
+ with the difference that operator*() and operator->() return a key
+ instead of a value.
+
+ For most uses QMultiHash::iterator and QMultiHash::const_iterator should be used,
+ you can easily access the key by calling QMultiHash::iterator::key():
+
+ \snippet code/src_corelib_tools_qhash.cpp 27
+
+ However, to have interoperability between QMultiHash's keys and STL-style
+ algorithms we need an iterator that dereferences to a key instead
+ of a value. With QMultiHash::key_iterator we can apply an algorithm to a
+ range of keys without having to call QMultiHash::keys(), which is inefficient
+ as it costs one QMultiHash iteration and memory allocation to create a temporary
+ QList.
+
+ \snippet code/src_corelib_tools_qhash.cpp 28
+
+ QMultiHash::key_iterator is const, it's not possible to modify the key.
+
+ The default QMultiHash::key_iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QMultiHash function like
+ QMultiHash::keyBegin() or QMultiHash::keyEnd().
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiHash::const_iterator, QMultiHash::iterator
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiHash<Key, T>::key_iterator::operator*() const
+
+ Returns the current item's key.
+*/
+
+/*! \fn template <class Key, class T> const T *QMultiHash<Key, T>::key_iterator::operator->() const
+
+ Returns a pointer to the current item's key.
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::key_iterator::operator==(key_iterator other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::key_iterator::operator!=(key_iterator other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator &QMultiHash<Key, T>::key_iterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the hash and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiHash::keyEnd() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::key_iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the hash and returns an iterator to the previous
+ item.
+*/
+
+/*! \fn template <class Key, class T> const_iterator QMultiHash<Key, T>::key_iterator::base() const
+ Returns the underlying const_iterator this key_iterator is based on.
+*/
+
+/*! \typedef QMultiHash::const_key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMap::const_key_value_iterator typedef provides an STL-style const iterator for QMultiHash and QMultiHash.
+
+ QMultiHash::const_key_value_iterator is essentially the same as QMultiHash::const_iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
+/*! \typedef QMultiHash::key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QMultiHash and QMultiHash.
+
+ QMultiHash::key_value_iterator is essentially the same as QMultiHash::iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
+/*! \fn template <class Key, class T> QDataStream &operator<<(QDataStream &out, const QMultiHash<Key, T>& hash)
+ \relates QMultiHash
+
+ Writes the hash \a hash to stream \a out.
+
+ This function requires the key and value types to implement \c
+ operator<<().
+
+ \sa {Serializing Qt Data Types}
+*/
+
+/*! \fn template <class Key, class T> QDataStream &operator>>(QDataStream &in, QMultiHash<Key, T> &hash)
+ \relates QMultiHash
+
+ Reads a hash from stream \a in into \a hash.
+
+ This function requires the key and value types to implement \c
+ operator>>().
+
+ \sa {Serializing Qt Data Types}
*/
/*!
- \fn template <class Key, class T> uint qHash(const QHash<Key, T> &key, uint seed = 0)
+ \fn template <class Key, class T> size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
\since 5.8
\relates QHash
@@ -2758,7 +3091,7 @@ uint qHash(long double key, uint seed) noexcept
*/
/*!
- \fn template <class Key, class T> uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
+ \fn template <class Key, class T> size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
\since 5.8
\relates QMultiHash
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 5078019602..2c39a9dfc8 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -1,7 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+** 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.
@@ -41,218 +40,724 @@
#ifndef QHASH_H
#define QHASH_H
-#include <QtCore/qchar.h>
#include <QtCore/qiterator.h>
-#include <QtCore/qlist.h>
+#include <QtCore/qvector.h>
#include <QtCore/qrefcount.h>
#include <QtCore/qhashfunctions.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qmath.h>
-#include <algorithm>
#include <initializer_list>
-#if defined(Q_CC_MSVC)
-#pragma warning( push )
-#pragma warning( disable : 4311 ) // disable pointer truncation warning
-#pragma warning( disable : 4127 ) // conditional expression is constant
-#endif
-
QT_BEGIN_NAMESPACE
-struct Q_CORE_EXPORT QHashData
+struct QHashDummyValue
{
- struct Node {
- Node *next;
- uint h;
- };
+ bool operator==(const QHashDummyValue &) const noexcept { return true; }
+};
- Node *fakeNext;
- Node **buckets;
- QtPrivate::RefCount ref;
- int size;
- int nodeSize;
- short userNumBits;
- short numBits;
- int numBuckets;
- uint seed;
- uint sharable : 1;
- uint strictAlignment : 1;
- uint reserved : 30;
-
- void *allocateNode(int nodeAlign);
- void freeNode(void *node);
- QHashData *detach_helper(void (*node_duplicate)(Node *, void *), void (*node_delete)(Node *),
- int nodeSize, int nodeAlign);
- bool willGrow();
- void hasShrunk();
- void rehash(int hint);
- void free_helper(void (*node_delete)(Node *));
- Node *firstNode();
-#ifdef QT_QHASH_DEBUG
- void dump();
- void checkSanity();
-#endif
- static Node *nextNode(Node *node);
- static Node *previousNode(Node *node);
+namespace QHashPrivate {
- static const QHashData shared_null;
-};
+// QHash uses a power of two growth policy.
+namespace GrowthPolicy
+{
+inline constexpr size_t maxNumBuckets() noexcept
+{
+ return size_t(1) << (8*sizeof(size_t) - 1);
+}
+inline constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
+{
+ if (requestedCapacity <= 8)
+ return 16;
+ if (requestedCapacity >= maxNumBuckets())
+ return maxNumBuckets();
+ return qNextPowerOfTwo(QIntegerForSize<sizeof(size_t)>::Unsigned(2*requestedCapacity - 1));
+}
+inline constexpr size_t bucketForHash(size_t nBuckets, size_t hash) noexcept
+{
+ return hash & (nBuckets - 1);
+}
+}
-inline bool QHashData::willGrow()
+template <typename Key, typename T>
+struct Node
{
- if (size >= numBuckets) {
- rehash(numBits + 1);
- return true;
- } else {
- return false;
+ using KeyType = Key;
+ using ValueType = T;
+
+ Key key;
+ T value;
+ template<typename ...Args>
+ static void createInPlace(Node *n, Key &&k, Args &&... args)
+ { new (n) Node{ std::move(k), T(std::forward<Args>(args)...) }; }
+ template<typename ...Args>
+ static void createInPlace(Node *n, const Key &k, Args &&... args)
+ { new (n) Node{ Key(k), T(std::forward<Args>(args)...) }; }
+ template<typename ...Args>
+ void emplaceValue(Args &&... args)
+ {
+ value = T(std::forward<Args>(args)...);
}
-}
+ T &&takeValue() noexcept(std::is_nothrow_move_assignable_v<T>)
+ {
+ return std::move(value);
+ }
+ bool valuesEqual(const Node *other) const { return value == other->value; }
+};
-inline void QHashData::hasShrunk()
+template <typename Key>
+struct Node<Key, QHashDummyValue> {
+ using KeyType = Key;
+ using ValueType = QHashDummyValue;
+
+ Key key;
+ template<typename ...Args>
+ static void createInPlace(Node *n, Key &&k, Args &&...)
+ { new (n) Node{ std::move(k) }; }
+ template<typename ...Args>
+ static void createInPlace(Node *n, const Key &k, Args &&...)
+ { new (n) Node{ k }; }
+ template<typename ...Args>
+ void emplaceValue(Args &&...)
+ {
+ }
+ ValueType takeValue() { return QHashDummyValue(); }
+ bool valuesEqual(const Node *) const { return true; }
+};
+
+template <typename T>
+struct MultiNodeChain
{
- if (size <= (numBuckets >> 3) && numBits > userNumBits) {
- QT_TRY {
- rehash(qMax(int(numBits) - 2, int(userNumBits)));
- } QT_CATCH(const std::bad_alloc &) {
- // ignore bad allocs - shrinking shouldn't throw. rehash is exception safe.
+ T value;
+ MultiNodeChain *next = nullptr;
+ ~MultiNodeChain()
+ {
+ }
+ qsizetype free() noexcept(std::is_nothrow_destructible_v<T>)
+ {
+ qsizetype nEntries = 0;
+ MultiNodeChain *e = this;
+ while (e) {
+ MultiNodeChain *n = e->next;
+ ++nEntries;
+ delete e;
+ e = n;
}
+ return nEntries;
}
-}
+ bool contains(const T &val) const noexcept
+ {
+ const MultiNodeChain *e = this;
+ while (e) {
+ if (e->value == val)
+ return true;
+ e = e->next;
+ }
+ return false;
+ }
+};
-inline QHashData::Node *QHashData::firstNode()
+template <typename Key, typename T>
+struct MultiNode
{
- Node *e = reinterpret_cast<Node *>(this);
- Node **bucket = buckets;
- int n = numBuckets;
- while (n--) {
- if (*bucket != e)
- return *bucket;
- ++bucket;
+ using KeyType = Key;
+ using ValueType = T;
+ using Chain = MultiNodeChain<T>;
+
+ Key key;
+ Chain *value;
+
+ template<typename ...Args>
+ static void createInPlace(MultiNode *n, Key &&k, Args &&... args)
+ { new (n) MultiNode(std::move(k), new Chain{ T(std::forward<Args>(args)...), nullptr }); }
+ template<typename ...Args>
+ static void createInPlace(MultiNode *n, const Key &k, Args &&... args)
+ { new (n) MultiNode(k, new Chain{ T(std::forward<Args>(args)...), nullptr }); }
+
+ MultiNode(const Key &k, Chain *c)
+ : key(k),
+ value(c)
+ {}
+ MultiNode(Key &&k, Chain *c) noexcept(std::is_nothrow_move_assignable_v<Key>)
+ : key(std::move(k)),
+ value(c)
+ {}
+
+ MultiNode(MultiNode &&other)
+ : key(other.key),
+ value(other.value)
+ {
+ other.value = nullptr;
}
- return e;
-}
-struct QHashDummyValue
-{
+ MultiNode(const MultiNode &other)
+ : key(other.key)
+ {
+ Chain *c = other.value;
+ Chain **e = &value;
+ while (c) {
+ Chain *chain = new Chain{ c->value, nullptr };
+ *e = chain;
+ e = &chain->next;
+ c = c->next;
+ }
+ }
+ ~MultiNode()
+ {
+ if (value)
+ value->free();
+ }
+ static qsizetype freeChain(MultiNode *n) noexcept(std::is_nothrow_destructible_v<T>)
+ {
+ qsizetype size = n->value->free();
+ n->value = nullptr;
+ return size;
+ }
+ template<typename ...Args>
+ void insertMulti(Args &&... args)
+ {
+ Chain *e = new Chain{ T(std::forward<Args>(args)...), nullptr };
+ e->next = value;
+ value = e;
+ }
+ template<typename ...Args>
+ void emplaceValue(Args &&... args)
+ {
+ value->value = T(std::forward<Args>(args)...);
+ }
+
+ // compiler generated move operators are fine
};
-constexpr bool operator==(const QHashDummyValue &, const QHashDummyValue &) noexcept
+template<typename Node>
+constexpr bool isRelocatable()
{
- return true;
+ return QTypeInfo<typename Node::KeyType>::isRelocatable && QTypeInfo<typename Node::ValueType>::isRelocatable;
}
-Q_DECLARE_TYPEINFO(QHashDummyValue, Q_MOVABLE_TYPE | Q_DUMMY_TYPE);
+// Regular hash tables consist of a list of buckets that can store Nodes. But simply allocating one large array of buckets
+// would waste a lot of memory. To avoid this, we split the vector of buckets up into a vector of Spans. Each Span represents
+// NEntries buckets. To quickly find the correct Span that holds a bucket, NEntries must be a power of two.
+//
+// Inside each Span, there is an offset array that represents the actual buckets. offsets contains either an index into the
+// actual storage space for the Nodes (the 'entries' member) or 0xff (UnusedEntry) to flag that the bucket is empty.
+// As we have only 128 entries per Span, the offset array can be represented using an unsigned char. This trick makes the hash
+// table have a very small memory overhead compared to many other implementations.
+template<typename Node>
+struct Span {
+ enum {
+ NEntries = 128,
+ LocalBucketMask = (NEntries - 1),
+ UnusedEntry = 0xff
+ };
+ static_assert ((NEntries & LocalBucketMask) == 0, "EntriesPerSpan must be a power of two.");
+
+ // Entry is a slot available for storing a Node. The Span holds a pointer to
+ // an array of Entries. Upon construction of the array, those entries are
+ // unused, and nextFree() is being used to set up a singly linked list
+ // of free entries.
+ // When a node gets inserted, the first free entry is being picked, removed
+ // from the singly linked list and the Node gets constructed in place.
+ struct Entry {
+ typename std::aligned_storage<sizeof(Node), alignof(Node)>::type storage;
+
+ unsigned char &nextFree() { return *reinterpret_cast<unsigned char *>(&storage); }
+ Node &node() { return *reinterpret_cast<Node *>(&storage); }
+ };
-template <class Key, class T>
-struct QHashNode
-{
- QHashNode *next;
- const uint h;
- const Key key;
- T value;
+ unsigned char offsets[NEntries];
+ Entry *entries = nullptr;
+ unsigned char allocated = 0;
+ unsigned char nextFree = 0;
+ Span() noexcept
+ {
+ memset(offsets, UnusedEntry, sizeof(offsets));
+ }
+ ~Span()
+ {
+ freeData();
+ }
+ void freeData() noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (entries) {
+ if constexpr (!std::is_trivially_destructible<Node>::value) {
+ for (auto o : offsets) {
+ if (o != UnusedEntry)
+ entries[o].node().~Node();
+ }
+ }
+ delete [] entries;
+ entries = nullptr;
+ }
+ }
+ Node *insert(size_t i)
+ {
+ Q_ASSERT(i <= NEntries);
+ Q_ASSERT(offsets[i] == UnusedEntry);
+ if (nextFree == allocated)
+ addStorage();
+ unsigned char entry = nextFree;
+ Q_ASSERT(entry < allocated);
+ nextFree = entries[entry].nextFree();
+ offsets[i] = entry;
+ return &entries[entry].node();
+ }
+ void erase(size_t bucket) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ Q_ASSERT(bucket <= NEntries);
+ Q_ASSERT(offsets[bucket] != UnusedEntry);
- inline QHashNode(const Key &key0, const T &value0, uint hash, QHashNode *n)
- : next(n), h(hash), key(key0), value(value0) {}
- inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; }
+ unsigned char entry = offsets[bucket];
+ offsets[bucket] = UnusedEntry;
-private:
- Q_DISABLE_COPY(QHashNode)
+ entries[entry].node().~Node();
+ entries[entry].nextFree() = nextFree;
+ nextFree = entry;
+ }
+ size_t offset(size_t i) const noexcept
+ {
+ return offsets[i];
+ }
+ bool hasNode(size_t i) const noexcept
+ {
+ return (offsets[i] != UnusedEntry);
+ }
+ Node &at(size_t i) noexcept
+ {
+ Q_ASSERT(i <= NEntries);
+ Q_ASSERT(offsets[i] != UnusedEntry);
+
+ return entries[offsets[i]].node();
+ }
+ const Node &at(size_t i) const noexcept
+ {
+ Q_ASSERT(i <= NEntries);
+ Q_ASSERT(offsets[i] != UnusedEntry);
+
+ return entries[offsets[i]].node();
+ }
+ Node &atOffset(size_t o) noexcept
+ {
+ Q_ASSERT(o < allocated);
+
+ return entries[o].node();
+ }
+ const Node &atOffset(size_t o) const noexcept
+ {
+ Q_ASSERT(o < allocated);
+
+ return entries[o].node();
+ }
+ void moveLocal(size_t from, size_t to) noexcept
+ {
+ Q_ASSERT(offsets[from] != UnusedEntry);
+ Q_ASSERT(offsets[to] == UnusedEntry);
+ offsets[to] = offsets[from];
+ offsets[from] = UnusedEntry;
+ }
+ void moveFromSpan(Span &fromSpan, size_t fromIndex, size_t to) noexcept(std::is_nothrow_move_constructible_v<Node>)
+ {
+ Q_ASSERT(to <= NEntries);
+ Q_ASSERT(offsets[to] == UnusedEntry);
+ Q_ASSERT(fromIndex <= NEntries);
+ Q_ASSERT(fromSpan.offsets[fromIndex] != UnusedEntry);
+ if (nextFree == allocated)
+ addStorage();
+ Q_ASSERT(nextFree < allocated);
+ offsets[to] = nextFree;
+ Entry &toEntry = entries[nextFree];
+ nextFree = toEntry.nextFree();
+
+ size_t fromOffset = fromSpan.offsets[fromIndex];
+ fromSpan.offsets[fromIndex] = UnusedEntry;
+ Entry &fromEntry = fromSpan.entries[fromOffset];
+
+ if constexpr (isRelocatable<Node>()) {
+ memcpy(&toEntry, &fromEntry, sizeof(Entry));
+ } else {
+ new (&toEntry.node()) Node(std::move(fromEntry.node()));
+ fromEntry.node().~Node();
+ }
+ fromEntry.nextFree() = fromSpan.nextFree;
+ fromSpan.nextFree = static_cast<unsigned char>(fromOffset);
+ }
+
+ void addStorage()
+ {
+ Q_ASSERT(allocated < NEntries);
+ Q_ASSERT(nextFree == allocated);
+ // the hash table should always be between 25 and 50% full
+ // this implies that we on average have between 32 and 64 entries
+ // in here. The likelihood of having below 16 entries is very small,
+ // so start with that and increment by 16 each time we need to add
+ // some more space
+ const size_t increment = NEntries/8;
+ size_t alloc = allocated + increment;
+ Entry *newEntries = new Entry[alloc];
+ // we only add storage if the previous storage was fully filled, so
+ // simply copy the old data over
+ if constexpr (isRelocatable<Node>()) {
+ memcpy(newEntries, entries, allocated*sizeof(Entry));
+ } else {
+ for (size_t i = 0; i < allocated; ++i) {
+ new (&newEntries[i].node()) Node(std::move(entries[i].node()));
+ entries[i].node().~Node();
+ }
+ }
+ for (size_t i = allocated; i < allocated + increment; ++i) {
+ newEntries[i].nextFree() = uchar(i + 1);
+ }
+ delete [] entries;
+ entries = newEntries;
+ allocated = uchar(alloc);
+ }
};
-// Specialize for QHashDummyValue in order to save some memory
-template <class Key>
-struct QHashNode<Key, QHashDummyValue>
+template <typename Node>
+struct iterator;
+
+template <typename Node>
+struct Data
{
- union {
- QHashNode *next;
- QHashDummyValue value;
+ using Key = typename Node::KeyType;
+ using T = typename Node::ValueType;
+ using Span = QHashPrivate::Span<Node>;
+ using iterator = QHashPrivate::iterator<Node>;
+
+ QtPrivate::RefCount ref = {{1}};
+ size_t size = 0;
+ size_t numBuckets = 0;
+ size_t seed = 0;
+
+
+ Span *spans = nullptr;
+
+ Data(size_t reserve = 0)
+ {
+ numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
+ size_t nSpans = (numBuckets + Span::LocalBucketMask) / Span::NEntries;
+ spans = new Span[nSpans];
+ seed = qGlobalQHashSeed();
+ }
+ Data(const Data &other, size_t reserved = 0)
+ : size(other.size),
+ numBuckets(other.numBuckets),
+ seed(other.seed)
+ {
+ if (reserved)
+ numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
+ bool resized = numBuckets != other.numBuckets;
+ size_t nSpans = (numBuckets + Span::LocalBucketMask) / Span::NEntries;
+ spans = new Span[nSpans];
+
+ for (size_t s = 0; s < nSpans; ++s) {
+ const Span &span = other.spans[s];
+ for (size_t index = 0; index < Span::NEntries; ++index) {
+ if (!span.hasNode(index))
+ continue;
+ const Node &n = span.at(index);
+ iterator it = resized ? find(n.key) : iterator{ this, s*Span::NEntries + index };
+ Q_ASSERT(it.isUnused());
+ Node *newNode = spans[it.span()].insert(it.index());
+ new (newNode) Node(n);
+ }
+ }
+ }
+
+ static Data *detached(Data *d, size_t size = 0)
+ {
+ if (!d)
+ return new Data(size);
+ Data *dd = new Data(*d, size);
+ if (!d->ref.deref())
+ delete d;
+ return dd;
+ }
+
+
+ void clear()
+ {
+ delete [] spans;
+ spans = nullptr;
+ size = 0;
+ numBuckets = 0;
+ }
+
+ iterator detachedIterator(iterator other) const noexcept
+ {
+ return iterator{this, other.bucket};
+ }
+
+ iterator begin() const noexcept
+ {
+ iterator it{ this, 0 };
+ if (it.isUnused())
+ ++it;
+ return it;
+ }
+
+ constexpr iterator end() const noexcept
+ {
+ return iterator();
+ }
+
+ void rehash(size_t sizeHint = 0)
+ {
+ if (sizeHint == 0)
+ sizeHint = size;
+ size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
+
+ Span *oldSpans = spans;
+ size_t oldBucketCount = numBuckets;
+ size_t nSpans = (newBucketCount + Span::LocalBucketMask) / Span::NEntries;
+ spans = new Span[nSpans];
+ numBuckets = newBucketCount;
+ size_t oldNSpans = (oldBucketCount + Span::LocalBucketMask) / Span::NEntries;
+
+ for (size_t s = 0; s < oldNSpans; ++s) {
+ Span &span = oldSpans[s];
+ for (size_t index = 0; index < Span::NEntries; ++index) {
+ if (!span.hasNode(index))
+ continue;
+ Node &n = span.at(index);
+ iterator it = find(n.key);
+ Q_ASSERT(it.isUnused());
+ Node *newNode = spans[it.span()].insert(it.index());
+ new (newNode) Node(std::move(n));
+ }
+ span.freeData();
+ }
+ delete [] oldSpans;
+ }
+
+ size_t nextBucket(size_t bucket) const noexcept
+ {
+ ++bucket;
+ if (bucket == numBuckets)
+ bucket = 0;
+ return bucket;
+ }
+
+ float loadFactor() const noexcept
+ {
+ return float(size)/numBuckets;
+ }
+ bool shouldGrow() const noexcept
+ {
+ return size >= (numBuckets >> 1);
+ }
+
+ iterator find(const Key &key) const noexcept
+ {
+ Q_ASSERT(numBuckets > 0);
+ size_t hash = qHash(key, seed);
+ size_t bucket = GrowthPolicy::bucketForHash(numBuckets, hash);
+ // loop over the buckets until we find the entry we search for
+ // or an empty slot, in which case we know the entry doesn't exist
+ while (true) {
+ // Split the bucket into the indexex of span array, and the local
+ // offset inside the span
+ size_t span = bucket / Span::NEntries;
+ size_t index = bucket & Span::LocalBucketMask;
+ Span &s = spans[span];
+ size_t offset = s.offset(index);
+ if (offset == Span::UnusedEntry) {
+ return iterator{ this, bucket };
+ } else {
+ Node &n = s.atOffset(offset);
+ if (n.key == key)
+ return iterator{ this, bucket };
+ }
+ bucket = nextBucket(bucket);
+ }
+ }
+
+ Node *findNode(const Key &key) const noexcept
+ {
+ if (!size)
+ return nullptr;
+ iterator it = find(key);
+ if (it.isUnused())
+ return nullptr;
+ return it.node();
+ }
+
+ struct InsertionResult {
+ iterator it;
+ bool initialized;
};
- const uint h;
- const Key key;
- inline QHashNode(const Key &key0, const QHashDummyValue &, uint hash, QHashNode *n)
- : next(n), h(hash), key(key0) {}
- inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; }
+ InsertionResult findOrInsert(const Key &key) noexcept
+ {
+ if (shouldGrow())
+ rehash(size + 1);
+ iterator it = find(key);
+ if (it.isUnused()) {
+ spans[it.span()].insert(it.index());
+ ++size;
+ return { it, false };
+ }
+ return { it, true };
+ }
-private:
- Q_DISABLE_COPY(QHashNode)
+ iterator erase(iterator it) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ size_t bucket = it.bucket;
+ size_t span = bucket / Span::NEntries;
+ size_t index = bucket & Span::LocalBucketMask;
+ Q_ASSERT(spans[span].hasNode(index));
+ spans[span].erase(index);
+ --size;
+
+ // re-insert the following entries to avoid holes
+ size_t hole = bucket;
+ size_t next = bucket;
+ while (true) {
+ next = nextBucket(next);
+ size_t nextSpan = next / Span::NEntries;
+ size_t nextIndex = next & Span::LocalBucketMask;
+ if (!spans[nextSpan].hasNode(nextIndex))
+ break;
+ size_t hash = qHash(spans[nextSpan].at(nextIndex).key, seed);
+ size_t newBucket = GrowthPolicy::bucketForHash(numBuckets, hash);
+ while (true) {
+ if (newBucket == next) {
+ // nothing to do, item is at the right plae
+ break;
+ } else if (newBucket == hole) {
+ // move into hole
+ size_t holeSpan = hole / Span::NEntries;
+ size_t holeIndex = hole & Span::LocalBucketMask;
+ if (nextSpan == holeSpan) {
+ spans[holeSpan].moveLocal(nextIndex, holeIndex);
+ } else {
+ // move between spans, more expensive
+ spans[holeSpan].moveFromSpan(spans[nextSpan], nextIndex, holeIndex);
+ }
+ hole = next;
+ break;
+ }
+ newBucket = nextBucket(newBucket);
+ }
+ }
+
+ // return correct position of the next element
+ if (!spans[span].hasNode(index))
+ ++it;
+ return it;
+ }
+
+ ~Data()
+ {
+ delete [] spans;
+ }
};
+template <typename Node>
+struct iterator {
+ using Span = QHashPrivate::Span<Node>;
-#if 0
-// ###
-// The introduction of the QHash random seed breaks this optimization, as it
-// relies on qHash(int i) = i. If the hash value is salted, then the hash
-// table becomes corrupted.
-//
-// A bit more research about whether it makes sense or not to salt integer
-// keys (and in general keys whose hash value is easy to invert)
-// is needed, or about how keep this optimization and the seed (f.i. by
-// specializing QHash for integer values, and re-apply the seed during lookup).
-//
-// Be aware that such changes can easily be binary incompatible, and therefore
-// cannot be made during the Qt 5 lifetime.
-#define Q_HASH_DECLARE_INT_NODES(key_type) \
- template <class T> \
- struct QHashDummyNode<key_type, T> { \
- QHashDummyNode *next; \
- union { uint h; key_type key; }; \
-\
- inline QHashDummyNode(key_type /* key0 */) {} \
- }; \
-\
- template <class T> \
- struct QHashNode<key_type, T> { \
- QHashNode *next; \
- union { uint h; key_type key; }; \
- T value; \
-\
- inline QHashNode(key_type /* key0 */) {} \
- inline QHashNode(key_type /* key0 */, const T &value0) : value(value0) {} \
- inline bool same_key(uint h0, key_type) const { return h0 == h; } \
- }
-
-#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-Q_HASH_DECLARE_INT_NODES(short);
-Q_HASH_DECLARE_INT_NODES(ushort);
-#endif
-Q_HASH_DECLARE_INT_NODES(int);
-Q_HASH_DECLARE_INT_NODES(uint);
-#undef Q_HASH_DECLARE_INT_NODES
-#endif // #if 0
+ const Data<Node> *d = nullptr;
+ size_t bucket = 0;
-template <class Key, class T>
-class QHash
-{
- typedef QHashNode<Key, T> Node;
+ size_t span() const noexcept { return bucket / Span::NEntries; }
+ size_t index() const noexcept { return bucket & Span::LocalBucketMask; }
+ inline bool isUnused() const noexcept { return !d->spans[span()].hasNode(index()); }
- union {
- QHashData *d;
- QHashNode<Key, T> *e;
- };
+ inline Node *node() const noexcept
+ {
+ Q_ASSERT(!isUnused());
+ return &d->spans[span()].at(index());
+ }
+ bool atEnd() const noexcept { return !d; }
- static inline Node *concrete(QHashData::Node *node) {
- return reinterpret_cast<Node *>(node);
+ iterator operator++() noexcept
+ {
+ while (true) {
+ ++bucket;
+ if (bucket == d->numBuckets) {
+ d = nullptr;
+ bucket = 0;
+ break;
+ }
+ if (!isUnused())
+ break;
+ }
+ return *this;
}
+ bool operator==(iterator other) const noexcept
+ { return d == other.d && bucket == other.bucket; }
+ bool operator!=(iterator other) const noexcept
+ { return !(*this == other); }
+};
+
+
+
+} // namespace QHashPrivate
- static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); }
+template <class Key, class T>
+class QHash
+{
+ using Node = QHashPrivate::Node<Key, T>;
+ using Data = QHashPrivate::Data<Node>;
+ friend class QSet<Key>;
+
+ Data *d = nullptr;
public:
- inline QHash() noexcept : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
+ using key_type = Key;
+ using mapped_type = T;
+ using value_type = T;
+ using size_type = qsizetype;
+ using difference_type = qsizetype;
+ using reference = T &;
+ using const_reference = const T &;
+
+ inline QHash() noexcept = default;
inline QHash(std::initializer_list<std::pair<Key,T> > list)
- : d(const_cast<QHashData *>(&QHashData::shared_null))
+ : d(new Data(list.size()))
{
- reserve(int(list.size()));
for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
insert(it->first, it->second);
}
- QHash(const QHash &other) : d(other.d) { d->ref.ref(); if (!d->sharable) detach(); }
- ~QHash() { if (!d->ref.deref()) freeData(d); }
+ QHash(const QHash &other) noexcept
+ : d(other.d)
+ {
+ if (d)
+ d->ref.ref();
+ }
+ ~QHash()
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ }
+
+ QHash &operator=(const QHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d != other.d) {
+ Data *o = other.d;
+ if (o)
+ o->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = o;
+ }
+ return *this;
+ }
- QHash &operator=(const QHash &other);
- QHash(QHash &&other) noexcept : d(other.d) { other.d = const_cast<QHashData *>(&QHashData::shared_null); }
- QHash &operator=(QHash &&other) noexcept
- { QHash moved(std::move(other)); swap(moved); return *this; }
+ QHash(QHash &&other) noexcept
+ : d(std::exchange(other.d, nullptr))
+ {
+ }
+ QHash &operator=(QHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d != other.d) {
+ if (d && !d->ref.deref())
+ delete d;
+ d = std::exchange(other.d, nullptr);
+ }
+ return *this;
+ }
#ifdef Q_QDOC
template <typename InputIterator>
QHash(InputIterator f, InputIterator l);
@@ -277,189 +782,222 @@ public:
#endif
void swap(QHash &other) noexcept { qSwap(d, other.d); }
- bool operator==(const QHash &other) const;
- bool operator!=(const QHash &other) const { return !(*this == other); }
+ bool operator==(const QHash &other) const noexcept
+ {
+ if (d == other.d)
+ return true;
+ if (size() != other.size())
+ return false;
+
+ for (const_iterator it = other.begin(); it != other.end(); ++it) {
+ const_iterator i = find(it.key());
+ if (i == end() || !i.i.node()->valuesEqual(it.i.node()))
+ return false;
+ }
+ // all values must be the same as size is the same
+ return true;
+ }
+ bool operator!=(const QHash &other) const noexcept { return !(*this == other); }
- inline int size() const { return d->size; }
+ inline qsizetype size() const noexcept { return d ? qsizetype(d->size) : 0; }
+ inline bool isEmpty() const noexcept { return !d || d->size == 0; }
- inline bool isEmpty() const { return d->size == 0; }
+ inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
+ void reserve(qsizetype size)
+ {
+ if (isDetached())
+ d->rehash(size);
+ else
+ d = Data::detached(d, size_t(size));
+ }
+ inline void squeeze() { reserve(0); }
- inline int capacity() const { return d->numBuckets; }
- void reserve(int size);
- inline void squeeze() { reserve(1); }
+ inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
+ inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
+ bool isSharedWith(const QHash &other) const noexcept { return d == other.d; }
- inline void detach() { if (d->ref.isShared()) detach_helper(); }
- inline bool isDetached() const { return !d->ref.isShared(); }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QHashData::shared_null) d->sharable = sharable; }
-#endif
- bool isSharedWith(const QHash &other) const { return d == other.d; }
-
- void clear();
-
- int remove(const Key &key);
- T take(const Key &key);
-
- bool contains(const Key &key) const;
- const Key key(const T &value) const;
- const Key key(const T &value, const Key &defaultKey) const;
- const T value(const Key &key) const;
- const T value(const Key &key, const T &defaultValue) const;
- T &operator[](const Key &key);
- const T operator[](const Key &key) const;
-
- QList<Key> keys() const;
- QList<Key> keys(const T &value) const;
- QList<T> values() const;
-#if QT_DEPRECATED_SINCE(5, 15)
- QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList<Key> uniqueKeys() const;
- QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QList<T> values(const Key &key) const;
-#endif
- int count(const Key &key) const;
+ void clear() noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = nullptr;
+ }
+
+ bool remove(const Key &key)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return false;
+ detach();
+
+ auto it = d->find(key);
+ if (it.isUnused())
+ return false;
+ d->erase(it);
+ return true;
+ }
+ T take(const Key &key)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return T();
+ detach();
+
+ auto it = d->find(key);
+ if (it.isUnused())
+ return T();
+ T value = it.node()->takeValue();
+ d->erase(it);
+ return value;
+ }
+
+ bool contains(const Key &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
+ }
+ qsizetype count(const Key &key) const noexcept
+ {
+ return contains(key) ? 1 : 0;
+ }
+
+ Key key(const T &value, const Key &defaultKey = Key()) const noexcept
+ {
+ if (d) {
+ const_iterator i = begin();
+ while (i != end()) {
+ if (i.value() == value)
+ return i.key();
+ ++i;
+ }
+ }
+
+ return defaultKey;
+ }
+ T value(const Key &key, const T &defaultValue = T()) const noexcept
+ {
+ if (d) {
+ Node *n = d->findNode(key);
+ if (n)
+ return n->value;
+ }
+ return defaultValue;
+ }
+ T &operator[](const Key &key)
+ {
+ detach();
+ auto result = d->findOrInsert(key);
+ Q_ASSERT(!result.it.atEnd());
+ if (!result.initialized)
+ Node::createInPlace(result.it.node(), key, T());
+ return result.it.node()->value;
+ }
+
+ const T operator[](const Key &key) const noexcept
+ {
+ return value(key);
+ }
+
+ QVector<Key> keys() const
+ {
+ return QVector<Key>(keyBegin(), keyEnd());
+ }
+ QVector<Key> keys(const T &value) const
+ {
+ QVector<Key> res;
+ const_iterator i = begin();
+ while (i != end()) {
+ if (i.value() == value)
+ res.append(i.key());
+ ++i;
+ }
+ return res;
+ }
+ QVector<T> values() const
+ {
+ return QVector<T>(begin(), end());
+ }
class const_iterator;
class iterator
{
+ using piter = typename QHashPrivate::iterator<Node>;
friend class const_iterator;
friend class QHash<Key, T>;
friend class QSet<Key>;
- QHashData::Node *i;
+ piter i;
+ explicit inline iterator(piter it) noexcept : i(it) { }
public:
-#if QT_DEPRECATED_WARNINGS_SINCE < QT_VERSION_CHECK(5, 15, 0)
- typedef std::bidirectional_iterator_tag iterator_category;
-#else
typedef std::forward_iterator_tag iterator_category;
-#endif
typedef qptrdiff difference_type;
typedef T value_type;
typedef T *pointer;
typedef T &reference;
- inline iterator() : i(nullptr) { }
- explicit inline iterator(void *node) : i(reinterpret_cast<QHashData::Node *>(node)) { }
+ constexpr iterator() noexcept = default;
- inline const Key &key() const { return concrete(i)->key; }
- inline T &value() const { return concrete(i)->value; }
- inline T &operator*() const { return concrete(i)->value; }
- inline T *operator->() const { return &concrete(i)->value; }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline T &value() const noexcept { return i.node()->value; }
+ inline T &operator*() const noexcept { return i.node()->value; }
+ inline T *operator->() const noexcept { return &i.node()->value; }
+ inline bool operator==(const iterator &o) const noexcept { return i == o.i; }
+ inline bool operator!=(const iterator &o) const noexcept { return i != o.i; }
- inline iterator &operator++() {
- i = QHashData::nextNode(i);
- return *this;
- }
- inline iterator operator++(int) {
- iterator r = *this;
- i = QHashData::nextNode(i);
- return r;
- }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 iterator &operator--()
+ inline iterator &operator++() noexcept
{
- i = QHashData::previousNode(i);
+ ++i;
return *this;
}
- inline QT_DEPRECATED_VERSION_5_15 iterator operator--(int)
+ inline iterator operator++(int) noexcept
{
iterator r = *this;
- i = QHashData::previousNode(i);
+ ++i;
return r;
}
- inline QT_DEPRECATED_VERSION_5_15 iterator operator+(int j) const
- { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline QT_DEPRECATED_VERSION_5_15 iterator operator-(int j) const { return operator+(-j); }
- inline QT_DEPRECATED_VERSION_5_15 iterator &operator+=(int j) { return *this = *this + j; }
- inline QT_DEPRECATED_VERSION_5_15 iterator &operator-=(int j) { return *this = *this - j; }
- friend inline QT_DEPRECATED_VERSION_5_15 iterator operator+(int j, iterator k) { return k + j; }
-#endif
-#ifndef QT_STRICT_ITERATORS
- public:
- inline bool operator==(const const_iterator &o) const
- { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const
- { return i != o.i; }
-#endif
+ inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
};
friend class iterator;
class const_iterator
{
+ using piter = typename QHashPrivate::iterator<Node>;
friend class iterator;
friend class QHash<Key, T>;
- friend class QMultiHash<Key, T>;
friend class QSet<Key>;
- QHashData::Node *i;
+ piter i;
+ explicit inline const_iterator(piter it) : i(it) { }
public:
-#if QT_DEPRECATED_WARNINGS_SINCE < QT_VERSION_CHECK(5, 15, 0)
- typedef std::bidirectional_iterator_tag iterator_category;
-#else
typedef std::forward_iterator_tag iterator_category;
-#endif
typedef qptrdiff difference_type;
typedef T value_type;
typedef const T *pointer;
typedef const T &reference;
- Q_DECL_CONSTEXPR inline const_iterator() : i(nullptr) { }
- explicit inline const_iterator(void *node)
- : i(reinterpret_cast<QHashData::Node *>(node)) { }
-#ifdef QT_STRICT_ITERATORS
- explicit inline const_iterator(const iterator &o)
-#else
- inline const_iterator(const iterator &o)
-#endif
- { i = o.i; }
+ constexpr const_iterator() noexcept = default;
+ inline const_iterator(const iterator &o) noexcept : i(o.i) { }
- inline const Key &key() const { return concrete(i)->key; }
- inline const T &value() const { return concrete(i)->value; }
- inline const T &operator*() const { return concrete(i)->value; }
- inline const T *operator->() const { return &concrete(i)->value; }
- Q_DECL_CONSTEXPR inline bool operator==(const const_iterator &o) const { return i == o.i; }
- Q_DECL_CONSTEXPR inline bool operator!=(const const_iterator &o) const { return i != o.i; }
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline const T &value() const noexcept { return i.node()->value; }
+ inline const T &operator*() const noexcept { return i.node()->value; }
+ inline const T *operator->() const noexcept { return &i.node()->value; }
+ inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
- inline const_iterator &operator++() {
- i = QHashData::nextNode(i);
- return *this;
- }
- inline const_iterator operator++(int) {
- const_iterator r = *this;
- i = QHashData::nextNode(i);
- return r;
- }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator--()
+ inline const_iterator &operator++() noexcept
{
- i = QHashData::previousNode(i);
+ ++i;
return *this;
}
- inline QT_DEPRECATED_VERSION_5_15 const_iterator operator--(int)
+ inline const_iterator operator++(int) noexcept
{
const_iterator r = *this;
- i = QHashData::previousNode(i);
+ ++i;
return r;
}
- inline QT_DEPRECATED_VERSION_5_15 const_iterator operator+(int j) const
- { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator operator-(int j) const { return operator+(-j); }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator+=(int j) { return *this = *this + j; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator-=(int j) { return *this = *this - j; }
- friend inline QT_DEPRECATED_VERSION_5_15 const_iterator operator+(int j, const_iterator k)
- {
- return k + j;
- }
-#endif
-
- // ### Qt 5: not sure this is necessary anymore
-#ifdef QT_STRICT_ITERATORS
- private:
- inline bool operator==(const iterator &o) const { return operator==(const_iterator(o)); }
- inline bool operator!=(const iterator &o) const { return operator!=(const_iterator(o)); }
-#endif
};
friend class const_iterator;
@@ -469,641 +1007,799 @@ public:
public:
typedef typename const_iterator::iterator_category iterator_category;
- typedef typename const_iterator::difference_type difference_type;
+ typedef qptrdiff difference_type;
typedef Key value_type;
typedef const Key *pointer;
typedef const Key &reference;
- key_iterator() = default;
- explicit key_iterator(const_iterator o) : i(o) { }
+ key_iterator() noexcept = default;
+ explicit key_iterator(const_iterator o) noexcept : i(o) { }
- const Key &operator*() const { return i.key(); }
- const Key *operator->() const { return &i.key(); }
- bool operator==(key_iterator o) const { return i == o.i; }
- bool operator!=(key_iterator o) const { return i != o.i; }
+ const Key &operator*() const noexcept { return i.key(); }
+ const Key *operator->() const noexcept { return &i.key(); }
+ bool operator==(key_iterator o) const noexcept { return i == o.i; }
+ bool operator!=(key_iterator o) const noexcept { return i != o.i; }
- inline key_iterator &operator++() { ++i; return *this; }
- inline key_iterator operator++(int) { return key_iterator(i++);}
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 key_iterator &operator--()
- {
- --i;
- return *this;
- }
- inline QT_DEPRECATED_VERSION_5_15 key_iterator operator--(int) { return key_iterator(i--); }
-#endif
- const_iterator base() const { return i; }
+ inline key_iterator &operator++() noexcept { ++i; return *this; }
+ inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
+ const_iterator base() const noexcept { return i; }
};
typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
// STL style
- inline iterator begin() { detach(); return iterator(d->firstNode()); }
- inline const_iterator begin() const { return const_iterator(d->firstNode()); }
- inline const_iterator cbegin() const { return const_iterator(d->firstNode()); }
- inline const_iterator constBegin() const { return const_iterator(d->firstNode()); }
- inline iterator end() { detach(); return iterator(e); }
- inline const_iterator end() const { return const_iterator(e); }
- inline const_iterator cend() const { return const_iterator(e); }
- inline const_iterator constEnd() const { return const_iterator(e); }
- inline key_iterator keyBegin() const { return key_iterator(begin()); }
- inline key_iterator keyEnd() const { return key_iterator(end()); }
+ inline iterator begin() { detach(); return iterator(d->begin()); }
+ inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline iterator end() noexcept { return iterator(); }
+ inline const_iterator end() const noexcept { return const_iterator(); }
+ inline const_iterator cend() const noexcept { return const_iterator(); }
+ inline const_iterator constEnd() const noexcept { return const_iterator(); }
+ inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
+ inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
- inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
- inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
- inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
- inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+
+ iterator erase(const_iterator it)
+ {
+ Q_ASSERT(it != constEnd());
+ detach();
+ // ensure a valid iterator across the detach:
+ iterator i = iterator{d->detachedIterator(it.i)};
- QPair<iterator, iterator> equal_range(const Key &key);
- QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept;
- iterator erase(iterator it) { return erase(const_iterator(it.i)); }
- iterator erase(const_iterator it);
+ i.i = d->erase(i.i);
+ return i;
+ }
+
+ QPair<iterator, iterator> equal_range(const Key &key)
+ {
+ auto first = find(key);
+ auto second = first;
+ if (second != iterator())
+ ++second;
+ return qMakePair(first, second);
+ }
+
+ QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ {
+ auto first = find(key);
+ auto second = first;
+ if (second != iterator())
+ ++second;
+ return qMakePair(first, second);
+ }
- // more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
- inline int count() const { return d->size; }
- iterator find(const Key &key);
- const_iterator find(const Key &key) const;
- const_iterator constFind(const Key &key) const;
- iterator insert(const Key &key, const T &value);
- void insert(const QHash &hash);
-#if QT_DEPRECATED_SINCE(5, 15)
- QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value);
- QT_DEPRECATED_VERSION_X_5_15("Use QMultiHash for hashes storing multiple values with the same key.") QHash &unite(const QHash &other);
-#endif
+ inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
+ iterator find(const Key &key)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return end();
+ detach();
+ auto it = d->find(key);
+ if (it.isUnused())
+ it = d->end();
+ return iterator(it);
+ }
+ const_iterator find(const Key &key) const noexcept
+ {
+ if (isEmpty())
+ return end();
+ auto it = d->find(key);
+ if (it.isUnused())
+ it = d->end();
+ return const_iterator(it);
+ }
+ const_iterator constFind(const Key &key) const noexcept
+ {
+ return find(key);
+ }
+ iterator insert(const Key &key, const T &value)
+ {
+ return emplace(key, value);
+ }
- // STL compatibility
- typedef T mapped_type;
- typedef Key key_type;
- typedef qptrdiff difference_type;
- typedef int size_type;
+ void insert(const QHash &hash)
+ {
+ if (d == hash.d || !hash.d)
+ return;
+ if (!d) {
+ *this = hash;
+ return;
+ }
- inline bool empty() const { return isEmpty(); }
+ detach();
-#ifdef QT_QHASH_DEBUG
- inline void dump() const { d->dump(); }
- inline void checkSanity() const { d->checkSanity(); }
-#endif
+ for (auto it = hash.begin(); it != hash.end(); ++it)
+ emplace(it.key(), it.value());
+ }
-private:
- void detach_helper();
- void freeData(QHashData *d);
- Node **findNode(const Key &key, uint *hp = nullptr) const;
- Node **findNode(const Key &key, uint h) const;
- Node *createNode(uint h, const Key &key, const T &value, Node **nextNode);
- void deleteNode(Node *node);
- static void deleteNode2(QHashData::Node *node);
-
- static void duplicateNode(QHashData::Node *originalNode, void *newNode);
-
- bool isValidIterator(const iterator &it) const noexcept
- { return isValidNode(it.i); }
- bool isValidIterator(const const_iterator &it) const noexcept
- { return isValidNode(it.i); }
- bool isValidNode(QHashData::Node *node) const noexcept
- {
-#if defined(QT_DEBUG) && !defined(Q_HASH_NO_ITERATOR_DEBUG)
- while (node->next)
- node = node->next;
- return (static_cast<void *>(node) == d);
-#else
- Q_UNUSED(node);
- return true;
-#endif
+ template <typename ...Args>
+ iterator emplace(const Key &key, Args &&... args)
+ {
+ return emplace(Key(key), std::forward<Args>(args)...);
}
- friend class QSet<Key>;
- friend class QMultiHash<Key, T>;
-};
+ template <typename ...Args>
+ iterator emplace(Key &&key, Args &&... args)
+ {
+ detach();
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(Node *node)
-{
- deleteNode2(reinterpret_cast<QHashData::Node*>(node));
- d->freeNode(node);
-}
+ auto result = d->findOrInsert(key);
+ if (!result.initialized)
+ Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
+ else
+ result.it.node()->emplaceValue(std::forward<Args>(args)...);
+ return iterator(result.it);
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode2(QHashData::Node *node)
-{
-#ifdef Q_CC_BOR
- concrete(node)->~QHashNode<Key, T>();
-#else
- concrete(node)->~Node();
-#endif
-}
+ float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
+ static float max_load_factor() noexcept { return 0.5; }
+ size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
+ static size_t max_bucket_count() noexcept { return QHashPrivate::GrowthPolicy::maxNumBuckets(); }
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::duplicateNode(QHashData::Node *node, void *newNode)
-{
- Node *concreteNode = concrete(node);
- new (newNode) Node(concreteNode->key, concreteNode->value, concreteNode->h, nullptr);
-}
+ inline bool empty() const noexcept { return isEmpty(); }
+};
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::Node *
-QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode)
-{
- Node *node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, *anextNode);
- *anextNode = node;
- ++d->size;
- return node;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x)
-{
- x->free_helper(deleteNode2);
-}
template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::clear()
+class QMultiHash
{
- *this = QHash();
-}
+ using Node = QHashPrivate::MultiNode<Key, T>;
+ using Data = QHashPrivate::Data<Node>;
+ using Chain = QHashPrivate::MultiNodeChain<T>;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
-{
- QHashData *x = d->detach_helper(duplicateNode, deleteNode2, sizeof(Node), alignOfNode());
- if (!d->ref.deref())
- freeData(d);
- d = x;
-}
+ Data *d = nullptr;
+ qsizetype m_size = 0;
-template <class Key, class T>
-Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::operator=(const QHash &other)
-{
- if (d != other.d) {
- QHashData *o = other.d;
- o->ref.ref();
- if (!d->ref.deref())
- freeData(d);
- d = o;
- if (!d->sharable)
- detach_helper();
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using value_type = T;
+ using size_type = qsizetype;
+ using difference_type = qsizetype;
+ using reference = T &;
+ using const_reference = const T &;
+
+ QMultiHash() noexcept = default;
+ inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
+ : d(new Data(list.size()))
+ {
+ for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
+ insert(it->first, it->second);
}
- return *this;
-}
-
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey) const
-{
- Node *node;
- if (d->size == 0 || (node = *findNode(akey)) == e) {
- return T();
- } else {
- return node->value;
+#ifdef Q_QDOC
+ template <typename InputIterator>
+ QMultiHash(InputIterator f, InputIterator l);
+#else
+ template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
+ QMultiHash(InputIterator f, InputIterator l)
+ {
+ QtPrivate::reserveIfForwardIterator(this, f, l);
+ for (; f != l; ++f)
+ insert(f.key(), f.value());
}
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey, const T &adefaultValue) const
-{
- Node *node;
- if (d->size == 0 || (node = *findNode(akey)) == e) {
- return adefaultValue;
- } else {
- return node->value;
+ template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
+ QMultiHash(InputIterator f, InputIterator l)
+ {
+ QtPrivate::reserveIfForwardIterator(this, f, l);
+ for (; f != l; ++f)
+ insert(f->first, f->second);
+ }
+#endif
+ QMultiHash(const QMultiHash &other) noexcept
+ : d(other.d), m_size(other.m_size)
+ {
+ if (d)
+ d->ref.ref();
+ }
+ ~QMultiHash()
+ {
+ if (d && !d->ref.deref())
+ delete d;
}
-}
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys() const
-{
- QList<Key> res;
- res.reserve(size());
- const_iterator i = begin();
- while (i != end()) {
- res.append(i.key());
- ++i;
- }
- return res;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys(const T &avalue) const
-{
- QList<Key> res;
- const_iterator i = begin();
- while (i != end()) {
- if (i.value() == avalue)
- res.append(i.key());
- ++i;
- }
- return res;
-}
+ QMultiHash &operator=(const QMultiHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d != other.d) {
+ Data *o = other.d;
+ if (o)
+ o->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = o;
+ m_size = other.m_size;
+ }
+ return *this;
+ }
+ QMultiHash(QMultiHash &&other) noexcept : d(other.d), m_size(other.m_size)
+ {
+ other.d = nullptr;
+ other.m_size = 0;
+ }
+ QMultiHash &operator=(QMultiHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ QMultiHash moved(std::move(other));
+ swap(moved);
+ return *this;
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue) const
-{
- return key(avalue, Key());
-}
+ QMultiHash(const QHash<Key, T> &other)
+ : QMultiHash(other.begin(), other.end())
+ {}
+ void swap(QMultiHash &other) noexcept { qSwap(d, other.d); qSwap(m_size, other.m_size); }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue, const Key &defaultValue) const
-{
- const_iterator i = begin();
- while (i != end()) {
- if (i.value() == avalue)
- return i.key();
- ++i;
+ bool operator==(const QMultiHash &other) const noexcept
+ {
+ if (d == other.d)
+ return true;
+ if (!d || ! other.d)
+ return false;
+ if (m_size != other.m_size || d->size != other.d->size)
+ return false;
+ for (auto it = other.d->begin(); it != other.d->end(); ++it) {
+ auto i = d->find(it.node()->key);
+ if (i == d->end())
+ return false;
+ Chain *e = it.node()->value;
+ while (e) {
+ Chain *oe = i.node()->value;
+ while (oe) {
+ if (oe->value == e->value)
+ break;
+ oe = oe->next;
+ }
+ if (!oe)
+ return false;
+ e = e->next;
+ }
+ }
+ // all values must be the same as size is the same
+ return true;
}
+ bool operator!=(const QMultiHash &other) const noexcept { return !(*this == other); }
- return defaultValue;
-}
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values() const
-{
- QList<T> res;
- res.reserve(size());
- const_iterator i = begin();
- while (i != end()) {
- res.append(i.value());
- ++i;
- }
- return res;
-}
+ inline qsizetype size() const noexcept { return m_size; }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::count(const Key &akey) const
-{
- int cnt = 0;
- Node *node = *findNode(akey);
- if (node != e) {
- do {
- ++cnt;
- } while ((node = node->next) != e && node->key == akey);
- }
- return cnt;
-}
+ inline bool isEmpty() const noexcept { return !m_size; }
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const
-{
- return value(akey);
-}
+ inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
+ void reserve(qsizetype size)
+ {
+ if (isDetached())
+ d->rehash(size);
+ else
+ d = Data::detached(d, size_t(size));
+ }
+ inline void squeeze() { reserve(0); }
-template <class Key, class T>
-Q_INLINE_TEMPLATE T &QHash<Key, T>::operator[](const Key &akey)
-{
- detach();
+ inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
+ inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
+ bool isSharedWith(const QMultiHash &other) const noexcept { return d == other.d; }
- uint h;
- Node **node = findNode(akey, &h);
- if (*node == e) {
- if (d->willGrow())
- node = findNode(akey, h);
- return createNode(h, akey, T(), node)->value;
+ void clear() noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = nullptr;
+ m_size = 0;
}
- return (*node)->value;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insert(const Key &akey,
- const T &avalue)
-{
- detach();
+ qsizetype remove(const Key &key)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return 0;
+ detach();
- uint h;
- Node **node = findNode(akey, &h);
- if (*node == e) {
- if (d->willGrow())
- node = findNode(akey, h);
- return iterator(createNode(h, akey, avalue, node));
+ auto it = d->find(key);
+ if (it.isUnused())
+ return 0;
+ qsizetype n = Node::freeChain(it.node());
+ m_size -= n;
+ Q_ASSERT(m_size >= 0);
+ d->erase(it);
+ return n;
}
+ T take(const Key &key)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return T();
+ detach();
- if (!std::is_same<T, QHashDummyValue>::value)
- (*node)->value = avalue;
- return iterator(*node);
-}
-
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::insert(const QHash &hash)
-{
- if (d == hash.d)
- return;
-
- detach();
-
- QHashData::Node *i = hash.d->firstNode();
- QHashData::Node *end = reinterpret_cast<QHashData::Node *>(hash.e);
- while (i != end) {
- Node *n = concrete(i);
- Node **node = findNode(n->key, n->h);
- if (*node == e) {
- if (d->willGrow())
- node = findNode(n->key, n->h);
- createNode(n->h, n->key, n->value, node);
+ auto it = d->find(key);
+ if (it.isUnused())
+ return T();
+ Chain *e = it.node()->value;
+ Q_ASSERT(e);
+ T t = std::move(e->value);
+ if (e->next) {
+ it.node()->value = e->next;
+ delete e;
} else {
- if (!std::is_same<T, QHashDummyValue>::value)
- (*node)->value = n->value;
+ // erase() deletes the values.
+ d->erase(it);
}
- i = QHashData::nextNode(i);
+ --m_size;
+ Q_ASSERT(m_size >= 0);
+ return t;
}
-}
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::remove(const Key &akey)
-{
- if (isEmpty()) // prevents detaching shared null
- return 0;
- detach();
-
- int oldSize = d->size;
- Node **node = findNode(akey);
- if (*node != e) {
- bool deleteNext = true;
- do {
- Node *next = (*node)->next;
- deleteNext = (next != e && next->key == (*node)->key);
- deleteNode(*node);
- *node = next;
- --d->size;
- } while (deleteNext);
- d->hasShrunk();
- }
- return oldSize - d->size;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey)
-{
- if (isEmpty()) // prevents detaching shared null
- return T();
- detach();
-
- Node **node = findNode(akey);
- if (*node != e) {
- T t = std::move((*node)->value);
- Node *next = (*node)->next;
- deleteNode(*node);
- *node = next;
- --d->size;
- d->hasShrunk();
- return t;
+ bool contains(const Key &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
}
- return T();
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::erase(const_iterator it)
-{
- Q_ASSERT_X(isValidIterator(it), "QHash::erase", "The specified iterator argument 'it' is invalid");
-
- if (it == const_iterator(e))
- return iterator(it.i);
-
- if (d->ref.isShared()) {
- // save 'it' across the detach:
- int bucketNum = (it.i->h % d->numBuckets);
- const_iterator bucketIterator(*(d->buckets + bucketNum));
- int stepsFromBucketStartToIte = 0;
- while (bucketIterator != it) {
- ++stepsFromBucketStartToIte;
- ++bucketIterator;
+ Key key(const T &value, const Key &defaultKey = Key()) const noexcept
+ {
+ if (d) {
+ auto i = d->begin();
+ while (i != d->end()) {
+ Chain *e = i.node()->value;
+ if (e->contains(value))
+ return i.node()->key;
+ ++i;
+ }
}
- detach();
- it = const_iterator(*(d->buckets + bucketNum));
- while (stepsFromBucketStartToIte > 0) {
- --stepsFromBucketStartToIte;
- ++it;
+
+ return defaultKey;
+ }
+ T value(const Key &key, const T &defaultValue = T()) const noexcept
+ {
+ if (d) {
+ Node *n = d->findNode(key);
+ if (n) {
+ Q_ASSERT(n->value);
+ return n->value->value;
+ }
}
+ return defaultValue;
}
- iterator ret(it.i);
- ++ret;
+ T &operator[](const Key &key)
+ {
+ detach();
+ auto result = d->findOrInsert(key);
+ Q_ASSERT(!result.it.atEnd());
+ if (!result.initialized)
+ Node::createInPlace(result.it.node(), key, T());
+ return result.it.node()->value->value;
+ }
- Node *node = concrete(it.i);
- Node **node_ptr = reinterpret_cast<Node **>(&d->buckets[node->h % d->numBuckets]);
- while (*node_ptr != node)
- node_ptr = &(*node_ptr)->next;
- *node_ptr = node->next;
- deleteNode(node);
- --d->size;
- return ret;
-}
+ const T operator[](const Key &key) const noexcept
+ {
+ return value(key);
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::reserve(int asize)
-{
- detach();
- d->rehash(-qMax(asize, 1));
-}
+ QVector<Key> uniqueKeys() const
+ {
+ QVector<Key> res;
+ if (d) {
+ auto i = d->begin();
+ while (i != d->end()) {
+ res.append(i.node()->key);
+ ++i;
+ }
+ }
+ return res;
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &akey) const
-{
- return const_iterator(*findNode(akey));
-}
+ QVector<Key> keys() const
+ {
+ return QVector<Key>(keyBegin(), keyEnd());
+ }
+ QVector<Key> keys(const T &value) const
+ {
+ QVector<Key> res;
+ const_iterator i = begin();
+ while (i != end()) {
+ if (i.value()->contains(value))
+ res.append(i.key());
+ ++i;
+ }
+ return res;
+ }
+ QVector<T> values() const
+ {
+ return QVector<T>(begin(), end());
+ }
+ QVector<T> values(const Key &key) const
+ {
+ QVector<T> values;
+ if (d) {
+ Node *n = d->findNode(key);
+ if (n) {
+ Chain *e = n->value;
+ while (e) {
+ values.append(e->value);
+ e = e->next;
+ }
+ }
+ }
+ return values;
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::constFind(const Key &akey) const
-{
- return const_iterator(*findNode(akey));
-}
+ class const_iterator;
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::find(const Key &akey)
-{
- detach();
- return iterator(*findNode(akey));
-}
+ class iterator
+ {
+ using piter = typename QHashPrivate::iterator<Node>;
+ friend class const_iterator;
+ friend class QMultiHash<Key, T>;
+ piter i;
+ Chain **e = nullptr;
+ explicit inline iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
+ {
+ if (!it.atEnd() && !e) {
+ e = &it.node()->value;
+ Q_ASSERT(e && *e);
+ }
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE bool QHash<Key, T>::contains(const Key &akey) const
-{
- return *findNode(akey) != e;
-}
+ public:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef qptrdiff difference_type;
+ typedef T value_type;
+ typedef T *pointer;
+ typedef T &reference;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(const Key &akey, uint h) const
-{
- Node **node;
+ constexpr iterator() noexcept = default;
+
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline T &value() const noexcept { return (*e)->value; }
+ inline T &operator*() const noexcept { return (*e)->value; }
+ inline T *operator->() const noexcept { return &(*e)->value; }
+ inline bool operator==(const iterator &o) const noexcept { return e == o.e; }
+ inline bool operator!=(const iterator &o) const noexcept { return e != o.e; }
+
+ inline iterator &operator++() noexcept {
+ Q_ASSERT(e && *e);
+ e = &(*e)->next;
+ Q_ASSERT(e);
+ if (!*e) {
+ ++i;
+ e = i.atEnd() ? nullptr : &i.node()->value;
+ }
+ return *this;
+ }
+ inline iterator operator++(int) noexcept {
+ iterator r = *this;
+ ++(*this);
+ return r;
+ }
- if (d->numBuckets) {
- node = reinterpret_cast<Node **>(&d->buckets[h % d->numBuckets]);
- Q_ASSERT(*node == e || (*node)->next);
- while (*node != e && !(*node)->same_key(h, akey))
- node = &(*node)->next;
- } else {
- node = const_cast<Node **>(reinterpret_cast<const Node * const *>(&e));
- }
- return node;
-}
+ inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
+ };
+ friend class iterator;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(const Key &akey,
- uint *ahp) const
-{
- uint h = 0;
+ class const_iterator
+ {
+ using piter = typename QHashPrivate::iterator<Node>;
+ friend class iterator;
+ friend class QMultiHash<Key, T>;
+ piter i;
+ Chain **e = nullptr;
+ explicit inline const_iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
+ {
+ if (!it.atEnd() && !e) {
+ e = &it.node()->value;
+ Q_ASSERT(e && *e);
+ }
+ }
- if (d->numBuckets || ahp) {
- h = qHash(akey, d->seed);
- if (ahp)
- *ahp = h;
- }
- return findNode(akey, h);
-}
+ public:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef qptrdiff difference_type;
+ typedef T value_type;
+ typedef const T *pointer;
+ typedef const T &reference;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
-{
- if (d == other.d)
- return true;
- if (size() != other.size())
- return false;
+ constexpr const_iterator() noexcept = default;
+ inline const_iterator(const iterator &o) noexcept : i(o.i), e(o.e) { }
+
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline T &value() const noexcept { return (*e)->value; }
+ inline T &operator*() const noexcept { return (*e)->value; }
+ inline T *operator->() const noexcept { return &(*e)->value; }
+ inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
+
+ inline const_iterator &operator++() noexcept {
+ Q_ASSERT(e && *e);
+ e = &(*e)->next;
+ Q_ASSERT(e);
+ if (!*e) {
+ ++i;
+ e = i.atEnd() ? nullptr : &i.node()->value;
+ }
+ return *this;
+ }
+ inline const_iterator operator++(int) noexcept
+ {
+ const_iterator r = *this;
+ ++(*this);
+ return r;
+ }
+ };
+ friend class const_iterator;
- const_iterator it = begin();
+ class key_iterator
+ {
+ const_iterator i;
- while (it != end()) {
- // Build two equal ranges for i.key(); one for *this and one for other.
- // For *this we can avoid a lookup via equal_range, as we know the beginning of the range.
- auto thisEqualRangeStart = it;
- const Key &thisEqualRangeKey = it.key();
- size_type n = 0;
- do {
- ++it;
- ++n;
- } while (it != end() && it.key() == thisEqualRangeKey);
+ public:
+ typedef typename const_iterator::iterator_category iterator_category;
+ typedef qptrdiff difference_type;
+ typedef Key value_type;
+ typedef const Key *pointer;
+ typedef const Key &reference;
- const auto otherEqualRange = other.equal_range(thisEqualRangeKey);
+ key_iterator() noexcept = default;
+ explicit key_iterator(const_iterator o) noexcept : i(o) { }
- if (n != std::distance(otherEqualRange.first, otherEqualRange.second))
- return false;
+ const Key &operator*() const noexcept { return i.key(); }
+ const Key *operator->() const noexcept { return &i.key(); }
+ bool operator==(key_iterator o) const noexcept { return i == o.i; }
+ bool operator!=(key_iterator o) const noexcept { return i != o.i; }
- // Keys in the ranges are equal by construction; this checks only the values.
- if (!qt_is_permutation(thisEqualRangeStart, it, otherEqualRange.first, otherEqualRange.second))
- return false;
- }
-
- return true;
-}
-
-template <class Key, class T>
-QPair<typename QHash<Key, T>::iterator, typename QHash<Key, T>::iterator> QHash<Key, T>::equal_range(const Key &akey)
-{
- detach();
- auto pair = qAsConst(*this).equal_range(akey);
- return qMakePair(iterator(pair.first.i), iterator(pair.second.i));
-}
+ inline key_iterator &operator++() noexcept { ++i; return *this; }
+ inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
+ const_iterator base() const noexcept { return i; }
+ };
-template <class Key, class T>
-QPair<typename QHash<Key, T>::const_iterator, typename QHash<Key, T>::const_iterator> QHash<Key, T>::equal_range(const Key &akey) const noexcept
-{
- Node *node = *findNode(akey);
- const_iterator firstIt = const_iterator(node);
+ typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
+ typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
- if (node != e) {
- // equal keys must hash to the same value and so they all
- // end up in the same bucket. So we can use node->next,
- // which only works within a bucket, instead of (out-of-line)
- // QHashData::nextNode()
- while (node->next != e && node->next->key == akey)
- node = node->next;
+ // STL style
+ inline iterator begin() { detach(); return iterator(d->begin()); }
+ inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline iterator end() noexcept { return iterator(); }
+ inline const_iterator end() const noexcept { return const_iterator(); }
+ inline const_iterator cend() const noexcept { return const_iterator(); }
+ inline const_iterator constEnd() const noexcept { return const_iterator(); }
+ inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
+ inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
+ inline key_value_iterator keyValueBegin() noexcept { return key_value_iterator(begin()); }
+ inline key_value_iterator keyValueEnd() noexcept { return key_value_iterator(end()); }
+ inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+
+ iterator detach(const_iterator it)
+ {
+ auto i = it.i;
+ Chain **e = it.e;
+ if (d->ref.isShared()) {
+ // need to store iterator position before detaching
+ qsizetype n = 0;
+ Chain *entry = i.node()->value;
+ while (entry != *it.e) {
+ ++n;
+ entry = entry->next;
+ }
+ Q_ASSERT(entry);
+ detach_helper();
- // 'node' may be the last node in the bucket. To produce the end iterator, we'd
- // need to enter the next bucket in this case, so we need to use
- // QHashData::nextNode() here, which, unlike node->next above, can move between
- // buckets.
- node = concrete(QHashData::nextNode(reinterpret_cast<QHashData::Node *>(node)));
+ i = d->detachedIterator(i);
+ e = &i.node()->value;
+ while (n) {
+ e = &(*e)->next;
+ --n;
+ }
+ Q_ASSERT(e && *e);
+ }
+ return iterator(i, e);
}
- return qMakePair(firstIt, const_iterator(node));
-}
+ iterator erase(const_iterator it)
+ {
+ Q_ASSERT(d);
+ iterator i = detach(it);
+ Chain *e = *i.e;
+ Chain *next = e->next;
+ *i.e = next;
+ delete e;
+ if (!next) {
+ if (i.e == &i.i.node()->value) {
+ // last remaining entry, erase
+ i = iterator(d->erase(i.i));
+ } else {
+ i = iterator(++it.i);
+ }
+ }
+ --m_size;
+ Q_ASSERT(m_size >= 0);
+ return i;
+ }
-template <class Key, class T>
-class QMultiHash : public QHash<Key, T>
-{
-public:
- QMultiHash() noexcept {}
- inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
+ // more Qt
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ inline qsizetype count() const noexcept { return size(); }
+ iterator find(const Key &key)
{
- this->reserve(int(list.size()));
- for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
- insert(it->first, it->second);
+ if (isEmpty())
+ return end();
+ detach();
+ auto it = d->find(key);
+ if (it.isUnused())
+ it = d->end();
+ return iterator(it);
}
-#ifdef Q_QDOC
- template <typename InputIterator>
- QMultiHash(InputIterator f, InputIterator l);
-#else
- template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
- QMultiHash(InputIterator f, InputIterator l)
+ const_iterator find(const Key &key) const noexcept
{
- QtPrivate::reserveIfForwardIterator(this, f, l);
- for (; f != l; ++f)
- insert(f.key(), f.value());
+ return constFind(key);
+ }
+ const_iterator constFind(const Key &key) const noexcept
+ {
+ if (isEmpty())
+ return end();
+ auto it = d->find(key);
+ if (it.isUnused())
+ it = d->end();
+ return const_iterator(it);
+ }
+ iterator insert(const Key &key, const T &value)
+ {
+ return emplace(key, value);
}
- template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
- QMultiHash(InputIterator f, InputIterator l)
+ template <typename ...Args>
+ iterator emplace(const Key &key, Args &&... args)
{
- QtPrivate::reserveIfForwardIterator(this, f, l);
- for (; f != l; ++f)
- insert(f->first, f->second);
+ return emplace(Key(key), std::forward<Args>(args)...);
}
-#endif
- // compiler-generated copy/move ctors/assignment operators are fine!
- // compiler-generated destructor is fine!
- QMultiHash(const QHash<Key, T> &other) : QHash<Key, T>(other) {}
- QMultiHash(QHash<Key, T> &&other) noexcept : QHash<Key, T>(std::move(other)) {}
- void swap(QMultiHash &other) noexcept { QHash<Key, T>::swap(other); } // prevent QMultiHash<->QHash swaps
+ template <typename ...Args>
+ iterator emplace(Key &&key, Args &&... args)
+ {
+ detach();
+
+ auto result = d->findOrInsert(key);
+ if (!result.initialized)
+ Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
+ else
+ result.it.node()->insertMulti(std::forward<Args>(args)...);
+ ++m_size;
+ return iterator(result.it);
+ }
+
+
+ float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
+ static float max_load_factor() noexcept { return 0.5; }
+ size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
+ static size_t max_bucket_count() noexcept { return QHashPrivate::GrowthPolicy::maxNumBuckets(); }
+
+ inline bool empty() const noexcept { return isEmpty(); }
+
+ inline iterator replace(const Key &key, const T &value)
+ {
+ return emplaceReplace(key, value);
+ }
- inline typename QHash<Key, T>::iterator replace(const Key &key, const T &value)
- { return QHash<Key, T>::insert(key, value); }
+ template <typename ...Args>
+ iterator emplaceReplace(const Key &key, Args &&... args)
+ {
+ return emplaceReplace(Key(key), std::forward<Args>(args)...);
+ }
- typename QHash<Key, T>::iterator insert(const Key &key, const T &value);
+ template <typename ...Args>
+ iterator emplaceReplace(Key &&key, Args &&... args)
+ {
+ detach();
- inline QMultiHash &unite(const QMultiHash &other);
+ auto result = d->findOrInsert(key);
+ if (!result.initialized) {
+ ++m_size;
+ Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
+ } else {
+ result.it.node()->emplaceValue(std::forward<Args>(args)...);
+ }
+ return iterator(result.it);
+ }
inline QMultiHash &operator+=(const QMultiHash &other)
- { return unite(other); }
+ { this->unite(other); return *this; }
inline QMultiHash operator+(const QMultiHash &other) const
{ QMultiHash result = *this; result += other; return result; }
- using QHash<Key, T>::contains;
- using QHash<Key, T>::remove;
- using QHash<Key, T>::count;
- using QHash<Key, T>::find;
- using QHash<Key, T>::constFind;
- using QHash<Key, T>::values;
- using QHash<Key, T>::findNode;
- using QHash<Key, T>::createNode;
- using QHash<Key, T>::concrete;
- using QHash<Key, T>::detach;
+ bool contains(const Key &key, const T &value) const noexcept
+ {
+ if (isEmpty())
+ return false;
+ auto n = d->findNode(key);
+ if (n == nullptr)
+ return false;
+ return n->value->contains(value);
+ }
- using typename QHash<Key, T>::Node;
- using typename QHash<Key, T>::iterator;
- using typename QHash<Key, T>::const_iterator;
+ qsizetype remove(const Key &key, const T &value)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return false;
+ detach();
- bool contains(const Key &key, const T &value) const;
+ auto it = d->find(key);
+ if (it.isUnused())
+ return 0;
+ qsizetype n = 0;
+ Chain **e = &it.node()->value;
+ while (*e) {
+ Chain *entry = *e;
+ if (entry->value == value) {
+ *e = entry->next;
+ delete entry;
+ ++n;
+ } else {
+ e = &entry->next;
+ }
+ }
+ if (!it.node()->value)
+ d->erase(it);
+ m_size -= n;
+ Q_ASSERT(m_size >= 0);
+ return n;
+ }
- int remove(const Key &key, const T &value);
+ qsizetype count(const Key &key) const noexcept
+ {
+ auto it = d->find(key);
+ if (it.isUnused())
+ return 0;
+ qsizetype n = 0;
+ Chain *e = it.node()->value;
+ while (e) {
+ ++n;
+ e = e->next;
+ }
- int count(const Key &key, const T &value) const;
+ return n;
+ }
- QList<Key> uniqueKeys() const;
+ qsizetype count(const Key &key, const T &value) const noexcept
+ {
+ auto it = d->find(key);
+ if (it.isUnused())
+ return 0;
+ qsizetype n = 0;
+ Chain *e = it.node()->value;
+ while (e) {
+ if (e->value == value)
+ ++n;
+ e = e->next;
+ }
- QList<T> values(const Key &akey) const;
+ return n;
+ }
- typename QHash<Key, T>::iterator find(const Key &key, const T &value) {
- typename QHash<Key, T>::iterator i(find(key));
- typename QHash<Key, T>::iterator end(this->end());
- while (i != end && i.key() == key) {
- if (i.value() == value)
- return i;
- ++i;
- }
- return end;
+ iterator find(const Key &key, const T &value)
+ {
+ detach();
+ auto it = constFind(key, value);
+ return iterator(it.i, it.e);
}
- typename QHash<Key, T>::const_iterator find(const Key &key, const T &value) const {
- typename QHash<Key, T>::const_iterator i(constFind(key));
- typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
+ const_iterator find(const Key &key, const T &value) const noexcept
+ {
+ return constFind(key, value);
+ }
+ const_iterator constFind(const Key &key, const T &value) const noexcept
+ {
+ const_iterator i(constFind(key));
+ const_iterator end(constEnd());
while (i != end && i.key() == key) {
if (i.value() == value)
return i;
@@ -1111,229 +1807,108 @@ public:
}
return end;
}
- typename QHash<Key, T>::const_iterator constFind(const Key &key, const T &value) const
- { return find(key, value); }
-private:
- T &operator[](const Key &key);
- const T operator[](const Key &key) const;
-};
-
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QMultiHash<Key, T>::insert(const Key &akey, const T &avalue)
-{
- detach();
- this->d->willGrow();
-
- uint h;
- Node **nextNode = findNode(akey, &h);
- return iterator(createNode(h, akey, avalue, nextNode));
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE QMultiHash<Key, T> &QMultiHash<Key, T>::unite(const QMultiHash &other)
-{
- if (this->d == &QHashData::shared_null) {
- *this = other;
- } else {
-#if QT_DEPRECATED_SINCE(5, 15)
- QMultiHash copy(other);
- const_iterator it = copy.constEnd();
- while (it != copy.constBegin()) {
- it.i = QHashData::previousNode(it.i);
- insert(it.key(), it.value());
- }
-#else
- const QMultiHash copy(other);
- const_iterator it = copy.cbegin();
- const const_iterator end = copy.cend();
- while (it != end) {
- const auto rangeStart = it++;
- while (it != end && rangeStart.key() == it.key())
- ++it;
- const qint64 last = std::distance(rangeStart, it) - 1;
- for (qint64 i = last; i >= 0; --i) {
- auto next = std::next(rangeStart, i);
- insert(next.key(), next.value());
- }
+ QMultiHash &unite(const QMultiHash &other)
+ {
+ if (isEmpty()) {
+ *this = other;
+ } else if (other.isEmpty()) {
+ ;
+ } else {
+ QMultiHash copy(other);
+ detach();
+ for (auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
+ insert(cit.key(), *cit);
}
-#endif
+ return *this;
}
- return *this;
-}
-
-
-template <class Key, class T>
-Q_INLINE_TEMPLATE bool QMultiHash<Key, T>::contains(const Key &key, const T &value) const
-{
- return constFind(key, value) != QHash<Key, T>::constEnd();
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiHash<Key, T>::remove(const Key &key, const T &value)
-{
- int n = 0;
- typename QHash<Key, T>::iterator i(find(key));
- typename QHash<Key, T>::iterator end(QHash<Key, T>::end());
- while (i != end && i.key() == key) {
- if (i.value() == value) {
- i = this->erase(i);
- ++n;
- } else {
- ++i;
- }
+ QPair<iterator, iterator> equal_range(const Key &key)
+ {
+ detach();
+ auto pair = qAsConst(*this).equal_range(key);
+ return qMakePair(iterator(pair.first.i), iterator(pair.second.i));
}
- return n;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &key, const T &value) const
-{
- int n = 0;
- typename QHash<Key, T>::const_iterator i(constFind(key));
- typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
- while (i != end && i.key() == key) {
- if (i.value() == value)
- ++n;
- ++i;
+ QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ {
+ auto it = d->find(key);
+ if (it.isUnused())
+ return qMakePair(end(), end());
+ auto end = it;
+ ++end;
+ return qMakePair(const_iterator(it), const_iterator(end));
}
- return n;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QMultiHash<Key, T>::uniqueKeys() const
-{
- QList<Key> res;
- res.reserve(QHash<Key, T>::size()); // May be too much, but assume short lifetime
- typename QHash<Key, T>::const_iterator i = QHash<Key, T>::begin();
- if (i != QHash<Key, T>::end()) {
- for (;;) {
- const Key &aKey = i.key();
- res.append(aKey);
- do {
- if (++i == QHash<Key, T>::end())
- goto break_out_of_outer_loop;
- } while (aKey == i.key());
+private:
+ void detach_helper()
+ {
+ if (!d) {
+ d = new Data;
+ return;
}
+ Data *dd = new Data(*d);
+ if (!d->ref.deref())
+ delete d;
+ d = dd;
}
-break_out_of_outer_loop:
- return res;
-}
-
-#if QT_DEPRECATED_SINCE(5, 15)
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &key, const T &value) {
- return static_cast<QMultiHash<Key, T> *>(this)->insert(key, value);
-}
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash &other) {
- return static_cast<QMultiHash<Key, T> *>(this)->unite(other);
-}
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values(const Key &akey) const
-{
- return static_cast<const QMultiHash<Key, T> *>(this)->values(akey);
-}
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::uniqueKeys() const
-{
- return static_cast<const QMultiHash<Key, T> *>(this)->uniqueKeys();
-}
-#endif
-
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QMultiHash<Key, T>::values(const Key &akey) const
-{
- QList<T> res;
- Node *node = *findNode(akey);
- if (node != this->e) {
- do {
- res.append(node->value);
- } while ((node = node->next) != this->e && node->key == akey);
- }
- return res;
-}
+};
#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
-template <class Key, class T>
+template<class Key, class T>
class QHashIterator
{
typedef typename QHash<Key, T>::const_iterator const_iterator;
typedef const_iterator Item;
QHash<Key, T> c;
const_iterator i, n;
- inline bool item_exists() const { return n != c.constEnd(); }
+ inline bool item_exists() const noexcept { return n != c.constEnd(); }
public:
- inline QHashIterator(const QHash<Key, T> &container)
+ inline QHashIterator(const QHash<Key, T> &container) noexcept
: c(container), i(c.constBegin()), n(c.constEnd())
- {
- }
- inline QHashIterator &operator=(const QHash<Key, T> &container)
+ { }
+ inline QHashIterator &operator=(const QHash<Key, T> &container) noexcept
{
c = container;
i = c.constBegin();
n = c.constEnd();
return *this;
}
- inline void toFront()
+ inline void toFront() noexcept
{
i = c.constBegin();
n = c.constEnd();
}
- inline void toBack()
+ inline void toBack() noexcept
{
i = c.constEnd();
n = c.constEnd();
}
- inline bool hasNext() const { return i != c.constEnd(); }
- inline Item next()
+ inline bool hasNext() const noexcept { return i != c.constEnd(); }
+ inline Item next() noexcept
{
n = i++;
return n;
}
- inline Item peekNext() const { return i; }
- inline const T &value() const
+ inline Item peekNext() const noexcept { return i; }
+ inline const T &value() const noexcept
{
Q_ASSERT(item_exists());
return *n;
}
- inline const Key &key() const
+ inline const Key &key() const noexcept
{
Q_ASSERT(item_exists());
return n.key();
}
- inline bool findNext(const T &t)
+ inline bool findNext(const T &t) noexcept
{
while ((n = i) != c.constEnd())
if (*i++ == t)
return true;
return false;
}
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 bool hasPrevious() const { return i != c.constBegin(); }
- inline QT_DEPRECATED_VERSION_5_15 Item previous()
- {
- n = --i;
- return n;
- }
- inline QT_DEPRECATED_VERSION_5_15 Item peekPrevious() const
- {
- const_iterator p = i;
- return --p;
- }
- inline bool QT_DEPRECATED_VERSION_5_15 findPrevious(const T &t)
- {
- while (i != c.constBegin())
- if (*(n = --i) == t)
- return true;
- n = c.constEnd();
- return false;
- }
-#endif
};
template<class Key, class T>
@@ -1344,10 +1919,11 @@ class QMutableHashIterator
typedef iterator Item;
QHash<Key, T> *c;
iterator i, n;
- inline bool item_exists() const { return const_iterator(n) != c->constEnd(); }
+ inline bool item_exists() const noexcept { return const_iterator(n) != c->constEnd(); }
public:
- inline QMutableHashIterator(QHash<Key, T> &container) : c(&container)
+ inline QMutableHashIterator(QHash<Key, T> &container)
+ : c(&container)
{
i = c->begin();
n = c->end();
@@ -1364,18 +1940,18 @@ public:
i = c->begin();
n = c->end();
}
- inline void toBack()
+ inline void toBack() noexcept
{
i = c->end();
n = c->end();
}
- inline bool hasNext() const { return const_iterator(i) != c->constEnd(); }
- inline Item next()
+ inline bool hasNext() const noexcept { return const_iterator(i) != c->constEnd(); }
+ inline Item next() noexcept
{
n = i++;
return n;
}
- inline Item peekNext() const { return i; }
+ inline Item peekNext() const noexcept { return i; }
inline void remove()
{
if (const_iterator(n) != c->constEnd()) {
@@ -1388,54 +1964,33 @@ public:
if (const_iterator(n) != c->constEnd())
*n = t;
}
- inline T &value()
+ inline T &value() noexcept
{
Q_ASSERT(item_exists());
return *n;
}
- inline const T &value() const
+ inline const T &value() const noexcept
{
Q_ASSERT(item_exists());
return *n;
}
- inline const Key &key() const
+ inline const Key &key() const noexcept
{
Q_ASSERT(item_exists());
return n.key();
}
- inline bool findNext(const T &t)
+ inline bool findNext(const T &t) noexcept
{
while (const_iterator(n = i) != c->constEnd())
if (*i++ == t)
return true;
return false;
}
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 bool hasPrevious() const { return const_iterator(i) != c->constBegin(); }
- inline QT_DEPRECATED_VERSION_5_15 Item previous()
- {
- n = --i;
- return n;
- }
- inline QT_DEPRECATED_VERSION_5_15 Item peekPrevious() const
- {
- iterator p = i;
- return --p;
- }
- inline QT_DEPRECATED_VERSION_5_15 bool findPrevious(const T &t)
- {
- while (const_iterator(i) != c->constBegin())
- if (*(n = --i) == t)
- return true;
- n = c->end();
- return false;
- }
-#endif
};
#endif // !QT_NO_JAVA_STYLE_ITERATORS
template <class Key, class T>
-uint qHash(const QHash<Key, T> &key, uint seed = 0)
+size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
QtPrivate::QHashCombineCommutative hash;
@@ -1448,7 +2003,7 @@ uint qHash(const QHash<Key, T> &key, uint seed = 0)
}
template <class Key, class T>
-inline uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
+inline size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
const QHash<Key, T> &key2 = key;
@@ -1457,8 +2012,4 @@ inline uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
QT_END_NAMESPACE
-#if defined(Q_CC_MSVC)
-#pragma warning( pop )
-#endif
-
#endif // QHASH_H
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index 2ff3464912..ef83682433 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -68,62 +68,100 @@ class QLatin1String;
Q_CORE_EXPORT int qGlobalQHashSeed();
Q_CORE_EXPORT void qSetGlobalQHashSeed(int newSeed);
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHashBits(const void *p, size_t size, uint seed = 0) noexcept;
-
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(char key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uchar key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(signed char key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ushort key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(short key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uint key, uint seed = 0) noexcept { return key ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(int key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ulong key, uint seed = 0) noexcept
+namespace QHashPrivate {
+
+Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
+{
+ key ^= seed;
+ if constexpr (sizeof(size_t) == 4) {
+ key ^= key >> 16;
+ key *= UINT32_C(0x45d9f3b);
+ key ^= key >> 16;
+ key *= UINT32_C(0x45d9f3b);
+ key ^= key >> 16;
+ return key;
+ } else {
+ quint64 key64 = key;
+ key64 ^= key64 >> 32;
+ key64 *= UINT64_C(0xd6e8feb86659fd93);
+ key64 ^= key64 >> 32;
+ key64 *= UINT64_C(0xd6e8feb86659fd93);
+ key64 ^= key64 >> 32;
+ return size_t(key64);
+ }
+}
+
+}
+
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHashBits(const void *p, size_t size, size_t seed = 0) noexcept;
+
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(char key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(uchar key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(signed char key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(ushort key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(short key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(uint key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(int key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(ulong key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(long key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline size_t qHash(quint64 key, size_t seed = 0) noexcept
{
- return (sizeof(ulong) > sizeof(uint))
- ? (uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U)) ^ seed)
- : (uint(key & (~0U)) ^ seed);
+ if (sizeof(quint64) > sizeof(size_t))
+ key ^= (key >> 32);
+ return QHashPrivate::hash(size_t(key), seed);
}
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(long key, uint seed = 0) noexcept { return qHash(ulong(key), seed); }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(quint64 key, uint seed = 0) noexcept
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept { return qHash(quint64(key), seed); }
+Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
{
- return uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U)) ^ seed;
+ // ensure -0 gets mapped to 0
+ key += 0.0f;
+ uint k;
+ memcpy(&k, &key, sizeof(float));
+ return QHashPrivate::hash(k, seed);
}
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(qint64 key, uint seed = 0) noexcept { return qHash(quint64(key), seed); }
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(float key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(double key, uint seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(double key, size_t seed = 0) noexcept;
#if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(long double key, uint seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(long double key, size_t seed = 0) noexcept;
#endif
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(const QChar key, uint seed = 0) noexcept { return qHash(key.unicode(), seed); }
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QByteArray &key, uint seed = 0) noexcept;
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(const QChar key, size_t seed = 0) noexcept { return qHash(key.unicode(), seed); }
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0) noexcept;
#if QT_STRINGVIEW_LEVEL < 2
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QString &key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QStringRef &key, uint seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QStringRef &key, size_t seed = 0) noexcept;
#endif
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QStringView key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QBitArray &key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QLatin1String key, uint seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &key, size_t seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1String key, size_t seed = 0) noexcept;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) noexcept;
-Q_DECL_CONST_FUNCTION inline uint qHash(std::nullptr_t, uint seed = 0) noexcept
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed = 0) noexcept
{
- return qHash(reinterpret_cast<quintptr>(nullptr), seed);
+ return seed;
}
-template <class T> inline uint qHash(const T *key, uint seed = 0) noexcept
+template <class T> inline size_t qHash(const T *key, size_t seed = 0) noexcept
{
return qHash(reinterpret_cast<quintptr>(key), seed);
}
-template<typename T> inline uint qHash(const T &t, uint seed)
+template<typename T> inline size_t qHash(const T &t, size_t seed)
noexcept(noexcept(qHash(t)))
{ return qHash(t) ^ seed; }
namespace QtPrivate {
struct QHashCombine {
- typedef uint result_type;
+ typedef size_t result_type;
template <typename T>
- Q_DECL_CONSTEXPR result_type operator()(uint seed, const T &t) const noexcept(noexcept(qHash(t)))
+ constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
// combiner taken from N3876 / boost::hash_combine
{ return seed ^ (qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2)) ; }
};
@@ -134,37 +172,38 @@ struct QHashCombineCommutative {
// usually what we want: {0,1,3} should hash differently than
// {1,3,0}. Except when it isn't (e.g. for QSet and
// QHash). Therefore, provide a commutative combiner, too.
- typedef uint result_type;
+ typedef size_t result_type;
template <typename T>
- Q_DECL_CONSTEXPR result_type operator()(uint seed, const T &t) const noexcept(noexcept(qHash(t)))
+ constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
{ return seed + qHash(t); } // don't use xor!
};
} // namespace QtPrivate
template <typename InputIterator>
-inline uint qHashRange(InputIterator first, InputIterator last, uint seed = 0)
+inline size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QtPrivate::QHashCombine());
}
template <typename InputIterator>
-inline uint qHashRangeCommutative(InputIterator first, InputIterator last, uint seed = 0)
+inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative());
}
-template <typename T1, typename T2> inline uint qHash(const QPair<T1, T2> &key, uint seed = 0)
+template <typename T1, typename T2> inline size_t qHash(const QPair<T1, T2> &key, size_t seed = 0)
noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
{
- uint h1 = qHash(key.first, seed);
- uint h2 = qHash(key.second, seed);
- return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed;
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, key.first);
+ seed = hash(seed, key.second);
+ return seed;
}
-template <typename T1, typename T2> inline uint qHash(const std::pair<T1, T2> &key, uint seed = 0)
+template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
{
QtPrivate::QHashCombine hash;
diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc
index 273370e797..9efc1bb48a 100644
--- a/src/corelib/tools/qiterator.qdoc
+++ b/src/corelib/tools/qiterator.qdoc
@@ -210,55 +210,6 @@
*/
/*!
- \class QLinkedListIterator
- \inmodule QtCore
- \obsolete
-
- \brief The QLinkedListIterator class provides a Java-style const iterator for QLinkedList.
-
- QLinkedList has both \l{Java-style iterators} and
- \l{STL-style iterators}. The Java-style iterators are more
- high-level and easier to use than the STL-style iterators; on the
- other hand, they are slightly less efficient.
-
- QLinkedListIterator\<T\> allows you to iterate over a
- QLinkedList\<T\>. If you want to modify the list as you iterate
- over it, use QMutableLinkedListIterator\<T\> instead.
-
- The QLinkedListIterator constructor takes a QLinkedList as
- argument. After construction, the iterator is located at the very
- beginning of the list (before the first item). Here's how to
- iterate over all the elements sequentially:
-
- \snippet code/doc_src_qiterator.cpp 2
-
- The next() function returns the next item in the list and
- advances the iterator. Unlike STL-style iterators, Java-style
- iterators point \e between items rather than directly \e at
- items. The first call to next() advances the iterator to the
- position between the first and second item, and returns the first
- item; the second call to next() advances the iterator to the
- position between the second and third item, and returns the second
- item; and so on.
-
- \image javaiterators1.png
-
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 3
-
- If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
-
- Multiple iterators can be used on the same list. If the list is
- modified while a QLinkedListIterator is active, the
- QLinkedListIterator will continue iterating over the original
- list, ignoring the modified copy.
-
- \sa QMutableLinkedListIterator, QLinkedList::const_iterator
-*/
-
-/*!
\class QVectorIterator
\inmodule QtCore
\brief The QVectorIterator class provides a Java-style const iterator for QVector and QStack.
@@ -424,68 +375,6 @@
*/
/*!
- \class QMutableLinkedListIterator
- \inmodule QtCore
- \obsolete
-
- \brief The QMutableLinkedListIterator class provides a Java-style non-const iterator for QLinkedList.
-
- QLinkedList has both \l{Java-style iterators} and
- \l{STL-style iterators}. The Java-style iterators are more
- high-level and easier to use than the STL-style iterators; on the
- other hand, they are slightly less efficient.
-
- QMutableLinkedListIterator\<T\> allows you to iterate over a
- QLinkedList\<T\> and modify the list. If you don't want to modify
- the list (or have a const QLinkedList), use the slightly faster
- QLinkedListIterator\<T\> instead.
-
- The QMutableLinkedListIterator constructor takes a QLinkedList as
- argument. After construction, the iterator is located at the very
- beginning of the list (before the first item). Here's how to
- iterate over all the elements sequentially:
-
- \snippet code/doc_src_qiterator.cpp 11
-
- The next() function returns the next item in the list and
- advances the iterator. Unlike STL-style iterators, Java-style
- iterators point \e between items rather than directly \e at
- items. The first call to next() advances the iterator to the
- position between the first and second item, and returns the first
- item; the second call to next() advances the iterator to the
- position between the second and third item, returning the second
- item; and so on.
-
- \image javaiterators1.png
-
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 12
-
- If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
-
- If you want to remove items as you iterate over the list, use
- remove(). If you want to modify the value of an item, use
- setValue(). If you want to insert a new item in the list, use
- insert().
-
- Example:
- \snippet code/doc_src_qiterator.cpp 13
-
- The example traverses a list, replacing negative numbers with
- their absolute values, and eliminating zeroes.
-
- Only one mutable iterator can be active on a given list at any
- time. Furthermore, no changes should be done directly to the list
- while the iterator is active (as opposed to through the
- iterator), since this could invalidate the iterator and lead to
- undefined behavior.
-
- \sa QLinkedListIterator, QLinkedList::iterator
-*/
-
-/*!
\class QMutableVectorIterator
\inmodule QtCore
@@ -604,9 +493,7 @@
/*!
\fn template <class T> QListIterator<T>::QListIterator(const QList<T> &list)
- \fn template <class T> QLinkedListIterator<T>::QLinkedListIterator(const QLinkedList<T> &list)
\fn template <class T> QMutableListIterator<T>::QMutableListIterator(QList<T> &list)
- \fn template <class T> QMutableLinkedListIterator<T>::QMutableLinkedListIterator(QLinkedList<T> &list)
Constructs an iterator for traversing \a list. The iterator is
set to be at the front of the list (before the first item).
@@ -635,9 +522,7 @@
*/
/*! \fn template <class T> QMutableListIterator &QMutableListIterator<T>::operator=(QList<T> &list)
- \fn template <class T> QMutableLinkedListIterator &QMutableLinkedListIterator<T>::operator=(QLinkedList<T> &list)
\fn template <class T> QListIterator &QListIterator<T>::operator=(const QList<T> &list)
- \fn template <class T> QLinkedListIterator &QLinkedListIterator<T>::operator=(const QLinkedList<T> &list)
Makes the iterator operate on \a list. The iterator is set to be
at the front of the list (before the first item).
@@ -664,11 +549,9 @@
*/
/*! \fn template <class T> void QListIterator<T>::toFront()
- \fn template <class T> void QLinkedListIterator<T>::toFront()
\fn template <class T> void QVectorIterator<T>::toFront()
\fn template <class T> void QSetIterator<T>::toFront()
\fn template <class T> void QMutableListIterator<T>::toFront()
- \fn template <class T> void QMutableLinkedListIterator<T>::toFront()
\fn template <class T> void QMutableVectorIterator<T>::toFront()
\fn template <class T> void QMutableSetIterator<T>::toFront()
@@ -679,11 +562,9 @@
*/
/*! \fn template <class T> void QListIterator<T>::toBack()
- \fn template <class T> void QLinkedListIterator<T>::toBack()
\fn template <class T> void QVectorIterator<T>::toBack()
\fn template <class T> void QSetIterator<T>::toBack()
\fn template <class T> void QMutableListIterator<T>::toBack()
- \fn template <class T> void QMutableLinkedListIterator<T>::toBack()
\fn template <class T> void QMutableVectorIterator<T>::toBack()
\fn template <class T> void QMutableSetIterator<T>::toBack()
@@ -694,11 +575,9 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasNext() const
- \fn template <class T> bool QLinkedListIterator<T>::hasNext() const
\fn template <class T> bool QVectorIterator<T>::hasNext() const
\fn template <class T> bool QSetIterator<T>::hasNext() const
\fn template <class T> bool QMutableListIterator<T>::hasNext() const
- \fn template <class T> bool QMutableLinkedListIterator<T>::hasNext() const
\fn template <class T> bool QMutableVectorIterator<T>::hasNext() const
\fn template <class T> bool QMutableSetIterator<T>::hasNext() const
@@ -710,7 +589,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::next()
- \fn template <class T> const T &QLinkedListIterator<T>::next()
\fn template <class T> const T &QVectorIterator<T>::next()
\fn template <class T> const T &QSetIterator<T>::next()
\fn template <class T> const T &QMutableSetIterator<T>::next()
@@ -724,7 +602,6 @@
*/
/*! \fn template <class T> T &QMutableListIterator<T>::next()
- \fn template <class T> T &QMutableLinkedListIterator<T>::next()
\fn template <class T> T &QMutableVectorIterator<T>::next()
Returns a reference to the next item, and advances the iterator
@@ -737,7 +614,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekNext() const
- \fn template <class T> const T &QLinkedListIterator<T>::peekNext() const
\fn template <class T> const T &QVectorIterator<T>::peekNext() const
\fn template <class T> const T &QSetIterator<T>::peekNext() const
\fn template <class T> const T &QMutableSetIterator<T>::peekNext() const
@@ -751,7 +627,6 @@
*/
/*! \fn template <class T> T &QMutableListIterator<T>::peekNext() const
- \fn template <class T> T &QMutableLinkedListIterator<T>::peekNext() const
\fn template <class T> T &QMutableVectorIterator<T>::peekNext() const
Returns a reference to the next item, without moving the iterator.
@@ -774,11 +649,9 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasPrevious() const
- \fn template <class T> bool QLinkedListIterator<T>::hasPrevious() const
\fn template <class T> bool QVectorIterator<T>::hasPrevious() const
\fn template <class T> bool QSetIterator<T>::hasPrevious() const
\fn template <class T> bool QMutableListIterator<T>::hasPrevious() const
- \fn template <class T> bool QMutableLinkedListIterator<T>::hasPrevious() const
\fn template <class T> bool QMutableVectorIterator<T>::hasPrevious() const
Returns \c true if there is at least one item behind the iterator,
@@ -802,7 +675,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::previous()
- \fn template <class T> const T &QLinkedListIterator<T>::previous()
\fn template <class T> const T &QVectorIterator<T>::previous()
\fn template <class T> const T &QSetIterator<T>::previous()
@@ -816,7 +688,6 @@
*/
/*! \fn template <class T> T &QMutableListIterator<T>::previous()
- \fn template <class T> T &QMutableLinkedListIterator<T>::previous()
\fn template <class T> T &QMutableVectorIterator<T>::previous()
Returns a reference to the previous item and moves the iterator
@@ -841,7 +712,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekPrevious() const
- \fn template <class T> const T &QLinkedListIterator<T>::peekPrevious() const
\fn template <class T> const T &QVectorIterator<T>::peekPrevious() const
\fn template <class T> const T &QSetIterator<T>::peekPrevious() const
@@ -854,7 +724,6 @@
*/
/*! \fn template <class T> T &QMutableListIterator<T>::peekPrevious() const
- \fn template <class T> T &QMutableLinkedListIterator<T>::peekPrevious() const
\fn template <class T> T &QMutableVectorIterator<T>::peekPrevious() const
Returns a reference to the previous item, without moving the iterator.
@@ -880,11 +749,9 @@
*/
/*! \fn template <class T> bool QListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QLinkedListIterator<T>::findNext(const T &value)
\fn template <class T> bool QVectorIterator<T>::findNext(const T &value)
\fn template <class T> bool QSetIterator<T>::findNext(const T &value)
\fn template <class T> bool QMutableListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QMutableLinkedListIterator<T>::findNext(const T &value)
\fn template <class T> bool QMutableVectorIterator<T>::findNext(const T &value)
Searches for \a value starting from the current iterator position
@@ -898,11 +765,9 @@
*/
/*! \fn template <class T> bool QListIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QLinkedListIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QVectorIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QSetIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QMutableListIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QMutableLinkedListIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QMutableVectorIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QMutableSetIterator<T>::findPrevious(const T &value)
@@ -928,17 +793,6 @@
\sa insert(), setValue()
*/
-/*! \fn template <class T> void QMutableLinkedListIterator<T>::remove()
-
- Removes the last item that was jumped over using one of the
- traversal functions (next(), previous(), findNext(), findPrevious()).
-
- Example:
- \snippet code/doc_src_qiterator.cpp 20
-
- \sa insert(), setValue()
-*/
-
/*! \fn template <class T> void QMutableVectorIterator<T>::remove()
Removes the last item that was jumped over using one of the
@@ -975,20 +829,6 @@
\sa value(), remove(), insert()
*/
-/*! \fn template <class T> void QMutableLinkedListIterator<T>::setValue(const T &value) const
-
- Replaces the value of the last item that was jumped over using
- one of the traversal functions with \a value.
-
- The traversal functions are next(), previous(), findNext(), and
- findPrevious().
-
- Example:
- \snippet code/doc_src_qiterator.cpp 24
-
- \sa value(), remove(), insert()
-*/
-
/*! \fn template <class T> void QMutableVectorIterator<T>::setValue(const T &value) const
Replaces the value of the last item that was jumped over using
@@ -1004,7 +844,6 @@
*/
/*! \fn template <class T> const T &QMutableListIterator<T>::value() const
- \fn template <class T> const T &QMutableLinkedListIterator<T>::value() const
\fn template <class T> const T &QMutableVectorIterator<T>::value() const
\fn template <class T> const T &QMutableSetIterator<T>::value() const
@@ -1019,7 +858,6 @@
/*!
\fn template <class T> T &QMutableListIterator<T>::value()
- \fn template <class T> T &QMutableLinkedListIterator<T>::value()
\fn template <class T> T &QMutableVectorIterator<T>::value()
\overload
@@ -1028,7 +866,6 @@
*/
/*! \fn template <class T> void QMutableListIterator<T>::insert(const T &value)
- \fn template <class T> void QMutableLinkedListIterator<T>::insert(const T &value)
\fn template <class T> void QMutableVectorIterator<T>::insert(const T &value)
Inserts \a value at the current iterator position. After the
diff --git a/src/corelib/tools/qlinkedlist.cpp b/src/corelib/tools/qlinkedlist.cpp
deleted file mode 100644
index 6a423545da..0000000000
--- a/src/corelib/tools/qlinkedlist.cpp
+++ /dev/null
@@ -1,1238 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#ifdef QT_NO_LINKED_LIST
-# undef QT_NO_LINKED_LIST
-#endif
-
-#include "qlinkedlist.h"
-
-QT_BEGIN_NAMESPACE
-
-#if QT_DEPRECATED_SINCE(5, 15)
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-
-const QLinkedListData QLinkedListData::shared_null = {
- const_cast<QLinkedListData *>(&QLinkedListData::shared_null),
- const_cast<QLinkedListData *>(&QLinkedListData::shared_null),
- Q_REFCOUNT_INITIALIZE_STATIC, 0, true
-};
-
-/*! \class QLinkedList
- \inmodule QtCore
- \obsolete
- \brief The QLinkedList class is a template class that provides linked lists.
-
- \ingroup tools
- \ingroup shared
-
- \reentrant
-
- \note This class is obsolete, please use std::list instead.
-
- QLinkedList\<T\> is one of Qt's generic \l{container classes}. It
- stores a list of values and provides iterator-based access as
- well as \l{constant time} insertions and removals.
-
- QList\<T\>, QLinkedList\<T\>, and QVector\<T\> provide similar
- functionality. Here's an overview:
-
- \list
- \li For most purposes, QList is the right class to use. Its
- index-based API is more convenient than QLinkedList's
- iterator-based API, and it is usually faster than
- QVector because of the way it stores its items in
- memory (see \l{Algorithmic Complexity} for details).
- It also expands to less code in your executable.
- \li If you need a real linked list, with guarantees of \l{constant
- time} insertions in the middle of the list and iterators to
- items rather than indexes, use QLinkedList.
- \li If you want the items to occupy adjacent memory positions,
- use QVector.
- \endlist
-
- Here's an example of a QLinkedList that stores integers and a
- QLinkedList that stores QTime values:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 0
-
- QLinkedList stores a list of items. The default constructor
- creates an empty list. To insert items into the list, you can use
- operator<<():
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 1
-
- If you want to get the first or last item in a linked list, use
- first() or last(). If you want to remove an item from either end
- of the list, use removeFirst() or removeLast(). If you want to
- remove all occurrences of a given value in the list, use
- removeAll().
-
- A common requirement is to remove the first or last item in the
- list and do something with it. For this, QLinkedList provides
- takeFirst() and takeLast(). Here's a loop that removes the items
- from a list one at a time and calls \c delete on them:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 2
-
- QLinkedList's value type must be an \l {assignable data type}. This
- covers most data types that are commonly used, but the compiler
- won't let you, for example, store a QWidget as a value; instead,
- store a QWidget *. A few functions have additional requirements;
- for example, contains() and removeAll() expect the value type to
- support \c operator==(). These requirements are documented on a
- per-function basis.
-
- If you want to insert, modify, or remove items in the middle of
- the list, you must use an iterator. QLinkedList provides both
- \l{Java-style iterators} (QLinkedListIterator and
- QMutableLinkedListIterator) and \l{STL-style iterators}
- (QLinkedList::const_iterator and QLinkedList::iterator). See the
- documentation for these classes for details.
-
- \sa QLinkedListIterator, QMutableLinkedListIterator, QList, QVector
-*/
-
-/*! \fn template <class T> QLinkedList<T>::QLinkedList()
-
- Constructs an empty list.
-*/
-
-/*!
- \fn template <class T> QLinkedList<T>::QLinkedList(QLinkedList<T> &&other)
-
- Move-constructs a QLinkedList instance, making it point at the same
- object that \a other was pointing to.
-
- \since 5.2
-*/
-
-/*! \fn template <class T> QLinkedList<T>::QLinkedList(const QLinkedList<T> &other)
-
- Constructs a copy of \a other.
-
- This operation occurs in \l{constant time}, because QLinkedList
- is \l{implicitly shared}. This makes returning a QLinkedList from
- a function very fast. If a shared instance is modified, it will
- be copied (copy-on-write), and this takes \l{linear time}.
-
- \sa operator=()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::QLinkedList(std::initializer_list<T> list)
- \since 5.2
-
- Constructs a list from the std::initializer_list specified by \a list.
-
- This constructor is only enabled if the compiler supports C++11
- initializer lists.
-*/
-
-/*! \fn template <class T> template<typename InputIterator> QLinkedList<T>::QLinkedList(InputIterator first, InputIterator last)
- \since 5.14
-
- Constructs a list with the contents in the iterator range [\a first, \a last).
-
- The value type of \c InputIterator must be convertible to \c T.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::~QLinkedList()
-
- Destroys the list. References to the values in the list, and all
- iterators over this list, become invalid.
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator=(const QLinkedList<T> &other)
-
- Assigns \a other to this list and returns a reference to this
- list.
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::swap(QLinkedList<T> &other)
- \since 4.8
-
- Swaps list \a other with this list. This operation is very
- fast and never fails.
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::operator==(const QLinkedList<T> &other) const
-
- Returns \c true if \a other is equal to this list; otherwise returns
- false.
-
- Two lists are considered equal if they contain the same values in
- the same order.
-
- This function requires the value type to implement \c
- operator==().
-
- \sa operator!=()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::operator!=(const QLinkedList<T> &other) const
-
- Returns \c true if \a other is not equal to this list; otherwise
- returns \c false.
-
- Two lists are considered equal if they contain the same values in
- the same order.
-
- This function requires the value type to implement \c
- operator==().
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::size() const
-
- Returns the number of items in the list.
-
- \sa isEmpty(), count()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::detach()
-
- \internal
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::isDetached() const
-
- \internal
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::setSharable(bool sharable)
-
- \internal
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::isSharedWith(const QLinkedList<T> &other) const
-
- \internal
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::isEmpty() const
-
- Returns \c true if the list contains no items; otherwise returns
- false.
-
- \sa size()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::clear()
-
- Removes all the items in the list.
-
- \sa removeAll()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::append(const T &value)
-
- Inserts \a value at the end of the list.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 3
-
- This is the same as list.insert(end(), \a value).
-
- \sa operator<<(), prepend(), insert()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::prepend(const T &value)
-
- Inserts \a value at the beginning of the list.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 4
-
- This is the same as list.insert(begin(), \a value).
-
- \sa append(), insert()
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::removeAll(const T &value)
-
- Removes all occurrences of \a value in the list.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 5
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa insert()
-*/
-
-/*!
- \fn template <class T> bool QLinkedList<T>::removeOne(const T &value)
- \since 4.4
-
- Removes the first occurrences of \a value in the list. Returns \c true on
- success; otherwise returns \c false.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 6
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa insert()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::contains(const T &value) const
-
- Returns \c true if the list contains an occurrence of \a value;
- otherwise returns \c false.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa QLinkedListIterator::findNext(), QLinkedListIterator::findPrevious()
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::count(const T &value) const
-
- Returns the number of occurrences of \a value in the list.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa contains()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::startsWith(const T &value) const
- \since 4.5
-
- Returns \c true if the list is not empty and its first
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), first()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::endsWith(const T &value) const
- \since 4.5
-
- Returns \c true if the list is not empty and its last
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), last()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::begin()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
- the list.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::begin() const
-
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::cbegin() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
-
- \sa begin(), cend()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::constBegin() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::end()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
- after the last item in the list.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::end() const
-
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::cend() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
-
- \sa cbegin(), end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::constEnd() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::reverse_iterator QLinkedList<T>::rbegin()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
-
- \sa begin(), crbegin(), rend()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::rbegin() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::crbegin() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
-
- \sa begin(), rbegin(), rend()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::reverse_iterator QLinkedList<T>::rend()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last item in the list, in reverse order.
-
- \sa end(), crend(), rbegin()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::rend() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::crend() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last item in the list, in reverse order.
-
- \sa end(), rend(), rbegin()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::insert(iterator before, const T &value)
-
- Inserts \a value in front of the item pointed to by the iterator
- \a before. Returns an iterator pointing at the inserted item.
-
- \sa erase()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::erase(iterator pos)
-
- Removes the item pointed to by the iterator \a pos from the list,
- and returns an iterator to the next item in the list (which may be
- end()).
-
- \sa insert()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::erase(iterator begin, iterator end)
-
- \overload
-
- Removes all the items from \a begin up to (but not including) \a
- end.
-*/
-
-/*! \typedef QLinkedList::Iterator
-
- Qt-style synonym for QLinkedList::iterator.
-*/
-
-/*! \typedef QLinkedList::ConstIterator
-
- Qt-style synonym for QLinkedList::const_iterator.
-*/
-
-/*! \typedef QLinkedList::reverse_iterator
- \since 5.6
-
- The QLinkedList::reverse_iterator typedef provides an STL-style non-const
- reverse iterator for QLinkedList.
-
- It is simply a typedef for \c{std::reverse_iterator<QLinkedList::iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::rbegin(), QLinkedList::rend(), QLinkedList::const_reverse_iterator, QLinkedList::iterator
-*/
-
-/*! \typedef QLinkedList::const_reverse_iterator
- \since 5.6
-
- The QLinkedList::const_reverse_iterator typedef provides an STL-style const
- reverse iterator for QLinkedList.
-
- It is simply a typedef for \c{std::reverse_iterator<QLinkedList::const_iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::rbegin(), QLinkedList::rend(), QLinkedList::reverse_iterator, QLinkedList::const_iterator
-*/
-
-/*!
- \typedef QLinkedList::size_type
-
- Typedef for int. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::value_type
-
- Typedef for T. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::pointer
-
- Typedef for T *. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::const_pointer
-
- Typedef for const T *. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::reference
-
- Typedef for T &. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::const_reference
-
- Typedef for const T &. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::difference_type
-
- Typedef for ptrdiff_t. Provided for STL compatibility.
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::count() const
-
- Same as size().
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::first()
-
- Returns a reference to the first item in the list. This function
- assumes that the list isn't empty.
-
- \sa last(), isEmpty()
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::first() const
-
- \overload
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::last()
-
- Returns a reference to the last item in the list. This function
- assumes that the list isn't empty.
-
- \sa first(), isEmpty()
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::last() const
-
- \overload
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::removeFirst()
-
- Removes the first item in the list.
-
- This is the same as erase(begin()).
-
- \sa removeLast(), erase()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::removeLast()
-
- Removes the last item in the list.
-
- \sa removeFirst(), erase()
-*/
-
-/*! \fn template <class T> T QLinkedList<T>::takeFirst()
-
- Removes the first item in the list and returns it.
-
- If you don't use the return value, removeFirst() is more
- efficient.
-
- \sa takeLast(), removeFirst()
-*/
-
-/*! \fn template <class T> T QLinkedList<T>::takeLast()
-
- Removes the last item in the list and returns it.
-
- If you don't use the return value, removeLast() is more
- efficient.
-
- \sa takeFirst(), removeLast()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::push_back(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to append(\a value).
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::push_front(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to prepend(\a value).
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::front()
-
- This function is provided for STL compatibility. It is equivalent
- to first().
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::front() const
-
- \overload
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::back()
-
- This function is provided for STL compatibility. It is equivalent
- to last().
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::back() const
-
- \overload
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::pop_front()
-
- This function is provided for STL compatibility. It is equivalent
- to removeFirst().
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::pop_back()
-
- This function is provided for STL compatibility. It is equivalent
- to removeLast().
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::empty() const
-
- This function is provided for STL compatibility. It is equivalent
- to isEmpty() and returns \c true if the list is empty.
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator+=(const QLinkedList<T> &other)
-
- Appends the items of the \a other list to this list and returns a
- reference to this list.
-
- \sa operator+(), append()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::operator+=(const T &value)
-
- \overload
-
- Appends \a value to the list.
-*/
-
-/*! \fn template <class T> QLinkedList<T> QLinkedList<T>::operator+(const QLinkedList<T> &other) const
-
- Returns a list that contains all the items in this list followed
- by all the items in the \a other list.
-
- \sa operator+=()
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator<<(const QLinkedList<T> &other)
-
- Appends the items of the \a other list to this list and returns a
- reference to this list.
-
- \sa operator+=(), append()
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator<<(const T &value)
-
- \overload
-
- Appends \a value to the list.
-*/
-
-/*! \class QLinkedList::iterator
- \inmodule QtCore
- \obsolete
- \brief The QLinkedList::iterator class provides an STL-style non-const iterator for QLinkedList.
-
- QLinkedList features both \l{STL-style iterators} and
- \l{Java-style iterators}. The STL-style iterators are more
- low-level and more cumbersome to use; on the other hand, they are
- slightly faster and, for developers who already know STL, have
- the advantage of familiarity.
-
- QLinkedList\<T\>::iterator allows you to iterate over a
- QLinkedList\<T\> and to modify the list item associated with the
- iterator. If you want to iterate over a const QLinkedList, use
- QLinkedList::const_iterator instead. It is generally good
- practice to use QLinkedList::const_iterator on a non-const
- QLinkedList as well, unless you need to change the QLinkedList
- through the iterator. Const iterators are slightly faster, and
- can improve code readability.
-
- The default QLinkedList::iterator constructor creates an
- uninitialized iterator. You must initialize it using a
- function like QLinkedList::begin(), QLinkedList::end(), or
- QLinkedList::insert() before you can start iterating. Here's a
- typical loop that prints all the items stored in a list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 7
-
- STL-style iterators can be used as arguments to \l{generic
- algorithms}. For example, here's how to find an item in the list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 8
-
- Let's see a few examples of things we can do with a
- QLinkedList::iterator that we cannot do with a QLinkedList::const_iterator.
- Here's an example that increments every value stored in a
- QLinkedList\<int\> by 2:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 9
-
- Here's an example that removes all the items that start with an
- underscore character in a QLinkedList\<QString\>:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 10
-
- The call to QLinkedList::erase() removes the item pointed to by
- the iterator from the list, and returns an iterator to the next
- item. Here's another way of removing an item while iterating:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 11
-
- It might be tempting to write code like this:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 12
-
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
- Multiple iterators can be used on the same list. If you add items
- to the list, existing iterators will remain valid. If you remove
- items from the list, iterators that point to the removed items
- will become dangling iterators.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::const_iterator, QMutableLinkedListIterator
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator::iterator()
-
- Constructs an uninitialized iterator.
-
- Functions like operator*() and operator++() should not be called
- on an uninitialized iterator. Use operator=() to assign a value
- to it before using it.
-
- \sa QLinkedList::begin(), QLinkedList::end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator::iterator(Node *node)
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::iterator_category
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::difference_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::value_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::pointer
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::reference
-
- \internal
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator::iterator(const iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator=(const iterator &other)
-
- Assigns \a other to this iterator.
-*/
-
-/*!
- \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator=(QLinkedList<T> &&other)
-
- Move-assigns \a other to this QLinkedList instance.
-
- \since 5.2
-*/
-
-/*! \fn template <class T> T &QLinkedList<T>::iterator::operator*() const
-
- Returns a modifiable reference to the current item.
-
- You can change the value of an item by using operator*() on the
- left side of an assignment, for example:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 13
-
- \sa operator->()
-*/
-
-/*! \fn template <class T> T *QLinkedList<T>::iterator::operator->() const
-
- Returns a pointer to the current item.
-
- \sa operator*()
-*/
-
-/*!
- \fn template <class T> bool QLinkedList<T>::iterator::operator==(const iterator &other) const
- \fn template <class T> bool QLinkedList<T>::iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*!
- \fn template <class T> bool QLinkedList<T>::iterator::operator!=(const iterator &other) const
- \fn template <class T> bool QLinkedList<T>::iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator++()
-
- The prefix ++ operator (\c{++it}) advances the iterator to the
- next item in the list and returns an iterator to the new current
- item.
-
- Calling this function on QLinkedList::end() leads to undefined
- results.
-
- \sa operator--()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator++(int)
-
- \overload
-
- The postfix ++ operator (\c{it++}) advances the iterator to the
- next item in the list and returns an iterator to the previously
- current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator--()
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QLinkedList::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator-(int j) const
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
-*/
-
-/*! \class QLinkedList::const_iterator
- \inmodule QtCore
- \obsolete
- \brief The QLinkedList::const_iterator class provides an STL-style const iterator for QLinkedList.
-
- QLinkedList features both \l{STL-style iterators} and
- \l{Java-style iterators}. The STL-style iterators are more
- low-level and more cumbersome to use; on the other hand, they are
- slightly faster and, for developers who already know STL, have
- the advantage of familiarity.
-
- QLinkedList\<T\>::const_iterator allows you to iterate over a
- QLinkedList\<T\>. If you want modify the QLinkedList as you iterate
- over it, you must use QLinkedList::iterator instead. It is
- generally good practice to use QLinkedList::const_iterator on a
- non-const QLinkedList as well, unless you need to change the
- QLinkedList through the iterator. Const iterators are slightly
- faster, and can improve code readability.
-
- The default QLinkedList::const_iterator constructor creates an
- uninitialized iterator. You must initialize it using a function
- like QLinkedList::constBegin(), QLinkedList::constEnd(), or
- QLinkedList::insert() before you can start iterating. Here's a
- typical loop that prints all the items stored in a list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 14
-
- STL-style iterators can be used as arguments to \l{generic
- algorithms}. For example, here's how to find an item in the list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 15
-
- Multiple iterators can be used on the same list. If you add items
- to the list, existing iterators will remain valid. If you remove
- items from the list, iterators that point to the removed items
- will become dangling iterators.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::iterator, QLinkedListIterator
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator()
-
- Constructs an uninitialized iterator.
-
- Functions like operator*() and operator++() should not be called
- on an uninitialized iterator. Use operator=() to assign a value
- to it before using it.
-
- \sa QLinkedList::constBegin(), QLinkedList::constEnd()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator(Node *node)
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::iterator_category
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::difference_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::value_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::pointer
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::reference
-
- \internal
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator(const const_iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator(iterator other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> typename QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator=(const const_iterator &other)
-
- Assigns \a other to this iterator.
-*/
-
-/*! \fn template <class T> const T &QLinkedList<T>::const_iterator::operator*() const
-
- Returns a reference to the current item.
-
- \sa operator->()
-*/
-
-/*! \fn template <class T> const T *QLinkedList<T>::const_iterator::operator->() const
-
- Returns a pointer to the current item.
-
- \sa operator*()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::const_iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::const_iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator++()
-
- The prefix ++ operator (\c{++it}) advances the iterator to the
- next item in the list and returns an iterator to the new current
- item.
-
- Calling this function on QLinkedList<T>::constEnd() leads to
- undefined results.
-
- \sa operator--()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator++(int)
-
- \overload
-
- The postfix ++ operator (\c{it++}) advances the iterator to the
- next item in the list and returns an iterator to the previously
- current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator--()
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QLinkedList::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator-(int j) const
-
- This function returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
-*/
-
-/*! \fn template <class T> QDataStream &operator<<(QDataStream &out, const QLinkedList<T> &list)
- \relates QLinkedList
-
- Writes the linked list \a list to stream \a out.
-
- This function requires the value type to implement \c
- operator<<().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*! \fn template <class T> QDataStream &operator>>(QDataStream &in, QLinkedList<T> &list)
- \relates QLinkedList
-
- Reads a linked list from stream \a in into \a list.
-
- This function requires the value type to implement \c operator>>().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*!
- \since 4.1
- \fn template <class T> QLinkedList<T> QLinkedList<T>::fromStdList(const std::list<T> &list)
-
- Returns a QLinkedList object with the data contained in \a list.
- The order of the elements in the QLinkedList is the same as in \a
- list.
-
- Example:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 16
-
- \sa toStdList()
-*/
-
-/*!
- \since 4.1
- \fn template <class T> std::list<T> QLinkedList<T>::toStdList() const
-
- Returns a std::list object with the data contained in this
- QLinkedList. Example:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 17
-
- \sa fromStdList()
-*/
-
-QT_WARNING_POP
-
-#endif // QT_DEPRECATED_SINCE(5, 15)
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h
deleted file mode 100644
index 14fbc34b9d..0000000000
--- a/src/corelib/tools/qlinkedlist.h
+++ /dev/null
@@ -1,615 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-#ifndef QLINKEDLIST_H
-#define QLINKEDLIST_H
-
-#include <QtCore/qglobal.h>
-
-#ifndef QT_NO_LINKED_LIST
-
-#include <QtCore/qiterator.h>
-#include <QtCore/qrefcount.h>
-#include <QtCore/qcontainertools_impl.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qtypeinfo.h>
-
-#include <algorithm>
-#include <initializer_list>
-#include <iterator>
-#include <list>
-
-
-#if 0
-// This is needed because of QTBUG-80347
-#pragma qt_class(QLinkedList)
-#pragma qt_class(QLinkedListData)
-#pragma qt_class(QLinkedListNode)
-#endif
-
-#if QT_DEPRECATED_SINCE(5, 15)
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-
-QT_BEGIN_NAMESPACE
-
-struct QT_DEPRECATED_VERSION_5_15 QLinkedListData
-{
- QLinkedListData *n, *p;
- QtPrivate::RefCount ref;
- int size;
- uint sharable : 1;
-
- Q_CORE_EXPORT static const QLinkedListData shared_null;
-};
-
-template <typename T>
-struct QT_DEPRECATED_VERSION_5_15 QLinkedListNode
-{
- inline QLinkedListNode(const T &arg): t(arg) { }
- QLinkedListNode *n, *p;
- T t;
-};
-
-template <class T>
-class QT_DEPRECATED_VERSION_X_5_15("Use std::list instead") QLinkedList
-{
- typedef QLinkedListNode<T> Node;
- union { QLinkedListData *d; QLinkedListNode<T> *e; };
-
-public:
- inline QLinkedList() noexcept : d(const_cast<QLinkedListData *>(&QLinkedListData::shared_null)) { }
- inline QLinkedList(const QLinkedList<T> &l) : d(l.d) { d->ref.ref(); if (!d->sharable) detach(); }
- inline QLinkedList(std::initializer_list<T> list)
- : QLinkedList(list.begin(), list.end()) {}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
- inline QLinkedList(InputIterator first, InputIterator last)
- : QLinkedList()
- {
- std::copy(first, last, std::back_inserter(*this));
- }
- ~QLinkedList();
- QLinkedList<T> &operator=(const QLinkedList<T> &);
- QLinkedList(QLinkedList<T> &&other) noexcept
- : d(other.d) { other.d = const_cast<QLinkedListData *>(&QLinkedListData::shared_null); }
- QLinkedList<T> &operator=(QLinkedList<T> &&other) noexcept
- { QLinkedList moved(std::move(other)); swap(moved); return *this; }
- inline void swap(QLinkedList<T> &other) noexcept { qSwap(d, other.d); }
- bool operator==(const QLinkedList<T> &l) const;
- inline bool operator!=(const QLinkedList<T> &l) const { return !(*this == l); }
-
- inline int size() const { return d->size; }
- inline void detach()
- { if (d->ref.isShared()) detach_helper2(this->e); }
- inline bool isDetached() const { return !d->ref.isShared(); }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QLinkedListData::shared_null) d->sharable = sharable; }
-#endif
- inline bool isSharedWith(const QLinkedList<T> &other) const { return d == other.d; }
-
- inline bool isEmpty() const { return d->size == 0; }
-
- void clear();
-
- void append(const T &);
- void prepend(const T &);
- T takeFirst();
- T takeLast();
- int removeAll(const T &t);
- bool removeOne(const T &t);
- bool contains(const T &t) const;
- int count(const T &t) const;
-
- class const_iterator;
-
- class iterator
- {
- public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
- Node *i;
- inline iterator() : i(nullptr) {}
- inline iterator(Node *n) : i(n) {}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- iterator(const iterator &other) noexcept : i(other.i) {}
- iterator &operator=(const iterator &other) noexcept { i = other.i; return *this; }
- iterator(iterator &&other) noexcept : i(other.i) {}
- iterator &operator=(iterator &&other) noexcept { return *this = other; }
-#endif
- inline T &operator*() const { return i->t; }
- inline T *operator->() const { return &i->t; }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
- inline bool operator==(const const_iterator &o) const
- { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const
- { return i != o.i; }
- inline iterator &operator++() { i = i->n; return *this; }
- inline iterator operator++(int) { Node *n = i; i = i->n; return n; }
- inline iterator &operator--() { i = i->p; return *this; }
- inline iterator operator--(int) { Node *n = i; i = i->p; return n; }
- inline iterator operator+(int j) const
- { Node *n = i; if (j > 0) while (j--) n = n->n; else while (j++) n = n->p; return n; }
- inline iterator operator-(int j) const { return operator+(-j); }
- inline iterator &operator+=(int j) { return *this = *this + j; }
- inline iterator &operator-=(int j) { return *this = *this - j; }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
- };
- friend class iterator;
-
- class const_iterator
- {
- public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
- Node *i;
- inline const_iterator() : i(nullptr) {}
- inline const_iterator(Node *n) : i(n) {}
- inline const_iterator(iterator ci) : i(ci.i){}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- const_iterator(const const_iterator &other) noexcept : i(other.i) {}
- const_iterator &operator=(const const_iterator &other) noexcept { i = other.i; return *this; }
- const_iterator(const_iterator &&other) noexcept : i(other.i) {}
- const_iterator &operator=(const_iterator &&other) noexcept { return *this = other; }
-#endif
- inline const T &operator*() const { return i->t; }
- inline const T *operator->() const { return &i->t; }
- inline bool operator==(const const_iterator &o) const { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const { return i != o.i; }
- inline const_iterator &operator++() { i = i->n; return *this; }
- inline const_iterator operator++(int) { Node *n = i; i = i->n; return n; }
- inline const_iterator &operator--() { i = i->p; return *this; }
- inline const_iterator operator--(int) { Node *n = i; i = i->p; return n; }
- inline const_iterator operator+(int j) const
- { Node *n = i; if (j > 0) while (j--) n = n->n; else while (j++) n = n->p; return n; }
- inline const_iterator operator-(int j) const { return operator+(-j); }
- inline const_iterator &operator+=(int j) { return *this = *this + j; }
- inline const_iterator &operator-=(int j) { return *this = *this - j; }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
- };
- friend class const_iterator;
-
- // stl style
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- inline iterator begin() { detach(); return e->n; }
- inline const_iterator begin() const noexcept { return e->n; }
- inline const_iterator cbegin() const noexcept { return e->n; }
- inline const_iterator constBegin() const noexcept { return e->n; }
- inline iterator end() { detach(); return e; }
- inline const_iterator end() const noexcept { return e; }
- inline const_iterator cend() const noexcept { return e; }
- inline const_iterator constEnd() const noexcept { return e; }
-
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
- const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
-
- iterator insert(iterator before, const T &t);
- iterator erase(iterator pos);
- iterator erase(iterator first, iterator last);
-
- // more Qt
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- inline int count() const { return d->size; }
- inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T& first() const { Q_ASSERT(!isEmpty()); return *begin(); }
- T& last() { Q_ASSERT(!isEmpty()); return *(--end()); }
- const T& last() const { Q_ASSERT(!isEmpty()); return *(--end()); }
- inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(begin()); }
- inline void removeLast() { Q_ASSERT(!isEmpty()); erase(--end()); }
- inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
- inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
-
- // stl compatibility
- inline void push_back(const T &t) { append(t); }
- inline void push_front(const T &t) { prepend(t); }
- inline T& front() { return first(); }
- inline const T& front() const { return first(); }
- inline T& back() { return last(); }
- inline const T& back() const { return last(); }
- inline void pop_front() { removeFirst(); }
- inline void pop_back() { removeLast(); }
- inline bool empty() const { return isEmpty(); }
- typedef int size_type;
- typedef T value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef value_type &reference;
- typedef const value_type &const_reference;
- typedef qptrdiff difference_type;
-
- static inline QLinkedList<T> fromStdList(const std::list<T> &list)
- { QLinkedList<T> tmp; std::copy(list.begin(), list.end(), std::back_inserter(tmp)); return tmp; }
- inline std::list<T> toStdList() const
- { std::list<T> tmp; std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; }
-
- // comfort
- QLinkedList<T> &operator+=(const QLinkedList<T> &l);
- QLinkedList<T> operator+(const QLinkedList<T> &l) const;
- inline QLinkedList<T> &operator+=(const T &t) { append(t); return *this; }
- inline QLinkedList<T> &operator<< (const T &t) { append(t); return *this; }
- inline QLinkedList<T> &operator<<(const QLinkedList<T> &l) { *this += l; return *this; }
-
-private:
- void detach_helper();
- iterator detach_helper2(iterator);
- void freeData(QLinkedListData*);
-};
-template <typename T>
-Q_DECLARE_TYPEINFO_BODY(QLinkedList<T>, Q_MOVABLE_TYPE|Q_RELOCATABLE_TYPE);
-
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
-template <typename InputIterator,
- typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
- QtPrivate::IfIsInputIterator<InputIterator> = true>
-QLinkedList(InputIterator, InputIterator) -> QLinkedList<ValueType>;
-#endif
-
-template <typename T>
-inline QLinkedList<T>::~QLinkedList()
-{
- if (!d->ref.deref())
- freeData(d);
-}
-
-template <typename T>
-void QLinkedList<T>::detach_helper()
-{
- detach_helper2(this->e);
-}
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::detach_helper2(iterator orgite)
-{
- // detach and convert orgite to an iterator in the detached instance
- bool isEndIterator = (orgite.i == this->e);
- union { QLinkedListData *d; Node *e; } x;
- x.d = new QLinkedListData;
- x.d->ref.initializeOwned();
- x.d->size = d->size;
- x.d->sharable = true;
- Node *original = e->n;
- Node *copy = x.e;
- Node *org = orgite.i;
-
- while (original != org) {
- QT_TRY {
- copy->n = new Node(original->t);
- copy->n->p = copy;
- original = original->n;
- copy = copy->n;
- } QT_CATCH(...) {
- copy->n = x.e;
- Q_ASSERT(!x.d->ref.deref()); // Don't trigger assert in free
- freeData(x.d);
- QT_RETHROW;
- }
- }
- iterator r(copy);
- while (original != e) {
- QT_TRY {
- copy->n = new Node(original->t);
- copy->n->p = copy;
- original = original->n;
- copy = copy->n;
- } QT_CATCH(...) {
- copy->n = x.e;
- Q_ASSERT(!x.d->ref.deref()); // Don't trigger assert in free
- freeData(x.d);
- QT_RETHROW;
- }
- }
- copy->n = x.e;
- x.e->p = copy;
- if (!d->ref.deref())
- freeData(d);
- d = x.d;
- if (!isEndIterator)
- ++r; // since we stored the element right before the original node.
- return r;
-}
-
-template <typename T>
-void QLinkedList<T>::freeData(QLinkedListData *x)
-{
- Node *y = reinterpret_cast<Node*>(x);
- Node *i = y->n;
- Q_ASSERT(x->ref.atomic.loadRelaxed() == 0);
- while (i != y) {
- Node *n = i;
- i = i->n;
- delete n;
- }
- delete x;
-}
-
-template <typename T>
-void QLinkedList<T>::clear()
-{
- *this = QLinkedList<T>();
-}
-
-template <typename T>
-QLinkedList<T> &QLinkedList<T>::operator=(const QLinkedList<T> &l)
-{
- if (d != l.d) {
- QLinkedListData *o = l.d;
- o->ref.ref();
- if (!d->ref.deref())
- freeData(d);
- d = o;
- if (!d->sharable)
- detach_helper();
- }
- return *this;
-}
-
-template <typename T>
-bool QLinkedList<T>::operator== (const QLinkedList<T> &l) const
-{
- if (d->size != l.d->size)
- return false;
- if (e == l.e)
- return true;
- Node *i = e->n;
- Node *il = l.e->n;
- while (i != e) {
- if (! (i->t == il->t))
- return false;
- i = i->n;
- il = il->n;
- }
- return true;
-}
-
-template <typename T>
-void QLinkedList<T>::append(const T &t)
-{
- detach();
- Node *i = new Node(t);
- i->n = e;
- i->p = e->p;
- i->p->n = i;
- e->p = i;
- d->size++;
-}
-
-template <typename T>
-void QLinkedList<T>::prepend(const T &t)
-{
- detach();
- Node *i = new Node(t);
- i->n = e->n;
- i->p = e;
- i->n->p = i;
- e->n = i;
- d->size++;
-}
-
-template <typename T>
-int QLinkedList<T>::removeAll(const T &_t)
-{
- detach();
- const T t = _t;
- Node *i = e->n;
- int c = 0;
- while (i != e) {
- if (i->t == t) {
- Node *n = i;
- i->n->p = i->p;
- i->p->n = i->n;
- i = i->n;
- delete n;
- c++;
- } else {
- i = i->n;
- }
- }
- d->size-=c;
- return c;
-}
-
-template <typename T>
-bool QLinkedList<T>::removeOne(const T &_t)
-{
- detach();
- iterator it = std::find(begin(), end(), _t);
- if (it != end()) {
- erase(it);
- return true;
- }
- return false;
-}
-
-template <typename T>
-inline T QLinkedList<T>::takeFirst()
-{
- T t = std::move(first());
- removeFirst();
- return t;
-}
-
-template <typename T>
-inline T QLinkedList<T>::takeLast()
-{
- T t = std::move(last());
- removeLast();
- return t;
-}
-
-template <typename T>
-bool QLinkedList<T>::contains(const T &t) const
-{
- Node *i = e;
- while ((i = i->n) != e)
- if (i->t == t)
- return true;
- return false;
-}
-
-template <typename T>
-int QLinkedList<T>::count(const T &t) const
-{
- Node *i = e;
- int c = 0;
- while ((i = i->n) != e)
- if (i->t == t)
- c++;
- return c;
-}
-
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::insert(iterator before, const T &t)
-{
- if (d->ref.isShared())
- before = detach_helper2(before);
-
- Node *i = before.i;
- Node *m = new Node(t);
- m->n = i;
- m->p = i->p;
- m->p->n = m;
- i->p = m;
- d->size++;
- return m;
-}
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::erase(typename QLinkedList<T>::iterator afirst,
- typename QLinkedList<T>::iterator alast)
-{
- while (afirst != alast)
- erase(afirst++);
- return alast;
-}
-
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::erase(iterator pos)
-{
- if (d->ref.isShared())
- pos = detach_helper2(pos);
-
- Node *i = pos.i;
- if (i != e) {
- Node *n = i;
- i->n->p = i->p;
- i->p->n = i->n;
- i = i->n;
- delete n;
- d->size--;
- }
- return i;
-}
-
-template <typename T>
-QLinkedList<T> &QLinkedList<T>::operator+=(const QLinkedList<T> &l)
-{
- detach();
- int n = l.d->size;
- d->size += n;
- Node *original = l.e->n;
- while (n--) {
- QT_TRY {
- Node *copy = new Node(original->t);
- original = original->n;
- copy->n = e;
- copy->p = e->p;
- copy->p->n = copy;
- e->p = copy;
- } QT_CATCH(...) {
- // restore the original list
- while (n++<d->size)
- removeLast();
- QT_RETHROW;
- }
- }
- return *this;
-}
-
-template <typename T>
-QLinkedList<T> QLinkedList<T>::operator+(const QLinkedList<T> &l) const
-{
- QLinkedList<T> n = *this;
- n += l;
- return n;
-}
-
-Q_DECLARE_SEQUENTIAL_ITERATOR(LinkedList)
-Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(LinkedList)
-
-#ifndef QT_NO_DATASTREAM
-template <typename T>
-inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
-{
- return QtPrivate::readListBasedContainer(s, l);
-}
-
-template <typename T>
-inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
-{
- return QtPrivate::writeSequentialContainer(s, l);
-}
-#endif
-
-QT_END_NAMESPACE
-
-Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(QLinkedList)
-
-QT_WARNING_POP
-
-#endif // QT_DEPRECATED_SINCE(5, 15)
-
-#endif // QT_NO_LINKED_LIST
-
-#endif // QLINKEDLIST_H
diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp
index 5d5da20752..62201fd5d6 100644
--- a/src/corelib/tools/qlist.cpp
+++ b/src/corelib/tools/qlist.cpp
@@ -63,2029 +63,4 @@ template class Q_CORE_EXPORT QVector<QPointF>;
template class Q_CORE_EXPORT QVector<QPoint>;
#endif
-
-/*
- QList as an array-list combines the easy-of-use of a random
- access interface with fast list operations and the low memory
- management overhead of an array. Accessing elements by index,
- appending, prepending, and removing elements from both the front
- and the back all happen in constant time O(1). Inserting or
- removing elements at random index positions \ai happens in linear
- time, or more precisly in O(min{i,n-i}) <= O(n/2), with n being
- the number of elements in the list.
-*/
-
-const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, { nullptr } };
-
-/*!
- * Detaches the QListData by allocating new memory for a list which will be bigger
- * than the copied one and is expected to grow further.
- * *idx is the desired insertion point and is clamped to the actual size of the list.
- * num is the number of new elements to insert at the insertion point.
- * Returns the old (shared) data, it is up to the caller to deref() and free().
- * For the new data node_copy needs to be called.
- *
- * \internal
- */
-QListData::Data *QListData::detach_grow(int *idx, int num)
-{
- Data *x = d;
- int l = x->end - x->begin;
- int nl = l + num;
- auto blockInfo = qCalculateGrowingBlockSize(nl, sizeof(void *), DataHeaderSize);
- Data* t = static_cast<Data *>(::malloc(blockInfo.size));
- Q_CHECK_PTR(t);
- t->alloc = int(uint(blockInfo.elementCount));
-
- t->ref.initializeOwned();
- // The space reservation algorithm's optimization is biased towards appending:
- // Something which looks like an append will put the data at the beginning,
- // while something which looks like a prepend will put it in the middle
- // instead of at the end. That's based on the assumption that prepending
- // is uncommon and even an initial prepend will eventually be followed by
- // at least some appends.
- int bg;
- if (*idx < 0) {
- *idx = 0;
- bg = (t->alloc - nl) >> 1;
- } else if (*idx > l) {
- *idx = l;
- bg = 0;
- } else if (*idx < (l >> 1)) {
- bg = (t->alloc - nl) >> 1;
- } else {
- bg = 0;
- }
- t->begin = bg;
- t->end = bg + nl;
- d = t;
-
- return x;
-}
-
-/*!
- * Detaches the QListData by allocating new memory for a list which possibly
- * has a different size than the copied one.
- * Returns the old (shared) data, it is up to the caller to deref() and free()
- * For the new data node_copy needs to be called.
- *
- * \internal
- */
-QListData::Data *QListData::detach(int alloc)
-{
- Data *x = d;
- Data* t = static_cast<Data *>(::malloc(qCalculateBlockSize(alloc, sizeof(void*), DataHeaderSize)));
- Q_CHECK_PTR(t);
-
- t->ref.initializeOwned();
- t->alloc = alloc;
- if (!alloc) {
- t->begin = 0;
- t->end = 0;
- } else {
- t->begin = x->begin;
- t->end = x->end;
- }
- d = t;
-
- return x;
-}
-
-void QListData::realloc(int alloc)
-{
- Q_ASSERT(!d->ref.isShared());
- Data *x = static_cast<Data *>(::realloc(d, qCalculateBlockSize(alloc, sizeof(void *), DataHeaderSize)));
- Q_CHECK_PTR(x);
-
- d = x;
- d->alloc = alloc;
- if (!alloc)
- d->begin = d->end = 0;
-}
-
-void QListData::realloc_grow(int growth)
-{
- Q_ASSERT(!d->ref.isShared());
- auto r = qCalculateGrowingBlockSize(d->alloc + growth, sizeof(void *), DataHeaderSize);
- Data *x = static_cast<Data *>(::realloc(d, r.size));
- Q_CHECK_PTR(x);
-
- d = x;
- d->alloc = int(uint(r.elementCount));
-}
-
-void QListData::dispose(Data *d)
-{
- Q_ASSERT(!d->ref.isShared());
- free(d);
-}
-
-// ensures that enough space is available to append n elements
-void **QListData::append(int n)
-{
- Q_ASSERT(!d->ref.isShared());
- int e = d->end;
- if (e + n > d->alloc) {
- int b = d->begin;
- if (b - n >= 2 * d->alloc / 3) {
- // we have enough space. Just not at the end -> move it.
- e -= b;
- ::memcpy(d->array, d->array + b, e * sizeof(void *));
- d->begin = 0;
- } else {
- realloc_grow(n);
- }
- }
- d->end = e + n;
- return d->array + e;
-}
-
-// ensures that enough space is available to append one element
-void **QListData::append()
-{
- return append(1);
-}
-
-// ensures that enough space is available to append the list
-void **QListData::append(const QListData& l)
-{
- return append(l.d->end - l.d->begin);
-}
-
-void **QListData::prepend()
-{
- Q_ASSERT(!d->ref.isShared());
- if (d->begin == 0) {
- if (d->end >= d->alloc / 3)
- realloc_grow(1);
-
- if (d->end < d->alloc / 3)
- d->begin = d->alloc - 2 * d->end;
- else
- d->begin = d->alloc - d->end;
-
- ::memmove(d->array + d->begin, d->array, d->end * sizeof(void *));
- d->end += d->begin;
- }
- return d->array + --d->begin;
-}
-
-void **QListData::insert(int i)
-{
- Q_ASSERT(!d->ref.isShared());
- if (i <= 0)
- return prepend();
- int size = d->end - d->begin;
- if (i >= size)
- return append();
-
- bool leftward = false;
-
- if (d->begin == 0) {
- if (d->end == d->alloc) {
- // If the array is full, we expand it and move some items rightward
- realloc_grow(1);
- } else {
- // If there is free space at the end of the array, we move some items rightward
- }
- } else {
- if (d->end == d->alloc) {
- // If there is free space at the beginning of the array, we move some items leftward
- leftward = true;
- } else {
- // If there is free space at both ends, we move as few items as possible
- leftward = (i < size - i);
- }
- }
-
- if (leftward) {
- --d->begin;
- ::memmove(d->array + d->begin, d->array + d->begin + 1, i * sizeof(void *));
- } else {
- ::memmove(d->array + d->begin + i + 1, d->array + d->begin + i,
- (size - i) * sizeof(void *));
- ++d->end;
- }
- return d->array + d->begin + i;
-}
-
-void QListData::remove(int i)
-{
- Q_ASSERT(!d->ref.isShared());
- i += d->begin;
- if (i - d->begin < d->end - i) {
- if (int offset = i - d->begin)
- ::memmove(d->array + d->begin + 1, d->array + d->begin, offset * sizeof(void *));
- d->begin++;
- } else {
- if (int offset = d->end - i - 1)
- ::memmove(d->array + i, d->array + i + 1, offset * sizeof(void *));
- d->end--;
- }
-}
-
-void QListData::remove(int i, int n)
-{
- Q_ASSERT(!d->ref.isShared());
- i += d->begin;
- int middle = i + n/2;
- if (middle - d->begin < d->end - middle) {
- ::memmove(d->array + d->begin + n, d->array + d->begin,
- (i - d->begin) * sizeof(void*));
- d->begin += n;
- } else {
- ::memmove(d->array + i, d->array + i + n,
- (d->end - i - n) * sizeof(void*));
- d->end -= n;
- }
-}
-
-void QListData::move(int from, int to)
-{
- Q_ASSERT(!d->ref.isShared());
- if (from == to)
- return;
-
- from += d->begin;
- to += d->begin;
- void *t = d->array[from];
-
- if (from < to) {
- if (d->end == d->alloc || 3 * (to - from) < 2 * (d->end - d->begin)) {
- ::memmove(d->array + from, d->array + from + 1, (to - from) * sizeof(void *));
- } else {
- // optimization
- if (int offset = from - d->begin)
- ::memmove(d->array + d->begin + 1, d->array + d->begin, offset * sizeof(void *));
- if (int offset = d->end - (to + 1))
- ::memmove(d->array + to + 2, d->array + to + 1, offset * sizeof(void *));
- ++d->begin;
- ++d->end;
- ++to;
- }
- } else {
- if (d->begin == 0 || 3 * (from - to) < 2 * (d->end - d->begin)) {
- ::memmove(d->array + to + 1, d->array + to, (from - to) * sizeof(void *));
- } else {
- // optimization
- if (int offset = to - d->begin)
- ::memmove(d->array + d->begin - 1, d->array + d->begin, offset * sizeof(void *));
- if (int offset = d->end - (from + 1))
- ::memmove(d->array + from, d->array + from + 1, offset * sizeof(void *));
- --d->begin;
- --d->end;
- --to;
- }
- }
- d->array[to] = t;
-}
-
-void **QListData::erase(void **xi)
-{
- Q_ASSERT(!d->ref.isShared());
- int i = xi - (d->array + d->begin);
- remove(i);
- return d->array + d->begin + i;
-}
-
-/*! \class QList
- \inmodule QtCore
- \brief The QList class is a template class that provides lists.
-
- \ingroup tools
- \ingroup shared
-
- \reentrant
-
- QList\<T\> is one of Qt's generic \l{container classes}. It
- stores items in a list that provides fast index-based access
- and index-based insertions and removals.
-
- QList\<T\>, QLinkedList\<T\>, and QVector\<T\> provide similar
- APIs and functionality. They are often interchangeable, but there
- are performance consequences. Here is an overview of use cases:
-
- \list
- \li QVector should be your default first choice.
- QVector\<T\> will usually give better performance than QList\<T\>,
- because QVector\<T\> always stores its items sequentially in memory,
- where QList\<T\> will allocate its items on the heap unless
- \c {sizeof(T) <= sizeof(void*)} and T has been declared to be
- either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
- \l {Q_DECLARE_TYPEINFO}. See the \l {Pros and Cons of Using QList}
- for an explanation.
- \li However, QList is used throughout the Qt APIs for passing
- parameters and for returning values. Use QList to interface with
- those APIs.
- \li If you need a real linked list, which guarantees
- \l {Algorithmic Complexity}{constant time} insertions mid-list and
- uses iterators to items rather than indexes, use QLinkedList.
- \endlist
-
- \note QVector and QVarLengthArray both guarantee C-compatible
- array layout. QList does not. This might be important if your
- application must interface with a C API.
-
- \note Iterators into a QLinkedList and references into
- heap-allocating QLists remain valid as long as the referenced items
- remain in the container. This is not true for iterators and
- references into a QVector and non-heap-allocating QLists.
-
- Internally, QList\<T\> is represented as an array of T if
- \c{sizeof(T) <= sizeof(void*)} and T has been declared to be
- either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
- \l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented
- as an array of T* and the items are allocated on the heap.
-
- The array representation allows very fast insertions and
- index-based access. The prepend() and append() operations are
- also very fast because QList preallocates memory at both
- ends of its internal array. (See \l{Algorithmic Complexity} for
- details.
-
- Note, however, that when the conditions specified above are not met,
- each append or insert of a new item requires allocating the new item
- on the heap, and this per item allocation will make QVector a better
- choice for use cases that do a lot of appending or inserting, because
- QVector can allocate memory for many items in a single heap allocation.
-
- Note that the internal array only ever gets bigger over the life
- of the list. It never shrinks. The internal array is deallocated
- by the destructor and by the assignment operator, when one list
- is assigned to another.
-
- Here's an example of a QList that stores integers and
- a QList that stores QDate values:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 0
-
- Qt includes a QStringList class that inherits QList\<QString\>
- and adds a few convenience functions, such as QStringList::join()
- and QStringList::filter(). QString::split() creates QStringLists
- from strings.
-
- QList stores a list of items. The default constructor creates an
- empty list. You can use the initializer-list constructor to create
- a list with elements:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 1a
-
- QList provides these basic functions to add, move, and remove
- items: insert(), replace(), removeAt(), move(), and swap(). In
- addition, it provides the following convenience functions:
- append(), \l{operator<<()}, \l{operator+=()}, prepend(), removeFirst(),
- and removeLast().
-
- \l{operator<<()} allows to conveniently add multiple elements to a list:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 1b
-
- QList uses 0-based indexes, just like C++ arrays. To access the
- item at a particular index position, you can use operator[](). On
- non-const lists, operator[]() returns a reference to the item and
- can be used on the left side of an assignment:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 2
-
- Because QList is implemented as an array of pointers for types
- that are larger than a pointer or are not movable, this operation
- requires (\l{Algorithmic Complexity}{constant time}). For read-only
- access, an alternative syntax is to use at():
-
- \snippet code/src_corelib_tools_qlistdata.cpp 3
-
- at() can be faster than operator[](), because it never causes a
- \l{deep copy} to occur.
-
- A common requirement is to remove an item from a list and do
- something with it. For this, QList provides takeAt(), takeFirst(),
- and takeLast(). Here's a loop that removes the items from a list
- one at a time and calls \c delete on them:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 4
-
- Inserting and removing items at either end of the list is very
- fast (\l{Algorithmic Complexity}{constant time} in most cases),
- because QList preallocates extra space on both sides of its
- internal buffer to allow for fast growth at both ends of the list.
-
- If you want to find all occurrences of a particular value in a
- list, use indexOf() or lastIndexOf(). The former searches forward
- starting from a given index position, the latter searches
- backward. Both return the index of a matching item if they find
- it; otherwise, they return -1. For example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 5
-
- If you simply want to check whether a list contains a particular
- value, use contains(). If you want to find out how many times a
- particular value occurs in the list, use count(). If you want to
- replace all occurrences of a particular value with another, use
- replace().
-
- QList's value type must be an \l{assignable data type}. This
- covers most data types that are commonly used, but the compiler
- won't let you, for example, store a QWidget as a value; instead,
- store a QWidget *. A few functions have additional requirements;
- for example, indexOf() and lastIndexOf() expect the value type to
- support \c operator==(). These requirements are documented on a
- per-function basis.
-
- Like the other container classes, QList provides \l{Java-style
- iterators} (QListIterator and QMutableListIterator) and
- \l{STL-style iterators} (QList::const_iterator and
- QList::iterator). In practice, these are rarely used, because you
- can use indexes into the QList. QList is implemented in such a way
- that direct index-based access is just as fast as using iterators.
-
- QList does \e not support inserting, prepending, appending or
- replacing with references to its own values. Doing so will cause
- your application to abort with an error message.
-
- To make QList as efficient as possible, its member functions don't
- validate their input before using it. Except for isEmpty(), member
- functions always assume the list is \e not empty. Member functions
- that take index values as parameters always assume their index
- value parameters are in the valid range. This means QList member
- functions can fail. If you define QT_NO_DEBUG when you compile,
- failures will not be detected. If you \e don't define QT_NO_DEBUG,
- failures will be detected using Q_ASSERT() or Q_ASSERT_X() with an
- appropriate message.
-
- To avoid failures when your list can be empty, call isEmpty()
- before calling other member functions. If you must pass an index
- value that might not be in the valid range, check that it is less
- than the value returned by size() but \e not less than 0.
-
- \section1 More Members
-
- If T is a QByteArray, this class has a couple more members that can be
- used. See the documentation for QByteArrayList for more information.
-
- If T is QString, this class has the following additional members:
- \l{QStringList::filter()}{filter},
- \l{QStringList::join()}{join},
- \l{QStringList::removeDuplicates()}{removeDuplicates},
- \l{QStringList::sort()}{sort}.
-
- \section1 More Information on Using Qt Containers
-
- For a detailed discussion comparing Qt containers with each other and
- with STL containers, see \l {Understand the Qt Containers}.
-
- \sa QListIterator, QMutableListIterator, QLinkedList, QVector
-*/
-
-/*!
- \fn template <class T> QList<T>::QList(QList<T> &&other)
-
- Move-constructs a QList instance, making it point at the same
- object that \a other was pointing to.
-
- \since 5.2
-*/
-
-/*! \fn template <class T> template<typename InputIterator> QList<T>::QList(InputIterator first, InputIterator last)
- \since 5.14
-
- Constructs a QList with the contents in the iterator range [\a first, \a last).
-
- The value type of \c InputIterator must be convertible to \c T.
-*/
-
-/*!
- \fn template <class T> QList<T> QList<T>::mid(int pos, int length) const
-
- Returns a sub-list which includes elements from this list,
- starting at position \a pos. If \a length is -1 (the default), all
- elements from \a pos are included; otherwise \a length elements (or
- all remaining elements if there are less than \a length elements)
- are included.
-*/
-
-/*! \fn template <class T> QList<T>::QList()
-
- Constructs an empty list.
-*/
-
-/*! \fn template <class T> QList<T>::QList(const QList<T> &other)
-
- Constructs a copy of \a other.
-
- This operation takes \l{Algorithmic Complexity}{constant time},
- because QList is \l{implicitly shared}. This makes returning a
- QList from a function very fast. If a shared instance is modified,
- it will be copied (copy-on-write), and that takes
- \l{Algorithmic Complexity}{linear time}.
-
- \sa operator=()
-*/
-
-/*! \fn template <class T> QList<T>::QList(std::initializer_list<T> args)
- \since 4.8
-
- Construct a list from the std::initializer_list specified by \a args.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
-*/
-
-/*! \fn template <class T> QList<T>::~QList()
-
- Destroys the list. References to the values in the list and all
- iterators of this list become invalid.
-*/
-
-/*! \fn template <class T> QList<T> &QList<T>::operator=(const QList<T> &other)
-
- Assigns \a other to this list and returns a reference to this
- list.
-*/
-
-/*!
- \fn template <class T> QList &QList<T>::operator=(QList<T> &&other)
-
- Move-assigns \a other to this QList instance.
-
- \since 5.2
-*/
-
-/*! \fn template <class T> void QList<T>::swap(QList<T> &other)
- \since 4.8
-
- Swaps list \a other with this list. This operation is very
- fast and never fails.
-*/
-
-/*! \fn template <class T> bool QList<T>::operator==(const QList<T> &other) const
-
- Returns \c true if \a other is equal to this list; otherwise returns
- false.
-
- Two lists are considered equal if they contain the same values in
- the same order.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa operator!=()
-*/
-
-/*! \fn template <class T> bool QList<T>::operator!=(const QList<T> &other) const
-
- Returns \c true if \a other is not equal to this list; otherwise
- returns \c false.
-
- Two lists are considered equal if they contain the same values in
- the same order.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> bool operator<(const QList<T> &lhs, const QList<T> &rhs)
- \since 5.6
- \relates QList
-
- Returns \c true if list \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically less than} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*! \fn template <class T> bool operator<=(const QList<T> &lhs, const QList<T> &rhs)
- \since 5.6
- \relates QList
-
- Returns \c true if list \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically less than or equal to} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*! \fn template <class T> bool operator>(const QList<T> &lhs, const QList<T> &rhs)
- \since 5.6
- \relates QList
-
- Returns \c true if list \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically greater than} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*! \fn template <class T> bool operator>=(const QList<T> &lhs, const QList<T> &rhs)
- \since 5.6
- \relates QList
-
- Returns \c true if list \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically greater than or equal to} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*!
- \fn template <class T> uint qHash(const QList<T> &key, uint seed = 0)
- \since 5.6
- \relates QList
-
- Returns the hash value for \a key,
- using \a seed to seed the calculation.
-
- This function requires qHash() to be overloaded for the value type \c T.
-*/
-
-/*!
- \fn template <class T> int QList<T>::size() const
-
- Returns the number of items in the list.
-
- \sa isEmpty(), count()
-*/
-
-/*! \fn template <class T> void QList<T>::detach()
-
- \internal
-*/
-
-/*! \fn template <class T> void QList<T>::detachShared()
-
- \internal
-
- like detach(), but does nothing if we're shared_null.
- This prevents needless mallocs, and makes QList more exception safe
- in case of cleanup work done in destructors on empty lists.
-*/
-
-/*! \fn template <class T> bool QList<T>::isDetached() const
-
- \internal
-*/
-
-/*! \fn template <class T> void QList<T>::setSharable(bool sharable)
-
- \internal
-*/
-
-/*! \fn template <class T> bool QList<T>::isSharedWith(const QList<T> &other) const
-
- \internal
-*/
-
-/*! \fn template <class T> bool QList<T>::isEmpty() const
-
- Returns \c true if the list contains no items; otherwise returns
- false.
-
- \sa size()
-*/
-
-/*! \fn template <class T> void QList<T>::clear()
-
- Removes all items from the list.
-
- \sa removeAll()
-*/
-
-/*! \fn template <class T> const T &QList<T>::at(int i) const
-
- Returns the item at index position \a i in the list. \a i must be
- a valid index position in the list (i.e., 0 <= \a i < size()).
-
- This function is very fast (\l{Algorithmic Complexity}{constant time}).
-
- \sa value(), operator[]()
-*/
-
-/*! \fn template <class T> T &QList<T>::operator[](int i)
-
- Returns the item at index position \a i as a modifiable reference.
- \a i must be a valid index position in the list (i.e., 0 <= \a i <
- size()).
-
- If this function is called on a list that is currently being shared, it
- will trigger a copy of all elements. Otherwise, this function runs in
- \l{Algorithmic Complexity}{constant time}. If you do not want to modify
- the list you should use QList::at().
-
- \sa at(), value()
-*/
-
-/*! \fn template <class T> const T &QList<T>::operator[](int i) const
-
- \overload
-
- Same as at(). This function runs in \l{Algorithmic Complexity}{constant time}.
-*/
-
-/*! \fn template <class T> void QList<T>::reserve(int alloc)
-
- Reserve space for \a alloc elements.
-
- If \a alloc is smaller than the current size of the list, nothing will happen.
-
- Use this function to avoid repetetive reallocation of QList's internal
- data if you can predict how many elements will be appended.
- Note that the reservation applies only to the internal pointer array.
-
- \since 4.7
-*/
-
-/*! \fn template <class T> void QList<T>::append(const T &value)
-
- Inserts \a value at the end of the list.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 6
-
- This is the same as list.insert(size(), \a value).
-
- If this list is not shared, this operation is typically
- very fast (amortized \l{Algorithmic Complexity}{constant time}),
- because QList preallocates extra space on both sides of its
- internal buffer to allow for fast growth at both ends of the list.
-
- \sa operator<<(), prepend(), insert()
-*/
-
-/*! \fn template <class T> void QList<T>::append(const QList<T> &value)
-
- \overload
-
- \since 4.5
-
- Appends the items of the \a value list to this list.
-
- \sa operator<<(), operator+=()
-*/
-
-/*! \fn template <class T> void QList<T>::prepend(const T &value)
-
- Inserts \a value at the beginning of the list.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 7
-
- This is the same as list.insert(0, \a value).
-
- If this list is not shared, this operation is typically
- very fast (amortized \l{Algorithmic Complexity}{constant time}),
- because QList preallocates extra space on both sides of its
- internal buffer to allow for fast growth at both ends of the list.
-
- \sa append(), insert()
-*/
-
-/*! \fn template <class T> void QList<T>::insert(int i, const T &value)
-
- Inserts \a value at index position \a i in the list.
-
- If \a i == 0, the value is prepended to the list. If \a i == size(),
- the value is appended to the list.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 8
-
- \sa append(), prepend(), replace(), removeAt()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::insert(iterator before, const T &value)
-
- \overload
-
- Inserts \a value in front of the item pointed to by the
- iterator \a before. Returns an iterator pointing at the inserted
- item. Note that the iterator passed to the function will be
- invalid after the call; the returned iterator should be used
- instead.
-*/
-
-/*! \fn template <class T> void QList<T>::replace(int i, const T &value)
-
- Replaces the item at index position \a i with \a value. \a i must
- be a valid index position in the list (i.e., 0 <= \a i < size()).
-
- \sa operator[](), removeAt()
-*/
-
-/*!
- \fn template <class T> int QList<T>::removeAll(const T &value)
-
- Removes all occurrences of \a value in the list and returns the
- number of entries removed.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 9
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa removeOne(), removeAt(), takeAt(), replace()
-*/
-
-/*!
- \fn template <class T> bool QList<T>::removeOne(const T &value)
- \since 4.4
-
- Removes the first occurrence of \a value in the list and returns
- true on success; otherwise returns \c false.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 10
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa removeAll(), removeAt(), takeAt(), replace()
-*/
-
-/*! \fn template <class T> void QList<T>::removeAt(int i)
-
- Removes the item at index position \a i. \a i must be a valid
- index position in the list (i.e., 0 <= \a i < size()).
-
- \sa takeAt(), removeFirst(), removeLast(), removeOne()
-*/
-
-/*! \fn template <class T> T QList<T>::takeAt(int i)
-
- Removes the item at index position \a i and returns it. \a i must
- be a valid index position in the list (i.e., 0 <= \a i < size()).
-
- If you don't use the return value, removeAt() is more efficient.
-
- \sa removeAt(), takeFirst(), takeLast()
-*/
-
-/*! \fn template <class T> T QList<T>::takeFirst()
-
- Removes the first item in the list and returns it. This is the
- same as takeAt(0). This function assumes the list is not empty. To
- avoid failure, call isEmpty() before calling this function.
-
- If this list is not shared, this operation takes
- \l {Algorithmic Complexity}{constant time}.
-
- If you don't use the return value, removeFirst() is more
- efficient.
-
- \sa takeLast(), takeAt(), removeFirst()
-*/
-
-/*! \fn template <class T> T QList<T>::takeLast()
-
- Removes the last item in the list and returns it. This is the
- same as takeAt(size() - 1). This function assumes the list is
- not empty. To avoid failure, call isEmpty() before calling this
- function.
-
- If this list is not shared, this operation takes
- \l {Algorithmic Complexity}{constant time}.
-
- If you don't use the return value, removeLast() is more
- efficient.
-
- \sa takeFirst(), takeAt(), removeLast()
-*/
-
-/*! \fn template <class T> void QList<T>::move(int from, int to)
-
- Moves the item at index position \a from to index position \a to.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 11
-
- This is the same as insert(\a{to}, takeAt(\a{from})).This function
- assumes that both \a from and \a to are at least 0 but less than
- size(). To avoid failure, test that both \a from and \a to are at
- least 0 and less than size().
-
- \sa swap(), insert(), takeAt()
-*/
-
-/*! \fn template <class T> void QList<T>::swap(int i, int j)
-
- \obsolete Use swapItemsAt()
-
- \sa move(), swapItemsAt()
-*/
-
-/*! \fn template <class T> void QList<T>::swapItemsAt(int i, int j)
- \since 5.13
-
- Exchange the item at index position \a i with the item at index
- position \a j. This function assumes that both \a i and \a j are
- at least 0 but less than size(). To avoid failure, test that both
- \a i and \a j are at least 0 and less than size().
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 12
-
- \sa move()
-*/
-
-/*! \fn template <class T> int QList<T>::indexOf(const T &value, int from = 0) const
-
- Returns the index position of the first occurrence of \a value in
- the list, searching forward from index position \a from. Returns
- -1 if no item matched.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 13
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- Note that QList uses 0-based indexes, just like C++ arrays. Negative
- indexes are not supported with the exception of the value mentioned
- above.
-
- \sa lastIndexOf(), contains()
-*/
-
-/*! \fn template <class T> int QList<T>::lastIndexOf(const T &value, int from = -1) const
-
- Returns the index position of the last occurrence of \a value in
- the list, searching backward from index position \a from. If \a
- from is -1 (the default), the search starts at the last item.
- Returns -1 if no item matched.
-
- Example:
- \snippet code/src_corelib_tools_qlistdata.cpp 14
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- Note that QList uses 0-based indexes, just like C++ arrays. Negative
- indexes are not supported with the exception of the value mentioned
- above.
-
- \sa indexOf()
-*/
-
-/*! \fn template <class T> bool QList<T>::contains(const T &value) const
-
- Returns \c true if the list contains an occurrence of \a value;
- otherwise returns \c false.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa indexOf(), count()
-*/
-
-/*! \fn template <class T> int QList<T>::count(const T &value) const
-
- Returns the number of occurrences of \a value in the list.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa contains(), indexOf()
-*/
-
-/*! \fn template <class T> bool QList<T>::startsWith(const T &value) const
- \since 4.5
-
- Returns \c true if this list is not empty and its first
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), contains()
-*/
-
-/*! \fn template <class T> bool QList<T>::endsWith(const T &value) const
- \since 4.5
-
- Returns \c true if this list is not empty and its last
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), contains()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::begin()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
- the list.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::begin() const
-
- \overload
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::cbegin() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
-
- \sa begin(), cend()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::constBegin() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::end()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
- after the last item in the list.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <class T> const_iterator QList<T>::end() const
-
- \overload
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::cend() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
-
- \sa cbegin(), end()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::constEnd() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <class T> QList<T>::reverse_iterator QList<T>::rbegin()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
-
- \sa begin(), crbegin(), rend()
-*/
-
-/*! \fn template <class T> QList<T>::const_reverse_iterator QList<T>::rbegin() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QList<T>::const_reverse_iterator QList<T>::crbegin() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
-
- \sa begin(), rbegin(), rend()
-*/
-
-/*! \fn template <class T> QList<T>::reverse_iterator QList<T>::rend()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last item in the list, in reverse order.
-
- \sa end(), crend(), rbegin()
-*/
-
-/*! \fn template <class T> QList<T>::const_reverse_iterator QList<T>::rend() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QList<T>::const_reverse_iterator QList<T>::crend() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last item in the list, in reverse order.
-
- \sa end(), rend(), rbegin()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::erase(iterator pos)
-
- Removes the item associated with the iterator \a pos from the
- list, and returns an iterator to the next item in the list (which
- may be end()).
-
- \sa insert(), removeAt()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::erase(iterator begin, iterator end)
-
- \overload
-
- Removes all the items from \a begin up to (but not including) \a
- end. Returns an iterator to the same item that \a end referred to
- before the call.
-*/
-
-/*! \typedef QList::Iterator
-
- Qt-style synonym for QList::iterator.
-*/
-
-/*! \typedef QList::ConstIterator
-
- Qt-style synonym for QList::const_iterator.
-*/
-
-/*!
- \typedef QList::size_type
-
- Typedef for int. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QList::value_type
-
- Typedef for T. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QList::difference_type
-
- Typedef for ptrdiff_t. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QList::pointer
-
- Typedef for T *. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QList::const_pointer
-
- Typedef for const T *. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QList::reference
-
- Typedef for T &. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QList::const_reference
-
- Typedef for const T &. Provided for STL compatibility.
-*/
-
-/*! \typedef QList::reverse_iterator
- \since 5.6
-
- The QList::reverse_iterator typedef provides an STL-style non-const
- reverse iterator for QList.
-
- It is simply a typedef for \c{std::reverse_iterator<iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QList::rbegin(), QList::rend(), QList::const_reverse_iterator, QList::iterator
-*/
-
-/*! \typedef QList::const_reverse_iterator
- \since 5.6
-
- The QList::const_reverse_iterator typedef provides an STL-style const
- reverse iterator for QList.
-
- It is simply a typedef for \c{std::reverse_iterator<const_iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QList::rbegin(), QList::rend(), QList::reverse_iterator, QList::const_iterator
-*/
-
-/*! \fn template <class T> int QList<T>::count() const
-
- Returns the number of items in the list. This is effectively the
- same as size().
-*/
-
-/*! \fn template <class T> int QList<T>::length() const
- \since 4.5
-
- This function is identical to count().
-
- \sa count()
-*/
-
-/*! \fn template <class T> T& QList<T>::first()
-
- Returns a reference to the first item in the list. The list must
- not be empty. If the list can be empty, call isEmpty() before
- calling this function.
-
- \sa constFirst(), last(), isEmpty()
-*/
-
-/*! \fn template <class T> const T& QList<T>::first() const
-
- \overload
-*/
-
-/*! \fn template <class T> const T& QList<T>::constFirst() const
- \since 5.6
-
- Returns a const reference to the first item in the list. The list must
- not be empty. If the list can be empty, call isEmpty() before
- calling this function.
-
- \sa constLast(), isEmpty(), first()
-*/
-
-/*! \fn template <class T> T& QList<T>::last()
-
- Returns a reference to the last item in the list. The list must
- not be empty. If the list can be empty, call isEmpty() before
- calling this function.
-
- \sa constLast(), first(), isEmpty()
-*/
-
-/*! \fn template <class T> const T& QList<T>::last() const
-
- \overload
-*/
-
-/*! \fn template <class T> const T& QList<T>::constLast() const
- \since 5.6
-
- Returns a reference to the last item in the list. The list must
- not be empty. If the list can be empty, call isEmpty() before
- calling this function.
-
- \sa constFirst(), isEmpty(), last()
-*/
-
-/*! \fn template <class T> void QList<T>::removeFirst()
-
- Removes the first item in the list. Calling this function is
- equivalent to calling removeAt(0). The list must not be empty. If
- the list can be empty, call isEmpty() before calling this
- function.
-
- \sa removeAt(), takeFirst()
-*/
-
-/*! \fn template <class T> void QList<T>::removeLast()
-
- Removes the last item in the list. Calling this function is
- equivalent to calling removeAt(size() - 1). The list must not be
- empty. If the list can be empty, call isEmpty() before calling
- this function.
-
- \sa removeAt(), takeLast()
-*/
-
-/*! \fn template <class T> T QList<T>::value(int i) const
-
- Returns the value at index position \a i in the list.
-
- If the index \a i is out of bounds, the function returns a
- \l{default-constructed value}. If you are certain that the index
- is going to be within bounds, you can use at() instead, which is
- slightly faster.
-
- \sa at(), operator[]()
-*/
-
-/*! \fn template <class T> T QList<T>::value(int i, const T &defaultValue) const
-
- \overload
-
- If the index \a i is out of bounds, the function returns
- \a defaultValue.
-*/
-
-/*! \fn template <class T> void QList<T>::push_back(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to \l{QList::append()}{append(\a value)}.
-*/
-
-/*! \fn template <class T> void QList<T>::push_front(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to \l{QList::prepend()}{prepend(\a value)}.
-*/
-
-/*! \fn template <class T> T& QList<T>::front()
-
- This function is provided for STL compatibility. It is equivalent
- to first(). The list must not be empty. If the list can be empty,
- call isEmpty() before calling this function.
-*/
-
-/*! \fn template <class T> const T& QList<T>::front() const
-
- \overload
-*/
-
-/*! \fn template <class T> T& QList<T>::back()
-
- This function is provided for STL compatibility. It is equivalent
- to last(). The list must not be empty. If the list can be empty,
- call isEmpty() before calling this function.
-*/
-
-/*! \fn template <class T> const T& QList<T>::back() const
-
- \overload
-*/
-
-/*! \fn template <class T> void QList<T>::pop_front()
-
- This function is provided for STL compatibility. It is equivalent
- to removeFirst(). The list must not be empty. If the list can be
- empty, call isEmpty() before calling this function.
-*/
-
-/*! \fn template <class T> void QList<T>::pop_back()
-
- This function is provided for STL compatibility. It is equivalent
- to removeLast(). The list must not be empty. If the list can be
- empty, call isEmpty() before calling this function.
-*/
-
-/*! \fn template <class T> bool QList<T>::empty() const
-
- This function is provided for STL compatibility. It is equivalent
- to isEmpty() and returns \c true if the list is empty.
-*/
-
-/*! \fn template <class T> QList<T> &QList<T>::operator+=(const QList<T> &other)
-
- Appends the items of the \a other list to this list and returns a
- reference to this list.
-
- \sa operator+(), append()
-*/
-
-/*! \fn template <class T> void QList<T>::operator+=(const T &value)
-
- \overload
-
- Appends \a value to the list.
-
- \sa append(), operator<<()
-*/
-
-/*! \fn template <class T> QList<T> QList<T>::operator+(const QList<T> &other) const
-
- Returns a list that contains all the items in this list followed
- by all the items in the \a other list.
-
- \sa operator+=()
-*/
-
-/*! \fn template <class T> QList<T> &QList<T>::operator<<(const QList<T> &other)
-
- Appends the items of the \a other list to this list and returns a
- reference to this list.
-
- \sa operator+=(), append()
-*/
-
-/*! \fn template <class T> void QList<T>::operator<<(const T &value)
-
- \overload
-
- Appends \a value to the list.
-*/
-
-/*! \class QList::iterator
- \inmodule QtCore
- \brief The QList::iterator class provides an STL-style non-const iterator for QList and QQueue.
-
- QList features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
- QList\<T\>::iterator allows you to iterate over a QList\<T\> (or
- QQueue\<T\>) and to modify the list item associated with the
- iterator. If you want to iterate over a const QList, use
- QList::const_iterator instead. It is generally good practice to
- use QList::const_iterator on a non-const QList as well, unless
- you need to change the QList through the iterator. Const
- iterators are slightly faster, and can improve code readability.
-
- The default QList::iterator constructor creates an uninitialized
- iterator. You must initialize it using a QList function like
- QList::begin(), QList::end(), or QList::insert() before you can
- start iterating. Here's a typical loop that prints all the items
- stored in a list:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 15
-
- Let's see a few examples of things we can do with a
- QList::iterator that we cannot do with a QList::const_iterator.
- Here's an example that increments every value stored in a
- QList\<int\> by 2:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 16
-
- Most QList functions accept an integer index rather than an
- iterator. For that reason, iterators are rarely useful in
- connection with QList. One place where STL-style iterators do
- make sense is as arguments to \l{generic algorithms}.
-
- For example, here's how to delete all the widgets stored in a
- QList\<QWidget *\>:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 17
-
- Multiple iterators can be used on the same list. However, be
- aware that any non-const function call performed on the QList
- will render all existing iterators undefined. If you need to keep
- iterators over a long period of time, we recommend that you use
- QLinkedList rather than QList.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QList::const_iterator, QMutableListIterator
-*/
-
-/*! \typedef QList::iterator::iterator_category
-
- A synonym for \e {std::random_access_iterator_tag} indicating
- this iterator is a random access iterator.
-*/
-
-/*! \typedef QList::iterator::difference_type
-
- \internal
-*/
-
-/*! \typedef QList::iterator::value_type
-
- \internal
-*/
-
-/*! \typedef QList::iterator::pointer
-
- \internal
-*/
-
-/*! \typedef QList::iterator::reference
-
- \internal
-*/
-
-/*! \fn template <class T> QList<T>::iterator::iterator()
-
- Constructs an uninitialized iterator.
-
- Functions like operator*() and operator++() should not be called
- on an uninitialized iterator. Use operator=() to assign a value
- to it before using it.
-
- \sa QList::begin(), QList::end()
-*/
-
-/*! \fn template <class T> QList<T>::iterator::iterator(Node *node)
-
- \internal
-*/
-
-/*! \fn template <class T> QList<T>::iterator::iterator(const iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> T &QList<T>::iterator::operator*() const
-
- Returns a modifiable reference to the current item.
-
- You can change the value of an item by using operator*() on the
- left side of an assignment, for example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 18
-
- \sa operator->()
-*/
-
-/*! \fn template <class T> T *QList<T>::iterator::operator->() const
-
- Returns a pointer to the current item.
-
- \sa operator*()
-*/
-
-/*! \fn template <class T> T &QList<T>::iterator::operator[](difference_type j) const
-
- Returns a modifiable reference to the item at position *this +
- \a{j}.
-
- This function is provided to make QList iterators behave like C++
- pointers.
-
- \sa operator+()
-*/
-
-/*!
- \fn template <class T> bool QList<T>::iterator::operator==(const iterator &other) const
- \fn template <class T> bool QList<T>::iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*!
- \fn template <class T> bool QList<T>::iterator::operator!=(const iterator &other) const
- \fn template <class T> bool QList<T>::iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
-/*!
- \fn template <class T> bool QList<T>::iterator::operator<(const iterator& other) const
- \fn template <class T> bool QList<T>::iterator::operator<(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
-*/
-
-/*!
- \fn template <class T> bool QList<T>::iterator::operator<=(const iterator& other) const
- \fn template <class T> bool QList<T>::iterator::operator<=(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
-*/
-
-/*!
- \fn template <class T> bool QList<T>::iterator::operator>(const iterator& other) const
- \fn template <class T> bool QList<T>::iterator::operator>(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
-*/
-
-/*!
- \fn template <class T> bool QList<T>::iterator::operator>=(const iterator& other) const
- \fn template <class T> bool QList<T>::iterator::operator>=(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
-*/
-
-/*! \fn template <class T> QList<T>::iterator &QList<T>::iterator::operator++()
-
- The prefix ++ operator (\c{++it}) advances the iterator to the
- next item in the list and returns an iterator to the new current
- item.
-
- Calling this function on QList::end() leads to undefined results.
-
- \sa operator--()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::iterator::operator++(int)
-
- \overload
-
- The postfix ++ operator (\c{it++}) advances the iterator to the
- next item in the list and returns an iterator to the previously
- current item.
-*/
-
-/*! \fn template <class T> QList<T>::iterator &QList<T>::iterator::operator--()
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QList::begin() leads to undefined results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*! \fn template <class T> QList<T>::iterator &QList<T>::iterator::operator+=(difference_type j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class T> QList<T>::iterator &QList<T>::iterator::operator-=(difference_type j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::iterator::operator+(difference_type j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- \sa operator-(), operator+=()
-*/
-
-/*! \fn template <class T> QList<T>::iterator QList<T>::iterator::operator-(difference_type j) const
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- \sa operator+(), operator-=()
-*/
-
-/*! \fn template <class T> int QList<T>::iterator::operator-(iterator other) const
-
- Returns the number of items between the item pointed to by \a
- other and the item pointed to by this iterator.
-*/
-
-/*! \class QList::const_iterator
- \inmodule QtCore
- \brief The QList::const_iterator class provides an STL-style const iterator for QList and QQueue.
-
- QList provides both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
- QList\<T\>::const_iterator allows you to iterate over a
- QList\<T\> (or a QQueue\<T\>). If you want to modify the QList as
- you iterate over it, use QList::iterator instead. It is generally
- good practice to use QList::const_iterator on a non-const QList
- as well, unless you need to change the QList through the
- iterator. Const iterators are slightly faster, and can improve
- code readability.
-
- The default QList::const_iterator constructor creates an
- uninitialized iterator. You must initialize it using a QList
- function like QList::constBegin(), QList::constEnd(), or
- QList::insert() before you can start iterating. Here's a typical
- loop that prints all the items stored in a list:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 19
-
- Most QList functions accept an integer index rather than an
- iterator. For that reason, iterators are rarely useful in
- connection with QList. One place where STL-style iterators do
- make sense is as arguments to \l{generic algorithms}.
-
- For example, here's how to delete all the widgets stored in a
- QList\<QWidget *\>:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 20
-
- Multiple iterators can be used on the same list. However, be
- aware that any non-const function call performed on the QList
- will render all existing iterators undefined. If you need to keep
- iterators over a long period of time, we recommend that you use
- QLinkedList rather than QList.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QList::iterator, QListIterator
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator::const_iterator()
-
- Constructs an uninitialized iterator.
-
- Functions like operator*() and operator++() should not be called
- on an uninitialized iterator. Use operator=() to assign a value
- to it before using it.
-
- \sa QList::constBegin(), QList::constEnd()
-*/
-
-/*! \typedef QList::const_iterator::iterator_category
-
- A synonym for \e {std::random_access_iterator_tag} indicating
- this iterator is a random access iterator.
-*/
-
-/*! \typedef QList::const_iterator::difference_type
-
- \internal
-*/
-
-/*! \typedef QList::const_iterator::value_type
-
- \internal
-*/
-
-/*! \typedef QList::const_iterator::pointer
-
- \internal
-*/
-
-/*! \typedef QList::const_iterator::reference
-
- \internal
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator::const_iterator(Node *node)
-
- \internal
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator::const_iterator(const const_iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator::const_iterator(const iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> const T &QList<T>::const_iterator::operator*() const
-
- Returns the current item.
-
- \sa operator->()
-*/
-
-/*! \fn template <class T> const T *QList<T>::const_iterator::operator->() const
-
- Returns a pointer to the current item.
-
- \sa operator*()
-*/
-
-/*! \fn template <class T> const T &QList<T>::const_iterator::operator[](difference_type j) const
-
- Returns the item at position *this + \a{j}.
-
- This function is provided to make QList iterators behave like C++
- pointers.
-
- \sa operator+()
-*/
-
-/*! \fn template <class T> bool QList<T>::const_iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*! \fn template <class T> bool QList<T>::const_iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
-/*!
- \fn template <class T> bool QList<T>::const_iterator::operator<(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
-*/
-
-/*!
- \fn template <class T> bool QList<T>::const_iterator::operator<=(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
-*/
-
-/*!
- \fn template <class T> bool QList<T>::const_iterator::operator>(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
-*/
-
-/*!
- \fn template <class T> bool QList<T>::const_iterator::operator>=(const const_iterator& other) const
-
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator &QList<T>::const_iterator::operator++()
-
- The prefix ++ operator (\c{++it}) advances the iterator to the
- next item in the list and returns an iterator to the new current
- item.
-
- Calling this function on QList::end() leads to undefined results.
-
- \sa operator--()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::const_iterator::operator++(int)
-
- \overload
-
- The postfix ++ operator (\c{it++}) advances the iterator to the
- next item in the list and returns an iterator to the previously
- current item.
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator &QList<T>::const_iterator::operator--()
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QList::begin() leads to undefined results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::const_iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator &QList<T>::const_iterator::operator+=(difference_type j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator &QList<T>::const_iterator::operator-=(difference_type j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::const_iterator::operator+(difference_type j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- \sa operator-(), operator+=()
-*/
-
-/*! \fn template <class T> QList<T>::const_iterator QList<T>::const_iterator::operator-(difference_type j) const
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- \sa operator+(), operator-=()
-*/
-
-/*! \fn template <class T> int QList<T>::const_iterator::operator-(const_iterator other) const
-
- Returns the number of items between the item pointed to by \a
- other and the item pointed to by this iterator.
-*/
-
-/*! \fn template <class T> QDataStream &operator<<(QDataStream &out, const QList<T> &list)
- \relates QList
-
- Writes the list \a list to stream \a out.
-
- This function requires the value type to implement \c
- operator<<().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*! \fn template <class T> QDataStream &operator>>(QDataStream &in, QList<T> &list)
- \relates QList
-
- Reads a list from stream \a in into \a list.
-
- This function requires the value type to implement \c
- operator>>().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*! \fn template <class T> QList<T> QList<T>::fromVector(const QVector<T> &vector)
-
- Returns a QList object with the data contained in \a vector.
-
- Example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 21
-
- \include containers-range-constructor.qdocinc
-
- \sa fromSet(), toVector(), QVector::toList()
-*/
-
-/*! \fn template <class T> QVector<T> QList<T>::toVector() const
-
- Returns a QVector object with the data contained in this QList.
-
- Example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 22
-
- \include containers-range-constructor.qdocinc
-
- \sa toSet(), fromVector(), QVector::fromList()
-*/
-
-/*! \fn template <class T> QList<T> QList<T>::fromSet(const QSet<T> &set)
-
- Returns a QList object with the data contained in \a set. The
- order of the elements in the QList is undefined.
-
- Example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 23
-
- \include containers-range-constructor.qdocinc
-
- \sa fromVector(), toSet(), QSet::toList()
-*/
-
-/*! \fn template <class T> QSet<T> QList<T>::toSet() const
-
- Returns a QSet object with the data contained in this QList.
- Since QSet doesn't allow duplicates, the resulting QSet might be
- smaller than the original list was.
-
- Example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 24
-
- \include containers-range-constructor.qdocinc
-
- \sa toVector(), fromSet(), QSet::fromList()
-*/
-
-/*! \fn template <class T> QList<T> QList<T>::fromStdList(const std::list<T> &list)
-
- Returns a QList object with the data contained in \a list. The
- order of the elements in the QList is the same as in \a list.
-
- Example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 25
-
- \include containers-range-constructor.qdocinc
-
- \sa toStdList(), QVector::fromStdVector()
-*/
-
-/*! \fn template <class T> std::list<T> QList<T>::toStdList() const
-
- Returns a std::list object with the data contained in this QList.
- Example:
-
- \snippet code/src_corelib_tools_qlistdata.cpp 26
-
- \include containers-range-constructor.qdocinc
-
- \sa fromStdList(), QVector::toStdVector()
-*/
-
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 8a11663c01..515fba6530 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -40,1163 +40,19 @@
#ifndef QLIST_H
#define QLIST_H
-#include <QtCore/qalgorithms.h>
-#include <QtCore/qiterator.h>
-#include <QtCore/qrefcount.h>
-#include <QtCore/qarraydata.h>
-#include <QtCore/qhashfunctions.h>
#include <QtCore/qvector.h>
-#include <QtCore/qcontainertools_impl.h>
-
-#include <algorithm>
-#include <initializer_list>
-#include <iterator>
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
-#include <list>
-#endif
-
-#include <stdlib.h>
-#include <new>
-#include <limits.h>
-#include <string.h>
-
-#ifdef Q_CC_MSVC
-#pragma warning( push )
-#pragma warning( disable : 4127 ) // "conditional expression is constant"
-#endif
+#include <QtCore/qcontainerfwd.h>
+#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
QT_BEGIN_NAMESPACE
-
-
-template <typename T> class QVector;
-template <typename T> class QSet;
-
-template <typename T> struct QListSpecialMethods
-{
-protected:
- ~QListSpecialMethods() = default;
-};
-template <> struct QListSpecialMethods<QByteArray>;
-template <> struct QListSpecialMethods<QString>;
-
-struct Q_CORE_EXPORT QListData {
- // tags for tag-dispatching of QList implementations,
- // based on QList's three different memory layouts:
- struct NotArrayCompatibleLayout {};
- struct NotIndirectLayout {};
- struct ArrayCompatibleLayout : NotIndirectLayout {}; // data laid out like a C array
- struct InlineWithPaddingLayout : NotArrayCompatibleLayout, NotIndirectLayout {}; // data laid out like a C array with padding
- struct IndirectLayout : NotArrayCompatibleLayout {}; // data allocated on the heap
-
- struct Data {
- QtPrivate::RefCount ref;
- int alloc, begin, end;
- void *array[1];
- };
- enum { DataHeaderSize = sizeof(Data) - sizeof(void *) };
-
- Data *detach(int alloc);
- Data *detach_grow(int *i, int n);
- void realloc(int alloc);
- void realloc_grow(int growth);
- inline void dispose() { dispose(d); }
- static void dispose(Data *d);
- static const Data shared_null;
- Data *d;
- void **erase(void **xi);
- void **append(int n);
- void **append();
- void **append(const QListData &l);
- void **prepend();
- void **insert(int i);
- void remove(int i);
- void remove(int i, int n);
- void move(int from, int to);
- inline int size() const noexcept { return int(d->end - d->begin); } // q6sizetype
- inline bool isEmpty() const noexcept { return d->end == d->begin; }
- inline void **at(int i) const noexcept { return d->array + d->begin + i; }
- inline void **begin() const noexcept { return d->array + d->begin; }
- inline void **end() const noexcept { return d->array + d->end; }
-};
-
-namespace QtPrivate {
- template <typename V, typename U> int indexOf(const QList<V> &list, const U &u, int from);
- template <typename V, typename U> int lastIndexOf(const QList<V> &list, const U &u, int from);
-}
-
-template <typename T>
-class QList
-#ifndef Q_QDOC
- : public QListSpecialMethods<T>
-#endif
-{
-public:
- struct MemoryLayout
- : std::conditional<
- // must stay isStatic until ### Qt 6 for BC reasons (don't use !isRelocatable)!
- QTypeInfo<T>::isStatic || QTypeInfo<T>::isLarge,
- QListData::IndirectLayout,
- typename std::conditional<
- sizeof(T) == sizeof(void*),
- QListData::ArrayCompatibleLayout,
- QListData::InlineWithPaddingLayout
- >::type>::type {};
-private:
- template <typename V, typename U> friend int QtPrivate::indexOf(const QList<V> &list, const U &u, int from);
- template <typename V, typename U> friend int QtPrivate::lastIndexOf(const QList<V> &list, const U &u, int from);
- struct Node { void *v;
-#if defined(Q_CC_BOR)
- Q_INLINE_TEMPLATE T &t();
-#else
- Q_INLINE_TEMPLATE T &t()
- { return *reinterpret_cast<T*>(QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
- ? v : this); }
-#endif
- };
-
- union { QListData p; QListData::Data *d; };
-
-public:
- inline QList() noexcept : d(const_cast<QListData::Data *>(&QListData::shared_null)) { }
- QList(const QList<T> &l);
- ~QList();
- QList<T> &operator=(const QList<T> &l);
- inline QList(QList<T> &&other) noexcept
- : d(other.d) { other.d = const_cast<QListData::Data *>(&QListData::shared_null); }
- inline QList &operator=(QList<T> &&other) noexcept
- { QList moved(std::move(other)); swap(moved); return *this; }
- inline void swap(QList<T> &other) noexcept { qSwap(d, other.d); }
- inline QList(std::initializer_list<T> args)
- : QList(args.begin(), args.end()) {}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
- QList(InputIterator first, InputIterator last);
- bool operator==(const QList<T> &l) const;
- inline bool operator!=(const QList<T> &l) const { return !(*this == l); }
-
- inline int size() const noexcept { return p.size(); }
-
- inline void detach() { if (d->ref.isShared()) detach_helper(); }
-
- inline void detachShared()
- {
- // The "this->" qualification is needed for GCCE.
- if (d->ref.isShared() && this->d != &QListData::shared_null)
- detach_helper();
- }
-
- inline bool isDetached() const { return !d->ref.isShared(); }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable)
- {
- if (sharable == d->ref.isSharable())
- return;
- if (!sharable)
- detach();
- if (d != &QListData::shared_null)
- d->ref.setSharable(sharable);
- }
-#endif
- inline bool isSharedWith(const QList<T> &other) const noexcept { return d == other.d; }
-
- inline bool isEmpty() const noexcept { return p.isEmpty(); }
-
- void clear();
-
- const T &at(int i) const;
- const T &operator[](int i) const;
- T &operator[](int i);
-
- void reserve(int size);
- void append(const T &t);
- void append(const QList<T> &t);
- void prepend(const T &t);
- void insert(int i, const T &t);
- void replace(int i, const T &t);
- void removeAt(int i);
- int removeAll(const T &t);
- bool removeOne(const T &t);
- T takeAt(int i);
- T takeFirst();
- T takeLast();
- void move(int from, int to);
- void swapItemsAt(int i, int j);
-#if QT_DEPRECATED_SINCE(5, 13) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
- QT_DEPRECATED_X("Use QList<T>::swapItemsAt()")
- void swap(int i, int j) { swapItemsAt(i, j); }
-#endif
- int indexOf(const T &t, int from = 0) const;
- int lastIndexOf(const T &t, int from = -1) const;
- bool contains(const T &t) const;
- int count(const T &t) const;
-
- class const_iterator;
-
- class iterator {
- public:
- Node *i;
- typedef std::random_access_iterator_tag iterator_category;
- // ### Qt6: use int
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
-
- inline iterator() noexcept : i(nullptr) {}
- inline iterator(Node *n) noexcept : i(n) {}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- // can't remove it in Qt 5, since doing so would make the type trivial,
- // which changes the way it's passed to functions by value.
- inline iterator(const iterator &o) noexcept : i(o.i){}
- inline iterator &operator=(const iterator &o) noexcept
- { i = o.i; return *this; }
-#endif
- inline T &operator*() const { return i->t(); }
- inline T *operator->() const { return &i->t(); }
- inline T &operator[](difference_type j) const { return i[j].t(); }
- inline bool operator==(const iterator &o) const noexcept { return i == o.i; }
- inline bool operator!=(const iterator &o) const noexcept { return i != o.i; }
- inline bool operator<(const iterator& other) const noexcept { return i < other.i; }
- inline bool operator<=(const iterator& other) const noexcept { return i <= other.i; }
- inline bool operator>(const iterator& other) const noexcept { return i > other.i; }
- inline bool operator>=(const iterator& other) const noexcept { return i >= other.i; }
-#ifndef QT_STRICT_ITERATORS
- inline bool operator==(const const_iterator &o) const noexcept
- { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const noexcept
- { return i != o.i; }
- inline bool operator<(const const_iterator& other) const noexcept
- { return i < other.i; }
- inline bool operator<=(const const_iterator& other) const noexcept
- { return i <= other.i; }
- inline bool operator>(const const_iterator& other) const noexcept
- { return i > other.i; }
- inline bool operator>=(const const_iterator& other) const noexcept
- { return i >= other.i; }
-#endif
- inline iterator &operator++() { ++i; return *this; }
- inline iterator operator++(int) { Node *n = i; ++i; return n; }
- inline iterator &operator--() { i--; return *this; }
- inline iterator operator--(int) { Node *n = i; i--; return n; }
- inline iterator &operator+=(difference_type j) { i+=j; return *this; }
- inline iterator &operator-=(difference_type j) { i-=j; return *this; }
- inline iterator operator+(difference_type j) const { return iterator(i+j); }
- inline iterator operator-(difference_type j) const { return iterator(i-j); }
- friend inline iterator operator+(difference_type j, iterator k) { return k + j; }
- inline int operator-(iterator j) const { return int(i - j.i); }
- };
- friend class iterator;
-
- class const_iterator {
- public:
- Node *i;
- typedef std::random_access_iterator_tag iterator_category;
- // ### Qt6: use int
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
-
- inline const_iterator() noexcept : i(nullptr) {}
- inline const_iterator(Node *n) noexcept : i(n) {}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- // can't remove it in Qt 5, since doing so would make the type trivial,
- // which changes the way it's passed to functions by value.
- inline const_iterator(const const_iterator &o) noexcept : i(o.i) {}
- inline const_iterator &operator=(const const_iterator &o) noexcept
- { i = o.i; return *this; }
-#endif
-#ifdef QT_STRICT_ITERATORS
- inline explicit const_iterator(const iterator &o) noexcept : i(o.i) {}
-#else
- inline const_iterator(const iterator &o) noexcept : i(o.i) {}
-#endif
- inline const T &operator*() const { return i->t(); }
- inline const T *operator->() const { return &i->t(); }
- inline const T &operator[](difference_type j) const { return i[j].t(); }
- inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
- inline bool operator<(const const_iterator& other) const noexcept { return i < other.i; }
- inline bool operator<=(const const_iterator& other) const noexcept { return i <= other.i; }
- inline bool operator>(const const_iterator& other) const noexcept { return i > other.i; }
- inline bool operator>=(const const_iterator& other) const noexcept { return i >= other.i; }
- inline const_iterator &operator++() { ++i; return *this; }
- inline const_iterator operator++(int) { Node *n = i; ++i; return n; }
- inline const_iterator &operator--() { i--; return *this; }
- inline const_iterator operator--(int) { Node *n = i; i--; return n; }
- inline const_iterator &operator+=(difference_type j) { i+=j; return *this; }
- inline const_iterator &operator-=(difference_type j) { i-=j; return *this; }
- inline const_iterator operator+(difference_type j) const { return const_iterator(i+j); }
- inline const_iterator operator-(difference_type j) const { return const_iterator(i-j); }
- friend inline const_iterator operator+(difference_type j, const_iterator k) { return k + j; }
- inline int operator-(const_iterator j) const { return int(i - j.i); }
- };
- friend class const_iterator;
-
- // stl style
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- inline iterator begin() { detach(); return reinterpret_cast<Node *>(p.begin()); }
- inline const_iterator begin() const noexcept { return reinterpret_cast<Node *>(p.begin()); }
- inline const_iterator cbegin() const noexcept { return reinterpret_cast<Node *>(p.begin()); }
- inline const_iterator constBegin() const noexcept { return reinterpret_cast<Node *>(p.begin()); }
- inline iterator end() { detach(); return reinterpret_cast<Node *>(p.end()); }
- inline const_iterator end() const noexcept { return reinterpret_cast<Node *>(p.end()); }
- inline const_iterator cend() const noexcept { return reinterpret_cast<Node *>(p.end()); }
- inline const_iterator constEnd() const noexcept { return reinterpret_cast<Node *>(p.end()); }
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
- const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
- iterator insert(iterator before, const T &t);
- iterator erase(iterator pos);
- iterator erase(iterator first, iterator last);
-
- // more Qt
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- inline int count() const { return p.size(); }
- inline int length() const { return p.size(); } // Same as count()
- inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T& constFirst() const { return first(); }
- inline const T& first() const { Q_ASSERT(!isEmpty()); return at(0); }
- T& last() { Q_ASSERT(!isEmpty()); return *(--end()); }
- const T& last() const { Q_ASSERT(!isEmpty()); return at(count() - 1); }
- inline const T& constLast() const { return last(); }
- inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(begin()); }
- inline void removeLast() { Q_ASSERT(!isEmpty()); erase(--end()); }
- inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
- inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
- QList<T> mid(int pos, int length = -1) const;
-
- T value(int i) const;
- T value(int i, const T &defaultValue) const;
-
- // stl compatibility
- inline void push_back(const T &t) { append(t); }
- inline void push_front(const T &t) { prepend(t); }
- inline T& front() { return first(); }
- inline const T& front() const { return first(); }
- inline T& back() { return last(); }
- inline const T& back() const { return last(); }
- inline void pop_front() { removeFirst(); }
- inline void pop_back() { removeLast(); }
- inline bool empty() const { return isEmpty(); }
- typedef int size_type;
- typedef T value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef value_type &reference;
- typedef const value_type &const_reference;
- // ### Qt6: use int
- typedef qptrdiff difference_type;
-
- // comfort
- QList<T> &operator+=(const QList<T> &l);
- inline QList<T> operator+(const QList<T> &l) const
- { QList n = *this; n += l; return n; }
- inline QList<T> &operator+=(const T &t)
- { append(t); return *this; }
- inline QList<T> &operator<< (const T &t)
- { append(t); return *this; }
- inline QList<T> &operator<<(const QList<T> &l)
- { *this += l; return *this; }
-
- static QList<T> fromVector(const QVector<T> &vector);
- QVector<T> toVector() const;
-
-#if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
- QT_DEPRECATED_X("Use QList<T>(set.begin(), set.end()) instead.")
- static QList<T> fromSet(const QSet<T> &set);
- QT_DEPRECATED_X("Use QSet<T>(list.begin(), list.end()) instead.")
- QSet<T> toSet() const;
-
- QT_DEPRECATED_X("Use QList<T>(list.begin(), list.end()) instead.")
- static inline QList<T> fromStdList(const std::list<T> &list)
- { return QList<T>(list.begin(), list.end()); }
- QT_DEPRECATED_X("Use std::list<T>(list.begin(), list.end()) instead.")
- inline std::list<T> toStdList() const
- { return std::list<T>(begin(), end()); }
-#endif
-
-private:
- Node *detach_helper_grow(int i, int n);
- void detach_helper(int alloc);
- void detach_helper();
- void dealloc(QListData::Data *d);
-
- void node_construct(Node *n, const T &t);
- void node_destruct(Node *n);
- void node_copy(Node *from, Node *to, Node *src);
- void node_destruct(Node *from, Node *to);
-
- bool isValidIterator(const iterator &i) const noexcept
- {
- const std::less<const Node *> less = {};
- return !less(i.i, cbegin().i) && !less(cend().i, i.i);
- }
-
-private:
- inline bool op_eq_impl(const QList &other, QListData::NotArrayCompatibleLayout) const;
- inline bool op_eq_impl(const QList &other, QListData::ArrayCompatibleLayout) const;
- inline bool contains_impl(const T &, QListData::NotArrayCompatibleLayout) const;
- inline bool contains_impl(const T &, QListData::ArrayCompatibleLayout) const;
- inline int count_impl(const T &, QListData::NotArrayCompatibleLayout) const;
- inline int count_impl(const T &, QListData::ArrayCompatibleLayout) const;
-};
-
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
-template <typename InputIterator,
- typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
- QtPrivate::IfIsInputIterator<InputIterator> = true>
-QList(InputIterator, InputIterator) -> QList<ValueType>;
-#endif
-
-#if defined(Q_CC_BOR)
-template <typename T>
-Q_INLINE_TEMPLATE T &QList<T>::Node::t()
-{ return QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic ? *(T*)v:*(T*)this; }
-#endif
-
-template <typename T>
-Q_INLINE_TEMPLATE void QList<T>::node_construct(Node *n, const T &t)
-{
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) n->v = new T(t);
- else if (QTypeInfo<T>::isComplex) new (n) T(t);
-#if (defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__IBMCPP__)) && !defined(__OPTIMIZE__)
- // This violates pointer aliasing rules, but it is known to be safe (and silent)
- // in unoptimized GCC builds (-fno-strict-aliasing). The other compilers which
- // set the same define are assumed to be safe.
- else *reinterpret_cast<T*>(n) = t;
-#else
- // This is always safe, but penaltizes unoptimized builds a lot.
- else ::memcpy(n, static_cast<const void *>(&t), sizeof(T));
-#endif
-}
-
-template <typename T>
-Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *n)
-{
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) delete reinterpret_cast<T*>(n->v);
- else if (QTypeInfo<T>::isComplex) reinterpret_cast<T*>(n)->~T();
-}
-
-template <typename T>
-Q_INLINE_TEMPLATE void QList<T>::node_copy(Node *from, Node *to, Node *src)
-{
- Node *current = from;
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- QT_TRY {
- while(current != to) {
- current->v = new T(*reinterpret_cast<T*>(src->v));
- ++current;
- ++src;
- }
- } QT_CATCH(...) {
- while (current-- != from)
- delete reinterpret_cast<T*>(current->v);
- QT_RETHROW;
- }
-
- } else if (QTypeInfo<T>::isComplex) {
- QT_TRY {
- while(current != to) {
- new (current) T(*reinterpret_cast<T*>(src));
- ++current;
- ++src;
- }
- } QT_CATCH(...) {
- while (current-- != from)
- (reinterpret_cast<T*>(current))->~T();
- QT_RETHROW;
- }
- } else {
- if (src != from && to - from > 0)
- memcpy(from, src, (to - from) * sizeof(Node));
- }
-}
-
-template <typename T>
-Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *from, Node *to)
-{
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
- while(from != to) --to, delete reinterpret_cast<T*>(to->v);
- else if (QTypeInfo<T>::isComplex)
- while (from != to) --to, reinterpret_cast<T*>(to)->~T();
-}
-
-template <typename T>
-Q_INLINE_TEMPLATE QList<T> &QList<T>::operator=(const QList<T> &l)
-{
- if (d != l.d) {
- QList<T> tmp(l);
- tmp.swap(*this);
- }
- return *this;
-}
-template <typename T>
-inline typename QList<T>::iterator QList<T>::insert(iterator before, const T &t)
-{
- Q_ASSERT_X(isValidIterator(before), "QList::insert", "The specified iterator argument 'before' is invalid");
-
- int iBefore = int(before.i - reinterpret_cast<Node *>(p.begin()));
- Node *n = nullptr;
- if (d->ref.isShared())
- n = detach_helper_grow(iBefore, 1);
- else
- n = reinterpret_cast<Node *>(p.insert(iBefore));
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- p.remove(iBefore);
- QT_RETHROW;
- }
- return n;
-}
-template <typename T>
-inline typename QList<T>::iterator QList<T>::erase(iterator it)
-{
- Q_ASSERT_X(isValidIterator(it), "QList::erase", "The specified iterator argument 'it' is invalid");
- if (d->ref.isShared()) {
- int offset = int(it.i - reinterpret_cast<Node *>(p.begin()));
- it = begin(); // implies detach()
- it += offset;
- }
- node_destruct(it.i);
- return reinterpret_cast<Node *>(p.erase(reinterpret_cast<void**>(it.i)));
-}
-template <typename T>
-inline const T &QList<T>::at(int i) const
-{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::at", "index out of range");
- return reinterpret_cast<Node *>(p.at(i))->t(); }
-template <typename T>
-inline const T &QList<T>::operator[](int i) const
-{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::operator[]", "index out of range");
- return reinterpret_cast<Node *>(p.at(i))->t(); }
-template <typename T>
-inline T &QList<T>::operator[](int i)
-{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::operator[]", "index out of range");
- detach(); return reinterpret_cast<Node *>(p.at(i))->t(); }
-template <typename T>
-inline void QList<T>::removeAt(int i)
-{
-#if !QT_DEPRECATED_SINCE(5, 15)
- Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::removeAt", "index out of range");
-#endif
- if (i < 0 || i >= p.size()) {
-#if !defined(QT_NO_DEBUG)
- qWarning("QList::removeAt(): Index out of range.");
-#endif
- return;
- }
- detach();
- node_destruct(reinterpret_cast<Node *>(p.at(i))); p.remove(i);
-}
-template <typename T>
-inline T QList<T>::takeAt(int i)
-{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::take", "index out of range");
- detach(); Node *n = reinterpret_cast<Node *>(p.at(i)); T t = std::move(n->t()); node_destruct(n);
- p.remove(i); return t; }
-template <typename T>
-inline T QList<T>::takeFirst()
-{ T t = std::move(first()); removeFirst(); return t; }
-template <typename T>
-inline T QList<T>::takeLast()
-{ T t = std::move(last()); removeLast(); return t; }
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE void QList<T>::reserve(int alloc)
-{
- if (d->alloc < alloc) {
- if (d->ref.isShared())
- detach_helper(alloc);
- else
- p.realloc(alloc);
- }
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
-{
- if (d->ref.isShared()) {
- Node *n = detach_helper_grow(INT_MAX, 1);
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- --d->end;
- QT_RETHROW;
- }
- } else {
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- Node *n = reinterpret_cast<Node *>(p.append());
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- --d->end;
- QT_RETHROW;
- }
- } else {
- Node *n, copy;
- node_construct(&copy, t); // t might be a reference to an object in the array
- QT_TRY {
- n = reinterpret_cast<Node *>(p.append());;
- } QT_CATCH(...) {
- node_destruct(&copy);
- QT_RETHROW;
- }
- *n = copy;
- }
- }
-}
-
-template <typename T>
-inline void QList<T>::prepend(const T &t)
-{
- if (d->ref.isShared()) {
- Node *n = detach_helper_grow(0, 1);
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- ++d->begin;
- QT_RETHROW;
- }
- } else {
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- Node *n = reinterpret_cast<Node *>(p.prepend());
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- ++d->begin;
- QT_RETHROW;
- }
- } else {
- Node *n, copy;
- node_construct(&copy, t); // t might be a reference to an object in the array
- QT_TRY {
- n = reinterpret_cast<Node *>(p.prepend());;
- } QT_CATCH(...) {
- node_destruct(&copy);
- QT_RETHROW;
- }
- *n = copy;
- }
- }
-}
-
-template <typename T>
-inline void QList<T>::insert(int i, const T &t)
-{
-#if !QT_DEPRECATED_SINCE(5, 15)
- Q_ASSERT_X(i >= 0 && i <= p.size(), "QList<T>::insert", "index out of range");
-#elif !defined(QT_NO_DEBUG)
- if (i < 0 || i > p.size())
- qWarning("QList::insert(): Index out of range.");
-#endif
- if (d->ref.isShared()) {
- Node *n = detach_helper_grow(i, 1);
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- p.remove(i);
- QT_RETHROW;
- }
- } else {
- if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
- Node *n = reinterpret_cast<Node *>(p.insert(i));
- QT_TRY {
- node_construct(n, t);
- } QT_CATCH(...) {
- p.remove(i);
- QT_RETHROW;
- }
- } else {
- Node *n, copy;
- node_construct(&copy, t); // t might be a reference to an object in the array
- QT_TRY {
- n = reinterpret_cast<Node *>(p.insert(i));;
- } QT_CATCH(...) {
- node_destruct(&copy);
- QT_RETHROW;
- }
- *n = copy;
- }
- }
-}
-
-template <typename T>
-inline void QList<T>::replace(int i, const T &t)
-{
- Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::replace", "index out of range");
- detach();
- reinterpret_cast<Node *>(p.at(i))->t() = t;
-}
-
-template <typename T>
-inline void QList<T>::swapItemsAt(int i, int j)
-{
- Q_ASSERT_X(i >= 0 && i < p.size() && j >= 0 && j < p.size(),
- "QList<T>::swap", "index out of range");
- detach();
- qSwap(d->array[d->begin + i], d->array[d->begin + j]);
-}
-
-template <typename T>
-inline void QList<T>::move(int from, int to)
-{
- Q_ASSERT_X(from >= 0 && from < p.size() && to >= 0 && to < p.size(),
- "QList<T>::move", "index out of range");
- detach();
- p.move(from, to);
-}
-
template<typename T>
-Q_OUTOFLINE_TEMPLATE QList<T> QList<T>::mid(int pos, int alength) const
-{
- using namespace QtPrivate;
- switch (QContainerImplHelper::mid(size(), &pos, &alength)) {
- case QContainerImplHelper::Null:
- case QContainerImplHelper::Empty:
- return QList<T>();
- case QContainerImplHelper::Full:
- return *this;
- case QContainerImplHelper::Subset:
- break;
- }
-
- QList<T> cpy;
- if (alength <= 0)
- return cpy;
- cpy.reserve(alength);
- cpy.d->end = alength;
- QT_TRY {
- cpy.node_copy(reinterpret_cast<Node *>(cpy.p.begin()),
- reinterpret_cast<Node *>(cpy.p.end()),
- reinterpret_cast<Node *>(p.begin() + pos));
- } QT_CATCH(...) {
- // restore the old end
- cpy.d->end = 0;
- QT_RETHROW;
- }
- return cpy;
-}
-
-template<typename T>
-Q_OUTOFLINE_TEMPLATE T QList<T>::value(int i) const
-{
- if (i < 0 || i >= p.size()) {
- return T();
- }
- return reinterpret_cast<Node *>(p.at(i))->t();
-}
-
+using QMutableListIterator = QMutableVectorIterator<T>;
template<typename T>
-Q_OUTOFLINE_TEMPLATE T QList<T>::value(int i, const T& defaultValue) const
-{
- return ((i < 0 || i >= p.size()) ? defaultValue : reinterpret_cast<Node *>(p.at(i))->t());
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE typename QList<T>::Node *QList<T>::detach_helper_grow(int i, int c)
-{
- Node *n = reinterpret_cast<Node *>(p.begin());
- QListData::Data *x = p.detach_grow(&i, c);
- QT_TRY {
- node_copy(reinterpret_cast<Node *>(p.begin()),
- reinterpret_cast<Node *>(p.begin() + i), n);
- } QT_CATCH(...) {
- p.dispose();
- d = x;
- QT_RETHROW;
- }
- QT_TRY {
- node_copy(reinterpret_cast<Node *>(p.begin() + i + c),
- reinterpret_cast<Node *>(p.end()), n + i);
- } QT_CATCH(...) {
- node_destruct(reinterpret_cast<Node *>(p.begin()),
- reinterpret_cast<Node *>(p.begin() + i));
- p.dispose();
- d = x;
- QT_RETHROW;
- }
-
- if (!x->ref.deref())
- dealloc(x);
-
- return reinterpret_cast<Node *>(p.begin() + i);
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper(int alloc)
-{
- Node *n = reinterpret_cast<Node *>(p.begin());
- QListData::Data *x = p.detach(alloc);
- QT_TRY {
- node_copy(reinterpret_cast<Node *>(p.begin()), reinterpret_cast<Node *>(p.end()), n);
- } QT_CATCH(...) {
- p.dispose();
- d = x;
- QT_RETHROW;
- }
-
- if (!x->ref.deref())
- dealloc(x);
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper()
-{
- detach_helper(d->alloc);
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QList<T>::QList(const QList<T> &l)
- : QListSpecialMethods<T>(l), d(l.d)
-{
- if (!d->ref.ref()) {
- p.detach(d->alloc);
-
- QT_TRY {
- node_copy(reinterpret_cast<Node *>(p.begin()),
- reinterpret_cast<Node *>(p.end()),
- reinterpret_cast<Node *>(l.p.begin()));
- } QT_CATCH(...) {
- QListData::dispose(d);
- QT_RETHROW;
- }
- }
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
-{
- if (!d->ref.deref())
- dealloc(d);
-}
-
-template <typename T>
-template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator>>
-QList<T>::QList(InputIterator first, InputIterator last)
- : QList()
-{
- QtPrivate::reserveIfForwardIterator(this, first, last);
- std::copy(first, last, std::back_inserter(*this));
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE bool QList<T>::operator==(const QList<T> &l) const
-{
- if (d == l.d)
- return true;
- if (p.size() != l.p.size())
- return false;
- return this->op_eq_impl(l, MemoryLayout());
-}
-
-template <typename T>
-inline bool QList<T>::op_eq_impl(const QList &l, QListData::NotArrayCompatibleLayout) const
-{
- Node *i = reinterpret_cast<Node *>(p.begin());
- Node *e = reinterpret_cast<Node *>(p.end());
- Node *li = reinterpret_cast<Node *>(l.p.begin());
- for (; i != e; ++i, ++li) {
- if (!(i->t() == li->t()))
- return false;
- }
- return true;
-}
-
-template <typename T>
-inline bool QList<T>::op_eq_impl(const QList &l, QListData::ArrayCompatibleLayout) const
-{
- const T *lb = reinterpret_cast<const T*>(l.p.begin());
- const T *b = reinterpret_cast<const T*>(p.begin());
- const T *e = reinterpret_cast<const T*>(p.end());
- return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(lb, l.p.size()));
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE void QList<T>::dealloc(QListData::Data *data)
-{
- node_destruct(reinterpret_cast<Node *>(data->array + data->begin),
- reinterpret_cast<Node *>(data->array + data->end));
- QListData::dispose(data);
-}
-
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE void QList<T>::clear()
-{
- *this = QList<T>();
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t)
-{
- int index = indexOf(_t);
- if (index == -1)
- return 0;
-
- const T t = _t;
- detach();
-
- Node *i = reinterpret_cast<Node *>(p.at(index));
- Node *e = reinterpret_cast<Node *>(p.end());
- Node *n = i;
- node_destruct(i);
- while (++i != e) {
- if (i->t() == t)
- node_destruct(i);
- else
- *n++ = *i;
- }
-
- int removedCount = int(e - n);
- d->end -= removedCount;
- return removedCount;
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE bool QList<T>::removeOne(const T &_t)
-{
- int index = indexOf(_t);
- if (index != -1) {
- removeAt(index);
- return true;
- }
- return false;
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE typename QList<T>::iterator QList<T>::erase(typename QList<T>::iterator afirst,
- typename QList<T>::iterator alast)
-{
- Q_ASSERT_X(isValidIterator(afirst), "QList::erase", "The specified iterator argument 'afirst' is invalid");
- Q_ASSERT_X(isValidIterator(alast), "QList::erase", "The specified iterator argument 'alast' is invalid");
-
- if (d->ref.isShared()) {
- // ### A block is erased and a detach is needed. We should shrink and only copy relevant items.
- int offsetfirst = int(afirst.i - reinterpret_cast<Node *>(p.begin()));
- int offsetlast = int(alast.i - reinterpret_cast<Node *>(p.begin()));
- afirst = begin(); // implies detach()
- alast = afirst;
- afirst += offsetfirst;
- alast += offsetlast;
- }
-
- for (Node *n = afirst.i; n < alast.i; ++n)
- node_destruct(n);
- int idx = afirst - begin();
- p.remove(idx, alast - afirst);
- return begin() + idx;
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l)
-{
- if (!l.isEmpty()) {
- if (d == &QListData::shared_null) {
- *this = l;
- } else {
- Node *n = (d->ref.isShared())
- ? detach_helper_grow(INT_MAX, l.size())
- : reinterpret_cast<Node *>(p.append(l.p));
- QT_TRY {
- node_copy(n, reinterpret_cast<Node *>(p.end()),
- reinterpret_cast<Node *>(l.p.begin()));
- } QT_CATCH(...) {
- // restore the old end
- d->end -= int(reinterpret_cast<Node *>(p.end()) - n);
- QT_RETHROW;
- }
- }
- }
- return *this;
-}
-
-template <typename T>
-inline void QList<T>::append(const QList<T> &t)
-{
- *this += t;
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE int QList<T>::indexOf(const T &t, int from) const
-{
- return QtPrivate::indexOf<T, T>(*this, t, from);
-}
-
-namespace QtPrivate
-{
-template <typename T, typename U>
-int indexOf(const QList<T> &list, const U &u, int from)
-{
- typedef typename QList<T>::Node Node;
-
- if (from < 0)
- from = qMax(from + list.p.size(), 0);
- if (from < list.p.size()) {
- Node *n = reinterpret_cast<Node *>(list.p.at(from -1));
- Node *e = reinterpret_cast<Node *>(list.p.end());
- while (++n != e)
- if (n->t() == u)
- return int(n - reinterpret_cast<Node *>(list.p.begin()));
- }
- return -1;
-}
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE int QList<T>::lastIndexOf(const T &t, int from) const
-{
- return QtPrivate::lastIndexOf<T, T>(*this, t, from);
-}
-
-namespace QtPrivate
-{
-template <typename T, typename U>
-int lastIndexOf(const QList<T> &list, const U &u, int from)
-{
- typedef typename QList<T>::Node Node;
-
- if (from < 0)
- from += list.p.size();
- else if (from >= list.p.size())
- from = list.p.size()-1;
- if (from >= 0) {
- Node *b = reinterpret_cast<Node *>(list.p.begin());
- Node *n = reinterpret_cast<Node *>(list.p.at(from + 1));
- while (n-- != b) {
- if (n->t() == u)
- return int(n - b);
- }
- }
- return -1;
-}
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE bool QList<T>::contains(const T &t) const
-{
- return contains_impl(t, MemoryLayout());
-}
-
-template <typename T>
-inline bool QList<T>::contains_impl(const T &t, QListData::NotArrayCompatibleLayout) const
-{
- Node *e = reinterpret_cast<Node *>(p.end());
- Node *i = reinterpret_cast<Node *>(p.begin());
- for (; i != e; ++i)
- if (i->t() == t)
- return true;
- return false;
-}
-
-template <typename T>
-inline bool QList<T>::contains_impl(const T &t, QListData::ArrayCompatibleLayout) const
-{
- const T *b = reinterpret_cast<const T*>(p.begin());
- const T *e = reinterpret_cast<const T*>(p.end());
- return std::find(b, e, t) != e;
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE int QList<T>::count(const T &t) const
-{
- return this->count_impl(t, MemoryLayout());
-}
-
-template <typename T>
-inline int QList<T>::count_impl(const T &t, QListData::NotArrayCompatibleLayout) const
-{
- int c = 0;
- Node *e = reinterpret_cast<Node *>(p.end());
- Node *i = reinterpret_cast<Node *>(p.begin());
- for (; i != e; ++i)
- if (i->t() == t)
- ++c;
- return c;
-}
-
-template <typename T>
-inline int QList<T>::count_impl(const T &t, QListData::ArrayCompatibleLayout) const
-{
- return int(std::count(reinterpret_cast<const T*>(p.begin()),
- reinterpret_cast<const T*>(p.end()),
- t));
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QVector<T> QList<T>::toVector() const
-{
- return QVector<T>(begin(), end());
-}
-
-template <typename T>
-QList<T> QList<T>::fromVector(const QVector<T> &vector)
-{
- return vector.toList();
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QList<T> QVector<T>::toList() const
-{
- return QList<T>(begin(), end());
-}
-
-template <typename T>
-QVector<T> QVector<T>::fromList(const QList<T> &list)
-{
- return list.toVector();
-}
-
-Q_DECLARE_SEQUENTIAL_ITERATOR(List)
-Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(List)
-
-template <typename T>
-uint qHash(const QList<T> &key, uint seed = 0)
- noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
-{
- return qHashRange(key.cbegin(), key.cend(), seed);
-}
-
-template <typename T>
-bool operator<(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end())))
-{
- return std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end());
-}
-
-template <typename T>
-inline bool operator>(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return rhs < lhs;
-}
-
-template <typename T>
-inline bool operator<=(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return !(lhs > rhs);
-}
-
-template <typename T>
-inline bool operator>=(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return !(lhs < rhs);
-}
-
+using QListIterator = QVectorIterator<T>;
QT_END_NAMESPACE
+#endif
#include <QtCore/qbytearraylist.h>
#include <QtCore/qstringlist.h>
-#ifdef Q_CC_MSVC
-#pragma warning( pop )
-#endif
-
#endif // QLIST_H
diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp
index cd139f01d4..6c9eba0c66 100644
--- a/src/corelib/tools/qmap.cpp
+++ b/src/corelib/tools/qmap.cpp
@@ -301,7 +301,7 @@ void QMapDataBase::recalcMostLeftNode()
mostLeftNode = mostLeftNode->left;
}
-static inline int qMapAlignmentThreshold()
+static inline size_t qMapAlignmentThreshold()
{
// malloc on 32-bit platforms should return pointers that are 8-byte
// aligned or more while on 64-bit platforms they should be 16-byte aligned
@@ -309,14 +309,14 @@ static inline int qMapAlignmentThreshold()
return 2 * sizeof(void*);
}
-static inline void *qMapAllocate(int alloc, int alignment)
+static inline void *qMapAllocate(size_t alloc, size_t alignment)
{
return alignment > qMapAlignmentThreshold()
? qMallocAligned(alloc, alignment)
: ::malloc(alloc);
}
-static inline void qMapDeallocate(QMapNodeBase *node, int alignment)
+static inline void qMapDeallocate(QMapNodeBase *node, size_t alignment)
{
if (alignment > qMapAlignmentThreshold())
qFreeAligned(node);
@@ -324,7 +324,7 @@ static inline void qMapDeallocate(QMapNodeBase *node, int alignment)
::free(node);
}
-QMapNodeBase *QMapDataBase::createNode(int alloc, int alignment, QMapNodeBase *parent, bool left)
+QMapNodeBase *QMapDataBase::createNode(size_t alloc, size_t alignment, QMapNodeBase *parent, bool left)
{
QMapNodeBase *node = static_cast<QMapNodeBase *>(qMapAllocate(alloc, alignment));
Q_CHECK_PTR(node);
@@ -346,7 +346,7 @@ QMapNodeBase *QMapDataBase::createNode(int alloc, int alignment, QMapNodeBase *p
return node;
}
-void QMapDataBase::freeTree(QMapNodeBase *root, int alignment)
+void QMapDataBase::freeTree(QMapNodeBase *root, size_t alignment)
{
if (root->left)
freeTree(root->left, alignment);
@@ -619,7 +619,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa operator==()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::size() const
+/*! \fn template <class Key, class T> qsizetype QMap<Key, T>::size() const
Returns the number of (key, value) pairs in the map.
@@ -672,7 +672,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa remove()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::remove(const Key &key)
+/*! \fn template <class Key, class T> qsizetype QMap<Key, T>::remove(const Key &key)
Removes all the items that have the key \a key from the map.
Returns the number of items removed which will be 1 if the key
@@ -704,7 +704,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa count(), QMultiMap::contains()
*/
-/*! \fn template <class Key, class T> const T QMap<Key, T>::value(const Key &key, const T &defaultValue) const
+/*! \fn template <class Key, class T> T QMap<Key, T>::value(const Key &key, const T &defaultValue) const
Returns the value associated with the key \a key.
@@ -812,14 +812,14 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa QMultiMap::values()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::count(const Key &key) const
+/*! \fn template <class Key, class T> qsizetype QMap<Key, T>::count(const Key &key) const
Returns the number of items associated with key \a key.
\sa contains(), QMultiMap::count()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::count() const
+/*! \fn template <class Key, class T> qsizetype QMap<Key, T>::count() const
\overload
@@ -1466,7 +1466,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
current item.
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator+(int j) const
+/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator+(qsizetype j) const
Returns an iterator to the item at \a j positions forward from
this iterator. (If \a j is negative, the iterator goes backward.)
@@ -1477,7 +1477,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator-(int j) const
+/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator-(qsizetype j) const
Returns an iterator to the item at \a j positions backward from
this iterator. (If \a j is negative, the iterator goes forward.)
@@ -1487,7 +1487,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa operator+()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator+=(int j)
+/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator+=(qsizetype j)
Advances the iterator by \a j items. (If \a j is negative, the
iterator goes backward.)
@@ -1495,7 +1495,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa operator-=(), operator+()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator-=(int j)
+/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator-=(qsizetype j)
Makes the iterator go back by \a j items. (If \a j is negative,
the iterator goes forward.)
@@ -1680,7 +1680,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
current item.
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator+(int j) const
+/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator+(qsizetype j) const
Returns an iterator to the item at \a j positions forward from
this iterator. (If \a j is negative, the iterator goes backward.)
@@ -1690,7 +1690,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa operator-()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator-(int j) const
+/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator-(qsizetype j) const
Returns an iterator to the item at \a j positions backward from
this iterator. (If \a j is negative, the iterator goes forward.)
@@ -1700,7 +1700,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa operator+()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator+=(int j)
+/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator+=(qsizetype j)
Advances the iterator by \a j items. (If \a j is negative, the
iterator goes backward.)
@@ -1710,7 +1710,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa operator-=(), operator+()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator-=(int j)
+/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator-=(qsizetype j)
Makes the iterator go back by \a j items. (If \a j is negative,
the iterator goes forward.)
@@ -2042,7 +2042,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
*/
/*!
- \fn template <class Key, class T> int QMultiMap<Key, T>::remove(const Key &key, const T &value)
+ \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::remove(const Key &key, const T &value)
\since 4.3
Removes all the items that have the key \a key and the value \a
@@ -2052,7 +2052,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
*/
/*!
- \fn template <class Key, class T> int QMultiMap<Key, T>::count(const Key &key, const T &value) const
+ \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::count(const Key &key, const T &value) const
\since 4.3
Returns the number of items with key \a key and value \a value.
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 0c69d13295..848ba5c4d4 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -180,7 +180,7 @@ inline QMapNode<Key, T> *QMapNode<Key, T>::upperBound(const Key &akey)
struct Q_CORE_EXPORT QMapDataBase
{
QtPrivate::RefCount ref;
- int size;
+ qsizetype size;
QMapNodeBase header;
QMapNodeBase *mostLeftNode;
@@ -190,8 +190,8 @@ struct Q_CORE_EXPORT QMapDataBase
void freeNodeAndRebalance(QMapNodeBase *z);
void recalcMostLeftNode();
- QMapNodeBase *createNode(int size, int alignment, QMapNodeBase *parent, bool left);
- void freeTree(QMapNodeBase *root, int alignment);
+ QMapNodeBase *createNode(size_t size, size_t alignment, QMapNodeBase *parent, bool left);
+ void freeTree(QMapNodeBase *root, size_t alignment);
static const QMapDataBase shared_null;
@@ -219,7 +219,7 @@ struct QMapData : public QMapDataBase
Node *createNode(const Key &k, const T &v, Node *parent = nullptr, bool left = false)
{
- Node *n = static_cast<Node *>(QMapDataBase::createNode(sizeof(Node), Q_ALIGNOF(Node),
+ Node *n = static_cast<Node *>(QMapDataBase::createNode(sizeof(Node), alignof(Node),
parent, left));
QT_TRY {
new (&n->key) Key(k);
@@ -243,7 +243,7 @@ struct QMapData : public QMapDataBase
void destroy() {
if (root()) {
root()->destroySubTree();
- freeTree(header.left, Q_ALIGNOF(Node));
+ freeTree(header.left, alignof(Node));
}
freeData(this);
}
@@ -350,33 +350,22 @@ public:
bool operator==(const QMap<Key, T> &other) const;
inline bool operator!=(const QMap<Key, T> &other) const { return !(*this == other); }
- inline int size() const { return d->size; }
+ inline qsizetype size() const { return d->size; }
inline bool isEmpty() const { return d->size == 0; }
inline void detach() { if (d->ref.isShared()) detach_helper(); }
inline bool isDetached() const { return !d->ref.isShared(); }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable)
- {
- if (sharable == d->ref.isSharable())
- return;
- if (!sharable)
- detach();
- // Don't call on shared_null
- d->ref.setSharable(sharable);
- }
-#endif
inline bool isSharedWith(const QMap<Key, T> &other) const { return d == other.d; }
void clear();
- int remove(const Key &key);
+ qsizetype remove(const Key &key);
T take(const Key &key);
bool contains(const Key &key) const;
- const Key key(const T &value, const Key &defaultKey = Key()) const;
- const T value(const Key &key, const T &defaultValue = T()) const;
+ Key key(const T &value, const Key &defaultKey = Key()) const;
+ T value(const Key &key, const T &defaultValue = T()) const;
T &operator[](const Key &key);
const T operator[](const Key &key) const;
@@ -387,7 +376,7 @@ public:
QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList<Key> uniqueKeys() const;
QT_DEPRECATED_VERSION_X_5_15("Use QMultiMap for maps storing multiple values with the same key.") QList<T> values(const Key &key) const;
#endif
- int count(const Key &key) const;
+ qsizetype count(const Key &key) const;
inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
@@ -440,20 +429,15 @@ public:
i = i->previousNode();
return r;
}
- inline iterator operator+(int j) const
+ inline iterator operator+(qsizetype j) const
{ iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline iterator operator-(int j) const { return operator+(-j); }
- inline iterator &operator+=(int j) { return *this = *this + j; }
- inline iterator &operator-=(int j) { return *this = *this - j; }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
+ inline iterator operator-(qsizetype j) const { return operator+(-j); }
+ inline iterator &operator+=(qsizetype j) { return *this = *this + j; }
+ inline iterator &operator-=(qsizetype j) { return *this = *this - j; }
+ friend inline iterator operator+(qsizetype j, iterator k) { return k + j; }
-#ifndef QT_STRICT_ITERATORS
- public:
- inline bool operator==(const const_iterator &o) const
- { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const
- { return i != o.i; }
-#endif
+ inline bool operator==(const const_iterator &o) const { return i == o.i; }
+ inline bool operator!=(const const_iterator &o) const { return i != o.i; }
friend class QMap<Key, T>;
friend class QMultiMap<Key, T>;
};
@@ -473,12 +457,7 @@ public:
Q_DECL_CONSTEXPR inline const_iterator() : i(nullptr) { }
inline const_iterator(const Node *node) : i(node) { }
-#ifdef QT_STRICT_ITERATORS
- explicit inline const_iterator(const iterator &o)
-#else
- inline const_iterator(const iterator &o)
-#endif
- { i = o.i; }
+ inline const_iterator(const iterator &o) { i = o.i; }
inline const Key &key() const { return i->key; }
inline const T &value() const { return i->value; }
@@ -505,18 +484,13 @@ public:
i = i->previousNode();
return r;
}
- inline const_iterator operator+(int j) const
+ inline const_iterator operator+(qsizetype j) const
{ const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline const_iterator operator-(int j) const { return operator+(-j); }
- inline const_iterator &operator+=(int j) { return *this = *this + j; }
- inline const_iterator &operator-=(int j) { return *this = *this - j; }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
-
-#ifdef QT_STRICT_ITERATORS
- private:
- inline bool operator==(const iterator &o) const { return operator==(const_iterator(o)); }
- inline bool operator!=(const iterator &o) const { return operator!=(const_iterator(o)); }
-#endif
+ inline const_iterator operator-(qsizetype j) const { return operator+(-j); }
+ inline const_iterator &operator+=(qsizetype j) { return *this = *this + j; }
+ inline const_iterator &operator-=(qsizetype j) { return *this = *this - j; }
+ friend inline const_iterator operator+(qsizetype j, const_iterator k) { return k + j; }
+
friend class QMap<Key, T>;
friend class QMultiMap<Key, T>;
};
@@ -573,7 +547,7 @@ public:
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
- inline int count() const { return d->size; }
+ inline qsizetype count() const { return d->size; }
iterator find(const Key &key);
const_iterator find(const Key &key) const;
const_iterator constFind(const Key &key) const;
@@ -594,7 +568,7 @@ public:
typedef Key key_type;
typedef T mapped_type;
typedef qptrdiff difference_type;
- typedef int size_type;
+ typedef qsizetype size_type;
inline bool empty() const { return isEmpty(); }
QPair<iterator, iterator> equal_range(const Key &akey);
QPair<const_iterator, const_iterator> equal_range(const Key &akey) const;
@@ -656,7 +630,7 @@ QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wreturn-stack-address")
template <class Key, class T>
-Q_INLINE_TEMPLATE const T QMap<Key, T>::value(const Key &akey, const T &adefaultValue) const
+Q_INLINE_TEMPLATE T QMap<Key, T>::value(const Key &akey, const T &adefaultValue) const
{
Node *n = d->findNode(akey);
return n ? n->value : adefaultValue;
@@ -681,7 +655,7 @@ Q_INLINE_TEMPLATE T &QMap<Key, T>::operator[](const Key &akey)
}
template <class Key, class T>
-Q_INLINE_TEMPLATE int QMap<Key, T>::count(const Key &akey) const
+Q_INLINE_TEMPLATE qsizetype QMap<Key, T>::count(const Key &akey) const
{
Node *firstNode;
Node *lastNode;
@@ -904,10 +878,10 @@ void QMap<Key, T>::dump() const
#endif
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE int QMap<Key, T>::remove(const Key &akey)
+Q_OUTOFLINE_TEMPLATE qsizetype QMap<Key, T>::remove(const Key &akey)
{
detach();
- int n = 0;
+ qsizetype n = 0;
while (Node *node = d->findNode(akey)) {
d->deleteNode(node);
++n;
@@ -940,7 +914,7 @@ Q_OUTOFLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::erase(iterato
if (d->ref.isShared()) {
const_iterator oldBegin = constBegin();
const_iterator old = const_iterator(it);
- int backStepsWithSameKey = 0;
+ qsizetype backStepsWithSameKey = 0;
while (old != oldBegin) {
--old;
@@ -1005,7 +979,7 @@ Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::keys(const T &avalue) const
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE const Key QMap<Key, T>::key(const T &avalue, const Key &defaultKey) const
+Q_OUTOFLINE_TEMPLATE Key QMap<Key, T>::key(const T &avalue, const Key &defaultKey) const
{
const_iterator i = begin();
while (i != end()) {
@@ -1157,9 +1131,9 @@ public:
bool contains(const Key &key, const T &value) const;
- int remove(const Key &key, const T &value);
+ qsizetype remove(const Key &key, const T &value);
- int count(const Key &key, const T &value) const;
+ qsizetype count(const Key &key, const T &value) const;
typename QMap<Key, T>::iterator find(const Key &key, const T &value) {
typename QMap<Key, T>::iterator i(find(key));
@@ -1315,9 +1289,9 @@ Q_INLINE_TEMPLATE bool QMultiMap<Key, T>::contains(const Key &key, const T &valu
}
template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value)
+Q_INLINE_TEMPLATE qsizetype QMultiMap<Key, T>::remove(const Key &key, const T &value)
{
- int n = 0;
+ qsizetype n = 0;
typename QMap<Key, T>::iterator i(find(key));
typename QMap<Key, T>::iterator end(QMap<Key, T>::end());
while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
@@ -1332,9 +1306,9 @@ Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value)
}
template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiMap<Key, T>::count(const Key &key, const T &value) const
+Q_INLINE_TEMPLATE qsizetype QMultiMap<Key, T>::count(const Key &key, const T &value) const
{
- int n = 0;
+ qsizetype n = 0;
typename QMap<Key, T>::const_iterator i(constFind(key));
typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd());
while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h
index f0a91c4ff8..1258e465dd 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -265,7 +265,6 @@ public:
#endif
private:
- friend class QMatrix;
friend class QTransform;
qreal xp;
diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h
index 2e5388ad9a..982a9c2bbf 100644
--- a/src/corelib/tools/qrefcount.h
+++ b/src/corelib/tools/qrefcount.h
@@ -53,10 +53,6 @@ class RefCount
public:
inline bool ref() noexcept {
int count = atomic.loadRelaxed();
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- if (count == 0) // !isSharable
- return false;
-#endif
if (count != -1) // !isStatic
atomic.ref();
return true;
@@ -64,32 +60,11 @@ public:
inline bool deref() noexcept {
int count = atomic.loadRelaxed();
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- if (count == 0) // !isSharable
- return false;
-#endif
if (count == -1) // isStatic
return true;
return atomic.deref();
}
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- bool setSharable(bool sharable) noexcept
- {
- Q_ASSERT(!isShared());
- if (sharable)
- return atomic.testAndSetRelaxed(0, 1);
- else
- return atomic.testAndSetRelaxed(1, 0);
- }
-
- bool isSharable() const noexcept
- {
- // Sharable === Shared ownership.
- return atomic.loadRelaxed() != 0;
- }
-#endif
-
bool isStatic() const noexcept
{
// Persistent object, never deleted
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index 4b2adcd851..f078e62999 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -86,9 +86,6 @@ public:
inline void detach() { q_hash.detach(); }
inline bool isDetached() const { return q_hash.isDetached(); }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable) { q_hash.setSharable(sharable); }
-#endif
inline void clear() { q_hash.clear(); }
@@ -108,11 +105,7 @@ public:
friend class QSet<T>;
public:
-#if QT_DEPRECATED_WARNINGS_SINCE < QT_VERSION_CHECK(5, 15, 0)
- typedef std::bidirectional_iterator_tag iterator_category;
-#else
typedef std::forward_iterator_tag iterator_category;
-#endif
typedef qptrdiff difference_type;
typedef T value_type;
typedef const T *pointer;
@@ -132,15 +125,6 @@ public:
{ return i != o.i; }
inline iterator &operator++() { ++i; return *this; }
inline iterator operator++(int) { iterator r = *this; ++i; return r; }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 iterator &operator--() { --i; return *this; }
- inline QT_DEPRECATED_VERSION_5_15 iterator operator--(int) { iterator r = *this; --i; return r; }
- inline QT_DEPRECATED_VERSION_5_15 iterator operator+(int j) const { return i + j; }
- inline QT_DEPRECATED_VERSION_5_15 iterator operator-(int j) const { return i - j; }
- friend inline QT_DEPRECATED_VERSION_5_15 iterator operator+(int j, iterator k) { return k + j; }
- inline QT_DEPRECATED_VERSION_5_15 iterator &operator+=(int j) { i += j; return *this; }
- inline QT_DEPRECATED_VERSION_5_15 iterator &operator-=(int j) { i -= j; return *this; }
-#endif
};
class const_iterator
@@ -151,11 +135,7 @@ public:
friend class QSet<T>;
public:
-#if QT_DEPRECATED_WARNINGS_SINCE < QT_VERSION_CHECK(5, 15, 0)
- typedef std::bidirectional_iterator_tag iterator_category;
-#else
typedef std::forward_iterator_tag iterator_category;
-#endif
typedef qptrdiff difference_type;
typedef T value_type;
typedef const T *pointer;
@@ -173,15 +153,6 @@ public:
inline bool operator!=(const const_iterator &o) const { return i != o.i; }
inline const_iterator &operator++() { ++i; return *this; }
inline const_iterator operator++(int) { const_iterator r = *this; ++i; return r; }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator--() { --i; return *this; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator operator--(int) { const_iterator r = *this; --i; return r; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator operator+(int j) const { return i + j; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator operator-(int j) const { return i - j; }
- friend inline QT_DEPRECATED_VERSION_5_15 const_iterator operator+(int j, const_iterator k) { return k + j; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator+=(int j) { i += j; return *this; }
- inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator-=(int j) { i -= j; return *this; }
-#endif
};
// STL style
@@ -194,24 +165,10 @@ public:
inline const_iterator cend() const noexcept { return q_hash.end(); }
inline const_iterator constEnd() const noexcept { return q_hash.constEnd(); }
-#if QT_DEPRECATED_SINCE(5, 15)
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- reverse_iterator QT_DEPRECATED_VERSION_5_15 rbegin() { return reverse_iterator(end()); }
- reverse_iterator QT_DEPRECATED_VERSION_5_15 rend() { return reverse_iterator(begin()); }
- const_reverse_iterator QT_DEPRECATED_VERSION_5_15 rbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator QT_DEPRECATED_VERSION_5_15 rend() const noexcept { return const_reverse_iterator(begin()); }
- const_reverse_iterator QT_DEPRECATED_VERSION_5_15 crbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator QT_DEPRECATED_VERSION_5_15 crend() const noexcept { return const_reverse_iterator(begin()); }
-#endif
-
- iterator erase(iterator i)
- { return erase(m2c(i)); }
iterator erase(const_iterator i)
{
- Q_ASSERT_X(isValidIterator(i), "QSet::erase", "The specified const_iterator argument 'i' is invalid");
- return q_hash.erase(reinterpret_cast<typename Hash::const_iterator &>(i));
+ Q_ASSERT(i != constEnd());
+ return q_hash.erase(i.i);
}
// more Qt
@@ -260,27 +217,9 @@ public:
{ QSet<T> result = *this; result -= other; return result; }
QList<T> values() const;
-#if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
- QT_DEPRECATED_X("Use values() instead.")
- QList<T> toList() const { return values(); }
- QT_DEPRECATED_X("Use QSet<T>(list.begin(), list.end()) instead.")
- static QSet<T> fromList(const QList<T> &list);
-#endif
private:
Hash q_hash;
-
- static const_iterator m2c(iterator it) noexcept
- { return const_iterator(typename Hash::const_iterator(it.i.i)); }
-
- bool isValidIterator(const iterator &i) const
- {
- return q_hash.isValidIterator(reinterpret_cast<const typename Hash::iterator&>(i));
- }
- bool isValidIterator(const const_iterator &i) const noexcept
- {
- return q_hash.isValidIterator(reinterpret_cast<const typename Hash::const_iterator&>(i));
- }
};
#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
@@ -291,7 +230,7 @@ QSet(InputIterator, InputIterator) -> QSet<ValueType>;
#endif
template <typename T>
-uint qHash(const QSet<T> &key, uint seed = 0)
+size_t qHash(const QSet<T> &key, size_t seed = 0)
noexcept(noexcept(qHashRangeCommutative(key.begin(), key.end(), seed)))
{
return qHashRangeCommutative(key.begin(), key.end(), seed);
@@ -338,24 +277,14 @@ Q_INLINE_TEMPLATE bool QSet<T>::intersects(const QSet<T> &other) const
const bool otherIsBigger = other.size() > size();
const QSet &smallestSet = otherIsBigger ? *this : other;
const QSet &biggestSet = otherIsBigger ? other : *this;
- const bool equalSeeds = q_hash.d->seed == other.q_hash.d->seed;
typename QSet::const_iterator i = smallestSet.cbegin();
typename QSet::const_iterator e = smallestSet.cend();
- if (Q_LIKELY(equalSeeds)) {
- // If seeds are equal we take the fast path so no hash is recalculated.
- while (i != e) {
- if (*biggestSet.q_hash.findNode(*i, i.i.i->h) != biggestSet.q_hash.e)
- return true;
- ++i;
- }
- } else {
- while (i != e) {
- if (biggestSet.contains(*i))
- return true;
- ++i;
- }
- }
+ while (i != e) {
+ if (biggestSet.contains(*i))
+ return true;
+ ++i;
+ }
return false;
}
@@ -397,30 +326,6 @@ Q_OUTOFLINE_TEMPLATE QList<T> QSet<T>::values() const
return result;
}
-#if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QSet<T> QList<T>::toSet() const
-{
- QSet<T> result;
- result.reserve(size());
- for (int i = 0; i < size(); ++i)
- result.insert(at(i));
- return result;
-}
-
-template <typename T>
-QSet<T> QSet<T>::fromList(const QList<T> &list)
-{
- return list.toSet();
-}
-
-template <typename T>
-QList<T> QList<T>::fromSet(const QSet<T> &set)
-{
- return set.toList();
-}
-#endif
-
Q_DECLARE_SEQUENTIAL_ITERATOR(Set)
#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
@@ -448,14 +353,6 @@ public:
inline const T &value() const { Q_ASSERT(item_exists()); return *n; }
inline bool findNext(const T &t)
{ while (c->constEnd() != (n = i)) if (*i++ == t) return true; return false; }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED_VERSION_5_15 bool hasPrevious() const { return c->constBegin() != i; }
- inline QT_DEPRECATED_VERSION_5_15 const T &previous() { n = --i; return *n; }
- inline QT_DEPRECATED_VERSION_5_15 const T &peekPrevious() const { iterator p = i; return *--p; }
- inline QT_DEPRECATED_VERSION_5_15 bool findPrevious(const T &t)
- { while (c->constBegin() != i) if (*(n = --i) == t) return true;
- n = c->end(); return false; }
-#endif
};
#endif // QT_NO_JAVA_STYLE_ITERATORS
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
index 42dd1288ac..eb6b542181 100644
--- a/src/corelib/tools/qset.qdoc
+++ b/src/corelib/tools/qset.qdoc
@@ -1136,7 +1136,7 @@
*/
/*!
- \fn template <class T> uint qHash(const QSet<T> &key, uint seed = 0)
+ \fn template <class T> size_t qHash(const QSet<T> &key, size_t seed = 0)
\relates QHash
\since 5.5
diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h
index f123f8e7b9..ef3e689e92 100644
--- a/src/corelib/tools/qshareddata.h
+++ b/src/corelib/tools/qshareddata.h
@@ -305,12 +305,12 @@ Q_INLINE_TEMPLATE void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlyShar
{ p1.swap(p2); }
template <class T>
-Q_INLINE_TEMPLATE uint qHash(const QSharedDataPointer<T> &ptr, uint seed = 0) noexcept
+Q_INLINE_TEMPLATE size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept
{
return qHash(ptr.data(), seed);
}
template <class T>
-Q_INLINE_TEMPLATE uint qHash(const QExplicitlySharedDataPointer<T> &ptr, uint seed = 0) noexcept
+Q_INLINE_TEMPLATE size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept
{
return qHash(ptr.data(), seed);
}
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index 0576fb2bd0..499546da4b 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -1630,7 +1630,7 @@ void QtSharedPointer::internalSafetyCheckCleanCheck()
qFatal("Internal consistency error: the number of pointers is not equal!");
if (Q_UNLIKELY(!kp->dPointers.isEmpty()))
- qFatal("Pointer cleaning failed: %d entries remaining", kp->dPointers.size());
+ qFatal("Pointer cleaning failed: %d entries remaining", int(kp->dPointers.size()));
# endif
}
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 362d57fb9a..b6aad5ff73 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -882,7 +882,7 @@ Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer<X> &ptr2)
// qHash
//
template <class T>
-Q_INLINE_TEMPLATE uint qHash(const QSharedPointer<T> &ptr, uint seed = 0)
+Q_INLINE_TEMPLATE size_t qHash(const QSharedPointer<T> &ptr, size_t seed = 0)
{
return QT_PREPEND_NAMESPACE(qHash)(ptr.data(), seed);
}
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
deleted file mode 100644
index 75c380ee8a..0000000000
--- a/src/corelib/tools/qsimd.cpp
+++ /dev/null
@@ -1,718 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2019 Intel Corporation.
-** 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$
-**
-****************************************************************************/
-
-#include "qsimd_p.h"
-#include "qalgorithms.h"
-#include <QByteArray>
-#include <stdio.h>
-
-#ifdef Q_OS_LINUX
-# include "../testlib/3rdparty/valgrind_p.h"
-#endif
-
-#if defined(Q_OS_WIN)
-# if !defined(Q_CC_GNU)
-# include <intrin.h>
-# endif
-#elif defined(Q_OS_LINUX) && (defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS_32))
-#include "private/qcore_unix_p.h"
-
-// the kernel header definitions for HWCAP_*
-// (the ones we need/may need anyway)
-
-// copied from <asm/hwcap.h> (ARM)
-#define HWCAP_CRUNCH 1024
-#define HWCAP_THUMBEE 2048
-#define HWCAP_NEON 4096
-#define HWCAP_VFPv3 8192
-#define HWCAP_VFPv3D16 16384
-
-// copied from <asm/hwcap.h> (ARM):
-#define HWCAP2_CRC32 (1 << 4)
-
-// copied from <asm/hwcap.h> (Aarch64)
-#define HWCAP_CRC32 (1 << 7)
-
-// copied from <linux/auxvec.h>
-#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
-#define AT_HWCAP2 26 /* extension of AT_HWCAP */
-
-#elif defined(Q_CC_GHS)
-#include <INTEGRITY_types.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*
- * Use kdesdk/scripts/generate_string_table.pl to update the table below. Note
- * we remove the terminating -1 that the script adds.
- */
-
-// begin generated
-#if defined(Q_PROCESSOR_ARM)
-/* Data:
- neon
- crc32
- */
-static const char features_string[] =
- " neon\0"
- " crc32\0"
- "\0";
-static const int features_indices[] = { 0, 6 };
-#elif defined(Q_PROCESSOR_MIPS)
-/* Data:
- dsp
- dspr2
-*/
-static const char features_string[] =
- " dsp\0"
- " dspr2\0"
- "\0";
-
-static const int features_indices[] = {
- 0, 5
-};
-#elif defined(Q_PROCESSOR_X86)
-# include "qsimd_x86.cpp" // generated by util/x86simdgen
-#else
-static const char features_string[] = "";
-static const int features_indices[] = { };
-#endif
-// end generated
-
-#if defined (Q_OS_NACL)
-static inline uint detectProcessorFeatures()
-{
- return 0;
-}
-#elif defined(Q_PROCESSOR_ARM)
-static inline quint64 detectProcessorFeatures()
-{
- quint64 features = 0;
-
-#if defined(Q_OS_LINUX)
-# if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64)
- features |= Q_UINT64_C(1) << CpuFeatureNEON; // NEON is always available on ARMv8 64bit.
-# endif
- int auxv = qt_safe_open("/proc/self/auxv", O_RDONLY);
- if (auxv != -1) {
- unsigned long vector[64];
- int nread;
- while (features == 0) {
- nread = qt_safe_read(auxv, (char *)vector, sizeof vector);
- if (nread <= 0) {
- // EOF or error
- break;
- }
-
- int max = nread / (sizeof vector[0]);
- for (int i = 0; i < max; i += 2) {
- if (vector[i] == AT_HWCAP) {
-# if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64)
- // For Aarch64:
- if (vector[i+1] & HWCAP_CRC32)
- features |= Q_UINT64_C(1) << CpuFeatureCRC32;
-# endif
- // Aarch32, or ARMv7 or before:
- if (vector[i+1] & HWCAP_NEON)
- features |= Q_UINT64_C(1) << CpuFeatureNEON;
- }
-# if defined(Q_PROCESSOR_ARM_32)
- // For Aarch32:
- if (vector[i] == AT_HWCAP2) {
- if (vector[i+1] & HWCAP2_CRC32)
- features |= Q_UINT64_C(1) << CpuFeatureCRC32;
- }
-# endif
- }
- }
-
- qt_safe_close(auxv);
- return features;
- }
- // fall back if /proc/self/auxv wasn't found
-#endif
-
-#if defined(__ARM_NEON__)
- features |= Q_UINT64_C(1) << CpuFeatureNEON;
-#endif
-#if defined(__ARM_FEATURE_CRC32)
- features |= Q_UINT64_C(1) << CpuFeatureCRC32;
-#endif
-
- return features;
-}
-
-#elif defined(Q_PROCESSOR_X86)
-
-#ifdef Q_PROCESSOR_X86_32
-# define PICreg "%%ebx"
-#else
-# define PICreg "%%rbx"
-#endif
-
-static bool checkRdrndWorks() noexcept;
-
-static int maxBasicCpuidSupported()
-{
-#if defined(Q_CC_EMSCRIPTEN)
- return 6; // All features supported by Emscripten
-#elif defined(Q_CC_GNU)
- qregisterint tmp1;
-
-# if Q_PROCESSOR_X86 < 5
- // check if the CPUID instruction is supported
- long cpuid_supported;
- asm ("pushf\n"
- "pop %0\n"
- "mov %0, %1\n"
- "xor $0x00200000, %0\n"
- "push %0\n"
- "popf\n"
- "pushf\n"
- "pop %0\n"
- "xor %1, %0\n" // %eax is now 0 if CPUID is not supported
- : "=a" (cpuid_supported), "=r" (tmp1)
- );
- if (!cpuid_supported)
- return 0;
-# endif
-
- int result;
- asm ("xchg " PICreg", %1\n"
- "cpuid\n"
- "xchg " PICreg", %1\n"
- : "=&a" (result), "=&r" (tmp1)
- : "0" (0)
- : "ecx", "edx");
- return result;
-#elif defined(Q_OS_WIN)
- // Use the __cpuid function; if the CPUID instruction isn't supported, it will return 0
- int info[4];
- __cpuid(info, 0);
- return info[0];
-#elif defined(Q_CC_GHS)
- unsigned int info[4];
- __CPUID(0, info);
- return info[0];
-#else
- return 0;
-#endif
-}
-
-static void cpuidFeatures01(uint &ecx, uint &edx)
-{
-#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
- qregisterint tmp1;
- asm ("xchg " PICreg", %2\n"
- "cpuid\n"
- "xchg " PICreg", %2\n"
- : "=&c" (ecx), "=&d" (edx), "=&r" (tmp1)
- : "a" (1));
-#elif defined(Q_OS_WIN)
- int info[4];
- __cpuid(info, 1);
- ecx = info[2];
- edx = info[3];
-#elif defined(Q_CC_GHS)
- unsigned int info[4];
- __CPUID(1, info);
- ecx = info[2];
- edx = info[3];
-#else
- Q_UNUSED(ecx);
- Q_UNUSED(edx);
-#endif
-}
-
-#ifdef Q_OS_WIN
-inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));}
-#endif
-
-static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
-{
-#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
- qregisteruint rbx; // in case it's 64-bit
- qregisteruint rcx = 0;
- qregisteruint rdx = 0;
- asm ("xchg " PICreg", %0\n"
- "cpuid\n"
- "xchg " PICreg", %0\n"
- : "=&r" (rbx), "+&c" (rcx), "+&d" (rdx)
- : "a" (7));
- ebx = rbx;
- ecx = rcx;
- edx = rdx;
-#elif defined(Q_OS_WIN)
- int info[4];
- __cpuidex(info, 7, 0);
- ebx = info[1];
- ecx = info[2];
- edx = info[3];
-#elif defined(Q_CC_GHS)
- unsigned int info[4];
- __CPUIDEX(7, 0, info);
- ebx = info[1];
- ecx = info[2];
- edx = info[3];
-#else
- Q_UNUSED(ebx);
- Q_UNUSED(ecx);
- Q_UNUSED(edx);
-#endif
-}
-
-#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS))
-// fallback overload in case this intrinsic does not exist: unsigned __int64 _xgetbv(unsigned int);
-inline quint64 _xgetbv(__int64) { return 0; }
-#endif
-static void xgetbv(uint in, uint &eax, uint &edx)
-{
-#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
- asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction
- : "=a" (eax), "=d" (edx)
- : "c" (in));
-#elif defined(Q_OS_WIN)
- quint64 result = _xgetbv(in);
- eax = result;
- edx = result >> 32;
-#else
- Q_UNUSED(in);
- Q_UNUSED(eax);
- Q_UNUSED(edx);
-#endif
-}
-
-static quint64 detectProcessorFeatures()
-{
- // Flags from the CR0 / XCR0 state register
- enum XCR0Flags {
- X87 = 1 << 0,
- XMM0_15 = 1 << 1,
- YMM0_15Hi128 = 1 << 2,
- BNDRegs = 1 << 3,
- BNDCSR = 1 << 4,
- OpMask = 1 << 5,
- ZMM0_15Hi256 = 1 << 6,
- ZMM16_31 = 1 << 7,
-
- SSEState = XMM0_15,
- AVXState = XMM0_15 | YMM0_15Hi128,
- AVX512State = AVXState | OpMask | ZMM0_15Hi256 | ZMM16_31
- };
- static const quint64 AllAVX2 = CpuFeatureAVX2 | AllAVX512;
- static const quint64 AllAVX = CpuFeatureAVX | AllAVX2;
-
- quint64 features = 0;
- int cpuidLevel = maxBasicCpuidSupported();
-#if Q_PROCESSOR_X86 < 5
- if (cpuidLevel < 1)
- return 0;
-#else
- Q_ASSERT(cpuidLevel >= 1);
-#endif
-
- uint results[X86CpuidMaxLeaf] = {};
- cpuidFeatures01(results[Leaf1ECX], results[Leaf1EDX]);
- if (cpuidLevel >= 7)
- cpuidFeatures07_00(results[Leaf7_0EBX], results[Leaf7_0ECX], results[Leaf7_0EDX]);
-
- // populate our feature list
- for (uint i = 0; i < sizeof(x86_locators) / sizeof(x86_locators[0]); ++i) {
- uint word = x86_locators[i] / 32;
- uint bit = 1U << (x86_locators[i] % 32);
- quint64 feature = Q_UINT64_C(1) << (i + 1);
- if (results[word] & bit)
- features |= feature;
- }
-
- // now check the AVX state
- uint xgetbvA = 0, xgetbvD = 0;
- if (results[Leaf1ECX] & (1u << 27)) {
- // XGETBV enabled
- xgetbv(0, xgetbvA, xgetbvD);
- }
-
- if ((xgetbvA & AVXState) != AVXState) {
- // support for YMM registers is disabled, disable all AVX
- features &= ~AllAVX;
- } else if ((xgetbvA & AVX512State) != AVX512State) {
- // support for ZMM registers or mask registers is disabled, disable all AVX512
- features &= ~AllAVX512;
- }
-
- if (features & CpuFeatureRDRND && !checkRdrndWorks())
- features &= ~(CpuFeatureRDRND | CpuFeatureRDSEED);
-
- return features;
-}
-
-#elif defined(Q_PROCESSOR_MIPS_32)
-
-#if defined(Q_OS_LINUX)
-//
-// Do not use QByteArray: it could use SIMD instructions itself at
-// some point, thus creating a recursive dependency. Instead, use a
-// QSimpleBuffer, which has the bare minimum needed to use memory
-// dynamically and read lines from /proc/cpuinfo of arbitrary sizes.
-//
-struct QSimpleBuffer {
- static const int chunk_size = 256;
- char *data;
- unsigned alloc;
- unsigned size;
-
- QSimpleBuffer(): data(0), alloc(0), size(0) {}
- ~QSimpleBuffer() { ::free(data); }
-
- void resize(unsigned newsize) {
- if (newsize > alloc) {
- unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1);
- if (newalloc < newsize) newalloc = newsize;
- if (newalloc != alloc) {
- data = static_cast<char*>(::realloc(data, newalloc));
- alloc = newalloc;
- }
- }
- size = newsize;
- }
- void append(const QSimpleBuffer &other, unsigned appendsize) {
- unsigned oldsize = size;
- resize(oldsize + appendsize);
- ::memcpy(data + oldsize, other.data, appendsize);
- }
- void popleft(unsigned amount) {
- if (amount >= size) return resize(0);
- size -= amount;
- ::memmove(data, data + amount, size);
- }
- char* cString() {
- if (!alloc) resize(1);
- return (data[size] = '\0', data);
- }
-};
-
-//
-// Uses a scratch "buffer" (which must be used for all reads done in the
-// same file descriptor) to read chunks of data from a file, to read
-// one line at a time. Lines include the trailing newline character ('\n').
-// On EOF, line.size is zero.
-//
-static void bufReadLine(int fd, QSimpleBuffer &line, QSimpleBuffer &buffer)
-{
- for (;;) {
- char *newline = static_cast<char*>(::memchr(buffer.data, '\n', buffer.size));
- if (newline) {
- unsigned piece_size = newline - buffer.data + 1;
- line.append(buffer, piece_size);
- buffer.popleft(piece_size);
- line.resize(line.size - 1);
- return;
- }
- if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) {
- int oldsize = buffer.size;
- buffer.resize(buffer.size + QSimpleBuffer::chunk_size);
- buffer.size = oldsize;
- }
- ssize_t read_bytes = ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size);
- if (read_bytes > 0) buffer.size += read_bytes;
- else return;
- }
-}
-
-//
-// Checks if any line with a given prefix from /proc/cpuinfo contains
-// a certain string, surrounded by spaces.
-//
-static bool procCpuinfoContains(const char *prefix, const char *string)
-{
- int cpuinfo_fd = ::qt_safe_open("/proc/cpuinfo", O_RDONLY);
- if (cpuinfo_fd == -1)
- return false;
-
- unsigned string_len = ::strlen(string);
- unsigned prefix_len = ::strlen(prefix);
- QSimpleBuffer line, buffer;
- bool present = false;
- do {
- line.resize(0);
- bufReadLine(cpuinfo_fd, line, buffer);
- char *colon = static_cast<char*>(::memchr(line.data, ':', line.size));
- if (colon && line.size > prefix_len + string_len) {
- if (!::strncmp(prefix, line.data, prefix_len)) {
- // prefix matches, next character must be ':' or space
- if (line.data[prefix_len] == ':' || ::isspace(line.data[prefix_len])) {
- // Does it contain the string?
- char *found = ::strstr(line.cString(), string);
- if (found && ::isspace(found[-1]) &&
- (::isspace(found[string_len]) || found[string_len] == '\0')) {
- present = true;
- break;
- }
- }
- }
- }
- } while (line.size);
-
- ::qt_safe_close(cpuinfo_fd);
- return present;
-}
-#endif
-
-static inline quint64 detectProcessorFeatures()
-{
- // NOTE: MIPS 74K cores are the only ones supporting DSPr2.
- quint64 flags = 0;
-
-#if defined __mips_dsp
- flags |= Q_UINT64_C(1) << CpuFeatureDSP;
-# if defined __mips_dsp_rev && __mips_dsp_rev >= 2
- flags |= Q_UINT64_C(1) << CpuFeatureDSPR2;
-# elif defined(Q_OS_LINUX)
- if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf"))
- flags |= Q_UINT64_C(1) << CpuFeatureDSPR2;
-# endif
-#elif defined(Q_OS_LINUX)
- if (procCpuinfoContains("ASEs implemented", "dsp")) {
- flags |= Q_UINT64_C(1) << CpuFeatureDSP;
- if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf"))
- flags |= Q_UINT64_C(1) << CpuFeatureDSPR2;
- }
-#endif
-
- return flags;
-}
-
-#else
-static inline uint detectProcessorFeatures()
-{
- return 0;
-}
-#endif
-
-static const int features_count = (sizeof features_indices) / (sizeof features_indices[0]);
-
-// record what CPU features were enabled by default in this Qt build
-static const quint64 minFeature = qCompilerCpuFeatures;
-
-#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
-Q_CORE_EXPORT QBasicAtomicInteger<quint64> qt_cpu_features[1] = { Q_BASIC_ATOMIC_INITIALIZER(0) };
-#else
-Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2] = { Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) };
-#endif
-
-quint64 qDetectCpuFeatures()
-{
- quint64 f = detectProcessorFeatures();
- QByteArray disable = qgetenv("QT_NO_CPU_FEATURE");
- if (!disable.isEmpty()) {
- disable.prepend(' ');
- for (int i = 0; i < features_count; ++i) {
- if (disable.contains(features_string + features_indices[i]))
- f &= ~(Q_UINT64_C(1) << i);
- }
- }
-
-#ifdef RUNNING_ON_VALGRIND
- bool runningOnValgrind = RUNNING_ON_VALGRIND;
-#else
- bool runningOnValgrind = false;
-#endif
- if (Q_UNLIKELY(!runningOnValgrind && minFeature != 0 && (f & minFeature) != minFeature)) {
- quint64 missing = minFeature & ~f;
- fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n ");
- for (int i = 0; i < features_count; ++i) {
- if (missing & (Q_UINT64_C(1) << i))
- fprintf(stderr, "%s", features_string + features_indices[i]);
- }
- fprintf(stderr, "\n");
- fflush(stderr);
- qFatal("Aborted. Incompatible processor: missing feature 0x%llx -%s.", missing,
- features_string + features_indices[qCountTrailingZeroBits(missing)]);
- }
-
- qt_cpu_features[0].storeRelaxed(f | quint32(QSimdInitialized));
-#ifndef Q_ATOMIC_INT64_IS_SUPPORTED
- qt_cpu_features[1].storeRelaxed(f >> 32);
-#endif
- return f;
-}
-
-void qDumpCPUFeatures()
-{
- quint64 features = qCpuFeatures() & ~quint64(QSimdInitialized);
- printf("Processor features: ");
- for (int i = 0; i < features_count; ++i) {
- if (features & (Q_UINT64_C(1) << i))
- printf("%s%s", features_string + features_indices[i],
- minFeature & (Q_UINT64_C(1) << i) ? "[required]" : "");
- }
- if ((features = (qCompilerCpuFeatures & ~features))) {
- printf("\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
- for (int i = 0; i < features_count; ++i) {
- if (features & (Q_UINT64_C(1) << i))
- printf("%s", features_string + features_indices[i]);
- }
- printf("\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!");
- }
- puts("");
-}
-
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
-
-# ifdef Q_PROCESSOR_X86_64
-# define _rdrandXX_step _rdrand64_step
-# define _rdseedXX_step _rdseed64_step
-# else
-# define _rdrandXX_step _rdrand32_step
-# define _rdseedXX_step _rdseed32_step
-# endif
-
-# if QT_COMPILER_SUPPORTS_HERE(RDSEED)
-static QT_FUNCTION_TARGET(RDSEED) unsigned *qt_random_rdseed(unsigned *ptr, unsigned *end) noexcept
-{
- // Unlike for the RDRAND code below, the Intel whitepaper describing the
- // use of the RDSEED instruction indicates we should not retry in a loop.
- // If the independent bit generator used by RDSEED is out of entropy, it
- // may take time to replenish.
- // https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
- while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
- if (_rdseedXX_step(reinterpret_cast<qregisteruint *>(ptr)) == 0)
- goto out;
- ptr += sizeof(qregisteruint)/sizeof(*ptr);
- }
-
- if (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
- if (_rdseed32_step(ptr) == 0)
- goto out;
- ++ptr;
- }
-
-out:
- return ptr;
-}
-# else
-static unsigned *qt_random_rdseed(unsigned *ptr, unsigned *)
-{
- return ptr;
-}
-# endif
-
-static QT_FUNCTION_TARGET(RDRND) unsigned *qt_random_rdrnd(unsigned *ptr, unsigned *end) noexcept
-{
- int retries = 10;
- while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
- if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
- ptr += sizeof(qregisteruint)/sizeof(*ptr);
- else if (--retries == 0)
- goto out;
- }
-
- while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
- bool ok = _rdrand32_step(ptr);
- if (!ok && --retries)
- continue;
- if (ok)
- ++ptr;
- break;
- }
-
-out:
- return ptr;
-}
-
-static QT_FUNCTION_TARGET(RDRND) Q_DECL_COLD_FUNCTION bool checkRdrndWorks() noexcept
-{
- /*
- * Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
- * failing random generation instruction, which always returns
- * 0xffffffff, even when generation was "successful".
- *
- * This code checks if hardware random generator generates four consecutive
- * equal numbers. If it does, then we probably have a failing one and
- * should disable it completely.
- *
- * https://bugreports.qt.io/browse/QTBUG-69423
- */
- constexpr qsizetype TestBufferSize = 4;
- unsigned testBuffer[TestBufferSize] = {};
-
- unsigned *end = qt_random_rdrnd(testBuffer, testBuffer + TestBufferSize);
- if (end < testBuffer + 3) {
- // Random generation didn't produce enough data for us to make a
- // determination whether it's working or not. Assume it isn't, but
- // don't print a warning.
- return false;
- }
-
- // Check the results for equality
- if (testBuffer[0] == testBuffer[1]
- && testBuffer[0] == testBuffer[2]
- && (end < testBuffer + TestBufferSize || testBuffer[0] == testBuffer[3])) {
- fprintf(stderr, "WARNING: CPU random generator seem to be failing, "
- "disabling hardware random number generation\n"
- "WARNING: RDRND generated:");
- for (unsigned *ptr = testBuffer; ptr < end; ++ptr)
- fprintf(stderr, " 0x%x", *ptr);
- fprintf(stderr, "\n");
- return false;
- }
-
- // We're good
- return true;
-}
-
-QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
-{
- unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
- unsigned *end = ptr + count;
-
- if (qCpuHasFeature(RDSEED))
- ptr = qt_random_rdseed(ptr, end);
-
- // fill the buffer with RDRND if RDSEED didn't
- ptr = qt_random_rdrnd(ptr, end);
- return ptr - reinterpret_cast<unsigned *>(buffer);
-}
-#elif defined(Q_PROCESSOR_X86) && !defined(Q_OS_NACL) && !defined(Q_PROCESSOR_ARM)
-static bool checkRdrndWorks() noexcept { return false; }
-#endif // Q_PROCESSOR_X86 && RDRND
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
deleted file mode 100644
index 26e98c4542..0000000000
--- a/src/corelib/tools/qsimd_p.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QSIMD_P_H
-#define QSIMD_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/private/qglobal_p.h>
-
-/*
- * qt_module_config.prf defines the QT_COMPILER_SUPPORTS_XXX macros.
- * They mean the compiler supports the necessary flags and the headers
- * for the x86 and ARM intrinsics:
- * - GCC: the -mXXX or march=YYY flag is necessary before #include
- * up to 4.8; GCC >= 4.9 can include unconditionally
- * - Intel CC: #include can happen unconditionally
- * - MSVC: #include can happen unconditionally
- * - RVCT: ???
- *
- * We will try to include all headers possible under this configuration.
- *
- * MSVC does not define __SSE2__ & family, so we will define them. MSVC 2013 &
- * up do define __AVX__ if the -arch:AVX option is passed on the command-line.
- *
- * Supported XXX are:
- * Flag | Arch | GCC | Intel CC | MSVC |
- * ARM_NEON | ARM | I & C | None | ? |
- * SSE2 | x86 | I & C | I & C | I & C |
- * SSE3 | x86 | I & C | I & C | I only |
- * SSSE3 | x86 | I & C | I & C | I only |
- * SSE4_1 | x86 | I & C | I & C | I only |
- * SSE4_2 | x86 | I & C | I & C | I only |
- * AVX | x86 | I & C | I & C | I & C |
- * AVX2 | x86 | I & C | I & C | I only |
- * AVX512xx | x86 | I & C | I & C | I only |
- * I = intrinsics; C = code generation
- *
- * Code can use the following constructs to determine compiler support & status:
- * - #ifdef __XXX__ (e.g: #ifdef __AVX__ or #ifdef __ARM_NEON__)
- * If this test passes, then the compiler is already generating code for that
- * given sub-architecture. The intrinsics for that sub-architecture are
- * #included and can be used without restriction or runtime check.
- *
- * - #if QT_COMPILER_SUPPORTS(XXX)
- * If this test passes, then the compiler is able to generate code for that
- * given sub-architecture in another translation unit, given the right set of
- * flags. Use of the intrinsics is not guaranteed. This is useful with
- * runtime detection (see below).
- *
- * - #if QT_COMPILER_SUPPORTS_HERE(XXX)
- * If this test passes, then the compiler is able to generate code for that
- * given sub-architecture in this translation unit, even if it is not doing
- * that now (it might be). Individual functions may be tagged with
- * QT_FUNCTION_TARGET(XXX) to cause the compiler to generate code for that
- * sub-arch. Only inside such functions is the use of the intrisics
- * guaranteed to work. This is useful with runtime detection (see below).
- *
- * Runtime detection of a CPU sub-architecture can be done with the
- * qCpuHasFeature(XXX) function. There are two strategies for generating
- * optimized code like that:
- *
- * 1) place the optimized code in a different translation unit (C or assembly
- * sources) and pass the correct flags to the compiler to enable support. Those
- * sources must not include qglobal.h, which means they cannot include this
- * file either. The dispatcher function would look like this:
- *
- * void foo()
- * {
- * #if QT_COMPILER_SUPPORTS(XXX)
- * if (qCpuHasFeature(XXX)) {
- * foo_optimized_xxx();
- * return;
- * }
- * #endif
- * foo_plain();
- * }
- *
- * 2) place the optimized code in a function tagged with QT_FUNCTION_TARGET and
- * surrounded by #if QT_COMPILER_SUPPORTS_HERE(XXX). That code can freely use
- * other Qt code. The dispatcher function would look like this:
- *
- * void foo()
- * {
- * #if QT_COMPILER_SUPPORTS_HERE(XXX)
- * if (qCpuHasFeature(XXX)) {
- * foo_optimized_xxx();
- * return;
- * }
- * #endif
- * foo_plain();
- * }
- */
-
-#if defined(__MINGW64_VERSION_MAJOR) || defined(Q_CC_MSVC)
-#include <intrin.h>
-#endif
-
-#define QT_COMPILER_SUPPORTS(x) (QT_COMPILER_SUPPORTS_ ## x - 0)
-
-#if defined(Q_PROCESSOR_ARM)
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ARM_FEATURE_ ## x)
-# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 600
- /* GCC requires attributes for a function */
-# define QT_FUNCTION_TARGET(x) __attribute__((__target__(QT_FUNCTION_TARGET_STRING_ ## x)))
-# else
-# define QT_FUNCTION_TARGET(x)
-# endif
-# if !defined(__ARM_FEATURE_NEON) && defined(__ARM_NEON__)
-# define __ARM_FEATURE_NEON // also support QT_COMPILER_SUPPORTS_HERE(NEON)
-# endif
-#elif defined(Q_PROCESSOR_MIPS)
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ ## x ## __)
-# define QT_FUNCTION_TARGET(x)
-# if !defined(__MIPS_DSP__) && defined(__mips_dsp) && defined(Q_PROCESSOR_MIPS_32)
-# define __MIPS_DSP__
-# endif
-# if !defined(__MIPS_DSPR2__) && defined(__mips_dspr2) && defined(Q_PROCESSOR_MIPS_32)
-# define __MIPS_DSPR2__
-# endif
-#elif defined(Q_PROCESSOR_X86) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)
-# define QT_COMPILER_SUPPORTS_HERE(x) ((__ ## x ## __) || QT_COMPILER_SUPPORTS(x))
-# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
- /* GCC requires attributes for a function */
-# define QT_FUNCTION_TARGET(x) __attribute__((__target__(QT_FUNCTION_TARGET_STRING_ ## x)))
-# else
-# define QT_FUNCTION_TARGET(x)
-# endif
-#else
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ ## x ## __)
-# define QT_FUNCTION_TARGET(x)
-#endif
-
-#ifdef Q_PROCESSOR_X86
-/* -- x86 intrinsic support -- */
-
-# if defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP >= 2)
-// MSVC doesn't define __SSE2__, so do it ourselves
-# define __SSE__ 1
-# define __SSE2__ 1
-# endif
-
-# ifdef __SSE2__
-// #include the intrinsics
-# include <immintrin.h>
-# endif
-
-# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
-// GCC 4.4 and Clang 2.8 added a few more intrinsics there
-# include <x86intrin.h>
-# endif
-
-# if defined(Q_CC_MSVC) && (defined(_M_AVX) || defined(__AVX__))
-// Visual Studio defines __AVX__ when /arch:AVX is passed, but not the earlier macros
-// See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx
-# define __SSE3__ 1
-# define __SSSE3__ 1
-// no Intel CPU supports SSE4a, so don't define it
-# define __SSE4_1__ 1
-# define __SSE4_2__ 1
-# ifndef __AVX__
-# define __AVX__ 1
-# endif
-# endif
-
-# if defined(__SSE4_2__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
-// POPCNT instructions:
-// All processors that support SSE4.2 support POPCNT
-// (but neither MSVC nor the Intel compiler define this macro)
-# define __POPCNT__ 1
-# endif
-
-// AVX intrinsics
-# if defined(__AVX__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
-// AES, PCLMULQDQ instructions:
-// All processors that support AVX support PCLMULQDQ
-// (but neither MSVC nor the Intel compiler define this macro)
-# define __PCLMUL__ 1
-# endif
-
-# if defined(__AVX2__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
-// F16C & RDRAND instructions:
-// All processors that support AVX2 support F16C & RDRAND:
-// (but neither MSVC nor the Intel compiler define these macros)
-# define __F16C__ 1
-# define __RDRND__ 1
-# endif
-
-# if defined(__BMI__) && !defined(__BMI2__) && defined(Q_CC_INTEL)
-// BMI2 instructions:
-// All processors that support BMI support BMI2 (and AVX2)
-// (but neither MSVC nor the Intel compiler define this macro)
-# define __BMI2__ 1
-# endif
-
-# include "qsimd_x86_p.h"
-
-// Haswell sub-architecture
-//
-// The Intel Core 4th generation was codenamed "Haswell" and introduced AVX2,
-// BMI1, BMI2, FMA, LZCNT, MOVBE, which makes it a good divider for a
-// sub-target for us. The first AMD processor with AVX2 support (Zen) has the
-// same features.
-//
-// macOS's fat binaries support the "x86_64h" sub-architecture and the GNU libc
-// ELF loader also supports a "haswell/" subdir (e.g., /usr/lib/haswell).
-# define QT_FUNCTION_TARGET_STRING_ARCH_HASWELL "arch=haswell"
-# if defined(__AVX2__) && defined(__BMI__) && defined(__BMI2__) && defined(__F16C__) && \
- defined(__FMA__) && defined(__LZCNT__) && defined(__RDRND__)
-# define __haswell__ 1
-# endif
-
-// This constant does not include all CPU features found in a Haswell, only
-// those that we'd have optimized code for.
-// Note: must use Q_CONSTEXPR here, as this file may be compiled in C mode.
-QT_BEGIN_NAMESPACE
-static const quint64 CpuFeatureArchHaswell = 0
- | CpuFeatureSSE2
- | CpuFeatureSSE3
- | CpuFeatureSSSE3
- | CpuFeatureSSE4_1
- | CpuFeatureSSE4_2
- | CpuFeatureFMA
- | CpuFeaturePOPCNT
- | CpuFeatureAVX
- | CpuFeatureF16C
- | CpuFeatureAVX2
- | CpuFeatureBMI
- | CpuFeatureBMI2;
-QT_END_NAMESPACE
-
-#endif /* Q_PROCESSOR_X86 */
-
-// Clang compiler fix, see http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20160222/151168.html
-// This should be tweaked with an "upper version" of clang once we know which release fixes the
-// issue. At that point we can rely on __ARM_FEATURE_CRC32 again.
-#if defined(Q_CC_CLANG) && defined(Q_OS_DARWIN) && defined (__ARM_FEATURE_CRC32)
-# undef __ARM_FEATURE_CRC32
-#endif
-
-// NEON intrinsics
-// note: as of GCC 4.9, does not support function targets for ARM
-#if defined(__ARM_NEON) || defined(__ARM_NEON__)
-#include <arm_neon.h>
-#define QT_FUNCTION_TARGET_STRING_NEON "+neon" // unused: gcc doesn't support function targets on non-aarch64, and on Aarch64 NEON is always available.
-#ifndef __ARM_NEON__
-// __ARM_NEON__ is not defined on AArch64, but we need it in our NEON detection.
-#define __ARM_NEON__
-#endif
-#endif
-// AArch64/ARM64
-#if defined(Q_PROCESSOR_ARM_V8) && defined(__ARM_FEATURE_CRC32)
-#if defined(Q_PROCESSOR_ARM_64)
-// only available on aarch64
-#define QT_FUNCTION_TARGET_STRING_CRC32 "+crc"
-#endif
-# include <arm_acle.h>
-#endif
-
-#ifdef __cplusplus
-#include <qatomic.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef Q_PROCESSOR_X86
-enum CPUFeatures {
-#if defined(Q_PROCESSOR_ARM)
- CpuFeatureNEON = 2,
- CpuFeatureARM_NEON = CpuFeatureNEON,
- CpuFeatureCRC32 = 4,
-#elif defined(Q_PROCESSOR_MIPS)
- CpuFeatureDSP = 2,
- CpuFeatureDSPR2 = 4,
-#endif
-
- // used only to indicate that the CPU detection was initialised
- QSimdInitialized = 1
-};
-
-static const quint64 qCompilerCpuFeatures = 0
-#if defined __ARM_NEON__
- | CpuFeatureNEON
-#endif
-#if defined __ARM_FEATURE_CRC32
- | CpuFeatureCRC32
-#endif
-#if defined __mips_dsp
- | CpuFeatureDSP
-#endif
-#if defined __mips_dspr2
- | CpuFeatureDSPR2
-#endif
- ;
-#endif
-
-#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
-extern Q_CORE_EXPORT QBasicAtomicInteger<quint64> qt_cpu_features[1];
-#else
-extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2];
-#endif
-Q_CORE_EXPORT quint64 qDetectCpuFeatures();
-
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) && !defined(QT_BOOTSTRAPPED)
-Q_CORE_EXPORT qsizetype qRandomCpu(void *, qsizetype) noexcept;
-#else
-static inline qsizetype qRandomCpu(void *, qsizetype) noexcept
-{
- return 0;
-}
-#endif
-
-static inline quint64 qCpuFeatures()
-{
- quint64 features = qt_cpu_features[0].loadRelaxed();
-#ifndef Q_ATOMIC_INT64_IS_SUPPORTED
- features |= quint64(qt_cpu_features[1].loadRelaxed()) << 32;
-#endif
- if (Q_UNLIKELY(features == 0)) {
- features = qDetectCpuFeatures();
- Q_ASSUME(features != 0);
- }
- return features;
-}
-
-#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
- || ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
-
-inline bool qHasHwrng()
-{
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
- return qCpuHasFeature(RDRND);
-#else
- return false;
-#endif
-}
-
-#define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \
- for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)
-
-#define ALIGNMENT_PROLOGUE_32BYTES(ptr, i, length) \
- for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((8 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x7)) & 0x7))); ++i)
-
-QT_END_NAMESPACE
-
-#endif // __cplusplus
-
-#define SIMD_EPILOGUE(i, length, max) \
- for (int _i = 0; _i < max && i < length; ++i, ++_i)
-
-#endif // QSIMD_P_H
diff --git a/src/corelib/tools/qsimd_x86.cpp b/src/corelib/tools/qsimd_x86.cpp
deleted file mode 100644
index 509af464b2..0000000000
--- a/src/corelib/tools/qsimd_x86.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// This is a generated file. DO NOT EDIT.
-// Please see util/x86simdgen/generate.pl
-#include "qsimd_p.h"
-
-static const char features_string[] =
- " sse2\0"
- " sse3\0"
- " ssse3\0"
- " fma\0"
- " sse4.1\0"
- " sse4.2\0"
- " movbe\0"
- " popcnt\0"
- " aes\0"
- " avx\0"
- " f16c\0"
- " rdrnd\0"
- " bmi\0"
- " hle\0"
- " avx2\0"
- " bmi2\0"
- " rtm\0"
- " avx512f\0"
- " avx512dq\0"
- " rdseed\0"
- " avx512ifma\0"
- " avx512pf\0"
- " avx512er\0"
- " avx512cd\0"
- " sha\0"
- " avx512bw\0"
- " avx512vl\0"
- " avx512vbmi\0"
- " avx512vbmi2\0"
- " gfni\0"
- " vaes\0"
- " avx512vnni\0"
- " avx512bitalg\0"
- " avx512vpopcntdq\0"
- " avx5124nniw\0"
- " avx5124fmaps\0"
- "\0";
-
-static const quint16 features_indices[] = {
- 306, 0, 6, 12, 19, 24, 32, 40,
- 47, 55, 60, 65, 71, 78, 83, 88,
- 94, 100, 105, 114, 124, 132, 144, 154,
- 164, 174, 179, 189, 199, 211, 224, 230,
- 236, 248, 262, 279, 292
-};
-
-enum X86CpuidLeaves {
- Leaf1ECX,
- Leaf1EDX,
- Leaf7_0EBX,
- Leaf7_0ECX,
- Leaf7_0EDX,
- X86CpuidMaxLeaf
-};
-
-static const quint8 x86_locators[] = {
- Leaf1EDX*32 + 26, // sse2
- Leaf1ECX*32 + 0, // sse3
- Leaf1ECX*32 + 9, // ssse3
- Leaf1ECX*32 + 12, // fma
- Leaf1ECX*32 + 19, // sse4.1
- Leaf1ECX*32 + 20, // sse4.2
- Leaf1ECX*32 + 22, // movbe
- Leaf1ECX*32 + 23, // popcnt
- Leaf1ECX*32 + 25, // aes
- Leaf1ECX*32 + 28, // avx
- Leaf1ECX*32 + 29, // f16c
- Leaf1ECX*32 + 30, // rdrnd
- Leaf7_0EBX*32 + 3, // bmi
- Leaf7_0EBX*32 + 4, // hle
- Leaf7_0EBX*32 + 5, // avx2
- Leaf7_0EBX*32 + 8, // bmi2
- Leaf7_0EBX*32 + 11, // rtm
- Leaf7_0EBX*32 + 16, // avx512f
- Leaf7_0EBX*32 + 17, // avx512dq
- Leaf7_0EBX*32 + 18, // rdseed
- Leaf7_0EBX*32 + 21, // avx512ifma
- Leaf7_0EBX*32 + 26, // avx512pf
- Leaf7_0EBX*32 + 27, // avx512er
- Leaf7_0EBX*32 + 28, // avx512cd
- Leaf7_0EBX*32 + 29, // sha
- Leaf7_0EBX*32 + 30, // avx512bw
- Leaf7_0EBX*32 + 31, // avx512vl
- Leaf7_0ECX*32 + 1, // avx512vbmi
- Leaf7_0ECX*32 + 6, // avx512vbmi2
- Leaf7_0ECX*32 + 8, // gfni
- Leaf7_0ECX*32 + 9, // vaes
- Leaf7_0ECX*32 + 11, // avx512vnni
- Leaf7_0ECX*32 + 12, // avx512bitalg
- Leaf7_0ECX*32 + 14, // avx512vpopcntdq
- Leaf7_0EDX*32 + 2, // avx5124nniw
- Leaf7_0EDX*32 + 3 // avx5124fmaps
-};
-
-// List of AVX512 features (see detectProcessorFeatures())
-static const quint64 AllAVX512 = 0
- | CpuFeatureAVX512F
- | CpuFeatureAVX512DQ
- | CpuFeatureAVX512IFMA
- | CpuFeatureAVX512PF
- | CpuFeatureAVX512ER
- | CpuFeatureAVX512CD
- | CpuFeatureAVX512BW
- | CpuFeatureAVX512VL
- | CpuFeatureAVX512VBMI
- | CpuFeatureAVX512VBMI2
- | CpuFeatureAVX512VNNI
- | CpuFeatureAVX512BITALG
- | CpuFeatureAVX512VPOPCNTDQ
- | CpuFeatureAVX5124NNIW
- | CpuFeatureAVX5124FMAPS;
diff --git a/src/corelib/tools/qsimd_x86_p.h b/src/corelib/tools/qsimd_x86_p.h
deleted file mode 100644
index 2434e2b797..0000000000
--- a/src/corelib/tools/qsimd_x86_p.h
+++ /dev/null
@@ -1,222 +0,0 @@
-// This is a generated file. DO NOT EDIT.
-// Please see util/x86simdgen/generate.pl
-#ifndef QSIMD_P_H
-# error "Please include <private/qsimd_p.h> instead"
-#endif
-#ifndef QSIMD_X86_P_H
-#define QSIMD_X86_P_H
-
-#include "qsimd_p.h"
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-QT_BEGIN_NAMESPACE
-
-// used only to indicate that the CPU detection was initialized
-#define QSimdInitialized (Q_UINT64_C(1) << 0)
-
-// in CPUID Leaf 1, EDX:
-#define CpuFeatureSSE2 (Q_UINT64_C(1) << 1)
-#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
-
-// in CPUID Leaf 1, ECX:
-#define CpuFeatureSSE3 (Q_UINT64_C(1) << 2)
-#define QT_FUNCTION_TARGET_STRING_SSE3 "sse3"
-#define CpuFeatureSSSE3 (Q_UINT64_C(1) << 3)
-#define QT_FUNCTION_TARGET_STRING_SSSE3 "ssse3"
-#define CpuFeatureFMA (Q_UINT64_C(1) << 4)
-#define QT_FUNCTION_TARGET_STRING_FMA "fma"
-#define CpuFeatureSSE4_1 (Q_UINT64_C(1) << 5)
-#define QT_FUNCTION_TARGET_STRING_SSE4_1 "sse4.1"
-#define CpuFeatureSSE4_2 (Q_UINT64_C(1) << 6)
-#define QT_FUNCTION_TARGET_STRING_SSE4_2 "sse4.2"
-#define CpuFeatureMOVBE (Q_UINT64_C(1) << 7)
-#define QT_FUNCTION_TARGET_STRING_MOVBE "movbe"
-#define CpuFeaturePOPCNT (Q_UINT64_C(1) << 8)
-#define QT_FUNCTION_TARGET_STRING_POPCNT "popcnt"
-#define CpuFeatureAES (Q_UINT64_C(1) << 9)
-#define QT_FUNCTION_TARGET_STRING_AES "aes,sse4.2"
-#define CpuFeatureAVX (Q_UINT64_C(1) << 10)
-#define QT_FUNCTION_TARGET_STRING_AVX "avx"
-#define CpuFeatureF16C (Q_UINT64_C(1) << 11)
-#define QT_FUNCTION_TARGET_STRING_F16C "f16c"
-#define CpuFeatureRDRND (Q_UINT64_C(1) << 12)
-#define QT_FUNCTION_TARGET_STRING_RDRND "rdrnd"
-
-// in CPUID Leaf 7, Sub-leaf 0, EBX:
-#define CpuFeatureBMI (Q_UINT64_C(1) << 13)
-#define QT_FUNCTION_TARGET_STRING_BMI "bmi"
-#define CpuFeatureHLE (Q_UINT64_C(1) << 14)
-#define QT_FUNCTION_TARGET_STRING_HLE "hle"
-#define CpuFeatureAVX2 (Q_UINT64_C(1) << 15)
-#define QT_FUNCTION_TARGET_STRING_AVX2 "avx2"
-#define CpuFeatureBMI2 (Q_UINT64_C(1) << 16)
-#define QT_FUNCTION_TARGET_STRING_BMI2 "bmi2"
-#define CpuFeatureRTM (Q_UINT64_C(1) << 17)
-#define QT_FUNCTION_TARGET_STRING_RTM "rtm"
-#define CpuFeatureAVX512F (Q_UINT64_C(1) << 18)
-#define QT_FUNCTION_TARGET_STRING_AVX512F "avx512f"
-#define CpuFeatureAVX512DQ (Q_UINT64_C(1) << 19)
-#define QT_FUNCTION_TARGET_STRING_AVX512DQ "avx512dq"
-#define CpuFeatureRDSEED (Q_UINT64_C(1) << 20)
-#define QT_FUNCTION_TARGET_STRING_RDSEED "rdseed"
-#define CpuFeatureAVX512IFMA (Q_UINT64_C(1) << 21)
-#define QT_FUNCTION_TARGET_STRING_AVX512IFMA "avx512ifma"
-#define CpuFeatureAVX512PF (Q_UINT64_C(1) << 22)
-#define QT_FUNCTION_TARGET_STRING_AVX512PF "avx512pf"
-#define CpuFeatureAVX512ER (Q_UINT64_C(1) << 23)
-#define QT_FUNCTION_TARGET_STRING_AVX512ER "avx512er"
-#define CpuFeatureAVX512CD (Q_UINT64_C(1) << 24)
-#define QT_FUNCTION_TARGET_STRING_AVX512CD "avx512cd"
-#define CpuFeatureSHA (Q_UINT64_C(1) << 25)
-#define QT_FUNCTION_TARGET_STRING_SHA "sha"
-#define CpuFeatureAVX512BW (Q_UINT64_C(1) << 26)
-#define QT_FUNCTION_TARGET_STRING_AVX512BW "avx512bw"
-#define CpuFeatureAVX512VL (Q_UINT64_C(1) << 27)
-#define QT_FUNCTION_TARGET_STRING_AVX512VL "avx512vl"
-
-// in CPUID Leaf 7, Sub-leaf 0, ECX:
-#define CpuFeatureAVX512VBMI (Q_UINT64_C(1) << 28)
-#define QT_FUNCTION_TARGET_STRING_AVX512VBMI "avx512vbmi"
-#define CpuFeatureAVX512VBMI2 (Q_UINT64_C(1) << 29)
-#define QT_FUNCTION_TARGET_STRING_AVX512VBMI2 "avx512vbmi2"
-#define CpuFeatureGFNI (Q_UINT64_C(1) << 30)
-#define QT_FUNCTION_TARGET_STRING_GFNI "gfni"
-#define CpuFeatureVAES (Q_UINT64_C(1) << 31)
-#define QT_FUNCTION_TARGET_STRING_VAES "vaes"
-#define CpuFeatureAVX512VNNI (Q_UINT64_C(1) << 32)
-#define QT_FUNCTION_TARGET_STRING_AVX512VNNI "avx512vnni"
-#define CpuFeatureAVX512BITALG (Q_UINT64_C(1) << 33)
-#define QT_FUNCTION_TARGET_STRING_AVX512BITALG "avx512bitalg"
-#define CpuFeatureAVX512VPOPCNTDQ (Q_UINT64_C(1) << 34)
-#define QT_FUNCTION_TARGET_STRING_AVX512VPOPCNTDQ "avx512vpopcntdq"
-
-// in CPUID Leaf 7, Sub-leaf 0, EDX:
-#define CpuFeatureAVX5124NNIW (Q_UINT64_C(1) << 35)
-#define QT_FUNCTION_TARGET_STRING_AVX5124NNIW "avx5124nniw"
-#define CpuFeatureAVX5124FMAPS (Q_UINT64_C(1) << 36)
-#define QT_FUNCTION_TARGET_STRING_AVX5124FMAPS "avx5124fmaps"
-
-static const quint64 qCompilerCpuFeatures = 0
-#ifdef __SSE2__
- | CpuFeatureSSE2
-#endif
-#ifdef __SSE3__
- | CpuFeatureSSE3
-#endif
-#ifdef __SSSE3__
- | CpuFeatureSSSE3
-#endif
-#ifdef __FMA__
- | CpuFeatureFMA
-#endif
-#ifdef __SSE4_1__
- | CpuFeatureSSE4_1
-#endif
-#ifdef __SSE4_2__
- | CpuFeatureSSE4_2
-#endif
-#ifdef __MOVBE__
- | CpuFeatureMOVBE
-#endif
-#ifdef __POPCNT__
- | CpuFeaturePOPCNT
-#endif
-#ifdef __AES__
- | CpuFeatureAES
-#endif
-#ifdef __AVX__
- | CpuFeatureAVX
-#endif
-#ifdef __F16C__
- | CpuFeatureF16C
-#endif
-#ifdef __RDRND__
- | CpuFeatureRDRND
-#endif
-#ifdef __BMI__
- | CpuFeatureBMI
-#endif
-#ifdef __HLE__
- | CpuFeatureHLE
-#endif
-#ifdef __AVX2__
- | CpuFeatureAVX2
-#endif
-#ifdef __BMI2__
- | CpuFeatureBMI2
-#endif
-#ifdef __RTM__
- | CpuFeatureRTM
-#endif
-#ifdef __AVX512F__
- | CpuFeatureAVX512F
-#endif
-#ifdef __AVX512DQ__
- | CpuFeatureAVX512DQ
-#endif
-#ifdef __RDSEED__
- | CpuFeatureRDSEED
-#endif
-#ifdef __AVX512IFMA__
- | CpuFeatureAVX512IFMA
-#endif
-#ifdef __AVX512PF__
- | CpuFeatureAVX512PF
-#endif
-#ifdef __AVX512ER__
- | CpuFeatureAVX512ER
-#endif
-#ifdef __AVX512CD__
- | CpuFeatureAVX512CD
-#endif
-#ifdef __SHA__
- | CpuFeatureSHA
-#endif
-#ifdef __AVX512BW__
- | CpuFeatureAVX512BW
-#endif
-#ifdef __AVX512VL__
- | CpuFeatureAVX512VL
-#endif
-#ifdef __AVX512VBMI__
- | CpuFeatureAVX512VBMI
-#endif
-#ifdef __AVX512VBMI2__
- | CpuFeatureAVX512VBMI2
-#endif
-#ifdef __GFNI__
- | CpuFeatureGFNI
-#endif
-#ifdef __VAES__
- | CpuFeatureVAES
-#endif
-#ifdef __AVX512VNNI__
- | CpuFeatureAVX512VNNI
-#endif
-#ifdef __AVX512BITALG__
- | CpuFeatureAVX512BITALG
-#endif
-#ifdef __AVX512VPOPCNTDQ__
- | CpuFeatureAVX512VPOPCNTDQ
-#endif
-#ifdef __AVX5124NNIW__
- | CpuFeatureAVX5124NNIW
-#endif
-#ifdef __AVX5124FMAPS__
- | CpuFeatureAVX5124FMAPS
-#endif
- ;
-
-QT_END_NAMESPACE
-
-#endif // QSIMD_X86_P_H
diff --git a/src/corelib/tools/qt_attribution.json b/src/corelib/tools/qt_attribution.json
new file mode 100644
index 0000000000..928ff537ca
--- /dev/null
+++ b/src/corelib/tools/qt_attribution.json
@@ -0,0 +1,15 @@
+{
+ "Id": "siphash",
+ "Name": "SipHash Algorithm",
+ "QDocModule": "qtcore",
+ "QtUsage": "Used in Qt Core (QHash)",
+
+ "Description": "Implements the SipHash algorithm.",
+ "Homepage": "https://131002.net/siphash/",
+ "DownloadLocation": "https://raw.githubusercontent.com/veorq/SipHash/adcbf09b1684a718f594faa650ffc56bacdb0777/siphash24.c",
+
+ "License": "Creative Commons Zero v1.0 Universal",
+ "LicenseId": "CC0-1.0",
+ "LicenseFile": "LICENSE.siphash",
+ "Copyright": "(C) 2012-2014 Jean-Philippe Aumasson, (C) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>"
+}
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h
new file mode 100644
index 0000000000..0c48fa6e4f
--- /dev/null
+++ b/src/corelib/tools/qtaggedpointer.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTAGGEDPOINTER_H
+#define QTAGGEDPOINTER_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qalgorithms.h>
+#include <QtCore/qmath.h>
+
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+ constexpr quint8 nextByteSize(quint8 bits) { return (bits + 7) / 8; }
+
+ template <typename T>
+ struct TagInfo
+ {
+ static constexpr size_t alignment = alignof(T);
+ static_assert((alignment & (alignment - 1)) == 0,
+ "Alignment of template parameter must be power of two");
+
+ static constexpr quint8 tagBits = QtPrivate::qConstexprCountTrailingZeroBits(alignment);
+ static_assert(tagBits > 0,
+ "Alignment of template parameter does not allow any tags");
+
+ static constexpr size_t tagSize = QtPrivate::qConstexprNextPowerOfTwo(nextByteSize(tagBits));
+ static_assert(tagSize < sizeof(quintptr),
+ "Alignment of template parameter allows tags masking away pointer");
+
+ using TagType = typename QIntegerForSize<tagSize>::Unsigned;
+ };
+}
+
+template <typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
+class QTaggedPointer
+{
+public:
+ using Type = T;
+ using TagType = Tag;
+
+ static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
+ static constexpr quintptr pointerMask() { return ~tagMask(); }
+
+ explicit QTaggedPointer(T *pointer = nullptr, Tag tag = Tag()) noexcept
+ : d(quintptr(pointer))
+ {
+ Q_STATIC_ASSERT(sizeof(Type*) == sizeof(QTaggedPointer<Type>));
+
+ Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0,
+ "QTaggedPointer<T, Tag>", "Pointer is not aligned");
+
+ setTag(tag);
+ }
+
+ Type &operator*() const noexcept
+ {
+ Q_ASSERT(data());
+ return *data();
+ }
+
+ Type *operator->() const noexcept
+ {
+ return data();
+ }
+
+ explicit operator bool() const noexcept
+ {
+ return !isNull();
+ }
+
+ QTaggedPointer<T, Tag> &operator=(T *other) noexcept
+ {
+ d = reinterpret_cast<quintptr>(other) | (d & tagMask());
+ return *this;
+ }
+
+ QTaggedPointer<T, Tag> &operator=(std::nullptr_t) noexcept
+ {
+ d &= tagMask();
+ return *this;
+ }
+
+ static constexpr Tag maximumTag() noexcept
+ {
+ return TagType(typename QtPrivate::TagInfo<T>::TagType(tagMask()));
+ }
+
+ void setTag(Tag tag)
+ {
+ Q_ASSERT_X((static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & pointerMask()) == 0,
+ "QTaggedPointer<T, Tag>::setTag", "Tag is larger than allowed by number of available tag bits");
+
+ d = (d & pointerMask()) | (static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & tagMask());
+ }
+
+ Tag tag() const noexcept
+ {
+ return TagType(typename QtPrivate::TagInfo<T>::TagType(d & tagMask()));
+ }
+
+ T* data() const noexcept
+ {
+ return reinterpret_cast<T*>(d & pointerMask());
+ }
+
+ bool isNull() const noexcept
+ {
+ return !data();
+ }
+
+ void swap(QTaggedPointer<T, Tag> &other) noexcept
+ {
+ qSwap(d, other.d);
+ }
+
+ friend inline bool operator==(const QTaggedPointer<T, Tag> &lhs, const QTaggedPointer<T, Tag> &rhs) noexcept
+ {
+ return lhs.data() == rhs.data();
+ }
+
+ friend inline bool operator!=(const QTaggedPointer<T, Tag> &lhs, const QTaggedPointer<T, Tag> &rhs) noexcept
+ {
+ return lhs.data() != rhs.data();
+ }
+
+ friend inline bool operator==(const QTaggedPointer<T, Tag> &lhs, std::nullptr_t) noexcept
+ {
+ return lhs.isNull();
+ }
+
+ friend inline bool operator==(std::nullptr_t, const QTaggedPointer<T, Tag> &rhs) noexcept
+ {
+ return rhs.isNull();
+ }
+
+ friend inline bool operator!=(const QTaggedPointer<T, Tag> &lhs, std::nullptr_t) noexcept
+ {
+ return !lhs.isNull();
+ }
+
+ friend inline bool operator!=(std::nullptr_t, const QTaggedPointer<T, Tag> &rhs) noexcept
+ {
+ return !rhs.isNull();
+ }
+
+ friend inline bool operator!(const QTaggedPointer<T, Tag> &ptr) noexcept
+ {
+ return !ptr.data();
+ }
+
+protected:
+ quintptr d;
+};
+
+template <typename T>
+Q_DECLARE_TYPEINFO_BODY(QTaggedPointer<T>, Q_MOVABLE_TYPE);
+
+template <typename T, typename Tag>
+inline void swap(QTaggedPointer<T, Tag> &p1, QTaggedPointer<T, Tag> &p2) noexcept
+{
+ p1.swap(p2);
+}
+
+QT_END_NAMESPACE
+
+#endif // QTAGGEDPOINTER_H
diff --git a/src/corelib/tools/qtaggedpointer.qdoc b/src/corelib/tools/qtaggedpointer.qdoc
new file mode 100644
index 0000000000..5b335e8739
--- /dev/null
+++ b/src/corelib/tools/qtaggedpointer.qdoc
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QTaggedPointer
+ \internal
+ \inmodule QtCore
+ \brief The QTaggedPointer class provides a low-level wrapper around raw
+ pointers that makes it possible to store additional information in otherwise unused bits.
+
+ \ingroup tools
+ \reentrant
+
+
+ Data structures in C++ tend to have a natural alignment in memory, based on
+ the alignment requirements of the members fields. For example a structure
+ containing an integer tends to be aligned to a 4-byte boundary in memory. That
+ means a pointer holding the address of an instance will always have the lower
+ two bits set to zero. QTaggedPointer makes it possible to store information
+ in these bits, such as a user provided enum. This is called a tag. The API allows
+ reading and writing the tag. When asked for the raw pointer, it will always return
+ a valid address with the bits used for the tag set to zero.
+
+ This pattern may be useful when creating low-level data structures that
+ need to be as dense as possible.
+
+ The first template parameter is the type the tagged pointer should point
+ to. The second template parameter is the type of the tag. If not specified it will
+ default to an unsigned integral. A more powerful pattern though is to define a
+ flag enum and use that as a tag type:
+
+ \code
+ struct LinkedListItem
+ {
+ enum MyFlag {
+ NoOption = 0x0,
+ SomeOption = 0x1,
+ ThirdWay = 0x2
+ };
+ Q_DECLARE_FLAGS(MyFlags, MyFlag)
+
+ QTaggedPointer<LinkedListItem, MyFlag> next;
+
+ ...
+ };
+
+ Q_DECLARE_OPERATORS_FOR_FLAGS(LinkedListItem::MyFlags)
+
+ LinkedListItem &listItem = ...
+ listItem.next = new LinkedListItem;
+ listItem.next.setTag(LinkedListItem::SomeOption | LinkedListItem::ThirdWay);
+ \endcode
+
+ \note QTaggedPointer does not provide ownership. You are responsible for deleting
+ the data the pointer points to.
+*/
+
+/*!
+ \typedef QTaggedPointer::Type
+
+ Typedef for T.
+*/
+
+/*!
+ \typedef QTaggedPointer::TagType
+
+ Typedef for Tag.
+*/
+
+
+/*!
+ \fn template <typename T, typename Tag> explicit QTaggedPointer<T, Tag>::QTaggedPointer(T *pointer = nullptr, Tag tag = Tag()) noexcept
+
+ Creates a tagged pointer that points to \a pointer and stores the specified \a tag.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> T &QTaggedPointer<T, Tag>::operator*() const noexcept
+
+ Provides access to the pointer's members.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> T *QTaggedPointer<T, Tag>::operator->() const noexcept
+
+ Provides access to the pointer's members.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!() const noexcept
+
+ Returns \c true if the pointer is \nullptr.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> explicit QTaggedPointer<T, Tag>::operator bool() const noexcept
+
+ Returns \c true if the pointer is \e not null.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> QTaggedPointer<T, Tag> &QTaggedPointer<T, Tag>::operator=(T *other) noexcept
+
+ Sets the pointer of this to \a other. The tag remains unchanged.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> void QTaggedPointer<T, Tag>::setTag(Tag tag)
+
+ Sets the tag value to the specified \a tag. The pointer remains unchanged.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> Tag QTaggedPointer<T, Tag>::tag() const noexcept
+
+ Returns the tag stored in the tagged pointer.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> Tag QTaggedPointer<T, Tag>::pointer() const noexcept
+
+ Returns the pointer stored in the tagged pointer.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::isNull() const noexcept
+
+ Returns \c true if the pointer is \nullptr; otherwise returns \c false.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> void QTaggedPointer<T, Tag>::swap(QTaggedPointer<T, Tag> &other) noexcept
+
+ Swaps this instance's pointer and tag with the pointer and tag in \a other.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> inline bool operator==(const QTaggedPointer<T, Tag> &lhs, const QTaggedPointer<T, Tag> &rhs) noexcept
+ \relates QTaggedPointer
+
+ Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
+
+ Two tagged pointers are considered equal if they point to the same object. Their tags are not compared.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> inline bool operator!=(const QTaggedPointer<T, Tag> &lhs, const QTaggedPointer<T, Tag> &rhs) noexcept
+ \relates QTaggedPointer
+
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise returns \c false.
+
+ Two tagged pointers are considered equal if they point to the same object. Their tags are not compared.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> inline bool operator==(const QTaggedPointer<T, Tag> &lhs, std::nullptr_t) noexcept
+ \relates QTaggedPointer
+
+ Returns \c true if \a lhs refers to \c nullptr.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> inline bool operator==(std::nullptr_t, const QTaggedPointer<T, Tag> &rhs) noexcept
+ \relates QTaggedPointer
+
+ Returns \c true if \a rhs refers to \c nullptr.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> inline bool operator!=(const QTaggedPointer<T, Tag> &lhs, std::nullptr_t) noexcept
+ \relates QTaggedPointer
+
+ Returns \c true if \a lhs refers to a valid (i.e. non-null) pointer.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> inline bool operator!=(std::nullptr_t, const QTaggedPointer<T, Tag> &rhs) noexcept
+ \relates QTaggedPointer
+
+ Returns \c true if \a rhs refers to a valid (i.e. non-null) pointer.
+*/
+
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 6be695e317..cf5e2ee8c7 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -57,13 +57,13 @@ QT_BEGIN_NAMESPACE
// Prealloc = 256 by default, specified in qcontainerfwd.h
-template<class T, int Prealloc>
+template<class T, qsizetype Prealloc>
class QVarLengthArray
{
public:
QVarLengthArray() : QVarLengthArray(0) {}
- inline explicit QVarLengthArray(int size);
+ inline explicit QVarLengthArray(qsizetype size);
inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
: a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
@@ -104,7 +104,7 @@ public:
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
{
- resize(int(list.size())); // ### q6sizetype
+ resize(qsizetype(list.size()));
std::copy(list.begin(), list.end(),
QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
return *this;
@@ -116,50 +116,50 @@ public:
ptr[s - 1].~T();
--s;
}
- inline int size() const { return s; }
- inline int count() const { return s; }
- inline int length() const { return s; }
+ inline qsizetype size() const { return s; }
+ inline qsizetype count() const { return s; }
+ inline qsizetype length() const { return s; }
inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
inline const T& first() const { Q_ASSERT(!isEmpty()); return *begin(); }
T& last() { Q_ASSERT(!isEmpty()); return *(end() - 1); }
const T& last() const { Q_ASSERT(!isEmpty()); return *(end() - 1); }
inline bool isEmpty() const { return (s == 0); }
- inline void resize(int size);
+ inline void resize(qsizetype size);
inline void clear() { resize(0); }
inline void squeeze();
- inline int capacity() const { return a; }
- inline void reserve(int size);
+ inline qsizetype capacity() const { return a; }
+ inline void reserve(qsizetype size);
- inline int indexOf(const T &t, int from = 0) const;
- inline int lastIndexOf(const T &t, int from = -1) const;
+ inline qsizetype indexOf(const T &t, qsizetype from = 0) const;
+ inline qsizetype lastIndexOf(const T &t, qsizetype from = -1) const;
inline bool contains(const T &t) const;
- inline T &operator[](int idx) {
+ inline T &operator[](qsizetype idx) {
Q_ASSERT(idx >= 0 && idx < s);
return ptr[idx];
}
- inline const T &operator[](int idx) const {
+ inline const T &operator[](qsizetype idx) const {
Q_ASSERT(idx >= 0 && idx < s);
return ptr[idx];
}
- inline const T &at(int idx) const { return operator[](idx); }
+ inline const T &at(qsizetype idx) const { return operator[](idx); }
- T value(int i) const;
- T value(int i, const T &defaultValue) const;
+ T value(qsizetype i) const;
+ T value(qsizetype i, const T &defaultValue) const;
inline void append(const T &t) {
if (s == a) { // i.e. s != 0
T copy(t);
realloc(s, s<<1);
- const int idx = s++;
+ const qsizetype idx = s++;
if (QTypeInfo<T>::isComplex) {
new (ptr + idx) T(std::move(copy));
} else {
ptr[idx] = std::move(copy);
}
} else {
- const int idx = s++;
+ const qsizetype idx = s++;
if (QTypeInfo<T>::isComplex) {
new (ptr + idx) T(t);
} else {
@@ -171,14 +171,14 @@ public:
void append(T &&t) {
if (s == a)
realloc(s, s << 1);
- const int idx = s++;
+ const qsizetype idx = s++;
if (QTypeInfo<T>::isComplex)
new (ptr + idx) T(std::move(t));
else
ptr[idx] = std::move(t);
}
- void append(const T *buf, int size);
+ void append(const T *buf, qsizetype size);
inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
{ append(t); return *this; }
inline QVarLengthArray<T, Prealloc> &operator<<(T &&t)
@@ -190,18 +190,18 @@ public:
void prepend(T &&t);
void prepend(const T &t);
- void insert(int i, T &&t);
- void insert(int i, const T &t);
- void insert(int i, int n, const T &t);
- void replace(int i, const T &t);
- void remove(int i);
- void remove(int i, int n);
+ void insert(qsizetype i, T &&t);
+ void insert(qsizetype i, const T &t);
+ void insert(qsizetype i, qsizetype n, const T &t);
+ void replace(qsizetype i, const T &t);
+ void remove(qsizetype i);
+ void remove(qsizetype i, qsizetype n);
inline T *data() { return ptr; }
inline const T *data() const { return ptr; }
inline const T * constData() const { return ptr; }
- typedef int size_type;
+ typedef qsizetype size_type;
typedef T value_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
@@ -229,7 +229,7 @@ public:
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
- iterator insert(const_iterator before, int n, const T &x);
+ iterator insert(const_iterator before, qsizetype n, const T &x);
iterator insert(const_iterator before, T &&x);
inline iterator insert(const_iterator before, const T &x) { return insert(before, 1, x); }
iterator erase(const_iterator begin, const_iterator end);
@@ -247,10 +247,10 @@ public:
void shrink_to_fit() { squeeze(); }
private:
- void realloc(int size, int alloc);
+ void realloc(qsizetype size, qsizetype alloc);
- int a; // capacity
- int s; // size
+ qsizetype a; // capacity
+ qsizetype s; // size
T *ptr; // data
union {
char array[Prealloc * sizeof(T)];
@@ -272,8 +272,8 @@ template <typename InputIterator,
QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray<ValueType>;
#endif
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(int asize)
+template <class T, qsizetype Prealloc>
+Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype asize)
: s(asize) {
Q_STATIC_ASSERT_X(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0.");
Q_ASSERT_X(s >= 0, "QVarLengthArray::QVarLengthArray()", "Size must be greater than or equal to 0.");
@@ -292,19 +292,19 @@ Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(int asize)
}
}
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(int asize)
+template <class T, qsizetype Prealloc>
+Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(qsizetype asize)
{ realloc(asize, qMax(asize, a)); }
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(int asize)
+template <class T, qsizetype Prealloc>
+Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(qsizetype asize)
{ if (asize > a) realloc(s, asize); }
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::indexOf(const T &t, int from) const
+template <class T, qsizetype Prealloc>
+Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::indexOf(const T &t, qsizetype from) const
{
if (from < 0)
- from = qMax(from + s, 0);
+ from = qMax(from + s, qsizetype(0));
if (from < s) {
T *n = ptr + from - 1;
T *e = ptr + s;
@@ -315,8 +315,8 @@ Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::indexOf(const T &t, int from
return -1;
}
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, int from) const
+template <class T, qsizetype Prealloc>
+Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, qsizetype from) const
{
if (from < 0)
from += s;
@@ -333,7 +333,7 @@ Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, int
return -1;
}
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const T &t) const
{
T *b = ptr;
@@ -345,14 +345,14 @@ Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const T &t) const
return false;
}
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int increment)
+template <class T, qsizetype Prealloc>
+Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, qsizetype increment)
{
Q_ASSERT(abuf);
if (increment <= 0)
return;
- const int asize = s + increment;
+ const qsizetype asize = s + increment;
if (asize >= a)
realloc(s, qMax(s*2, asize));
@@ -367,18 +367,18 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, in
}
}
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::squeeze()
{ realloc(s, s); }
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int aalloc)
+template <class T, qsizetype Prealloc>
+Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(qsizetype asize, qsizetype aalloc)
{
Q_ASSERT(aalloc >= asize);
T *oldPtr = ptr;
- int osize = s;
+ qsizetype osize = s;
- const int copySize = qMin(asize, osize);
+ const qsizetype copySize = qMin(asize, osize);
Q_ASSUME(copySize >= 0);
if (aalloc != a) {
if (aalloc > Prealloc) {
@@ -402,7 +402,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
}
} QT_CATCH(...) {
// clean up all the old objects and then free the old ptr
- int sClean = s;
+ qsizetype sClean = s;
while (sClean < osize)
(oldPtr+(sClean++))->~T();
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
@@ -433,61 +433,60 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
}
}
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i) const
+template <class T, qsizetype Prealloc>
+Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(qsizetype i) const
{
- if (uint(i) >= uint(size())) {
+ if (size_t(i) >= size_t(size()))
return T();
- }
return at(i);
}
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i, const T &defaultValue) const
+template <class T, qsizetype Prealloc>
+Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(qsizetype i, const T &defaultValue) const
{
- return (uint(i) >= uint(size())) ? defaultValue : at(i);
+ return (size_t(i) >= size_t(size())) ? defaultValue : at(i);
}
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::insert(int i, T &&t)
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, T &&t)
{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
insert(cbegin() + i, std::move(t)); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::insert(int i, const T &t)
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, const T &t)
{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
insert(begin() + i, 1, t); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::insert(int i, int n, const T &t)
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, qsizetype n, const T &t)
{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
insert(begin() + i, n, t); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::remove(int i, int n)
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::remove(qsizetype i, qsizetype n)
{ Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= s, "QVarLengthArray::remove", "index out of range");
erase(begin() + i, begin() + i + n); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::remove(int i)
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::remove(qsizetype i)
{ Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::remove", "index out of range");
erase(begin() + i, begin() + i + 1); }
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
inline void QVarLengthArray<T, Prealloc>::prepend(T &&t)
{ insert(cbegin(), std::move(t)); }
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
inline void QVarLengthArray<T, Prealloc>::prepend(const T &t)
{ insert(begin(), 1, t); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::replace(int i, const T &t)
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::replace(qsizetype i, const T &t)
{
Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::replace", "index out of range");
const T copy(t);
data()[i] = copy;
}
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&t)
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
- int offset = int(before - ptr);
+ qsizetype offset = qsizetype(before - ptr);
reserve(s + 1);
if (!QTypeInfo<T>::isRelocatable) {
T *b = ptr + offset;
@@ -511,12 +510,12 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
return ptr + offset;
}
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, size_type n, const T &t)
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
- int offset = int(before - ptr);
+ qsizetype offset = qsizetype(before - ptr);
if (n != 0) {
resize(s + n);
const T copy(t);
@@ -540,15 +539,15 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
return ptr + offset;
}
-template <class T, int Prealloc>
+template <class T, qsizetype Prealloc>
Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator abegin, const_iterator aend)
{
Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::insert", "The specified const_iterator argument 'abegin' is invalid");
Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::insert", "The specified const_iterator argument 'aend' is invalid");
- int f = int(abegin - ptr);
- int l = int(aend - ptr);
- int n = l - f;
+ qsizetype f = qsizetype(abegin - ptr);
+ qsizetype l = qsizetype(aend - ptr);
+ qsizetype n = l - f;
if (QTypeInfo<T>::isComplex) {
std::copy(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f));
T *i = ptr + s;
@@ -564,7 +563,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
return ptr + f;
}
-template <typename T, int Prealloc1, int Prealloc2>
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
{
if (l.size() != r.size())
@@ -575,13 +574,13 @@ bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T,
return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(rb, r.size()));
}
-template <typename T, int Prealloc1, int Prealloc2>
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
{
return !(l == r);
}
-template <typename T, int Prealloc1, int Prealloc2>
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
bool operator<(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end())))
@@ -590,29 +589,29 @@ bool operator<(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T
rhs.begin(), rhs.end());
}
-template <typename T, int Prealloc1, int Prealloc2>
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
inline bool operator>(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
noexcept(noexcept(lhs < rhs))
{
return rhs < lhs;
}
-template <typename T, int Prealloc1, int Prealloc2>
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
inline bool operator<=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
noexcept(noexcept(lhs < rhs))
{
return !(lhs > rhs);
}
-template <typename T, int Prealloc1, int Prealloc2>
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
inline bool operator>=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
noexcept(noexcept(lhs < rhs))
{
return !(lhs < rhs);
}
-template <typename T, int Prealloc>
-uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0)
+template <typename T, qsizetype Prealloc>
+size_t qHash(const QVarLengthArray<T, Prealloc> &key, size_t seed = 0)
noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
{
return qHashRange(key.cbegin(), key.cend(), seed);
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 3dab41dd22..e43d6f152a 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -87,10 +87,10 @@
places inside Qt and was added to Qt's public API for the
convenience of advanced users.
- \sa QVector, QList, QLinkedList
+ \sa QVector, QList
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(int size)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype size)
Constructs an array with an initial size of \a size elements.
@@ -101,7 +101,7 @@
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(std::initializer_list<T> args)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(std::initializer_list<T> args)
\since 5.5
Constructs an array from the std::initializer_list given by \a args.
@@ -110,7 +110,7 @@
lists.
*/
-/*! \fn template<class T, int Prealloc> template<typename InputIterator> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
+/*! \fn template<class T, qsizetype Prealloc> template<typename InputIterator> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
\since 5.14
Constructs an array with the contents in the iterator range [\a first, \a last).
@@ -119,26 +119,26 @@
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::~QVarLengthArray()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::~QVarLengthArray()
Destroys the array.
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::size() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::size() const
Returns the number of elements in the array.
\sa isEmpty(), resize()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::count() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::count() const
Same as size().
\sa isEmpty(), resize()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::length() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::length() const
\since 5.0
Same as size().
@@ -146,7 +146,7 @@
\sa isEmpty(), resize()
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::first()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::first()
Returns a reference to the first item in the array. The array must
not be empty. If the array can be empty, check isEmpty() before
@@ -155,24 +155,24 @@
\sa last(), isEmpty()
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::first() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::first() const
\overload
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::front()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::front()
\since 5.0
Same as first(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::front() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::front() const
\since 5.0
\overload
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::last()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::last()
Returns a reference to the last item in the array. The array must
not be empty. If the array can be empty, check isEmpty() before
@@ -181,37 +181,37 @@
\sa first(), isEmpty()
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::last() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::last() const
\overload
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::back()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::back()
\since 5.0
Same as last(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::back() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::back() const
\since 5.0
\overload
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::shrink_to_fit()
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::shrink_to_fit()
\since 5.10
Same as squeeze(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> bool QVarLengthArray<T, Prealloc>::isEmpty() const
+/*! \fn template<class T, qsizetype Prealloc> bool QVarLengthArray<T, Prealloc>::isEmpty() const
Returns \c true if the array has size 0; otherwise returns \c false.
\sa size(), resize()
*/
-/*! \fn template<class T, int Prealloc> bool QVarLengthArray<T, Prealloc>::empty() const
+/*! \fn template<class T, qsizetype Prealloc> bool QVarLengthArray<T, Prealloc>::empty() const
\since 5.0
Returns \c true if the array has size 0; otherwise returns \c false.
@@ -219,14 +219,14 @@
Same as isEmpty(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::clear()
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::clear()
Removes all the elements from the array.
Same as resize(0).
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::resize(int size)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::resize(qsizetype size)
Sets the size of the array to \a size. If \a size is greater than
the current size, elements are added to the end. If \a size is
@@ -240,7 +240,7 @@
\sa size(), squeeze()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::capacity() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::capacity() const
Returns the maximum number of elements that can be stored in the
array without forcing a reallocation.
@@ -253,7 +253,7 @@
\sa reserve(), squeeze()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::reserve(int size)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::reserve(qsizetype size)
Attempts to allocate memory for at least \a size elements. If you
know in advance how large the array can get, you can call this
@@ -270,7 +270,7 @@
\sa capacity(), squeeze()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::squeeze()
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::squeeze()
\since 5.1
Releases any memory not required to store the items.
@@ -284,7 +284,7 @@
\sa reserve(), capacity(), resize()
*/
-/*! \fn template<class T, int Prealloc> T &QVarLengthArray<T, Prealloc>::operator[](int i)
+/*! \fn template<class T, qsizetype Prealloc> T &QVarLengthArray<T, Prealloc>::operator[](qsizetype i)
Returns a reference to the item at index position \a i.
@@ -294,14 +294,14 @@
\sa data(), at()
*/
-/*! \fn template<class T, int Prealloc> const T &QVarLengthArray<T, Prealloc>::operator[](int i) const
+/*! \fn template<class T, qsizetype Prealloc> const T &QVarLengthArray<T, Prealloc>::operator[](qsizetype i) const
\overload
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::append(const T &t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::append(const T &t)
Appends item \a t to the array, extending the array if necessary.
@@ -309,7 +309,7 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::push_back(const T &t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::push_back(const T &t)
\since 5.0
Appends item \a t to the array, extending the array if necessary.
@@ -317,7 +317,7 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::append(T &&t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::append(T &&t)
\overload append
\since 5.9
@@ -331,7 +331,7 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::push_back(T &&t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::push_back(T &&t)
\overload push_back
\since 5.9
@@ -345,7 +345,7 @@
*/
/*!
- \fn template<class T, int Prealloc> inline void QVarLengthArray<T, Prealloc>::removeLast()
+ \fn template<class T, qsizetype Prealloc> inline void QVarLengthArray<T, Prealloc>::removeLast()
\since 4.5
Decreases the size of the array by one. The allocated size is not changed.
@@ -354,20 +354,20 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::pop_back()
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::pop_back()
\since 5.0
Same as removeLast(). Provided for STL-compatibility.
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::append(const T *buf, int size)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::append(const T *buf, qsizetype size)
Appends \a size amount of items referenced by \a buf to this array.
*/
-/*! \fn template<class T, int Prealloc> T *QVarLengthArray<T, Prealloc>::data()
+/*! \fn template<class T, qsizetype Prealloc> T *QVarLengthArray<T, Prealloc>::data()
Returns a pointer to the data stored in the array. The pointer can
be used to access and modify the items in the array.
@@ -383,12 +383,12 @@
\sa constData(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> const T *QVarLengthArray<T, Prealloc>::data() const
+/*! \fn template<class T, qsizetype Prealloc> const T *QVarLengthArray<T, Prealloc>::data() const
\overload
*/
-/*! \fn template<class T, int Prealloc> const T *QVarLengthArray<T, Prealloc>::constData() const
+/*! \fn template<class T, qsizetype Prealloc> const T *QVarLengthArray<T, Prealloc>::constData() const
Returns a const pointer to the data stored in the array. The
pointer can be used to access the items in the array. The
@@ -400,11 +400,11 @@
\sa data(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(const QVarLengthArray<T, Prealloc> &other)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(const QVarLengthArray<T, Prealloc> &other)
Assigns \a other to this array and returns a reference to this array.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(std::initializer_list<T> list)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(std::initializer_list<T> list)
\since 5.5
Assigns the values of \a list to this array, and returns a reference to this array.
@@ -413,11 +413,11 @@
lists.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
Constructs a copy of \a other.
*/
-/*! \fn template<class T, int Prealloc> const T &QVarLengthArray<T, Prealloc>::at(int i) const
+/*! \fn template<class T, qsizetype Prealloc> const T &QVarLengthArray<T, Prealloc>::at(qsizetype i) const
Returns a reference to the item at index position \a i.
@@ -427,7 +427,7 @@
\sa value(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> T QVarLengthArray<T, Prealloc>::value(int i) const
+/*! \fn template<class T, qsizetype Prealloc> T QVarLengthArray<T, Prealloc>::value(qsizetype i) const
Returns the value at index position \a i.
@@ -439,7 +439,7 @@
\sa at(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> T QVarLengthArray<T, Prealloc>::value(int i, const T &defaultValue) const
+/*! \fn template<class T, qsizetype Prealloc> T QVarLengthArray<T, Prealloc>::value(qsizetype i, const T &defaultValue) const
\overload
@@ -525,8 +525,8 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::prepend(const T &value)
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::prepend(T &&value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::prepend(const T &value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::prepend(T &&value)
\since 4.8
Inserts \a value at the beginning of the array.
@@ -537,13 +537,12 @@
For large arrays, this operation can be slow (\l{linear time}),
because it requires moving all the items in the vector by one
position further in memory. If you want a container class that
- provides a fast prepend() function, use QList or QLinkedList
- instead.
+ provides a fast prepend() function, use std::list instead.
\sa append(), insert()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::replace(int i, const T &value)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::replace(qsizetype i, const T &value)
\since 4.8
Replaces the item at index position \a i with \a value.
@@ -554,7 +553,7 @@
\sa operator[](), remove()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::remove(int i)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::remove(qsizetype i)
\overload
\since 4.8
@@ -564,7 +563,7 @@
\sa insert(), replace()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::remove(int i, int count)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::remove(qsizetype i, qsizetype count)
\overload
\since 4.8
@@ -575,7 +574,7 @@
\sa insert(), replace()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::begin()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::begin()
\since 4.8
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
@@ -584,12 +583,12 @@
\sa constBegin(), end()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::begin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::begin() const
\since 4.8
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cbegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cbegin() const
\since 5.0
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
@@ -598,7 +597,7 @@
\sa begin(), cend()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constBegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constBegin() const
\since 4.8
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
@@ -607,7 +606,7 @@
\sa begin(), constEnd()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::end()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::end()
\since 4.8
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
@@ -616,13 +615,13 @@
\sa begin(), constEnd()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::end() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::end() const
\since 4.8
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cend() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cend() const
\since 5.0
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
@@ -631,7 +630,7 @@
\sa cbegin(), end()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constEnd() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constEnd() const
\since 4.8
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
@@ -640,7 +639,7 @@
\sa constBegin(), end()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rbegin()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rbegin()
\since 5.6
Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
@@ -649,12 +648,12 @@
\sa begin(), crbegin(), rend()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rbegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rbegin() const
\since 5.6
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crbegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crbegin() const
\since 5.6
Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
@@ -663,7 +662,7 @@
\sa begin(), rbegin(), rend()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rend()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rend()
\since 5.6
Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
@@ -672,12 +671,12 @@
\sa end(), crend(), rbegin()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rend() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rend() const
\since 5.6
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crend() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crend() const
\since 5.6
Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
@@ -686,7 +685,7 @@
\sa end(), rend(), rbegin()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator pos)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator pos)
\since 4.8
Removes the item pointed to by the iterator \a pos from the
@@ -696,7 +695,7 @@
\sa insert(), remove()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator begin, const_iterator end)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator begin, const_iterator end)
\overload
\since 4.8
@@ -707,8 +706,8 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::insert(int i, const T &value)
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::insert(int i, T &&value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::insert(qsizetype i, const T &value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::insert(qsizetype i, T &&value)
\since 4.8
Inserts \a value at index position \a i in the array. If \a i is
@@ -718,13 +717,13 @@
For large arrays, this operation can be slow (\l{linear time}),
because it requires moving all the items at indexes \a i and
above by one position further in memory. If you want a container
- class that provides a fast insert() function, use QLinkedList
+ class that provides a fast insert() function, use std::list
instead.
\sa remove()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::insert(int i, int count, const T &value)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::insert(qsizetype i, qsizetype count, const T &value)
\overload
\since 4.8
@@ -733,8 +732,8 @@
vector.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value)
- \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value)
+ \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&value)
\overload
\since 4.8
@@ -743,7 +742,7 @@
\a before. Returns an iterator pointing at the inserted item.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, int count, const T &value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, qsizetype count, const T &value)
\since 4.8
Inserts \a count copies of \a value in front of the item pointed to
@@ -753,7 +752,7 @@
-/*! \fn template<class T, int Prealloc1, int Prealloc2> bool operator==(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
+/*! \fn template<class T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator==(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
\relates QVarLengthArray
\since 4.8
@@ -768,7 +767,7 @@
\sa operator!=()
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator!=(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator!=(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
\relates QVarLengthArray
\since 4.8
@@ -783,7 +782,7 @@
\sa operator==()
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator<(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator<(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -795,7 +794,7 @@
of \c operator<().
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator<=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator<=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -807,7 +806,7 @@
of \c operator<().
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator>(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator>(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -819,7 +818,7 @@
of \c operator<().
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator>=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator>=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -831,7 +830,7 @@
of \c operator<().
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(const T &value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(const T &value)
\since 4.8
Appends \a value to the array and returns a reference to this
@@ -840,7 +839,7 @@
\sa append(), operator+=()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(T &&value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(T &&value)
\since 5.11
\overload
@@ -848,7 +847,7 @@
\sa append(), operator+=()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(const T &value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(const T &value)
\since 4.8
Appends \a value to the array and returns a reference to this vector.
@@ -856,7 +855,7 @@
\sa append(), operator<<()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(T &&value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(T &&value)
\since 5.11
\overload
@@ -864,7 +863,7 @@
\sa append(), operator<<()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::indexOf(const T &value, int from = 0) const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::indexOf(const T &value, qsizetype from = 0) const
\since 5.3
Returns the index position of the first occurrence of \a value in
@@ -877,7 +876,7 @@
\sa lastIndexOf(), contains()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &value, int from = -1) const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const T &value, qsizetype from = -1) const
\since 5.3
Returns the index position of the last occurrence of the value \a
@@ -891,7 +890,7 @@
\sa indexOf(), contains()
*/
-/*! \fn template<class T, int Prealloc> bool QVarLengthArray<T, Prealloc>::contains(const T &value) const
+/*! \fn template<class T, qsizetype Prealloc> bool QVarLengthArray<T, Prealloc>::contains(const T &value) const
\since 5.3
Returns \c true if the array contains an occurrence of \a value;
@@ -904,7 +903,7 @@
*/
/*!
- \fn template <typename T, int Prealloc> uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0)
+ \fn template <typename T, qsizetype Prealloc> size_t qHash(const QVarLengthArray<T, Prealloc> &key, size_t seed = 0)
\relates QVarLengthArray
\since 5.14
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 288c082c44..88c942ca15 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 Intel Corporation
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -40,127 +41,280 @@
#ifndef QVECTOR_H
#define QVECTOR_H
-#include <QtCore/qalgorithms.h>
-#include <QtCore/qiterator.h>
-#include <QtCore/qrefcount.h>
-#include <QtCore/qarraydata.h>
+#include <QtCore/qarraydatapointer.h>
+#include <QtCore/qnamespace.h>
#include <QtCore/qhashfunctions.h>
-#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qiterator.h>
-#include <iterator>
+#include <functional>
+#include <limits>
#include <initializer_list>
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
-#include <vector>
-#endif
-#include <stdlib.h>
-#include <string.h>
-
-#include <algorithm>
+#include <type_traits>
QT_BEGIN_NAMESPACE
+namespace QtPrivate {
+ template <typename V, typename U> int indexOf(const QVector<V> &list, const U &u, int from);
+ template <typename V, typename U> int lastIndexOf(const QVector<V> &list, const U &u, int from);
+}
+
+template <typename T> struct QVectorSpecialMethods
+{
+protected:
+ ~QVectorSpecialMethods() = default;
+};
+template <> struct QVectorSpecialMethods<QByteArray>;
+template <> struct QVectorSpecialMethods<QString>;
+
template <typename T>
class QVector
+#ifndef Q_QDOC
+ : public QVectorSpecialMethods<T>
+#endif
{
typedef QTypedArrayData<T> Data;
- Data *d;
+ typedef QArrayDataOps<T> DataOps;
+ typedef QArrayDataPointer<T> DataPointer;
+ class DisableRValueRefs {};
+
+ DataPointer d;
+
+ template <typename V, typename U> friend int QtPrivate::indexOf(const QVector<V> &list, const U &u, int from);
+ template <typename V, typename U> friend int QtPrivate::lastIndexOf(const QVector<V> &list, const U &u, int from);
public:
- inline QVector() noexcept : d(Data::sharedNull()) { }
- explicit QVector(int size);
- QVector(int size, const T &t);
- inline QVector(const QVector<T> &v);
- inline ~QVector() { if (!d->ref.deref()) freeData(d); }
- QVector<T> &operator=(const QVector<T> &v);
- QVector(QVector<T> &&other) noexcept : d(other.d) { other.d = Data::sharedNull(); }
- QVector<T> &operator=(QVector<T> &&other) noexcept
- { QVector moved(std::move(other)); swap(moved); return *this; }
- void swap(QVector<T> &other) noexcept { qSwap(d, other.d); }
- inline QVector(std::initializer_list<T> args);
- QVector<T> &operator=(std::initializer_list<T> args);
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
- inline QVector(InputIterator first, InputIterator last);
- explicit QVector(QArrayDataPointerRef<T> ref) noexcept : d(ref.ptr) {}
+ typedef T Type;
+ typedef T value_type;
+ typedef value_type *pointer;
+ typedef const value_type *const_pointer;
+ typedef value_type &reference;
+ typedef const value_type &const_reference;
+ typedef int size_type;
+ typedef qptrdiff difference_type;
+ typedef typename Data::iterator iterator;
+ typedef typename Data::const_iterator const_iterator;
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef typename DataPointer::parameter_type parameter_type;
+ using rvalue_ref = typename std::conditional<DataPointer::pass_parameter_by_value, DisableRValueRefs, T &&>::type;
- bool operator==(const QVector<T> &v) const;
- inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
+private:
+ void resize_internal(int i, Qt::Initialization);
+ bool isValidIterator(const_iterator i) const
+ {
+ const std::less<const T*> less = {};
+ return !less(d->end(), i) && !less(i, d->begin());
+ }
+public:
+ QVector(DataPointer dd) noexcept
+ : d(dd)
+ {
+ }
- inline int size() const { return d->size; }
+public:
+ inline QVector() noexcept { }
+ explicit QVector(int size)
+ : d(Data::allocate(size))
+ {
+ if (size)
+ d->appendInitialize(size);
+ }
+ QVector(int size, const T &t)
+ : d(Data::allocate(size))
+ {
+ if (size)
+ d->copyAppend(size, t);
+ }
- inline bool isEmpty() const { return d->size == 0; }
+ inline QVector(const QVector<T> &other) noexcept : d(other.d) {}
+ QVector(QVector<T> &&other) noexcept : d(std::move(other.d)) {}
+ inline QVector(std::initializer_list<T> args)
+ : d(Data::allocate(args.size()))
+ {
+ if (args.size())
+ d->copyAppend(args.begin(), args.end());
+ }
- void resize(int size);
+ ~QVector() /*noexcept(std::is_nothrow_destructible<T>::value)*/ {}
+ QVector<T> &operator=(const QVector<T> &other) { d = other.d; return *this; }
+ QVector &operator=(QVector &&other) noexcept(std::is_nothrow_destructible<T>::value)
+ {
+ d = std::move(other.d);
+ return *this;
+ }
+ QVector<T> &operator=(std::initializer_list<T> args)
+ {
+ d = DataPointer(Data::allocate(args.size()));
+ if (args.size())
+ d->copyAppend(args.begin(), args.end());
+ return *this;
+ }
+ template <typename InputIterator, QtPrivate::IfIsForwardIterator<InputIterator> = true>
+ QVector(InputIterator i1, InputIterator i2)
+ : d(Data::allocate(std::distance(i1, i2)))
+ {
+ if (std::distance(i1, i2))
+ d->copyAppend(i1, i2);
+ }
- inline int capacity() const { return int(d->alloc); }
- void reserve(int size);
- inline void squeeze()
+ template <typename InputIterator, QtPrivate::IfIsNotForwardIterator<InputIterator> = true>
+ QVector(InputIterator i1, InputIterator i2)
+ : QVector()
{
- if (d->size < int(d->alloc)) {
- if (!d->size) {
- *this = QVector<T>();
- return;
- }
- realloc(d->size);
- }
- if (d->capacityReserved) {
- // capacity reserved in a read only memory would be useless
- // this checks avoid writing to such memory.
- d->capacityReserved = 0;
- }
+ QtPrivate::reserveIfForwardIterator(this, i1, i2);
+ std::copy(i1, i2, std::back_inserter(*this));
}
- inline void detach();
- inline bool isDetached() const { return !d->ref.isShared(); }
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- inline void setSharable(bool sharable)
+ void swap(QVector<T> &other) noexcept { qSwap(d, other.d); }
+
+ friend bool operator==(const QVector &l, const QVector &r)
{
- if (sharable == d->ref.isSharable())
- return;
- if (!sharable)
- detach();
+ if (l.size() != r.size())
+ return false;
+ if (l.begin() == r.begin())
+ return true;
- if (d == Data::unsharableEmpty()) {
- if (sharable)
- d = Data::sharedNull();
+ // do element-by-element comparison
+ return l.d->compare(l.begin(), r.begin(), l.size());
+ }
+ friend bool operator!=(const QVector &l, const QVector &r)
+ {
+ return !(l == r);
+ }
+
+ int size() const noexcept { return int(d->size); }
+ int count() const noexcept { return size(); }
+ int length() const noexcept { return size(); }
+
+ inline bool isEmpty() const noexcept { return d->size == 0; }
+
+ void resize(int size)
+ {
+ resize_internal(size, Qt::Uninitialized);
+ if (size > this->size())
+ d->appendInitialize(size);
+ }
+ void resize(int size, parameter_type c)
+ {
+ resize_internal(size, Qt::Uninitialized);
+ if (size > this->size())
+ d->copyAppend(size - this->size(), c);
+ }
+
+ inline int capacity() const { return int(d->constAllocatedCapacity()); }
+ void reserve(int size);
+ inline void squeeze();
+
+ void detach() { d.detach(); }
+ bool isDetached() const noexcept { return !d->isShared(); }
+
+ inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
+
+ pointer data() { detach(); return d->data(); }
+ const_pointer data() const noexcept { return d->data(); }
+ const_pointer constData() const noexcept { return d->data(); }
+ void clear() {
+ if (!size())
+ return;
+ if (d->needsDetach()) {
+ // must allocate memory
+ DataPointer detached(Data::allocate(d.allocatedCapacity(), d->detachFlags()));
+ d.swap(detached);
} else {
- d->ref.setSharable(sharable);
+ d->truncate(0);
}
- Q_ASSERT(d->ref.isSharable() == sharable);
}
+
+ const_reference at(int i) const noexcept
+ {
+ Q_ASSERT_X(size_t(i) < size_t(d->size), "QVector::at", "index out of range");
+ return data()[i];
+ }
+ reference operator[](int i)
+ {
+ Q_ASSERT_X(size_t(i) < size_t(d->size), "QVector::operator[]", "index out of range");
+ detach();
+ return data()[i];
+ }
+ const_reference operator[](int i) const noexcept { return at(i); }
+ void append(const_reference t)
+ { append(const_iterator(std::addressof(t)), const_iterator(std::addressof(t)) + 1); }
+ void append(const_iterator i1, const_iterator i2);
+ void append(rvalue_ref t) { emplaceBack(std::move(t)); }
+ void append(const QVector<T> &l) { append(l.constBegin(), l.constEnd()); }
+ void prepend(rvalue_ref t);
+ void prepend(const T &t);
+
+ template <typename ...Args>
+ reference emplaceBack(Args&&... args) { return *emplace(count(), std::forward<Args>(args)...); }
+
+ iterator insert(int i, parameter_type t)
+ { return insert(i, 1, t); }
+ iterator insert(int i, int n, parameter_type t);
+ iterator insert(const_iterator before, parameter_type t)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
+ return insert(before, 1, t);
+ }
+ iterator insert(const_iterator before, int n, parameter_type t)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
+ return insert(std::distance(constBegin(), before), n, t);
+ }
+ iterator insert(const_iterator before, rvalue_ref t)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
+ return insert(std::distance(constBegin(), before), std::move(t));
+ }
+ iterator insert(int i, rvalue_ref t) { return emplace(i, std::move(t)); }
+
+ template <typename ...Args>
+ iterator emplace(const_iterator before, Args&&... args)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QVector::emplace", "The specified iterator argument 'before' is invalid");
+ return emplace(std::distance(constBegin(), before), std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ iterator emplace(int i, Args&&... args);
+#if 0
+ template< class InputIt >
+ iterator insert( const_iterator pos, InputIt first, InputIt last );
+ iterator insert( const_iterator pos, std::initializer_list<T> ilist );
#endif
+ void replace(int i, const T &t)
+ {
+ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
+ const T copy(t);
+ data()[i] = copy;
+ }
+ void replace(int i, rvalue_ref t)
+ {
+ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
+ const T copy(std::move(t));
+ data()[i] = std::move(copy);
+ }
- inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
+ void remove(int i, int n = 1);
+ void removeFirst() { Q_ASSERT(!isEmpty()); remove(0); }
+ void removeLast() { Q_ASSERT(!isEmpty()); remove(size() - 1); }
+ value_type takeFirst() { Q_ASSERT(!isEmpty()); value_type v = std::move(first()); remove(0); return v; }
+ value_type takeLast() { Q_ASSERT(!isEmpty()); value_type v = std::move(last()); remove(size() - 1); return v; }
- inline T *data() { detach(); return d->begin(); }
- inline const T *data() const { return d->begin(); }
- inline const T *constData() const { return d->begin(); }
- void clear();
-
- const T &at(int i) const;
- T &operator[](int i);
- const T &operator[](int i) const;
- void append(const T &t);
- void append(T &&t);
- inline void append(const QVector<T> &l) { *this += l; }
- void prepend(T &&t);
- void prepend(const T &t);
- void insert(int i, T &&t);
- void insert(int i, const T &t);
- void insert(int i, int n, const T &t);
- void replace(int i, const T &t);
- void remove(int i);
- void remove(int i, int n);
- inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(d->begin()); }
- inline void removeLast();
- T takeFirst() { Q_ASSERT(!isEmpty()); T r = std::move(first()); removeFirst(); return r; }
- T takeLast() { Q_ASSERT(!isEmpty()); T r = std::move(last()); removeLast(); return r; }
-
- QVector<T> &fill(const T &t, int size = -1);
-
- int indexOf(const T &t, int from = 0) const;
- int lastIndexOf(const T &t, int from = -1) const;
- bool contains(const T &t) const;
- int count(const T &t) const;
+ QVector<T> &fill(parameter_type t, int size = -1);
+
+ int indexOf(const T &t, int from = 0) const noexcept;
+ int lastIndexOf(const T &t, int from = -1) const noexcept;
+ bool contains(const T &t) const noexcept
+ {
+ return indexOf(t) != -1;
+ }
+ int count(const T &t) const noexcept
+ {
+ return int(std::count(&*cbegin(), &*cend(), t));
+ }
// QList compatibility
void removeAt(int i) { remove(i); }
@@ -169,10 +323,10 @@ public:
const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
if (cit == ce)
return 0;
+ int index = cit - this->cbegin();
// next operation detaches, so ce, cit, t may become invalidated:
const T tCopy = t;
- const int firstFoundIdx = std::distance(this->cbegin(), cit);
- const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, tCopy);
+ const iterator e = end(), it = std::remove(begin() + index, e, tCopy);
const int result = std::distance(it, e);
erase(it, e);
return result;
@@ -185,7 +339,6 @@ public:
remove(i);
return true;
}
- int length() const { return size(); }
T takeAt(int i) { T t = std::move((*this)[i]); remove(i); return t; }
void move(int from, int to)
{
@@ -202,43 +355,26 @@ public:
}
// STL-style
- typedef typename Data::iterator iterator;
- typedef typename Data::const_iterator const_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-#if !defined(QT_STRICT_ITERATORS) || defined(Q_CLANG_QDOC)
- inline iterator begin() { detach(); return d->begin(); }
- inline const_iterator begin() const noexcept { return d->constBegin(); }
- inline const_iterator cbegin() const noexcept { return d->constBegin(); }
- inline const_iterator constBegin() const noexcept { return d->constBegin(); }
- inline iterator end() { detach(); return d->end(); }
- inline const_iterator end() const noexcept { return d->constEnd(); }
- inline const_iterator cend() const noexcept { return d->constEnd(); }
- inline const_iterator constEnd() const noexcept { return d->constEnd(); }
-#else
- inline iterator begin(iterator = iterator()) { detach(); return d->begin(); }
- inline const_iterator begin(const_iterator = const_iterator()) const noexcept { return d->constBegin(); }
- inline const_iterator cbegin(const_iterator = const_iterator()) const noexcept { return d->constBegin(); }
- inline const_iterator constBegin(const_iterator = const_iterator()) const noexcept { return d->constBegin(); }
- inline iterator end(iterator = iterator()) { detach(); return d->end(); }
- inline const_iterator end(const_iterator = const_iterator()) const noexcept { return d->constEnd(); }
- inline const_iterator cend(const_iterator = const_iterator()) const noexcept { return d->constEnd(); }
- inline const_iterator constEnd(const_iterator = const_iterator()) const noexcept { return d->constEnd(); }
-#endif
+ iterator begin() { detach(); return d->begin(); }
+ iterator end() { detach(); return d->end(); }
+
+ const_iterator begin() const noexcept { return d->constBegin(); }
+ const_iterator end() const noexcept { return d->constEnd(); }
+ const_iterator cbegin() const noexcept { return d->constBegin(); }
+ const_iterator cend() const noexcept { return d->constEnd(); }
+ const_iterator constBegin() const noexcept { return d->constBegin(); }
+ const_iterator constEnd() const noexcept { return d->constEnd(); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
- iterator insert(iterator before, int n, const T &x);
- inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
- inline iterator insert(iterator before, T &&x);
- iterator erase(iterator begin, iterator end);
- inline iterator erase(iterator pos) { return erase(pos, pos+1); }
+
+ iterator erase(const_iterator begin, const_iterator end);
+ inline iterator erase(const_iterator pos) { return erase(pos, pos+1); }
// more Qt
- inline int count() const { return d->size; }
inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
inline const T &constFirst() const { Q_ASSERT(!isEmpty()); return *begin(); }
@@ -249,7 +385,7 @@ public:
inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
QVector<T> mid(int pos, int len = -1) const;
- T value(int i) const;
+ T value(int i) const { return value(i, T()); }
T value(int i, const T &defaultValue) const;
void swapItemsAt(int i, int j) {
@@ -260,31 +396,26 @@ public:
}
// STL compatibility
- typedef T value_type;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef qptrdiff difference_type;
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- typedef int size_type;
inline void push_back(const T &t) { append(t); }
- void push_back(T &&t) { append(std::move(t)); }
- void push_front(T &&t) { prepend(std::move(t)); }
+ void push_back(rvalue_ref t) { append(std::move(t)); }
+ void push_front(rvalue_ref t) { prepend(std::move(t)); }
inline void push_front(const T &t) { prepend(t); }
void pop_back() { removeLast(); }
void pop_front() { removeFirst(); }
+
+ template <typename ...Args>
+ reference emplace_back(Args&&... args) { return emplaceBack(std::forward<Args>(args)...); }
+
inline bool empty() const
{ return d->size == 0; }
- inline T& front() { return first(); }
+ inline reference front() { return first(); }
inline const_reference front() const { return first(); }
inline reference back() { return last(); }
inline const_reference back() const { return last(); }
void shrink_to_fit() { squeeze(); }
// comfort
- QVector<T> &operator+=(const QVector<T> &l);
+ QVector<T> &operator+=(const QVector<T> &l) { append(l.cbegin(), l.cend()); return *this; }
inline QVector<T> operator+(const QVector<T> &l) const
{ QVector n = *this; n += l; return n; }
inline QVector<T> &operator+=(const T &t)
@@ -293,37 +424,17 @@ public:
{ append(t); return *this; }
inline QVector<T> &operator<<(const QVector<T> &l)
{ *this += l; return *this; }
- inline QVector<T> &operator+=(T &&t)
+ inline QVector<T> &operator+=(rvalue_ref t)
{ append(std::move(t)); return *this; }
- inline QVector<T> &operator<<(T &&t)
+ inline QVector<T> &operator<<(rvalue_ref t)
{ append(std::move(t)); return *this; }
- static QVector<T> fromList(const QList<T> &list);
- QList<T> toList() const;
+ // Consider deprecating in 6.4 or later
+ static QVector<T> fromList(const QVector<T> &list) { return list; }
+ QVector<T> toList() const { return *this; }
-#if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
- QT_DEPRECATED_X("Use QVector<T>(vector.begin(), vector.end()) instead.")
- static inline QVector<T> fromStdVector(const std::vector<T> &vector)
- { return QVector<T>(vector.begin(), vector.end()); }
- QT_DEPRECATED_X("Use std::vector<T>(vector.begin(), vector.end()) instead.")
- inline std::vector<T> toStdVector() const
- { return std::vector<T>(d->begin(), d->end()); }
-#endif
-private:
- // ### Qt6: remove methods, they are unused
- void reallocData(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
- void reallocData(const int sz) { reallocData(sz, d->alloc); }
- void realloc(int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
- void freeData(Data *d);
- void defaultConstruct(T *from, T *to);
- void copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom);
- void destruct(T *from, T *to);
- bool isValidIterator(const iterator &i) const
- {
- const std::less<const T*> less = {};
- return !less(d->end(), i) && !less(i, d->begin());
- }
- class AlignmentDummy { Data header; T array[1]; };
+ static inline QVector<T> fromVector(const QVector<T> &vector) { return vector; }
+ inline QVector<T> toVector() const { return *this; }
};
#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
@@ -333,785 +444,329 @@ template <typename InputIterator,
QVector(InputIterator, InputIterator) -> QVector<ValueType>;
#endif
-#ifdef Q_CC_MSVC
-// behavior change: an object of POD type constructed with an initializer of the form ()
-// will be default-initialized
-# pragma warning ( push )
-# pragma warning ( disable : 4345 )
-# pragma warning(disable : 4127) // conditional expression is constant
-#endif
-
template <typename T>
-void QVector<T>::defaultConstruct(T *from, T *to)
+inline void QVector<T>::resize_internal(int newSize, Qt::Initialization)
{
- if (QTypeInfo<T>::isComplex) {
- while (from != to) {
- new (from++) T();
- }
- } else {
- ::memset(static_cast<void *>(from), 0, (to - from) * sizeof(T));
- }
-}
+ Q_ASSERT(newSize >= 0);
-template <typename T>
-void QVector<T>::copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom)
-{
- if (QTypeInfo<T>::isComplex) {
- while (srcFrom != srcTo)
- new (dstFrom++) T(*srcFrom++);
- } else {
- ::memcpy(static_cast<void *>(dstFrom), static_cast<const void *>(srcFrom), (srcTo - srcFrom) * sizeof(T));
- }
-}
-
-template <typename T>
-void QVector<T>::destruct(T *from, T *to)
-{
- if (QTypeInfo<T>::isComplex) {
- while (from != to) {
- from++->~T();
+ if (d->needsDetach() || newSize > capacity()) {
+ // must allocate memory
+ DataPointer detached(Data::allocate(d->detachCapacity(newSize),
+ d->detachFlags()));
+ if (size() && newSize) {
+ detached->copyAppend(constBegin(), constBegin() + qMin(newSize, size()));
}
+ d.swap(detached);
}
-}
-
-template <typename T>
-inline QVector<T>::QVector(const QVector<T> &v)
-{
- if (v.d->ref.ref()) {
- d = v.d;
- } else {
- if (v.d->capacityReserved) {
- d = Data::allocate(v.d->alloc);
- Q_CHECK_PTR(d);
- d->capacityReserved = true;
- } else {
- d = Data::allocate(v.d->size);
- Q_CHECK_PTR(d);
- }
- if (d->alloc) {
- copyConstruct(v.d->begin(), v.d->end(), d->begin());
- d->size = v.d->size;
- }
- }
-}
-#if defined(Q_CC_MSVC)
-#pragma warning( pop )
-#endif
-
-template <typename T>
-void QVector<T>::detach()
-{
- if (!isDetached()) {
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- if (!d->alloc)
- d = Data::unsharableEmpty();
- else
-#endif
- realloc(int(d->alloc));
- }
- Q_ASSERT(isDetached());
+ if (newSize < size())
+ d->truncate(newSize);
}
template <typename T>
void QVector<T>::reserve(int asize)
{
- if (asize > int(d->alloc))
- realloc(asize);
- if (isDetached()
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- && d != Data::unsharableEmpty()
-#endif
- )
- d->capacityReserved = 1;
- Q_ASSERT(capacity() >= asize);
-}
-
-template <typename T>
-void QVector<T>::resize(int asize)
-{
- if (asize == d->size)
- return detach();
- if (asize > int(d->alloc) || !isDetached()) { // there is not enough space
- QArrayData::AllocationOptions opt = asize > int(d->alloc) ? QArrayData::Grow : QArrayData::Default;
- realloc(qMax(int(d->alloc), asize), opt);
+ // capacity() == 0 for immutable data, so this will force a detaching below
+ if (asize <= capacity()) {
+ if (d->flags() & Data::CapacityReserved)
+ return; // already reserved, don't shrink
+ if (!d->isShared()) {
+ // accept current allocation, don't shrink
+ d->flags() |= Data::CapacityReserved;
+ return;
+ }
}
- if (asize < d->size)
- destruct(begin() + asize, end());
- else
- defaultConstruct(end(), begin() + asize);
- d->size = asize;
-}
-template <typename T>
-inline void QVector<T>::clear()
-{
- if (!d->size)
- return;
- destruct(begin(), end());
- d->size = 0;
-}
-template <typename T>
-inline const T &QVector<T>::at(int i) const
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
- return d->begin()[i]; }
-template <typename T>
-inline const T &QVector<T>::operator[](int i) const
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
- return d->begin()[i]; }
-template <typename T>
-inline T &QVector<T>::operator[](int i)
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
- return data()[i]; }
-template <typename T>
-inline void QVector<T>::insert(int i, const T &t)
-{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- insert(begin() + i, 1, t); }
-template <typename T>
-inline void QVector<T>::insert(int i, int n, const T &t)
-{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- insert(begin() + i, n, t); }
-template <typename T>
-inline void QVector<T>::insert(int i, T &&t)
-{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- insert(begin() + i, std::move(t)); }
-template <typename T>
-inline void QVector<T>::remove(int i, int n)
-{ Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= d->size, "QVector<T>::remove", "index out of range");
- erase(d->begin() + i, d->begin() + i + n); }
-template <typename T>
-inline void QVector<T>::remove(int i)
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::remove", "index out of range");
- erase(d->begin() + i, d->begin() + i + 1); }
-template <typename T>
-inline void QVector<T>::prepend(const T &t)
-{ insert(begin(), 1, t); }
-template <typename T>
-inline void QVector<T>::prepend(T &&t)
-{ insert(begin(), std::move(t)); }
-template <typename T>
-inline void QVector<T>::replace(int i, const T &t)
-{
- Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
- const T copy(t);
- data()[i] = copy;
+ DataPointer detached(Data::allocate(qMax(asize, size()),
+ d->detachFlags() | Data::CapacityReserved));
+ detached->copyAppend(constBegin(), constEnd());
+ d.swap(detached);
}
template <typename T>
-QVector<T> &QVector<T>::operator=(const QVector<T> &v)
+inline void QVector<T>::squeeze()
{
- if (v.d != d) {
- QVector<T> tmp(v);
- tmp.swap(*this);
- }
- return *this;
-}
-
-template <typename T>
-QVector<T>::QVector(int asize)
-{
- Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
- if (Q_LIKELY(asize > 0)) {
- d = Data::allocate(asize);
- Q_CHECK_PTR(d);
- d->size = asize;
- defaultConstruct(d->begin(), d->end());
- } else {
- d = Data::sharedNull();
+ if (d->needsDetach() || size() != capacity()) {
+ // must allocate memory
+ DataPointer detached(Data::allocate(size(), d->detachFlags() & ~Data::CapacityReserved));
+ if (size()) {
+ detached->copyAppend(constBegin(), constEnd());
+ }
+ d.swap(detached);
}
}
template <typename T>
-QVector<T>::QVector(int asize, const T &t)
+inline void QVector<T>::remove(int i, int n)
{
- Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
- if (asize > 0) {
- d = Data::allocate(asize);
- Q_CHECK_PTR(d);
- d->size = asize;
- T* i = d->end();
- while (i != d->begin())
- new (--i) T(t);
- } else {
- d = Data::sharedNull();
- }
-}
+ Q_ASSERT_X(size_t(i) + size_t(n) <= size_t(d->size), "QVector::remove", "index out of range");
+ Q_ASSERT_X(n >= 0, "QVector::remove", "invalid count");
-#if defined(Q_CC_MSVC)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
-#endif // Q_CC_MSVC
+ if (n == 0)
+ return;
-template <typename T>
-QVector<T>::QVector(std::initializer_list<T> args)
-{
- if (args.size() > 0) {
- d = Data::allocate(args.size());
- Q_CHECK_PTR(d);
- // std::initializer_list<T>::iterator is guaranteed to be
- // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct
- copyConstruct(args.begin(), args.end(), d->begin());
- d->size = int(args.size());
+ const size_t newSize = size() - n;
+ if (d->needsDetach() ||
+ ((d->flags() & Data::CapacityReserved) == 0
+ && newSize < d->allocatedCapacity()/2)) {
+ // allocate memory
+ DataPointer detached(Data::allocate(d->detachCapacity(newSize),
+ d->detachFlags() & ~(Data::GrowsBackwards | Data::GrowsForward)));
+ const_iterator where = constBegin() + i;
+ if (newSize) {
+ detached->copyAppend(constBegin(), where);
+ detached->copyAppend(where + n, constEnd());
+ }
+ d.swap(detached);
} else {
- d = Data::sharedNull();
+ // we're detached and we can just move data around
+ d->erase(d->begin() + i, d->begin() + i + n);
}
}
template <typename T>
-QVector<T> &QVector<T>::operator=(std::initializer_list<T> args)
-{
- QVector<T> tmp(args);
- tmp.swap(*this);
- return *this;
-}
-
-#if defined(Q_CC_MSVC)
-QT_WARNING_POP
-#endif // Q_CC_MSVC
-
+inline void QVector<T>::prepend(const T &t)
+{ insert(0, 1, t); }
template <typename T>
-template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator>>
-QVector<T>::QVector(InputIterator first, InputIterator last)
- : QVector()
-{
- QtPrivate::reserveIfForwardIterator(this, first, last);
- std::copy(first, last, std::back_inserter(*this));
-}
+void QVector<T>::prepend(rvalue_ref t)
+{ insert(0, std::move(t)); }
-template <typename T>
-void QVector<T>::freeData(Data *x)
+template<typename T>
+inline T QVector<T>::value(int i, const T &defaultValue) const
{
- destruct(x->begin(), x->end());
- Data::deallocate(x);
+ return size_t(i) < size_t(d->size) ? at(i) : defaultValue;
}
-#if defined(Q_CC_MSVC)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
-#endif
-
template <typename T>
-void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::AllocationOptions options)
+inline void QVector<T>::append(const_iterator i1, const_iterator i2)
{
- Q_ASSERT(asize >= 0 && asize <= aalloc);
- Data *x = d;
-
- const bool isShared = d->ref.isShared();
-
- if (aalloc != 0) {
- if (aalloc != int(d->alloc) || isShared) {
- QT_TRY {
- // allocate memory
- x = Data::allocate(aalloc, options);
- Q_CHECK_PTR(x);
- // aalloc is bigger then 0 so it is not [un]sharedEmpty
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable));
-#endif
- Q_ASSERT(!x->ref.isStatic());
- x->size = asize;
-
- T *srcBegin = d->begin();
- T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
- T *dst = x->begin();
-
- if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
- QT_TRY {
- if (isShared || !std::is_nothrow_move_constructible<T>::value) {
- // we can not move the data, we need to copy construct it
- while (srcBegin != srcEnd)
- new (dst++) T(*srcBegin++);
- } else {
- while (srcBegin != srcEnd)
- new (dst++) T(std::move(*srcBegin++));
- }
- } QT_CATCH (...) {
- // destruct already copied objects
- destruct(x->begin(), dst);
- QT_RETHROW;
- }
- } else {
- ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
- dst += srcEnd - srcBegin;
-
- // destruct unused / not moved data
- if (asize < d->size)
- destruct(d->begin() + asize, d->end());
- }
-
- if (asize > d->size) {
- // construct all new objects when growing
- if (!QTypeInfo<T>::isComplex) {
- ::memset(static_cast<void *>(dst), 0, (static_cast<T *>(x->end()) - dst) * sizeof(T));
- } else {
- QT_TRY {
- while (dst != x->end())
- new (dst++) T();
- } QT_CATCH (...) {
- // destruct already copied objects
- destruct(x->begin(), dst);
- QT_RETHROW;
- }
- }
- }
- } QT_CATCH (...) {
- Data::deallocate(x);
- QT_RETHROW;
- }
- x->capacityReserved = d->capacityReserved;
- } else {
- Q_ASSERT(int(d->alloc) == aalloc); // resize, without changing allocation size
- Q_ASSERT(isDetached()); // can be done only on detached d
- Q_ASSERT(x == d); // in this case we do not need to allocate anything
- if (asize <= d->size) {
- destruct(x->begin() + asize, x->end()); // from future end to current end
- } else {
- defaultConstruct(x->end(), x->begin() + asize); // from current end to future end
- }
- x->size = asize;
- }
+ if (i1 == i2)
+ return;
+ const size_t newSize = size() + std::distance(i1, i2);
+ if (d->needsDetach() || newSize > d->allocatedCapacity()) {
+ DataPointer detached(Data::allocate(d->detachCapacity(newSize),
+ d->detachFlags() | Data::GrowsForward));
+ detached->copyAppend(constBegin(), constEnd());
+ detached->copyAppend(i1, i2);
+ d.swap(detached);
} else {
- x = Data::sharedNull();
- }
- if (d != x) {
- if (!d->ref.deref()) {
- if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
- // data was copy constructed, we need to call destructors
- // or if !alloc we did nothing to the old 'd'.
- freeData(d);
- } else {
- Data::deallocate(d);
- }
- }
- d = x;
+ // we're detached and we can just move data around
+ d->copyAppend(i1, i2);
}
-
- Q_ASSERT(d->data());
- Q_ASSERT(uint(d->size) <= d->alloc);
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- Q_ASSERT(d != Data::unsharableEmpty());
-#endif
- Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull());
- Q_ASSERT(d->alloc >= uint(aalloc));
- Q_ASSERT(d->size == asize);
}
-template<typename T>
-void QVector<T>::realloc(int aalloc, QArrayData::AllocationOptions options)
+template <typename T>
+inline typename QVector<T>::iterator
+QVector<T>::insert(int i, int n, parameter_type t)
{
- Q_ASSERT(aalloc >= d->size);
- Data *x = d;
+ Q_ASSERT_X(size_t(i) <= size_t(d->size), "QVector<T>::insert", "index out of range");
- const bool isShared = d->ref.isShared();
+ // we don't have a quick exit for n == 0
+ // it's not worth wasting CPU cycles for that
- QT_TRY {
- // allocate memory
- x = Data::allocate(aalloc, options);
- Q_CHECK_PTR(x);
- // aalloc is bigger then 0 so it is not [un]sharedEmpty
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable));
-#endif
- Q_ASSERT(!x->ref.isStatic());
- x->size = d->size;
-
- T *srcBegin = d->begin();
- T *srcEnd = d->end();
- T *dst = x->begin();
-
- if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
- QT_TRY {
- if (isShared || !std::is_nothrow_move_constructible<T>::value) {
- // we can not move the data, we need to copy construct it
- while (srcBegin != srcEnd)
- new (dst++) T(*srcBegin++);
- } else {
- while (srcBegin != srcEnd)
- new (dst++) T(std::move(*srcBegin++));
- }
- } QT_CATCH (...) {
- // destruct already copied objects
- destruct(x->begin(), dst);
- QT_RETHROW;
- }
- } else {
- ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
- dst += srcEnd - srcBegin;
- }
+ const size_t newSize = size() + n;
+ if (d->needsDetach() || newSize > d->allocatedCapacity()) {
+ typename Data::ArrayOptions flags = d->detachFlags() | Data::GrowsForward;
+ if (size_t(i) <= newSize / 4)
+ flags |= Data::GrowsBackwards;
- } QT_CATCH (...) {
- Data::deallocate(x);
- QT_RETHROW;
- }
- x->capacityReserved = d->capacityReserved;
-
- Q_ASSERT(d != x);
- if (!d->ref.deref()) {
- if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
- // data was copy constructed, we need to call destructors
- // or if !alloc we did nothing to the old 'd'.
- freeData(d);
+ DataPointer detached(Data::allocate(d->detachCapacity(newSize), flags));
+ const_iterator where = constBegin() + i;
+ detached->copyAppend(constBegin(), where);
+ detached->copyAppend(n, t);
+ detached->copyAppend(where, constEnd());
+ d.swap(detached);
+ } else {
+ // we're detached and we can just move data around
+ if (i == size()) {
+ d->copyAppend(n, t);
} else {
- Data::deallocate(d);
+ T copy(t);
+ d->insert(d.begin() + i, n, copy);
}
}
- d = x;
-
- Q_ASSERT(d->data());
- Q_ASSERT(uint(d->size) <= d->alloc);
-#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
- Q_ASSERT(d != Data::unsharableEmpty());
-#endif
- Q_ASSERT(d != Data::sharedNull());
- Q_ASSERT(d->alloc >= uint(aalloc));
-}
-
-#if defined(Q_CC_MSVC)
-QT_WARNING_POP
-#endif
-
-template<typename T>
-Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
-{
- if (uint(i) >= uint(d->size)) {
- return T();
- }
- return d->begin()[i];
-}
-template<typename T>
-Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
-{
- return uint(i) >= uint(d->size) ? defaultValue : d->begin()[i];
+ return d.begin() + i;
}
template <typename T>
-void QVector<T>::append(const T &t)
+template <typename ...Args>
+typename QVector<T>::iterator
+QVector<T>::emplace(int i, Args&&... args)
{
- const bool isTooSmall = uint(d->size + 1) > d->alloc;
- if (!isDetached() || isTooSmall) {
- T copy(t);
- QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
- realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
-
- if (QTypeInfo<T>::isComplex)
- new (d->end()) T(std::move(copy));
- else
- *d->end() = std::move(copy);
+ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- } else {
- if (QTypeInfo<T>::isComplex)
- new (d->end()) T(t);
- else
- *d->end() = t;
- }
- ++d->size;
-}
-
-template <typename T>
-void QVector<T>::append(T &&t)
-{
- const bool isTooSmall = uint(d->size + 1) > d->alloc;
- if (!isDetached() || isTooSmall) {
- QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
- realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
- }
+ const size_t newSize = size() + 1;
+ if (d->needsDetach() || newSize > d->allocatedCapacity()) {
+ typename Data::ArrayOptions flags = d->detachFlags() | Data::GrowsForward;
+ if (size_t(i) <= newSize / 4)
+ flags |= Data::GrowsBackwards;
- new (d->end()) T(std::move(t));
+ DataPointer detached(Data::allocate(d->detachCapacity(newSize), flags));
+ const_iterator where = constBegin() + i;
- ++d->size;
-}
+ // First, create an element to handle cases, when a user moves
+ // the element from a container to the same container
+ detached->createInPlace(detached.begin() + i, std::forward<Args>(args)...);
-template <typename T>
-void QVector<T>::removeLast()
-{
- Q_ASSERT(!isEmpty());
- Q_ASSERT(d->alloc);
+ // Then, put the first part of the elements to the new location
+ detached->copyAppend(constBegin(), where);
- if (d->ref.isShared())
- detach();
- --d->size;
- if (QTypeInfo<T>::isComplex)
- (d->data() + d->size)->~T();
-}
+ // After that, increase the actual size, because we created
+ // one extra element
+ ++detached.size;
-template <typename T>
-typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
-{
- Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
+ // Finally, put the rest of the elements to the new location
+ detached->copyAppend(where, constEnd());
- const auto offset = std::distance(d->begin(), before);
- if (n != 0) {
- const T copy(t);
- if (!isDetached() || d->size + n > int(d->alloc))
- realloc(d->size + n, QArrayData::Grow);
- if (!QTypeInfoQuery<T>::isRelocatable) {
- T *b = d->end();
- T *i = d->end() + n;
- while (i != b)
- new (--i) T;
- i = d->end();
- T *j = i + n;
- b = d->begin() + offset;
- while (i != b)
- *--j = *--i;
- i = b+n;
- while (i != b)
- *--i = copy;
- } else {
- T *b = d->begin() + offset;
- T *i = b + n;
- memmove(static_cast<void *>(i), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
- while (i != b)
- new (--i) T(copy);
- }
- d->size += n;
- }
- return d->begin() + offset;
-}
-
-template <typename T>
-typename QVector<T>::iterator QVector<T>::insert(iterator before, T &&t)
-{
- Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
-
- const auto offset = std::distance(d->begin(), before);
- if (!isDetached() || d->size + 1 > int(d->alloc))
- realloc(d->size + 1, QArrayData::Grow);
- if (!QTypeInfoQuery<T>::isRelocatable) {
- T *i = d->end();
- T *j = i + 1;
- T *b = d->begin() + offset;
- // The new end-element needs to be constructed, the rest must be move assigned
- if (i != b) {
- new (--j) T(std::move(*--i));
- while (i != b)
- *--j = std::move(*--i);
- *b = std::move(t);
- } else {
- new (b) T(std::move(t));
- }
+ d.swap(detached);
} else {
- T *b = d->begin() + offset;
- memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
- new (b) T(std::move(t));
+ d->emplace(d.begin() + i, std::forward<Args>(args)...);
}
- d->size += 1;
- return d->begin() + offset;
+ return d.begin() + i;
}
template <typename T>
-typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
+typename QVector<T>::iterator QVector<T>::erase(const_iterator abegin, const_iterator aend)
{
Q_ASSERT_X(isValidIterator(abegin), "QVector::erase", "The specified iterator argument 'abegin' is invalid");
Q_ASSERT_X(isValidIterator(aend), "QVector::erase", "The specified iterator argument 'aend' is invalid");
+ Q_ASSERT(aend >= abegin);
- const auto itemsToErase = aend - abegin;
+ int i = std::distance(d.constBegin(), abegin);
+ int n = std::distance(abegin, aend);
+ remove(i, n);
- if (!itemsToErase)
- return abegin;
-
- Q_ASSERT(abegin >= d->begin());
- Q_ASSERT(aend <= d->end());
- Q_ASSERT(abegin <= aend);
-
- const auto itemsUntouched = abegin - d->begin();
-
- // FIXME we could do a proper realloc, which copy constructs only needed data.
- // FIXME we are about to delete data - maybe it is good time to shrink?
- // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this.
- if (d->alloc) {
- detach();
- abegin = d->begin() + itemsUntouched;
- aend = abegin + itemsToErase;
- if (!QTypeInfoQuery<T>::isRelocatable) {
- iterator moveBegin = abegin + itemsToErase;
- iterator moveEnd = d->end();
- while (moveBegin != moveEnd) {
- if (QTypeInfo<T>::isComplex)
- static_cast<T *>(abegin)->~T();
- new (abegin++) T(*moveBegin++);
- }
- if (abegin < d->end()) {
- // destroy rest of instances
- destruct(abegin, d->end());
- }
- } else {
- destruct(abegin, aend);
- // QTBUG-53605: static_cast<void *> masks clang errors of the form
- // error: destination for this 'memmove' call is a pointer to class containing a dynamic class
- // FIXME maybe use std::is_polymorphic (as soon as allowed) to avoid the memmove
- memmove(static_cast<void *>(abegin), static_cast<void *>(aend),
- (d->size - itemsToErase - itemsUntouched) * sizeof(T));
- }
- d->size -= int(itemsToErase);
- }
- return d->begin() + itemsUntouched;
+ return d.begin() + i;
}
template <typename T>
-bool QVector<T>::operator==(const QVector<T> &v) const
+inline QVector<T> &QVector<T>::fill(parameter_type t, int newSize)
{
- if (d == v.d)
- return true;
- if (d->size != v.d->size)
- return false;
- const T *vb = v.d->begin();
- const T *b = d->begin();
- const T *e = d->end();
- return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(vb, v.d->size));
-}
-
-template <typename T>
-QVector<T> &QVector<T>::fill(const T &from, int asize)
-{
- const T copy(from);
- resize(asize < 0 ? d->size : asize);
- if (d->size) {
- T *i = d->end();
- T *b = d->begin();
- while (i != b)
- *--i = copy;
- }
- return *this;
-}
-
-template <typename T>
-QVector<T> &QVector<T>::operator+=(const QVector &l)
-{
- if (d->size == 0) {
- *this = l;
+ if (newSize == -1)
+ newSize = size();
+ if (d->needsDetach() || newSize > capacity()) {
+ // must allocate memory
+ DataPointer detached(Data::allocate(d->detachCapacity(newSize),
+ d->detachFlags()));
+ detached->copyAppend(newSize, t);
+ d.swap(detached);
} else {
- uint newSize = d->size + l.d->size;
- const bool isTooSmall = newSize > d->alloc;
- if (!isDetached() || isTooSmall) {
- QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
- realloc(isTooSmall ? newSize : d->alloc, opt);
- }
-
- if (d->alloc) {
- T *w = d->begin() + newSize;
- T *i = l.d->end();
- T *b = l.d->begin();
- while (i != b) {
- if (QTypeInfo<T>::isComplex)
- new (--w) T(*--i);
- else
- *--w = *--i;
- }
- d->size = newSize;
- }
+ // we're detached
+ const T copy(t);
+ d->assign(d.begin(), d.begin() + qMin(size(), newSize), t);
+ if (newSize > size())
+ d->copyAppend(newSize - size(), copy);
}
return *this;
}
-template <typename T>
-int QVector<T>::indexOf(const T &t, int from) const
+namespace QtPrivate {
+template <typename T, typename U>
+int indexOf(const QVector<T> &vector, const U &u, int from)
{
if (from < 0)
- from = qMax(from + d->size, 0);
- if (from < d->size) {
- T* n = d->begin() + from - 1;
- T* e = d->end();
+ from = qMax(from + vector.size(), 0);
+ if (from < vector.size()) {
+ auto n = vector.begin() + from - 1;
+ auto e = vector.end();
while (++n != e)
- if (*n == t)
- return n - d->begin();
+ if (*n == u)
+ return int(n - vector.begin());
}
return -1;
}
-template <typename T>
-int QVector<T>::lastIndexOf(const T &t, int from) const
+template <typename T, typename U>
+int lastIndexOf(const QVector<T> &vector, const U &u, int from)
{
if (from < 0)
- from += d->size;
- else if (from >= d->size)
- from = d->size-1;
+ from += vector.d->size;
+ else if (from >= vector.size())
+ from = vector.size() - 1;
if (from >= 0) {
- T* b = d->begin();
- T* n = d->begin() + from + 1;
+ auto b = vector.begin();
+ auto n = vector.begin() + from + 1;
while (n != b) {
- if (*--n == t)
- return n - b;
+ if (*--n == u)
+ return int(n - b);
}
}
return -1;
}
+}
template <typename T>
-bool QVector<T>::contains(const T &t) const
+int QVector<T>::indexOf(const T &t, int from) const noexcept
{
- const T *b = d->begin();
- const T *e = d->end();
- return std::find(b, e, t) != e;
+ return QtPrivate::indexOf<T, T>(*this, t, from);
}
template <typename T>
-int QVector<T>::count(const T &t) const
+int QVector<T>::lastIndexOf(const T &t, int from) const noexcept
{
- const T *b = d->begin();
- const T *e = d->end();
- return int(std::count(b, e, t));
+ return QtPrivate::lastIndexOf(*this, t, from);
}
template <typename T>
-Q_OUTOFLINE_TEMPLATE QVector<T> QVector<T>::mid(int pos, int len) const
+inline QVector<T> QVector<T>::mid(int pos, int len) const
{
using namespace QtPrivate;
- switch (QContainerImplHelper::mid(d->size, &pos, &len)) {
+ switch (QContainerImplHelper::mid(d.size, &pos, &len)) {
case QContainerImplHelper::Null:
case QContainerImplHelper::Empty:
- return QVector<T>();
+ return QVector();
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
break;
}
- QVector<T> midResult;
- midResult.realloc(len);
- T *srcFrom = d->begin() + pos;
- T *srcTo = d->begin() + pos + len;
- midResult.copyConstruct(srcFrom, srcTo, midResult.data());
- midResult.d->size = len;
- return midResult;
+ // Allocate memory
+ DataPointer copied(Data::allocate(len));
+ copied->copyAppend(constBegin() + pos, constBegin() + pos + len);
+ return copied;
}
Q_DECLARE_SEQUENTIAL_ITERATOR(Vector)
Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector)
template <typename T>
-uint qHash(const QVector<T> &key, uint seed = 0)
+size_t qHash(const QVector<T> &key, size_t seed = 0)
noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
{
return qHashRange(key.cbegin(), key.cend(), seed);
}
template <typename T>
-bool operator<(const QVector<T> &lhs, const QVector<T> &rhs)
+auto operator<(const QVector<T> &lhs, const QVector<T> &rhs)
noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end())))
+ rhs.begin(), rhs.end())))
+ -> decltype(std::declval<T>() < std::declval<T>())
{
return std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end());
}
template <typename T>
-inline bool operator>(const QVector<T> &lhs, const QVector<T> &rhs)
+auto operator>(const QVector<T> &lhs, const QVector<T> &rhs)
noexcept(noexcept(lhs < rhs))
+ -> decltype(lhs < rhs)
{
return rhs < lhs;
}
template <typename T>
-inline bool operator<=(const QVector<T> &lhs, const QVector<T> &rhs)
+auto operator<=(const QVector<T> &lhs, const QVector<T> &rhs)
noexcept(noexcept(lhs < rhs))
+ -> decltype(lhs < rhs)
{
return !(lhs > rhs);
}
template <typename T>
-inline bool operator>=(const QVector<T> &lhs, const QVector<T> &rhs)
+auto operator>=(const QVector<T> &lhs, const QVector<T> &rhs)
noexcept(noexcept(lhs < rhs))
+ -> decltype(lhs < rhs)
{
return !(lhs < rhs);
}
@@ -1135,4 +790,7 @@ QVector<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*thi
QT_END_NAMESPACE
+#include <QtCore/qbytearraylist.h>
+#include <QtCore/qstringlist.h>
+
#endif // QVECTOR_H
diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc
index 116d962411..cbb118ddb9 100644
--- a/src/corelib/tools/qvector.qdoc
+++ b/src/corelib/tools/qvector.qdoc
@@ -39,7 +39,7 @@
stores its items in adjacent memory locations and provides fast
index-based access.
- QList\<T\>, QLinkedList\<T\>, QVector\<T\>, and QVarLengthArray\<T\>
+ QList\<T\>, QVector\<T\>, and QVarLengthArray\<T\>
provide similar APIs and functionality. They are often interchangeable,
but there are performance consequences. Here is an overview of use cases:
@@ -57,18 +57,13 @@
those APIs.
\li If you need a real linked list, which guarantees
\l{Algorithmic Complexity}{constant time} insertions mid-list and
- uses iterators to items rather than indexes, use QLinkedList.
+ uses iterators to items rather than indexes, use std::list.
\endlist
\note QVector and QVarLengthArray both guarantee C-compatible
array layout. QList does not. This might be important if your
application must interface with a C API.
- \note Iterators into a QLinkedList and references into
- heap-allocating QLists remain valid as long as the referenced items
- remain in the container. This is not true for iterators and
- references into a QVector and non-heap-allocating QLists.
-
Here's an example of a QVector that stores integers and a QVector
that stores QString values:
@@ -129,7 +124,7 @@
(\l{linear time}) for large vectors, because they require moving many
items in the vector by one position in memory. If you want a container
class that provides fast insertion/removal in the middle, use
- QList or QLinkedList instead.
+ std::list instead.
Unlike plain C++ arrays, QVectors can be resized at any time by
calling resize(). If the new size is larger than the old size,
@@ -190,8 +185,6 @@
holding a lot of allocated memory, especially large, contiguous blocks.
Such considerations, the configuration of such behavior or any mitigation
are outside the scope of the Qt API.
-
- \sa QVectorIterator, QMutableVectorIterator, QList, QLinkedList
*/
/*!
@@ -398,7 +391,7 @@
*/
/*!
- \fn template <typename T> uint qHash(const QVector<T> &key, uint seed = 0)
+ \fn template <typename T> size_t qHash(const QVector<T> &key, size_t seed = 0)
\since 5.6
\relates QVector
@@ -640,12 +633,34 @@
For large vectors, this operation can be slow (\l{linear time}),
because it requires moving all the items in the vector by one
position further in memory. If you want a container class that
- provides a fast prepend() function, use QList or QLinkedList
+ provides a fast prepend operation, use std::list
instead.
\sa append(), insert()
*/
+/*!
+ \fn template <typename T> template <typename ...Args> T &QVector<T>::emplaceBack(Args&&... args)
+ \fn template <typename T> template <typename ...Args> T &QVector<T>::emplace_back(Args&&... args)
+
+ Adds a new element to the end for the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
+
+ Returns a reference to the new element.
+
+ Example:
+ \snippet code/src_corelib_tools_qvector.cpp emplace-back
+
+ It is also possible to access a newly created object by using
+ returned reference:
+ \snippet code/src_corelib_tools_qvector.cpp emplace-back-ref
+
+ This is the same as vector.emplace(vector.size(), \a args).
+
+ \sa emplace
+*/
+
/*! \fn template <typename T> void QVector<T>::insert(int i, const T &value)
\fn template <typename T> void QVector<T>::insert(int i, T &&value)
@@ -659,7 +674,7 @@
For large vectors, this operation can be slow (\l{linear time}),
because it requires moving all the items at indexes \a i and
above by one position further in memory. If you want a container
- class that provides a fast insert() function, use QLinkedList
+ class that provides a fast insert() function, use std::list
instead.
\sa append(), prepend(), remove()
@@ -693,6 +708,26 @@
first of the inserted items.
*/
+/*!
+ \fn template <typename T> template <typename ...Args> QVector<T>::iterator QVector<T>::emplace(int i, Args&&... args)
+
+ Extends the container by inserting a new element at position \a i.
+ This new element is constructed in-place using \a args as the
+ arguments for its construction.
+
+ Returns an iterator to the new element.
+
+ Example:
+ \snippet code/src_corelib_tools_qvector.cpp emplace
+
+ \note It is garanteed that the element will be created in place
+ at the beginning, but after that it might be copied or
+ moved to the right position.
+
+ \sa emplaceBack
+*/
+
+
/*! \fn template <typename T> void QVector<T>::replace(int i, const T &value)
Replaces the item at index position \a i with \a value.
@@ -838,6 +873,17 @@
\sa takeFirst(), removeLast()
*/
+/*!
+ \fn template <typename T> template <typename ...Args> QVector<T>::iterator QVector<T>::emplace(QVector<T>::iterator before, Args&&... args)
+
+ \overload
+
+ Creates a new element in front of the item pointed to by the
+ iterator \a before. This new element is constructed in-place
+ using \a args as the arguments for its construction.
+
+ Returns an iterator to the new element.
+*/
/*! \fn template <typename T> QVector<T> &QVector<T>::fill(const T &value, int size = -1)
diff --git a/src/corelib/tools/qvector_msvc.cpp b/src/corelib/tools/qvector_msvc.cpp
index cee343e72b..7e87467d42 100644
--- a/src/corelib/tools/qvector_msvc.cpp
+++ b/src/corelib/tools/qvector_msvc.cpp
@@ -47,12 +47,5 @@
# error "This file must be compiled with no precompiled headers"
#endif
-// invert the setting of QT_STRICT_ITERATORS, whichever it was
-#ifdef QT_STRICT_ITERATORS
-# undef QT_STRICT_ITERATORS
-#else
-# define QT_STRICT_ITERATORS
-#endif
-
// the Q_TEMPLATE_EXTERN at the bottom of qvector.h will do the trick
#include <QtCore/qvector.h>
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 58e3c15560..4aed715999 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -541,14 +541,14 @@ QDebug operator<<(QDebug debug, const QVersionNumber &version)
#endif
/*!
- \fn uint qHash(const QVersionNumber &key, uint seed)
+ \fn size_t qHash(const QVersionNumber &key, size_t seed)
\relates QHash
\since 5.6
Returns the hash value for the \a key, using \a seed to seed the
calculation.
*/
-uint qHash(const QVersionNumber &key, uint seed)
+size_t qHash(const QVersionNumber &key, size_t seed)
{
QtPrivate::QHashCombine hash;
for (int i = 0; i < key.segmentCount(); ++i)
@@ -556,5 +556,199 @@ uint qHash(const QVersionNumber &key, uint seed)
return seed;
}
-QT_END_NAMESPACE
+/*!
+ \class QTypeRevision
+ \inmodule QtCore
+ \since 6.0
+ \brief The QTypeRevision class contains a lightweight representation of
+ a version number with two 8-bit segments, major and minor, either
+ of which can be unknown.
+
+ Use this class to describe revisions of a type. Compatible revisions can be
+ expressed as increments of the minor version. Breaking changes can be
+ expressed as increments of the major version. The return values of
+ \l QMetaMethod::revision() and \l QMetaProperty::revision() can be passed to
+ \l QTypeRevision::fromEncodedVersion(). The resulting major and minor versions
+ specify in which Qt versions the properties and methods were added.
+
+ \sa QMetaMethod::revision(), QMetaProperty::revision()
+*/
+
+/*!
+ \fn template<typename Integer> static bool QTypeRevision::isValidSegment(Integer segment)
+
+ Returns true if the given number can be used as either major or minor
+ version in a QTypeRevision. Valid segments need to be \c {>= 0} and \c {< 255}.
+*/
+
+/*!
+ \fn QTypeRevision::QTypeRevision()
+
+ Produces an invalid revision.
+
+ \sa isValid()
+*/
+
+/*!
+ \fn template <typename Major, typename Minor> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion)
+
+ Produces a QTypeRevision from the given \a majorVersion and \a minorVersion,
+ both of which need to be a valid segments.
+
+ \sa isValidSegment()
+*/
+
+/*!
+ \fn template <typename Major> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion)
+
+ Produces a QTypeRevision from the given \a majorVersion with an invalid minor
+ version. \a majorVersion needs to be a valid segment.
+
+ \sa isValidSegment()
+*/
+
+/*!
+ \fn template <typename Minor> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion)
+
+ Produces a QTypeRevision from the given \a minorVersion with an invalid major
+ version. \a minorVersion needs to be a valid segment.
+
+ \sa isValidSegment()
+*/
+
+/*!
+ \fn template <typename Integer> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value)
+
+ Produces a QTypeRevision from the given \a value. \a value encodes both the
+ minor and major versions in the least significant and second least
+ significant byte, respectively.
+
+ \a value must not have any bits outside the least significant two bytes set.
+ \c Integer needs to be at least 16 bits wide, and must not have a sign bit
+ in the least significant 16 bits.
+
+ \sa toEncodedVersion()
+*/
+
+/*!
+ \fn static QTypeRevision QTypeRevision::zero()
+
+ Produces a QTypeRevision with major and minor version \c{0}.
+*/
+
+/*!
+ \fn bool QTypeRevision::hasMajorVersion() const
+
+ Returns true if the major version is known, otherwise false.
+
+ \sa majorVersion(), hasMinorVersion()
+*/
+
+/*!
+ \fn quint8 QTypeRevision::majorVersion() const
+
+ Returns the major version encoded in the revision.
+
+ \sa hasMajorVersion(), minorVersion()
+*/
+
+/*!
+ \fn bool QTypeRevision::hasMinorVersion() const
+
+ Returns true if the minor version is known, otherwise false.
+
+ \sa minorVersion(), hasMajorVersion()
+*/
+/*!
+ \fn quint8 QTypeRevision::minorVersion() const
+
+ Returns the minor version encoded in the revision.
+
+ \sa hasMinorVersion(), majorVersion()
+*/
+
+/*!
+ \fn bool QTypeRevision::isValid() const
+
+ Returns true if the major version or the minor version is known,
+ otherwise false.
+
+ \sa hasMajorVersion(), hasMinorVersion()
+*/
+
+/*!
+ \fn template<typename Integer> Integer QTypeRevision::toEncodedVersion() const
+
+ Transforms the revision into an integer value, encoding the minor
+ version into the least significant byte, and the major version into
+ the second least significant byte.
+
+ \c Integer needs to be at least 16 bits wide, and must not have a sign bit
+ in the least significant 16 bits.
+
+ \sa fromEncodedVersion()
+*/
+
+#ifndef QT_NO_DATASTREAM
+/*!
+ \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision)
+ \relates QTypeRevision
+ \since 6.0
+
+ Writes the revision \a revision to stream \a out.
+ */
+QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision)
+{
+ return out << revision.toEncodedVersion<quint16>();
+}
+
+/*!
+ \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision)
+ \relates QTypeRevision
+ \since 6.0
+
+ Reads a revision from stream \a in and stores it in \a revision.
+ */
+QDataStream& operator>>(QDataStream &in, QTypeRevision &revision)
+{
+ quint16 value;
+ in >> value;
+ revision = QTypeRevision::fromEncodedVersion(value);
+ return in;
+}
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QTypeRevision &revision)
+{
+ QDebugStateSaver saver(debug);
+ if (revision.hasMajorVersion()) {
+ if (revision.hasMinorVersion())
+ debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion();
+ else
+ debug.nospace().noquote() << revision.majorVersion() << ".x";
+ } else {
+ if (revision.hasMinorVersion())
+ debug << revision.minorVersion();
+ else
+ debug.noquote() << "invalid";
+ }
+ return debug;
+}
+#endif
+
+/*!
+ \fn size_t qHash(const QTypeRevision &key, size_t seed)
+ \relates QHash
+ \since 6.0
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+*/
+size_t qHash(const QTypeRevision &key, size_t seed)
+{
+ return qHash(key.toEncodedVersion<quint16>(), seed);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index d43b86ba51..184aeac692 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -47,11 +47,12 @@
#include <QtCore/qvector.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qtypeinfo.h>
+#include <limits>
QT_BEGIN_NAMESPACE
class QVersionNumber;
-Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed = 0);
+Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed = 0);
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QVersionNumber &version);
@@ -282,7 +283,7 @@ private:
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
#endif
- friend Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed);
+ friend Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed);
};
Q_DECLARE_TYPEINFO(QVersionNumber, Q_MOVABLE_TYPE);
@@ -309,8 +310,160 @@ Q_REQUIRED_RESULT inline bool operator==(const QVersionNumber &lhs, const QVersi
Q_REQUIRED_RESULT inline bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
{ return QVersionNumber::compare(lhs, rhs) != 0; }
+class QTypeRevision;
+Q_CORE_EXPORT size_t qHash(const QTypeRevision &key, size_t seed = 0);
+
+#ifndef QT_NO_DATASTREAM
+Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision);
+Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QTypeRevision &revision);
+#endif
+
+class QTypeRevision
+{
+public:
+ template<typename Integer>
+ using if_valid_segment_type = typename std::enable_if<
+ std::is_integral<Integer>::value, bool>::type;
+
+ template<typename Integer>
+ using if_valid_value_type = typename std::enable_if<
+ std::is_integral<Integer>::value
+ && (sizeof(Integer) > sizeof(quint16)
+ || (sizeof(Integer) == sizeof(quint16)
+ && !std::is_signed<Integer>::value)), bool>::type;
+
+ template<typename Integer, if_valid_segment_type<Integer> = true>
+ static constexpr bool isValidSegment(Integer segment)
+ {
+ // using extra parentheses around max to avoid expanding it if it is a macro
+ return segment >= Integer(0)
+ && ((std::numeric_limits<Integer>::max)() < Integer(SegmentUnknown)
+ || segment < Integer(SegmentUnknown));
+ }
+
+ template<typename Major, typename Minor,
+ if_valid_segment_type<Major> = true,
+ if_valid_segment_type<Minor> = true>
+ static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
+ {
+ return Q_ASSERT(isValidSegment(majorVersion)),
+ Q_ASSERT(isValidSegment(minorVersion)),
+ QTypeRevision(quint8(majorVersion), quint8(minorVersion));
+ }
+
+ template<typename Major, if_valid_segment_type<Major> = true>
+ static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
+ {
+ return Q_ASSERT(isValidSegment(majorVersion)),
+ QTypeRevision(quint8(majorVersion), SegmentUnknown);
+ }
+
+ template<typename Minor, if_valid_segment_type<Minor> = true>
+ static constexpr QTypeRevision fromMinorVersion(Minor minorVersion)
+ {
+ return Q_ASSERT(isValidSegment(minorVersion)),
+ QTypeRevision(SegmentUnknown, quint8(minorVersion));
+ }
+
+ template<typename Integer, if_valid_value_type<Integer> = true>
+ static constexpr QTypeRevision fromEncodedVersion(Integer value)
+ {
+ return Q_ASSERT((value & ~Integer(0xffff)) == Integer(0)),
+ QTypeRevision((value & Integer(0xff00)) >> 8, value & Integer(0xff));
+ }
+
+ static constexpr QTypeRevision zero() { return QTypeRevision(0, 0); }
+
+ constexpr QTypeRevision() = default;
+
+ constexpr bool hasMajorVersion() const { return m_majorVersion != SegmentUnknown; }
+ constexpr quint8 majorVersion() const { return m_majorVersion; }
+
+ constexpr bool hasMinorVersion() const { return m_minorVersion != SegmentUnknown; }
+ constexpr quint8 minorVersion() const { return m_minorVersion; }
+
+ constexpr bool isValid() const { return hasMajorVersion() || hasMinorVersion(); }
+
+ template<typename Integer, if_valid_value_type<Integer> = true>
+ constexpr Integer toEncodedVersion() const
+ {
+ return Integer(m_majorVersion << 8) | Integer(m_minorVersion);
+ }
+
+private:
+ enum { SegmentUnknown = quint8(~0U) };
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ constexpr QTypeRevision(quint8 major, quint8 minor)
+ : m_minorVersion(minor), m_majorVersion(major) {}
+
+ quint8 m_minorVersion = SegmentUnknown;
+ quint8 m_majorVersion = SegmentUnknown;
+#else
+ constexpr QTypeRevision(quint8 major, quint8 minor)
+ : m_majorVersion(major), m_minorVersion(minor) {}
+
+ quint8 m_majorVersion = SegmentUnknown;
+ quint8 m_minorVersion = SegmentUnknown;
+#endif
+};
+
+inline constexpr bool operator==(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>();
+}
+
+inline constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>();
+}
+
+inline constexpr bool operator<(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return (!lhs.hasMajorVersion() && rhs.hasMajorVersion())
+ // non-0 major > unspecified major > major 0
+ ? rhs.majorVersion() != 0
+ : ((lhs.hasMajorVersion() && !rhs.hasMajorVersion())
+ // major 0 < unspecified major < non-0 major
+ ? lhs.majorVersion() == 0
+ : (lhs.majorVersion() != rhs.majorVersion()
+ // both majors specified and non-0
+ ? lhs.majorVersion() < rhs.majorVersion()
+ : ((!lhs.hasMinorVersion() && rhs.hasMinorVersion())
+ // non-0 minor > unspecified minor > minor 0
+ ? rhs.minorVersion() != 0
+ : ((lhs.hasMinorVersion() && !rhs.hasMinorVersion())
+ // minor 0 < unspecified minor < non-0 minor
+ ? lhs.minorVersion() == 0
+ // both minors specified and non-0
+ : lhs.minorVersion() < rhs.minorVersion()))));
+}
+
+inline constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs != rhs && !(lhs < rhs);
+}
+
+inline constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs == rhs || lhs < rhs;
+}
+
+inline constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs == rhs || !(lhs < rhs);
+}
+
+Q_STATIC_ASSERT(sizeof(QTypeRevision) == 2);
+Q_DECLARE_TYPEINFO(QTypeRevision, Q_MOVABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QTypeRevision &revision);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QVersionNumber)
+Q_DECLARE_METATYPE(QTypeRevision)
#endif //QVERSIONNUMBER_H
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index e078ab4409..607a6eaf06 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -13,12 +13,12 @@ HEADERS += \
tools/qcontainertools_impl.h \
tools/qcryptographichash.h \
tools/qduplicatetracker_p.h \
+ tools/qflatmap_p.h \
tools/qfreelist_p.h \
tools/qhash.h \
tools/qhashfunctions.h \
tools/qiterator.h \
tools/qline.h \
- tools/qlinkedlist.h \
tools/qlist.h \
tools/qmakearray_p.h \
tools/qmap.h \
@@ -40,15 +40,14 @@ HEADERS += \
tools/qsharedpointer.h \
tools/qsharedpointer_impl.h \
tools/qset.h \
- tools/qsimd_p.h \
tools/qsize.h \
tools/qstack.h \
tools/qtools_p.h \
+ tools/qtaggedpointer.h \
tools/qvarlengtharray.h \
tools/qvector.h \
tools/qversionnumber.h
-
SOURCES += \
tools/qarraydata.cpp \
tools/qbitarray.cpp \
@@ -56,7 +55,6 @@ SOURCES += \
tools/qfreelist.cpp \
tools/qhash.cpp \
tools/qline.cpp \
- tools/qlinkedlist.cpp \
tools/qlist.cpp \
tools/qpoint.cpp \
tools/qmap.cpp \
@@ -68,7 +66,6 @@ SOURCES += \
tools/qringbuffer.cpp \
tools/qshareddata.cpp \
tools/qsharedpointer.cpp \
- tools/qsimd.cpp \
tools/qsize.cpp \
tools/qversionnumber.cpp