summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qalgorithms.h69
-rw-r--r--src/corelib/tools/qalgorithms.qdoc41
-rw-r--r--src/corelib/tools/qarraydata.cpp170
-rw-r--r--src/corelib/tools/qarraydata.h114
-rw-r--r--src/corelib/tools/qarraydataops.h128
-rw-r--r--src/corelib/tools/qarraydatapointer.h211
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.h127
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.qdoc123
-rw-r--r--src/corelib/tools/qbitarray.cpp402
-rw-r--r--src/corelib/tools/qbitarray.h181
-rw-r--r--src/corelib/tools/qcache.h79
-rw-r--r--src/corelib/tools/qcache.qdoc28
-rw-r--r--src/corelib/tools/qcommandlineoption.cpp56
-rw-r--r--src/corelib/tools/qcommandlineoption.h44
-rw-r--r--src/corelib/tools/qcommandlineparser.cpp195
-rw-r--r--src/corelib/tools/qcommandlineparser.h40
-rw-r--r--src/corelib/tools/qcontainerfwd.h69
-rw-r--r--src/corelib/tools/qcontainertools_impl.h264
-rw-r--r--src/corelib/tools/qcontiguouscache.cpp42
-rw-r--r--src/corelib/tools/qcontiguouscache.h54
-rw-r--r--src/corelib/tools/qcryptographichash.cpp1202
-rw-r--r--src/corelib/tools/qcryptographichash.h55
-rw-r--r--src/corelib/tools/qduplicatetracker_p.h53
-rw-r--r--src/corelib/tools/qeasingcurve.cpp64
-rw-r--r--src/corelib/tools/qeasingcurve.h42
-rw-r--r--src/corelib/tools/qflatmap_p.h484
-rw-r--r--src/corelib/tools/qfreelist.cpp52
-rw-r--r--src/corelib/tools/qfreelist_p.h43
-rw-r--r--src/corelib/tools/qfunctionaltools_impl.cpp47
-rw-r--r--src/corelib/tools/qfunctionaltools_impl.h77
-rw-r--r--src/corelib/tools/qhash.cpp1265
-rw-r--r--src/corelib/tools/qhash.h1049
-rw-r--r--src/corelib/tools/qhashfunctions.h190
-rw-r--r--src/corelib/tools/qiterator.h125
-rw-r--r--src/corelib/tools/qiterator.qdoc92
-rw-r--r--src/corelib/tools/qline.cpp53
-rw-r--r--src/corelib/tools/qline.h49
-rw-r--r--src/corelib/tools/qlist.h173
-rw-r--r--src/corelib/tools/qlist.qdoc184
-rw-r--r--src/corelib/tools/qmakearray_p.h42
-rw-r--r--src/corelib/tools/qmap.h123
-rw-r--r--src/corelib/tools/qmap.qdoc198
-rw-r--r--src/corelib/tools/qmargins.cpp57
-rw-r--r--src/corelib/tools/qmargins.h71
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.cpp283
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.h67
-rw-r--r--src/corelib/tools/qminimalflatset_p.h156
-rw-r--r--src/corelib/tools/qmultimap.qdoc149
-rw-r--r--src/corelib/tools/qoffsetstringarray_p.h109
-rw-r--r--src/corelib/tools/qpair.h47
-rw-r--r--src/corelib/tools/qpair.qdoc28
-rw-r--r--src/corelib/tools/qpoint.cpp53
-rw-r--r--src/corelib/tools/qpoint.h62
-rw-r--r--src/corelib/tools/qqueue.cpp40
-rw-r--r--src/corelib/tools/qqueue.h40
-rw-r--r--src/corelib/tools/qrect.cpp59
-rw-r--r--src/corelib/tools/qrect.h55
-rw-r--r--src/corelib/tools/qrefcount.cpp40
-rw-r--r--src/corelib/tools/qrefcount.h40
-rw-r--r--src/corelib/tools/qringbuffer.cpp93
-rw-r--r--src/corelib/tools/qringbuffer_p.h86
-rw-r--r--src/corelib/tools/qscopedpointer.cpp52
-rw-r--r--src/corelib/tools/qscopedpointer.h57
-rw-r--r--src/corelib/tools/qscopedvaluerollback.cpp40
-rw-r--r--src/corelib/tools/qscopedvaluerollback.h49
-rw-r--r--src/corelib/tools/qscopeguard.h49
-rw-r--r--src/corelib/tools/qscopeguard.qdoc30
-rw-r--r--src/corelib/tools/qset.h77
-rw-r--r--src/corelib/tools/qset.qdoc62
-rw-r--r--src/corelib/tools/qshareddata.cpp40
-rw-r--r--src/corelib/tools/qshareddata.h67
-rw-r--r--src/corelib/tools/qshareddata_impl.h46
-rw-r--r--src/corelib/tools/qsharedpointer.cpp188
-rw-r--r--src/corelib/tools/qsharedpointer.h86
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h173
-rw-r--r--src/corelib/tools/qsize.cpp53
-rw-r--r--src/corelib/tools/qsize.h62
-rw-r--r--src/corelib/tools/qspan.h452
-rw-r--r--src/corelib/tools/qspan.qdoc651
-rw-r--r--src/corelib/tools/qspan_p.h24
-rw-r--r--src/corelib/tools/qstack.cpp40
-rw-r--r--src/corelib/tools/qstack.h63
-rw-r--r--src/corelib/tools/qtaggedpointer.h81
-rw-r--r--src/corelib/tools/qtaggedpointer.qdoc30
-rw-r--r--src/corelib/tools/qtimeline.cpp84
-rw-r--r--src/corelib/tools/qtimeline.h40
-rw-r--r--src/corelib/tools/qtools_p.h118
-rw-r--r--src/corelib/tools/qtyperevision.cpp217
-rw-r--r--src/corelib/tools/qtyperevision.h167
-rw-r--r--src/corelib/tools/quniquehandle_p.h225
-rw-r--r--src/corelib/tools/qvarlengtharray.h943
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc132
-rw-r--r--src/corelib/tools/qvector.h46
-rw-r--r--src/corelib/tools/qversionnumber.cpp449
-rw-r--r--src/corelib/tools/qversionnumber.h383
95 files changed, 8945 insertions, 5965 deletions
diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h
index 11e4d9da39..8889effece 100644
--- a/src/corelib/tools/qalgorithms.h
+++ b/src/corelib/tools/qalgorithms.h
@@ -1,45 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QALGORITHMS_H
#define QALGORITHMS_H
+#if 0
+#pragma qt_class(QtAlgorithms)
+#endif
+
#include <QtCore/qglobal.h>
#if __has_include(<bit>) && __cplusplus > 201703L
@@ -73,19 +41,11 @@ inline void qDeleteAll(const Container &c)
*/
namespace QAlgorithmsPrivate {
-#ifdef Q_CC_CLANG
-// Clang had a bug where __builtin_ctz/clz/popcount were not marked as constexpr.
-# if (defined __apple_build_version__ && __clang_major__ >= 7) || (Q_CC_CLANG >= 307)
-# define QT_HAS_CONSTEXPR_BUILTINS
-# endif
-#elif defined(Q_CC_MSVC) && !defined(Q_CC_INTEL) && !defined(Q_PROCESSOR_ARM)
-# define QT_HAS_CONSTEXPR_BUILTINS
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+// We use C++20 <bit> operations instead which ensures constexpr bit ops
+# define QT_HAS_CONSTEXPR_BITOPS
#elif defined(Q_CC_GNU)
-# define QT_HAS_CONSTEXPR_BUILTINS
-#endif
-
-#if defined QT_HAS_CONSTEXPR_BUILTINS
-#if defined(Q_CC_GNU) || defined(Q_CC_CLANG)
+# define QT_HAS_CONSTEXPR_BITOPS
# define QT_HAS_BUILTIN_CTZS
constexpr Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept
{
@@ -201,9 +161,7 @@ Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept
// architecture), but unlike the other compilers, MSVC has no option
// to generate code for those processors.
// So it's an acceptable compromise.
-#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
-// We use C++20 <bit> operations instead which ensures constexpr popcount
-#elif defined(__AVX__) || defined(__SSE4_2__) || defined(__POPCNT__)
+#if defined(__AVX__) || defined(__SSE4_2__) || defined(__POPCNT__)
#define QT_POPCOUNT_CONSTEXPR
#define QT_POPCOUNT_RELAXED_CONSTEXPR
#define QALGORITHMS_USE_BUILTIN_POPCOUNT
@@ -232,7 +190,6 @@ Q_ALWAYS_INLINE uint qt_builtin_popcountll(quint64 v) noexcept
#endif // __AVX__ || __SSE4_2__ || __POPCNT__
#endif // MSVC
-#endif // QT_HAS_CONSTEXPR_BUILTINS
#ifndef QT_POPCOUNT_CONSTEXPR
#define QT_POPCOUNT_CONSTEXPR constexpr
@@ -333,7 +290,7 @@ constexpr inline uint qConstexprCountTrailingZeroBits(quint64 v) noexcept
constexpr inline uint qConstexprCountTrailingZeroBits(quint8 v) noexcept
{
unsigned int c = 8; // c will be the number of zero bits on the right
- v &= -signed(v);
+ v &= quint8(-signed(v));
if (v) c--;
if (v & 0x0000000F) c -= 4;
if (v & 0x00000033) c -= 2;
@@ -344,7 +301,7 @@ constexpr inline uint qConstexprCountTrailingZeroBits(quint8 v) noexcept
constexpr inline uint qConstexprCountTrailingZeroBits(quint16 v) noexcept
{
unsigned int c = 16; // c will be the number of zero bits on the right
- v &= -signed(v);
+ v &= quint16(-signed(v));
if (v) c--;
if (v & 0x000000FF) c -= 8;
if (v & 0x00000F0F) c -= 4;
diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc
index 4249cad72e..5fe0b3e8c3 100644
--- a/src/corelib/tools/qalgorithms.qdoc
+++ b/src/corelib/tools/qalgorithms.qdoc
@@ -1,32 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\headerfile <QtAlgorithms>
+ \inmodule QtCore
\title Generic Algorithms
\ingroup funclists
\keyword generic algorithms
@@ -132,18 +109,6 @@
\sa {container classes}, <QtGlobal>
*/
-/*! \fn template <typename T> void qSwap(T &var1, T &var2)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::swap instead.
-
- Exchanges the values of variables \a var1 and \a var2.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 0
-*/
-
/*!
\fn template <typename ForwardIterator> void qDeleteAll(ForwardIterator begin, ForwardIterator end)
\relates <QtAlgorithms>
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 9a52898716..6aebd4306a 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 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.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qarraydata.h>
#include <QtCore/private/qnumeric_p.h>
@@ -90,8 +54,8 @@ qsizetype qCalculateBlockSize(qsizetype elementCount, qsizetype elementSize, qsi
Q_ASSERT(elementSize);
size_t bytes;
- if (Q_UNLIKELY(mul_overflow(size_t(elementSize), size_t(elementCount), &bytes)) ||
- Q_UNLIKELY(add_overflow(bytes, size_t(headerSize), &bytes)))
+ if (Q_UNLIKELY(qMulOverflow(size_t(elementSize), size_t(elementCount), &bytes)) ||
+ Q_UNLIKELY(qAddOverflow(bytes, size_t(headerSize), &bytes)))
return -1;
if (Q_UNLIKELY(qsizetype(bytes) < 0))
return -1;
@@ -143,33 +107,30 @@ qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizet
return result;
}
-/*!
- \internal
+/*
+ Calculate the byte size for a block of \a capacity objects of size \a
+ objectSize, with a header of size \a headerSize. If the \a option is
+ QArrayData::Grow, the capacity itself adjusted up, preallocating room for
+ more elements to be added later; otherwise, it is an exact calculation.
- Returns \a allocSize plus extra reserved bytes necessary to store '\0'.
- */
-static inline qsizetype reserveExtraBytes(qsizetype allocSize)
+ Returns a structure containing the size in bytes and elements available.
+*/
+static inline CalculateGrowingBlockSizeResult
+calculateBlockSize(qsizetype capacity, qsizetype objectSize, qsizetype headerSize, QArrayData::AllocationOption option)
{
- // We deal with QByteArray and QString only
- constexpr qsizetype extra = qMax(sizeof(QByteArray::value_type), sizeof(QString::value_type));
- if (Q_UNLIKELY(allocSize < 0))
- return -1;
- if (Q_UNLIKELY(add_overflow(allocSize, extra, &allocSize)))
- return -1;
- return allocSize;
-}
+ // Adjust the header size up to account for the trailing null for QString
+ // and QByteArray. This is not checked for overflow because headers sizes
+ // should not be anywhere near the overflow limit.
+ constexpr qsizetype FooterSize = qMax(sizeof(QString::value_type), sizeof(QByteArray::value_type));
+ if (objectSize <= FooterSize)
+ headerSize += FooterSize;
-static inline qsizetype calculateBlockSize(qsizetype &capacity, qsizetype objectSize, qsizetype headerSize, QArrayData::AllocationOption option)
-{
- // Calculate the byte size
// allocSize = objectSize * capacity + headerSize, but checked for overflow
// plus padded to grow in size
if (option == QArrayData::Grow) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- return r.size;
+ return qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
} else {
- return qCalculateBlockSize(capacity, objectSize, headerSize);
+ return { qCalculateBlockSize(capacity, objectSize, headerSize), capacity };
}
}
@@ -184,27 +145,20 @@ static QArrayData *allocateData(qsizetype allocSize)
return header;
}
-
namespace {
-// QArrayData with strictest alignment requirements supported by malloc()
-struct alignas(std::max_align_t) AlignedQArrayData : QArrayData
-{
+struct AllocationResult {
+ void *data;
+ QArrayData *header;
};
}
+using QtPrivate::AlignedQArrayData;
-
-void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
- qsizetype capacity, QArrayData::AllocationOption option) noexcept
+static inline AllocationResult
+allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
+ QArrayData::AllocationOption option) noexcept
{
- Q_ASSERT(dptr);
- // Alignment is a power of two
- Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
- && !(alignment & (alignment - 1)));
-
- if (capacity == 0) {
- *dptr = nullptr;
- return nullptr;
- }
+ if (capacity == 0)
+ return {};
qsizetype headerSize = sizeof(AlignedQArrayData);
const qsizetype headerAlignment = alignof(AlignedQArrayData);
@@ -213,16 +167,16 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
// Allocate extra (alignment - Q_ALIGNOF(AlignedQArrayData)) 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!
+ // Effectively, we allocate one QTypedArrayData<T>::AlignmentDummy.
headerSize += alignment - headerAlignment;
}
Q_ASSERT(headerSize > 0);
- qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
- allocSize = reserveExtraBytes(allocSize);
- if (Q_UNLIKELY(allocSize < 0)) { // handle overflow. cannot allocate reliably
- *dptr = nullptr;
- return nullptr;
- }
+ auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option);
+ capacity = blockSize.elementCount;
+ qsizetype allocSize = blockSize.size;
+ if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot allocate reliably
+ return {};
QArrayData *header = allocateData(allocSize);
void *data = nullptr;
@@ -232,20 +186,54 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
header->alloc = qsizetype(capacity);
}
- *dptr = header;
- return data;
+ return { data, header };
}
-QPair<QArrayData *, void *>
+// Generic size and alignment allocation function
+void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
+ qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(dptr);
+ // Alignment is a power of two
+ Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
+ && !(alignment & (alignment - 1)));
+
+ auto r = allocateHelper(objectSize, alignment, capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
+
+// Fixed size and alignment allocation functions
+void *QArrayData::allocate1(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(dptr);
+
+ auto r = allocateHelper(1, alignof(AlignedQArrayData), capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
+
+void *QArrayData::allocate2(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(dptr);
+
+ auto r = allocateHelper(2, alignof(AlignedQArrayData), capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
+
+std::pair<QArrayData *, void *>
QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
qsizetype objectSize, qsizetype capacity, AllocationOption option) noexcept
{
Q_ASSERT(!data || !data->isShared());
const qsizetype headerSize = sizeof(AlignedQArrayData);
- qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
+ auto r = calculateBlockSize(capacity, objectSize, headerSize, option);
+ qsizetype allocSize = r.size;
+ capacity = r.elementCount;
if (Q_UNLIKELY(allocSize < 0))
- return qMakePair<QArrayData *, void *>(nullptr, nullptr);
+ return {};
const qptrdiff offset = dataPointer
? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data)
@@ -253,10 +241,6 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
Q_ASSERT(offset > 0);
Q_ASSERT(offset <= allocSize); // equals when all free space is at the beginning
- allocSize = reserveExtraBytes(allocSize);
- if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot reallocate reliably
- return qMakePair(data, dataPointer);
-
QArrayData *header = static_cast<QArrayData *>(::realloc(data, size_t(allocSize)));
if (header) {
header->alloc = capacity;
@@ -264,7 +248,7 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
} else {
dataPointer = nullptr;
}
- return qMakePair(static_cast<QArrayData *>(header), dataPointer);
+ return {header, dataPointer};
}
void QArrayData::deallocate(QArrayData *data, qsizetype objectSize,
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index e4250cce47..da83fc1a21 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -1,52 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2019 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QARRAYDATA_H
#define QARRAYDATA_H
#include <QtCore/qpair.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qcontainerfwd.h>
#include <string.h>
QT_BEGIN_NAMESPACE
+#if __has_cpp_attribute(gnu::malloc)
+# define Q_DECL_MALLOCLIKE [[nodiscard, gnu::malloc]]
+#else
+# define Q_DECL_MALLOCLIKE [[nodiscard]]
+#endif
+
template <class T> struct QTypedArrayData;
struct QArrayData
@@ -102,7 +74,7 @@ struct QArrayData
// 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() const noexcept
+ bool needsDetach() noexcept
{
return ref_.loadRelaxed() > 1;
}
@@ -114,13 +86,17 @@ struct QArrayData
return newSize;
}
- [[nodiscard]]
-#if defined(Q_CC_GNU)
- __attribute__((__malloc__))
-#endif
+ Q_DECL_MALLOCLIKE
static Q_CORE_EXPORT void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
qsizetype capacity, AllocationOption option = QArrayData::KeepSize) noexcept;
- [[nodiscard]] static Q_CORE_EXPORT QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
+ Q_DECL_MALLOCLIKE
+ static Q_CORE_EXPORT void *allocate1(QArrayData **pdata, qsizetype capacity,
+ AllocationOption option = QArrayData::KeepSize) noexcept;
+ Q_DECL_MALLOCLIKE
+ static Q_CORE_EXPORT void *allocate2(QArrayData **pdata, qsizetype capacity,
+ AllocationOption option = QArrayData::KeepSize) noexcept;
+
+ [[nodiscard]] static Q_CORE_EXPORT std::pair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
qsizetype objectSize, qsizetype newCapacity, AllocationOption option) noexcept;
static Q_CORE_EXPORT void deallocate(QArrayData *data, qsizetype objectSize,
qsizetype alignment) noexcept;
@@ -128,30 +104,56 @@ struct QArrayData
Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions)
+namespace QtPrivate {
+// QArrayData with strictest alignment requirements supported by malloc()
+#if defined(Q_PROCESSOR_X86_32) && defined(Q_CC_GNU)
+// GCC's definition is incorrect since GCC 8 (commit r240248 in SVN; commit
+// 63012d9a57edc950c5f30242d1e19318b5708060 in Git). This is applied to all
+// GCC-like compilers in case they decide to follow GCC's lead in being wrong.
+constexpr size_t MaxPrimitiveAlignment = 2 * sizeof(void *);
+#else
+constexpr size_t MaxPrimitiveAlignment = alignof(std::max_align_t);
+#endif
+
+struct alignas(MaxPrimitiveAlignment) AlignedQArrayData : QArrayData
+{
+};
+}
+
template <class T>
struct QTypedArrayData
: QArrayData
{
- struct AlignmentDummy { QArrayData header; T data; };
+ struct AlignmentDummy { QtPrivate::AlignedQArrayData header; T data; };
- [[nodiscard]] static QPair<QTypedArrayData *, T *> allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize)
+ [[nodiscard]] static std::pair<QTypedArrayData *, T *> allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize)
{
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
QArrayData *d;
- void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option);
+ void *result;
+ if constexpr (sizeof(T) == 1) {
+ // necessarily, alignof(T) == 1
+ result = allocate1(&d, capacity, option);
+ } else if constexpr (sizeof(T) == 2) {
+ // alignof(T) may be 1, but that makes no difference
+ result = allocate2(&d, capacity, option);
+ } else {
+ result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option);
+ }
#if __has_builtin(__builtin_assume_aligned)
+ // and yet we do offer results that have stricter alignment
result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy));
#endif
- return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result));
+ return {static_cast<QTypedArrayData *>(d), static_cast<T *>(result)};
}
- static QPair<QTypedArrayData *, T *>
+ static std::pair<QTypedArrayData *, T *>
reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity, AllocationOption option)
{
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
- QPair<QArrayData *, void *> pair =
+ std::pair<QArrayData *, void *> pair =
QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, option);
- return qMakePair(static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second));
+ return {static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second)};
}
static void deallocate(QArrayData *data) noexcept
@@ -168,6 +170,12 @@ struct QTypedArrayData
(quintptr(data) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1));
return static_cast<T *>(start);
}
+
+ constexpr static qsizetype max_size() noexcept
+ {
+ // -1 to deal with the pointer one-past-the-end
+ return (QtPrivate::MaxAllocSize - sizeof(QtPrivate::AlignedQArrayData) - 1) / sizeof(T);
+ }
};
namespace QtPrivate {
@@ -208,6 +216,8 @@ struct Q_CORE_EXPORT QContainerImplHelper
};
}
+#undef Q_DECL_MALLOCLIKE
+
QT_END_NAMESPACE
#endif // include guard
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 173e3cac2e..c3e9821e81 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -1,50 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QARRAYDATAOPS_H
#define QARRAYDATAOPS_H
#include <QtCore/qarraydata.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qnamespace.h>
-#include <algorithm>
+#include <memory>
#include <new>
#include <string.h>
#include <utility>
@@ -71,6 +36,8 @@ protected:
public:
typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
+ using QArrayDataPointer<T>::QArrayDataPointer;
+
void appendInitialize(qsizetype newSize) noexcept
{
Q_ASSERT(this->isMutable());
@@ -249,6 +216,51 @@ public:
--this->size;
}
+ template <typename Predicate>
+ qsizetype eraseIf(Predicate pred)
+ {
+ qsizetype result = 0;
+ if (this->size == 0)
+ return result;
+
+ if (!this->needsDetach()) {
+ auto end = this->end();
+ auto it = std::remove_if(this->begin(), end, pred);
+ if (it != end) {
+ result = std::distance(it, end);
+ erase(it, result);
+ }
+ } else {
+ const auto begin = this->begin();
+ const auto end = this->end();
+ auto it = std::find_if(begin, end, pred);
+ if (it == end)
+ return result;
+
+ QPodArrayOps<T> other(this->size);
+ Q_CHECK_PTR(other.data());
+ auto dest = other.begin();
+ // std::uninitialized_copy will fallback to ::memcpy/memmove()
+ dest = std::uninitialized_copy(begin, it, dest);
+ dest = q_uninitialized_remove_copy_if(std::next(it), end, dest, pred);
+ other.size = std::distance(other.data(), dest);
+ result = this->size - other.size;
+ this->swap(other);
+ }
+ return result;
+ }
+
+ struct Span { T *begin; T *end; };
+
+ void copyRanges(std::initializer_list<Span> ranges)
+ {
+ auto it = this->begin();
+ std::for_each(ranges.begin(), ranges.end(), [&it](const auto &span) {
+ it = std::copy(span.begin, span.end, it);
+ });
+ this->size = std::distance(this->begin(), it);
+ }
+
void assign(T *b, T *e, parameter_type t) noexcept
{
Q_ASSERT(b <= e);
@@ -911,11 +923,14 @@ public:
Q_ASSERT(distance >= 0 && distance <= this->allocatedCapacity() - this->size);
Q_UNUSED(distance);
-#if __cplusplus >= 202002L
- if constexpr (
- std::is_convertible_v<
- typename std::iterator_traits<It>::iterator_category,
- std::contiguous_iterator_tag>) {
+#if __cplusplus >= 202002L && defined(__cpp_concepts) && defined(__cpp_lib_concepts)
+ constexpr bool canUseCopyAppend =
+ std::contiguous_iterator<It> &&
+ std::is_same_v<
+ std::remove_cv_t<typename std::iterator_traits<It>::value_type>,
+ T
+ >;
+ if constexpr (canUseCopyAppend) {
this->copyAppend(std::to_address(b), std::to_address(e));
} else
#endif
@@ -938,15 +953,32 @@ public:
DataPointer old;
// points into range:
- if (QtPrivate::q_points_into_range(b, this->begin(), this->end())) {
+ if (QtPrivate::q_points_into_range(b, *this))
this->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
- } else {
+ else
this->detachAndGrow(QArrayData::GrowsAtEnd, n, nullptr, nullptr);
- }
Q_ASSERT(this->freeSpaceAtEnd() >= n);
// b might be updated so use [b, n)
this->copyAppend(b, b + n);
}
+
+ void appendUninitialized(qsizetype newSize)
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
+
+ T *const b = this->begin();
+ do {
+ auto ptr = b + this->size;
+
+ if constexpr (std::is_constructible_v<T, Qt::Initialization>)
+ new (ptr) T(Qt::Uninitialized);
+ else
+ new (ptr) T; // not T() -- default-construct
+ } while (++this->size != newSize);
+ }
};
} // namespace QtPrivate
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index 4d83b890cc..6657d40cf9 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QARRAYDATAPOINTER_H
#define QARRAYDATAPOINTER_H
@@ -43,6 +7,9 @@
#include <QtCore/qarraydataops.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/q20functional.h>
+#include <QtCore/q20memory.h>
+
QT_BEGIN_NAMESPACE
template <class T>
@@ -60,27 +27,39 @@ public:
typedef typename std::conditional<pass_parameter_by_value, T, const T &>::type parameter_type;
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer() noexcept
: d(nullptr), ptr(nullptr), size(0)
{
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(const QArrayDataPointer &other) noexcept
: d(other.d), ptr(other.ptr), size(other.size)
{
ref();
}
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0) noexcept
: d(header), ptr(adata), size(n)
{
}
- explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
+ Q_NODISCARD_CTOR
+ explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
: d(adata.first), ptr(adata.second), size(n)
{
}
+ Q_NODISCARD_CTOR explicit
+ QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
+ QArrayData::AllocationOption option = QArrayData::KeepSize)
+ : QArrayDataPointer(Data::allocate(alloc, option), n)
+ {
+ }
+
+ Q_NODISCARD_CTOR
static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
{
Q_ASSERT(rawData || !length);
@@ -94,12 +73,12 @@ public:
return *this;
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(QArrayDataPointer &&other) noexcept
- : d(other.d), ptr(other.ptr), size(other.size)
+ : d(std::exchange(other.d, nullptr)),
+ ptr(std::exchange(other.ptr, nullptr)),
+ size(std::exchange(other.size, 0))
{
- other.d = nullptr;
- other.ptr = nullptr;
- other.size = 0;
}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
@@ -128,7 +107,7 @@ public:
{
if (!deref()) {
(*this)->destroyAll();
- Data::deallocate(d);
+ free(d);
}
}
@@ -149,9 +128,9 @@ public:
void swap(QArrayDataPointer &other) noexcept
{
- qSwap(d, other.d);
- qSwap(ptr, other.ptr);
- qSwap(size, other.size);
+ qt_ptr_swap(d, other.d);
+ qt_ptr_swap(ptr, other.ptr);
+ std::swap(size, other.size);
}
void clear() noexcept(std::is_nothrow_destructible<T>::value)
@@ -168,6 +147,28 @@ public:
/*! \internal
+ Reinterprets the data of this QArrayDataPointer to type X. It's the
+ caller's responsibility to ensure that the data contents are valid and
+ properly aligned, particularly if T and X are not trivial types (i.e,
+ don't do that). The current size is kept and the allocated capacity is
+ updated to account for the difference in the element type's size.
+
+ This is used in QString::fromLatin1 to perform in-place conversion of
+ QString to QByteArray.
+ */
+ template <typename X> QArrayDataPointer<X> reinterpreted() &&
+ {
+ if (sizeof(T) != sizeof(X)) {
+ Q_ASSERT(!d->isShared());
+ d->alloc = d->alloc * sizeof(T) / sizeof(X);
+ }
+ auto od = reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d, nullptr));
+ auto optr = reinterpret_cast<X *>(std::exchange(ptr, nullptr));
+ return { od, optr, std::exchange(size, 0) };
+ }
+
+ /*! \internal
+
Detaches this (optionally) and grows to accommodate the free space for
\a n elements at the required side. The side is determined from \a pos.
@@ -314,11 +315,123 @@ public:
T *res = this->ptr + offset;
QtPrivate::q_relocate_overlap_n(this->ptr, this->size, res);
// first update data pointer, then this->ptr
- if (data && QtPrivate::q_points_into_range(*data, this->begin(), this->end()))
+ if (data && QtPrivate::q_points_into_range(*data, *this))
*data += offset;
this->ptr = res;
}
+ template <typename InputIterator, typename Projection = q20::identity>
+ void assign(InputIterator first, InputIterator last, Projection proj = {})
+ {
+ // This function only provides the basic exception guarantee.
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag>;
+ constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
+
+ if constexpr (IsFwdIt) {
+ const qsizetype n = std::distance(first, last);
+ if (needsDetach() || n > constAllocatedCapacity()) {
+ QArrayDataPointer allocated(detachCapacity(n));
+ swap(allocated);
+ }
+ } else if (needsDetach()) {
+ QArrayDataPointer allocated(allocatedCapacity());
+ swap(allocated);
+ // We don't want to copy data that we know we'll overwrite
+ }
+
+ auto offset = freeSpaceAtBegin();
+ const auto capacityBegin = begin() - offset;
+ const auto prependBufferEnd = begin();
+
+ if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ // If construction can throw, and we have freeSpaceAtBegin(),
+ // it's easiest to just clear the container and start fresh.
+ // The alternative would be to keep track of two active, disjoint ranges.
+ if (offset) {
+ (*this)->truncate(0);
+ setBegin(capacityBegin);
+ offset = 0;
+ }
+ }
+
+ auto dst = capacityBegin;
+ const auto dend = end();
+ if (offset) { // avoids dead stores
+ setBegin(capacityBegin); // undo prepend optimization
+
+ // By construction, the following loop is nothrow!
+ // (otherwise, we can't reach here)
+ // Assumes InputIterator operations don't throw.
+ // (but we can't statically assert that, as these operations
+ // have preconditons, so typically aren't noexcept)
+ while (true) {
+ if (dst == prependBufferEnd) { // ran out of prepend buffer space
+ size += offset;
+ // we now have a contiguous buffer, continue with the main loop:
+ break;
+ }
+ if (first == last) { // ran out of elements to assign
+ std::destroy(prependBufferEnd, dend);
+ size = dst - begin();
+ return;
+ }
+ // construct element in prepend buffer
+ q20::construct_at(dst, std::invoke(proj, *first));
+ ++dst;
+ ++first;
+ }
+ }
+
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt && IsIdentity) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else if constexpr (IsFwdIt && !IsIdentity
+ && std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ for (; first != last; ++dst, ++first) // uninitialized_copy with projection
+ q20::construct_at(dst, std::invoke(proj, *first));
+ break;
+ } else {
+ do {
+ (*this)->emplace(size, std::invoke(proj, *first));
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = std::invoke(proj, *first); // overwrite existing element
+ ++dst;
+ ++first;
+ }
+ size = dst - begin();
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
+ {
+ QArrayDataPointer result(n);
+ std::uninitialized_copy_n(begin() + pos, n, result.begin());
+ result.size = n;
+ return result;
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
+ {
+ if (needsDetach())
+ return sliced(pos, n);
+ T *newBeginning = begin() + pos;
+ std::destroy(begin(), newBeginning);
+ std::destroy(newBeginning + n, end());
+ setBegin(newBeginning);
+ size = n;
+ return std::move(*this);
+ }
+
// forwards from QArrayData
qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
@@ -393,7 +506,7 @@ public:
};
template <class T>
-inline void qSwap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
+inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
{
p1.swap(p2);
}
diff --git a/src/corelib/tools/qatomicscopedvaluerollback.h b/src/corelib/tools/qatomicscopedvaluerollback.h
new file mode 100644
index 0000000000..8f653acba5
--- /dev/null
+++ b/src/corelib/tools/qatomicscopedvaluerollback.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QATOMICSCOPEDVALUEROLLBACK_H
+#define QATOMICSCOPEDVALUEROLLBACK_H
+
+#include <QtCore/qassert.h>
+#include <QtCore/qatomic.h>
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtconfigmacros.h>
+
+#include <atomic>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T>
+class QAtomicScopedValueRollback
+{
+ std::atomic<T> &m_atomic;
+ T m_value;
+ std::memory_order m_mo;
+
+ Q_DISABLE_COPY_MOVE(QAtomicScopedValueRollback)
+
+ static constexpr std::memory_order store_part(std::memory_order mo) noexcept
+ {
+ switch (mo) {
+ case std::memory_order_relaxed:
+ case std::memory_order_consume:
+ case std::memory_order_acquire: return std::memory_order_relaxed;
+ case std::memory_order_release:
+ case std::memory_order_acq_rel: return std::memory_order_release;
+ case std::memory_order_seq_cst: return std::memory_order_seq_cst;
+ }
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
+ Q_UNREACHABLE();
+#endif
+ return std::memory_order_seq_cst;
+ }
+
+ static constexpr std::memory_order load_part(std::memory_order mo) noexcept
+ {
+ switch (mo) {
+ case std::memory_order_relaxed:
+ case std::memory_order_release: return std::memory_order_relaxed;
+ case std::memory_order_consume: return std::memory_order_consume;
+ case std::memory_order_acquire:
+ case std::memory_order_acq_rel: return std::memory_order_acquire;
+ case std::memory_order_seq_cst: return std::memory_order_seq_cst;
+ }
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
+ Q_UNREACHABLE();
+#endif
+ return std::memory_order_seq_cst;
+ }
+public:
+ //
+ // std::atomic:
+ //
+ Q_NODISCARD_CTOR
+ explicit constexpr
+ QAtomicScopedValueRollback(std::atomic<T> &var,
+ std::memory_order mo = std::memory_order_seq_cst)
+ : m_atomic(var), m_value(var.load(load_part(mo))), m_mo(mo) {}
+
+ Q_NODISCARD_CTOR
+ explicit constexpr
+ QAtomicScopedValueRollback(std::atomic<T> &var, T value,
+ std::memory_order mo = std::memory_order_seq_cst)
+ : m_atomic(var), m_value(var.exchange(value, mo)), m_mo(mo) {}
+
+ //
+ // Q(Basic)AtomicInteger:
+ //
+ Q_NODISCARD_CTOR
+ explicit constexpr
+ QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var,
+ std::memory_order mo = std::memory_order_seq_cst)
+ : QAtomicScopedValueRollback(var._q_value, mo) {}
+
+ Q_NODISCARD_CTOR
+ explicit constexpr
+ QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, T value,
+ std::memory_order mo = std::memory_order_seq_cst)
+ : QAtomicScopedValueRollback(var._q_value, value, mo) {}
+
+ //
+ // Q(Basic)AtomicPointer:
+ //
+ Q_NODISCARD_CTOR
+ explicit constexpr
+ QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var,
+ std::memory_order mo = std::memory_order_seq_cst)
+ : QAtomicScopedValueRollback(var._q_value, mo) {}
+
+ Q_NODISCARD_CTOR
+ explicit constexpr
+ QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, T value,
+ std::memory_order mo = std::memory_order_seq_cst)
+ : QAtomicScopedValueRollback(var._q_value, value, mo) {}
+
+ ~QAtomicScopedValueRollback()
+ {
+ m_atomic.store(m_value, store_part(m_mo));
+ }
+
+ void commit()
+ {
+ m_value = m_atomic.load(load_part(m_mo));
+ }
+};
+
+template <typename T>
+QAtomicScopedValueRollback(QBasicAtomicPointer<T> &)
+ -> QAtomicScopedValueRollback<T*>;
+template <typename T>
+QAtomicScopedValueRollback(QBasicAtomicPointer<T> &, std::memory_order)
+ -> QAtomicScopedValueRollback<T*>;
+
+QT_END_NAMESPACE
+
+#endif // QATOMICASCOPEDVALUEROLLBACK_H
diff --git a/src/corelib/tools/qatomicscopedvaluerollback.qdoc b/src/corelib/tools/qatomicscopedvaluerollback.qdoc
new file mode 100644
index 0000000000..8c8161cb35
--- /dev/null
+++ b/src/corelib/tools/qatomicscopedvaluerollback.qdoc
@@ -0,0 +1,123 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAtomicScopedValueRollback
+ \inmodule QtCore
+ \brief Provides a QScopedValueRollback for atomic variables.
+ \ingroup misc
+ \ingroup tools
+ \since 6.7
+
+ The QAtomicScopedValueRollback class resets an atomic variable to its
+ prior value on destruction. It can be used to revert state when an
+ exception is thrown without the need to write try-catch blocks.
+
+ It can also be used to manage variables that are temporarily set, such as
+ reentrancy guards. By using this class, the variable will be reset whether the
+ function is exited normally, exited early by a return statement, or exited by
+ an exception.
+
+ The class works on std::atomic and the Qt atomic classes: QBasicAtomicInteger,
+ \l QAtomicInteger, \l QAtomicInt, QBasicAtomicPointer and \l QAtomicPointer.
+
+ \target Memory Order
+ The memory accesses to the atomic variable \a var are specified using the value
+ of \c mo. The memory order follows this mapping:
+ \br
+ \list
+ \li When writing to the atomic variable:
+ \list
+ \li An acquire ordering performs a relaxed operation instead.
+ \li A hybrid acquire-release ordering performs a release operation instead.
+ \endlist
+ \li When reading from the atomic variable:
+ \list
+ \li A release ordering performs a relaxed operation instead.
+ \li A consume ordering performs a consume operation.
+ \li A hybrid acquire-release ordering performs an acquire operation instead.
+ \endlist
+ \endlist
+ \br
+ Otherwise, the default memory order is sequential consistent ordering.
+
+ \note You should never name the template arguments explicitly, but exclusively
+ use Class Template Argument Deduction (CTAD) and let the compiler pick the
+ template argument.
+
+ \note There is a chance that other threads modify the variable too, which means
+ you may lose updates performed by other threads between the call to the
+ QAtomicScopedValueRollback constructor and commit() or between commit() and the
+ destructor.
+
+ \sa QScopedValueRollback
+*/
+
+/*!
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(std::atomic<T> &var, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, std::memory_order mo = std::memory_order_seq_cst)
+
+ Records the value of \a var in order to restore it on destruction.
+
+ This is equivalent to:
+ \code
+ T old_value = var.load(mo);
+ // And in the destructor: var.store(old_value, mo);
+ \endcode
+ The \c{mo} adjustment for the load is described in the \l {Memory Order} section.
+*/
+
+/*!
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(std::atomic<T> &var, T value, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, T value, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, T value, std::memory_order mo = std::memory_order_seq_cst)
+
+ Assigns \a value to \a var and stores the prior value of \a var internally for
+ reverting on destruction.
+
+ This is equivalent to:
+ \code
+ T old_value = var.exchange(new_value, mo);
+ // And in the destructor: var.store(old_value, mo);
+ \endcode
+*/
+
+/*!
+ \fn template <typename T> QAtomicScopedValueRollback<T>::~QAtomicScopedValueRollback()
+
+ Restores the stored value that was current at construction time, or
+ at the last call to commit(), to the managed variable.
+
+ This is equivalent to:
+ \code
+ // In the constructor: T old_value = var.load(mo);
+ // or: T old_value = exchange(new_value, mo);
+ var.store(old_value, mo);
+ \endcode
+ Where \c{mo} is the same as the one initially passed to the constructor.
+ See \l{Memory Order} for the meaning of \c{mo}.
+*/
+
+/*!
+ \fn template <typename T> void QAtomicScopedValueRollback<T>::commit()
+
+ Updates the stored value to the managed variable's current value, loaded
+ with the same memory order as on construction.
+
+ This updated value will be restored on destruction, instead of the original
+ prior value.
+
+ This is equivalent to:
+ \code
+ // Given constructor: T old_value = var.load(mo);
+ old_value = var.load(mo); // referesh it
+ // And, in the destructor: var.store(old_value, mo);
+ \endcode
+ Where \c{mo} is the same as the one initially passed to the constructor.
+ See \l{Memory Order} for the meaning of \c{mo}.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index 18ce7035d9..e4276d383d 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2019 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbitarray.h"
#include <qalgorithms.h>
#include <qdatastream.h>
#include <qdebug.h>
#include <qendian.h>
+
+#include <limits>
+
#include <string.h>
QT_BEGIN_NAMESPACE
@@ -56,6 +23,8 @@ QT_BEGIN_NAMESPACE
\ingroup shared
\reentrant
+ \compares equality
+
A QBitArray is an array that gives access to individual bits and
provides operators (\l{operator&()}{AND}, \l{operator|()}{OR},
\l{operator^()}{XOR}, and \l{operator~()}{NOT}) that work on
@@ -110,6 +79,7 @@ QT_BEGIN_NAMESPACE
\sa QByteArray, QList
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
\fn QBitArray::QBitArray(QBitArray &&other)
@@ -118,6 +88,7 @@ QT_BEGIN_NAMESPACE
\since 5.2
*/
+#endif
/*! \fn QBitArray::QBitArray()
@@ -140,22 +111,39 @@ QT_BEGIN_NAMESPACE
* inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
*/
+static constexpr qsizetype storage_size(qsizetype size)
+{
+ // avoid overflow when adding 7, by doing the arithmetic in unsigned space:
+ return qsizetype((size_t(size) + 7) / 8);
+}
+
+static constexpr qsizetype allocation_size(qsizetype size)
+{
+ return size <= 0 ? 0 : storage_size(size) + 1;
+}
+
+static void adjust_head_and_tail(char *data, qsizetype storageSize, qsizetype logicalSize)
+{
+ quint8 *c = reinterpret_cast<quint8 *>(data);
+ // store the difference between storage and logical size in d[0]:
+ *c = quint8(size_t(storageSize) * 8 - logicalSize);
+ // reset unallocated bits to 0:
+ if (logicalSize & 7)
+ *(c + 1 + logicalSize / 8) &= (1 << (logicalSize & 7)) - 1;
+}
+
/*!
Constructs a bit array containing \a size bits. The bits are
initialized with \a value, which defaults to false (0).
*/
QBitArray::QBitArray(qsizetype size, bool value)
- : d(size <= 0 ? 0 : 1 + (size + 7) / 8, Qt::Uninitialized)
+ : d(allocation_size(size), value ? 0xFF : 0x00)
{
Q_ASSERT_X(size >= 0, "QBitArray::QBitArray", "Size must be greater than or equal to 0.");
if (size <= 0)
return;
- uchar *c = reinterpret_cast<uchar *>(d.data());
- memset(c + 1, value ? 0xff : 0, d.size() - 1);
- *c = d.size() * 8 - size;
- if (value && size && size & 7)
- *(c + 1 + size / 8) &= (1 << (size & 7)) - 1;
+ adjust_head_and_tail(d.data(), d.size(), size);
}
/*! \fn qsizetype QBitArray::size() const
@@ -219,17 +207,12 @@ qsizetype QBitArray::count(bool on) const
*/
void QBitArray::resize(qsizetype size)
{
- if (!size) {
+ Q_ASSERT_X(size >= 0, "QBitArray::resize", "Size must be greater than or equal to 0.");
+ if (size <= 0) {
d.resize(0);
} else {
- qsizetype s = d.size();
- d.resize(1 + (size + 7) / 8);
- uchar *c = reinterpret_cast<uchar *>(d.data());
- if (size > (s << 3))
- memset(c + s, 0, d.size() - s);
- else if (size & 7)
- *(c + 1 + size / 8) &= (1 << (size & 7)) - 1;
- *c = d.size() * 8 - size;
+ d.resize(allocation_size(size), 0x00);
+ adjust_head_and_tail(d.data(), d.size(), size);
}
}
@@ -325,20 +308,15 @@ void QBitArray::fill(bool value, qsizetype begin, qsizetype end)
*/
QBitArray QBitArray::fromBits(const char *data, qsizetype size)
{
+ Q_ASSERT_X(size >= 0, "QBitArray::fromBits", "Size must be greater than or equal to 0.");
QBitArray result;
- if (size == 0)
+ if (size <= 0)
return result;
- qsizetype nbytes = (size + 7) / 8;
-
- result.d = QByteArray(nbytes + 1, Qt::Uninitialized);
- char *bits = result.d.data();
- memcpy(bits + 1, data, nbytes);
-
- // clear any unused bits from the last byte
- if (size & 7)
- bits[nbytes] &= 0xffU >> (8 - (size & 7));
- *bits = result.d.size() * 8 - size;
+ auto &d = result.d;
+ d.resize(allocation_size(size));
+ memcpy(d.data() + 1, data, d.size() - 1);
+ adjust_head_and_tail(d.data(), d.size(), size);
return result;
}
@@ -489,7 +467,8 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\overload
*/
-/*! \fn QBitArray::QBitArray(const QBitArray &other)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+/*! \fn QBitArray::QBitArray(const QBitArray &other) noexcept
Constructs a copy of \a other.
@@ -501,7 +480,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa operator=()
*/
-/*! \fn QBitArray &QBitArray::operator=(const QBitArray &other)
+/*! \fn QBitArray &QBitArray::operator=(const QBitArray &other) noexcept
Assigns \a other to this bit array and returns a reference to
this bit array.
@@ -513,6 +492,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
Moves \a other to this bit array and returns a reference to
this bit array.
*/
+#endif // Qt 6
/*! \fn void QBitArray::swap(QBitArray &other)
\since 4.8
@@ -521,23 +501,145 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
fast and never fails.
*/
-/*! \fn bool QBitArray::operator==(const QBitArray &other) const
+/*! \fn bool QBitArray::operator==(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is equal to this bit array; otherwise
+ Returns \c true if \a lhs is equal to \a rhs bit array; otherwise
returns \c false.
\sa operator!=()
*/
-/*! \fn bool QBitArray::operator!=(const QBitArray &other) const
+/*! \fn bool QBitArray::operator!=(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is not equal to this bit array;
+ Returns \c true if \a lhs is not equal to \a rhs bit array;
otherwise returns \c false.
\sa operator==()
*/
+// Returns a new QBitArray that has the same size as the bigger of \a a1 and
+// \a a2, but whose contents are uninitialized.
+static QBitArray sizedForOverwrite(const QBitArray &a1, const QBitArray &a2)
+{
+ QBitArray result;
+ const QByteArrayData &d1 = a1.data_ptr();
+ const QByteArrayData &d2 = a2.data_ptr();
+ qsizetype n1 = d1.size;
+ qsizetype n2 = d2.size;
+ qsizetype n = qMax(n1, n2);
+
+ QByteArrayData bytes(n, n);
+
+ // initialize the count of bits in the last byte (see construction note)
+ if (n1 > n2)
+ *bytes.ptr = *d1.ptr;
+ else if (n2 > n1)
+ *bytes.ptr = *d2.ptr;
+ else if (n1) // n1 == n2
+ *bytes.ptr = qMin(*d1.ptr, *d2.ptr);
+
+ result.data_ptr() = std::move(bytes);
+ return result;
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationHelper(QBitArray &out, const QBitArray &a1,
+ const QBitArray &a2, BitwiseOp op)
+{
+ const QByteArrayData &d1 = a1.data_ptr();
+ const QByteArrayData &d2 = a2.data_ptr();
+
+ // Sizes in bytes (including the initial bit difference counter)
+ qsizetype n1 = d1.size;
+ qsizetype n2 = d2.size;
+ Q_ASSERT(out.data_ptr().size == qMax(n1, n2));
+ Q_ASSERT(out.data_ptr().size == 0 || !out.data_ptr().needsDetach());
+
+ // Bypass QByteArray's emptiness verification; we won't dereference
+ // these pointers if their size is zero.
+ auto dst = reinterpret_cast<uchar *>(out.data_ptr().data());
+ auto p1 = reinterpret_cast<const uchar *>(d1.data());
+ auto p2 = reinterpret_cast<const uchar *>(d2.data());
+
+ // Main: perform the operation in the range where both arrays have data
+ if (n1 < n2) {
+ std::swap(n1, n2);
+ std::swap(p1, p2);
+ }
+ for (qsizetype i = 1; i < n2; ++i)
+ dst[i] = op(p1[i], p2[i]);
+
+ // Tail: operate as if both arrays had the same data by padding zeroes to
+ // the end of the shorter of the two (for std::bit_or and std::bit_xor, this is
+ // a memmove; for std::bit_and, it's memset to 0).
+ for (qsizetype i = qMax(n2, qsizetype(1)); i < n1; ++i)
+ dst[i] = op(p1[i], uchar(0));
+
+ return out;
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationInCopy(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ QBitArray tmp(std::move(self));
+ self = sizedForOverwrite(tmp, other);
+ return performBitwiseOperationHelper(self, tmp, other, op);
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationInPlace(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ if (self.size() < other.size())
+ self.resize(other.size());
+ return performBitwiseOperationHelper(self, self, other, op);
+}
+
+template <typename BitwiseOp> static
+QBitArray &performBitwiseOperation(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ if (self.data_ptr().needsDetach())
+ return performBitwiseOperationInCopy(self, other, op);
+ return performBitwiseOperationInPlace(self, other, op);
+}
+
+// SCARY helper
+enum { InCopy, InPlace };
+static auto prepareForBitwiseOperation(QBitArray &self, QBitArray &other)
+{
+ QByteArrayData &d1 = self.data_ptr();
+ QByteArrayData &d2 = other.data_ptr();
+ bool detached1 = !d1.needsDetach();
+ bool detached2 = !d2.needsDetach();
+ if (!detached1 && !detached2)
+ return InCopy;
+
+ // at least one of the two is detached, we'll reuse its buffer
+ bool swap = false;
+ if (detached1 && detached2) {
+ // both are detached, so choose the larger of the two
+ swap = d1.allocatedCapacity() < d2.allocatedCapacity();
+ } else if (detached2) {
+ // we can re-use other's buffer but not self's, so swap the two
+ swap = true;
+ }
+ if (swap)
+ self.swap(other);
+ return InPlace;
+}
+
+template <typename BitwiseOp> static
+QBitArray &performBitwiseOperation(QBitArray &self, QBitArray &other, BitwiseOp op)
+{
+ auto choice = prepareForBitwiseOperation(self, other);
+ if (choice == InCopy)
+ return performBitwiseOperationInCopy(self, other, std::move(op));
+ return performBitwiseOperationInPlace(self, other, std::move(op));
+}
+
/*!
+ \fn QBitArray &QBitArray::operator&=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator&=(QBitArray &&other)
+
Performs the AND operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -552,21 +654,20 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa operator&(), operator|=(), operator^=(), operator~()
*/
+QBitArray &QBitArray::operator&=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_and<uchar>());
+}
+
QBitArray &QBitArray::operator&=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar *>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- qsizetype n = other.d.size() - 1;
- qsizetype p = d.size() - 1 - n;
- while (n-- > 0)
- *a1++ &= *a2++;
- while (p-- > 0)
- *a1++ = 0;
- return *this;
+ return performBitwiseOperation(*this, other, std::bit_and<uchar>());
}
/*!
+ \fn QBitArray &QBitArray::operator|=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator|=(QBitArray &&other)
+
Performs the OR operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -581,18 +682,20 @@ QBitArray &QBitArray::operator&=(const QBitArray &other)
\sa operator|(), operator&=(), operator^=(), operator~()
*/
+QBitArray &QBitArray::operator|=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_or<uchar>());
+}
+
QBitArray &QBitArray::operator|=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar *>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- qsizetype n = other.d.size() - 1;
- while (n-- > 0)
- *a1++ |= *a2++;
- return *this;
+ return performBitwiseOperation(*this, other, std::bit_or<uchar>());
}
/*!
+ \fn QBitArray &QBitArray::operator^=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator^=(QBitArray &&other)
+
Performs the XOR operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -607,20 +710,20 @@ QBitArray &QBitArray::operator|=(const QBitArray &other)
\sa operator^(), operator&=(), operator|=(), operator~()
*/
+QBitArray &QBitArray::operator^=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
+}
+
QBitArray &QBitArray::operator^=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar *>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- qsizetype n = other.d.size() - 1;
- while (n-- > 0)
- *a1++ ^= *a2++;
- return *this;
+ return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
}
/*!
- Returns a bit array that contains the inverted bits of this bit
- array.
+ \fn QBitArray QBitArray::operator~(QBitArray a)
+ Returns a bit array that contains the inverted bits of the bit
+ array \a a.
Example:
\snippet code/src_corelib_tools_qbitarray.cpp 11
@@ -628,24 +731,42 @@ QBitArray &QBitArray::operator^=(const QBitArray &other)
\sa operator&(), operator|(), operator^()
*/
-QBitArray QBitArray::operator~() const
+Q_NEVER_INLINE QBitArray QBitArray::inverted_inplace() &&
{
- qsizetype sz = size();
- QBitArray a(sz);
- const uchar *a1 = reinterpret_cast<const uchar *>(d.constData()) + 1;
- uchar *a2 = reinterpret_cast<uchar *>(a.d.data()) + 1;
- qsizetype n = d.size() - 1;
-
- while (n-- > 0)
- *a2++ = ~*a1++;
-
- if (sz && sz % 8)
- *(a2 - 1) &= (1 << (sz % 8)) - 1;
- return a;
+ qsizetype n = d.size();
+ uchar *dst = reinterpret_cast<uchar *>(data_ptr().data());
+ const uchar *src = dst;
+ QBitArray result([&] {
+ if (d.isDetached() || n == 0)
+ return std::move(d.data_ptr()); // invert in-place
+
+ QByteArrayData tmp(n, n);
+ dst = reinterpret_cast<uchar *>(tmp.data());
+ return tmp;
+ }());
+
+ uchar bitdiff = 8;
+ if (n)
+ bitdiff = dst[0] = src[0]; // copy the count of bits in the last byte
+
+ for (qsizetype i = 1; i < n; ++i)
+ dst[i] = ~src[i];
+
+ if (int tailCount = 16 - bitdiff; tailCount != 8) {
+ // zero the bits beyond our size in the last byte
+ Q_ASSERT(n > 1);
+ uchar tailMask = (1U << tailCount) - 1;
+ dst[n - 1] &= tailMask;
+ }
+
+ return result;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator&(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator&(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator&(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator&(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the AND of the bit arrays \a a1 and \a
a2.
@@ -662,13 +783,16 @@ QBitArray QBitArray::operator~() const
QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp &= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_and<uchar>());
return tmp;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator|(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator|(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator|(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator|(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the OR of the bit arrays \a a1 and \a
a2.
@@ -685,13 +809,16 @@ QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp |= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_or<uchar>());
return tmp;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator^(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator^(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator^(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator^(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the XOR of the bit arrays \a a1 and \a
a2.
@@ -708,8 +835,8 @@ QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp ^= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_xor<uchar>());
return tmp;
}
@@ -769,19 +896,19 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
QDataStream &operator<<(QDataStream &out, const QBitArray &ba)
{
+ const qsizetype len = ba.size();
if (out.version() < QDataStream::Qt_6_0) {
- quint32 len = ba.size();
- out << len;
- if (len > 0)
- out.writeRawData(ba.d.constData() + 1, ba.d.size() - 1);
- return out;
+ if (Q_UNLIKELY(len > qsizetype{(std::numeric_limits<qint32>::max)()})) {
+ out.setStatus(QDataStream::Status::SizeLimitExceeded);
+ return out;
+ }
+ out << quint32(len);
} else {
- quint64 len = ba.size();
- out << len;
- if (len > 0)
- out.writeRawData(ba.d.constData() + 1, ba.d.size() - 1);
- return out;
+ out << quint64(len);
}
+ if (len > 0)
+ out.writeRawData(ba.d.data() + 1, ba.d.size() - 1);
+ return out;
}
/*!
@@ -799,10 +926,18 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
if (in.version() < QDataStream::Qt_6_0) {
quint32 tmp;
in >> tmp;
+ if (Q_UNLIKELY(tmp > quint32((std::numeric_limits<qint32>::max)()))) {
+ in.setStatus(QDataStream::ReadCorruptData);
+ return in;
+ }
len = tmp;
} else {
quint64 tmp;
in >> tmp;
+ if (Q_UNLIKELY(tmp > quint64((std::numeric_limits<qsizetype>::max)()))) {
+ in.setStatus(QDataStream::Status::SizeLimitExceeded);
+ return in;
+ }
len = tmp;
}
if (len == 0) {
@@ -811,7 +946,7 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
}
const qsizetype Step = 8 * 1024 * 1024;
- qsizetype totalBytes = (len + 7) / 8;
+ const qsizetype totalBytes = storage_size(len);
qsizetype allocated = 0;
while (allocated < totalBytes) {
@@ -825,14 +960,13 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
allocated += blockSize;
}
- qsizetype paddingMask = ~((0x1 << (len & 0x7)) - 1);
- if (paddingMask != ~0x0 && (ba.d.constData()[ba.d.size() - 1] & paddingMask)) {
+ const auto fromStream = ba.d.back();
+ adjust_head_and_tail(ba.d.data(), ba.d.size(), len);
+ if (ba.d.back() != fromStream) {
ba.clear();
in.setStatus(QDataStream::ReadCorruptData);
return in;
}
-
- *ba.d.data() = ba.d.size() * 8 - len;
return in;
}
#endif // QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h
index 75d680dc84..b9c36b5320 100644
--- a/src/corelib/tools/qbitarray.h
+++ b/src/corelib/tools/qbitarray.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBITARRAY_H
#define QBITARRAY_H
@@ -47,25 +11,70 @@ QT_BEGIN_NAMESPACE
class QBitRef;
class Q_CORE_EXPORT QBitArray
{
+ Q_CORE_EXPORT friend QBitArray operator&(const QBitArray &a1, const QBitArray &a2);
+ friend QBitArray operator&(QBitArray &&a1, const QBitArray &a2)
+ { return a1 &= a2; }
+ friend QBitArray operator&(const QBitArray &a1, QBitArray &&a2)
+ { return a2 &= a1; }
+ friend QBitArray operator&(QBitArray &&a1, QBitArray &&a2)
+ { return a1 &= a2; }
+
+ Q_CORE_EXPORT friend QBitArray operator|(const QBitArray &a1, const QBitArray &a2);
+ friend QBitArray operator|(QBitArray &&a1, const QBitArray &a2)
+ { return a1 |= a2; }
+ friend QBitArray operator|(const QBitArray &a1, QBitArray &&a2)
+ { return a2 |= a1; }
+ friend QBitArray operator|(QBitArray &&a1, QBitArray &&a2)
+ { return a1 |= a2; }
+
+ Q_CORE_EXPORT friend QBitArray operator^(const QBitArray &a1, const QBitArray &a2);
+ friend QBitArray operator^(QBitArray &&a1, const QBitArray &a2)
+ { return a1 ^= a2; }
+ friend QBitArray operator^(const QBitArray &a1, QBitArray &&a2)
+ { return a2 ^= a1; }
+ friend QBitArray operator^(QBitArray &&a1, QBitArray &&a2)
+ { return a1 ^= a2; }
+
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QBitArray &);
#endif
friend Q_CORE_EXPORT size_t qHash(const QBitArray &key, size_t seed) noexcept;
+ friend QBitArray operator~(QBitArray a)
+ { return std::move(a).inverted_inplace(); }
QByteArray d;
+ QBitArray(QByteArrayData &&dd) : d(std::move(dd)) {}
+
+ template <typename BitArray> static auto bitLocation(BitArray &ba, qsizetype i)
+ {
+ Q_ASSERT(size_t(i) < size_t(ba.size()));
+ struct R {
+ decltype(ba.d[1]) byte;
+ uchar bitMask;
+ };
+ qsizetype byteIdx = i >> 3;
+ qsizetype bitIdx = i & 7;
+ return R{ ba.d[1 + byteIdx], uchar(1U << bitIdx) };
+ }
+
+ QBitArray inverted_inplace() &&;
+
public:
inline QBitArray() noexcept {}
explicit QBitArray(qsizetype size, bool val = false);
- QBitArray(const QBitArray &other) : d(other.d) {}
- inline QBitArray &operator=(const QBitArray &other) { d = other.d; return *this; }
+ // Rule Of Zero applies
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QBitArray(const QBitArray &other) noexcept : d(other.d) {}
+ inline QBitArray &operator=(const QBitArray &other) noexcept { d = other.d; return *this; }
inline QBitArray(QBitArray &&other) noexcept : d(std::move(other.d)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QBitArray)
+#endif // Qt 6
- inline void swap(QBitArray &other) noexcept { qSwap(d, other.d); }
+ void swap(QBitArray &other) noexcept { d.swap(other.d); }
- inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
- inline qsizetype count() const { return (d.size() << 3) - *d.constData(); }
+ qsizetype size() const { return qsizetype((size_t(d.size()) << 3) - *d.constData()); }
+ qsizetype count() const { return size(); }
qsizetype count(bool on) const;
inline bool isEmpty() const { return d.isEmpty(); }
@@ -77,25 +86,43 @@ public:
inline bool isDetached() const { return d.isDetached(); }
inline void clear() { d.clear(); }
- bool testBit(qsizetype i) const;
- void setBit(qsizetype i);
- void setBit(qsizetype i, bool val);
- void clearBit(qsizetype i);
- bool toggleBit(qsizetype i);
-
- bool at(qsizetype i) const;
- QBitRef operator[](qsizetype i);
- bool operator[](qsizetype i) const;
-
+ bool testBit(qsizetype i) const
+ { auto r = bitLocation(*this, i); return r.byte & r.bitMask; }
+ void setBit(qsizetype i)
+ { auto r = bitLocation(*this, i); r.byte |= r.bitMask; }
+ void setBit(qsizetype i, bool val)
+ { if (val) setBit(i); else clearBit(i); }
+ void clearBit(qsizetype i)
+ { auto r = bitLocation(*this, i); r.byte &= ~r.bitMask; }
+ bool toggleBit(qsizetype i)
+ {
+ auto r = bitLocation(*this, i);
+ bool cl = r.byte & r.bitMask;
+ r.byte ^= r.bitMask;
+ return cl;
+ }
+
+ bool at(qsizetype i) const { return testBit(i); }
+ inline QBitRef operator[](qsizetype i);
+ bool operator[](qsizetype i) const { return testBit(i); }
+
+ QBitArray &operator&=(QBitArray &&);
+ QBitArray &operator|=(QBitArray &&);
+ QBitArray &operator^=(QBitArray &&);
QBitArray &operator&=(const QBitArray &);
QBitArray &operator|=(const QBitArray &);
QBitArray &operator^=(const QBitArray &);
+#if QT_CORE_REMOVED_SINCE(6, 7)
QBitArray operator~() const;
+#endif
- inline bool operator==(const QBitArray &other) const { return d == other.d; }
- inline bool operator!=(const QBitArray &other) const { return d != other.d; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QBitArray &other) const { return comparesEqual(d, other.d); }
+ inline bool operator!=(const QBitArray &other) const { return !operator==(other); }
+#endif
- inline bool fill(bool val, qsizetype size = -1);
+ bool fill(bool aval, qsizetype asize = -1)
+ { *this = QBitArray((asize < 0 ? this->size() : asize), aval); return true; }
void fill(bool val, qsizetype first, qsizetype last);
inline void truncate(qsizetype pos) { if (pos < size()) resize(pos); }
@@ -108,39 +135,17 @@ public:
public:
typedef QByteArray::DataPointer DataPtr;
inline DataPtr &data_ptr() { return d.data_ptr(); }
-};
+ inline const DataPtr &data_ptr() const { return d.data_ptr(); }
-inline bool QBitArray::fill(bool aval, qsizetype asize)
-{ *this = QBitArray((asize < 0 ? this->size() : asize), aval); return true; }
-
-Q_CORE_EXPORT QBitArray operator&(const QBitArray &, const QBitArray &);
-Q_CORE_EXPORT QBitArray operator|(const QBitArray &, const QBitArray &);
-Q_CORE_EXPORT QBitArray operator^(const QBitArray &, const QBitArray &);
-
-inline bool QBitArray::testBit(qsizetype i) const
-{ Q_ASSERT(size_t(i) < size_t(size()));
- return (*(reinterpret_cast<const uchar*>(d.constData())+1+(i>>3)) & (1 << (i & 7))) != 0; }
-
-inline void QBitArray::setBit(qsizetype i)
-{ Q_ASSERT(size_t(i) < size_t(size()));
- *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) |= uchar(1 << (i & 7)); }
-
-inline void QBitArray::clearBit(qsizetype i)
-{ Q_ASSERT(size_t(i) < size_t(size()));
- *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) &= ~uchar(1 << (i & 7)); }
-
-inline void QBitArray::setBit(qsizetype i, bool val)
-{ if (val) setBit(i); else clearBit(i); }
-
-inline bool QBitArray::toggleBit(qsizetype i)
-{ Q_ASSERT(size_t(i) < size_t(size()));
- uchar b = uchar(1<<(i&7)); uchar* p = reinterpret_cast<uchar*>(d.data())+1+(i>>3);
- uchar c = uchar(*p&b); *p^=b; return c!=0; }
-
-inline bool QBitArray::operator[](qsizetype i) const { return testBit(i); }
-inline bool QBitArray::at(qsizetype i) const { return testBit(i); }
+private:
+ friend bool comparesEqual(const QBitArray &lhs, const QBitArray &rhs) noexcept
+ {
+ return lhs.d == rhs.d;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QBitArray)
+};
-class Q_CORE_EXPORT QBitRef
+class QT6_ONLY(Q_CORE_EXPORT) QBitRef
{
private:
QBitArray &a;
@@ -155,7 +160,7 @@ public:
QBitRef &operator=(bool val) { a.setBit(i, val); return *this; }
};
-inline QBitRef QBitArray::operator[](qsizetype i)
+QBitRef QBitArray::operator[](qsizetype i)
{ Q_ASSERT(i >= 0); return QBitRef(*this, i); }
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qcache.h b/src/corelib/tools/qcache.h
index 8a341c8555..952b88bafb 100644
--- a/src/corelib/tools/qcache.h
+++ b/src/corelib/tools/qcache.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCACHE_H
#define QCACHE_H
@@ -64,8 +28,8 @@ class QCache
}
Value &operator=(Value &&other) noexcept
{
- qSwap(t, other.t);
- qSwap(cost, other.cost);
+ qt_ptr_swap(t, other.t);
+ std::swap(cost, other.cost);
return *this;
}
~Value() { delete t; }
@@ -109,23 +73,6 @@ class QCache
{
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, 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; }
Node(Node &&other)
: Chain(other),
@@ -155,11 +102,13 @@ class QCache
n->prev->next = n->next;
n->next->prev = n->prev;
total -= n->value.cost;
- auto it = d.find(n->key);
+ auto it = d.findBucket(n->key);
d.erase(it);
}
T *relink(const Key &key) const noexcept
{
+ if (isEmpty())
+ return nullptr;
Node *n = d.findNode(key);
if (!n)
return nullptr;
@@ -179,11 +128,9 @@ class QCache
void trim(qsizetype 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);
+ while (chain.prev != &chain && total > m) {
+ Node *n = static_cast<Node *>(chain.prev);
+ unlink(n);
}
}
@@ -269,11 +216,13 @@ public:
}
inline bool contains(const Key &key) const noexcept
{
- return d.findNode(key) != nullptr;
+ return !isEmpty() && d.findNode(key) != nullptr;
}
bool remove(const Key &key) noexcept(std::is_nothrow_destructible_v<Node>)
{
+ if (isEmpty())
+ return false;
Node *n = d.findNode(key);
if (!n) {
return false;
@@ -285,6 +234,8 @@ public:
T *take(const Key &key) noexcept(std::is_nothrow_destructible_v<Key>)
{
+ if (isEmpty())
+ return nullptr;
Node *n = d.findNode(key);
if (!n)
return nullptr;
diff --git a/src/corelib/tools/qcache.qdoc b/src/corelib/tools/qcache.qdoc
index f9b1ffa8f4..9a4b86aa67 100644
--- a/src/corelib/tools/qcache.qdoc
+++ b/src/corelib/tools/qcache.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QCache
diff --git a/src/corelib/tools/qcommandlineoption.cpp b/src/corelib/tools/qcommandlineoption.cpp
index bfb6f68f08..6b990cecf1 100644
--- a/src/corelib/tools/qcommandlineoption.cpp
+++ b/src/corelib/tools/qcommandlineoption.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
-** Copyright (C) 2013 David Faure <faure@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
+// Copyright (C) 2013 David Faure <faure@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcommandlineoption.h"
@@ -152,8 +116,7 @@ QCommandLineOption::QCommandLineOption(const QStringList &names)
The default value for the option is set to \a defaultValue.
In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4
- and later, it no longer is and can be used for C++11-style uniform
- initialization:
+ and later, it no longer is and can be used for uniform initialization:
\snippet code/src_corelib_tools_qcommandlineoption.cpp cxx11-init
@@ -188,8 +151,7 @@ QCommandLineOption::QCommandLineOption(const QString &name, const QString &descr
The default value for the option is set to \a defaultValue.
In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4
- and later, it no longer is and can be used for C++11-style uniform
- initialization:
+ and later, it no longer is and can be used for uniform initialization:
\snippet code/src_corelib_tools_qcommandlineoption.cpp cxx11-init-list
@@ -261,11 +223,11 @@ namespace {
return warn("be empty");
const QChar c = name.at(0);
- if (Q_UNLIKELY(c == QLatin1Char('-')))
+ if (Q_UNLIKELY(c == u'-'))
return warn("start with a '-'");
- if (Q_UNLIKELY(c == QLatin1Char('/')))
+ if (Q_UNLIKELY(c == u'/'))
return warn("start with a '/'");
- if (Q_UNLIKELY(name.contains(QLatin1Char('='))))
+ if (Q_UNLIKELY(name.contains(u'=')))
return warn("contain a '='");
return false;
diff --git a/src/corelib/tools/qcommandlineoption.h b/src/corelib/tools/qcommandlineoption.h
index 2e7d8fd9da..63c90a4005 100644
--- a/src/corelib/tools/qcommandlineoption.h
+++ b/src/corelib/tools/qcommandlineoption.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOMMANDLINEOPTION_H
#define QCOMMANDLINEOPTION_H
@@ -75,7 +39,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCommandLineOption)
void swap(QCommandLineOption &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
QStringList names() const;
diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp
index f294449b5f..2880eedf77 100644
--- a/src/corelib/tools/qcommandlineparser.cpp
+++ b/src/corelib/tools/qcommandlineparser.cpp
@@ -1,48 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
-** Copyright (C) 2013 David Faure <faure@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
+// Copyright (C) 2013 David Faure <faure@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcommandlineparser.h"
#include <qcoreapplication.h>
#include <private/qcoreapplication_p.h>
#include <qhash.h>
+#include <qvarlengtharray.h>
#include <qlist.h>
#include <qdebug.h>
#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
@@ -53,9 +18,11 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
extern void Q_CORE_EXPORT qt_call_post_routines();
-typedef QHash<QString, int> NameHash_t;
+typedef QHash<QString, qsizetype> NameHash_t;
class QCommandLineParserPrivate
{
@@ -88,7 +55,7 @@ public:
NameHash_t nameHash;
//! Option values found (only for options with a value)
- QHash<int, QStringList> optionValuesHash;
+ QHash<qsizetype, QStringList> optionValuesHash;
//! Names of options found on the command line.
QStringList optionNames;
@@ -158,24 +125,24 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
The parser handles short names, long names, more than one name for the same
option, and option values.
- Options on the command line are recognized as starting with a single or
- double \c{-} character(s).
+ Options on the command line are recognized as starting with one or two
+ \c{-} characters, followed by the option name.
The option \c{-} (single dash alone) is a special case, often meaning standard
- input, and not treated as an option. The parser will treat everything after the
+ input, and is not treated as an option. The parser will treat everything after the
option \c{--} (double dash) as positional arguments.
Short options are single letters. The option \c{v} would be specified by
passing \c{-v} on the command line. In the default parsing mode, short options
can be written in a compact form, for instance \c{-abc} is equivalent to \c{-a -b -c}.
- The parsing mode for can be set to ParseAsLongOptions, in which case \c{-abc}
+ The parsing mode can be changed to ParseAsLongOptions, in which case \c{-abc}
will be parsed as the long option \c{abc}.
Long options are more than one letter long and cannot be compacted together.
The long option \c{verbose} would be passed as \c{--verbose} or \c{-verbose}.
- Passing values to options can be done using the assignment operator: \c{-v=value}
- \c{--verbose=value}, or a space: \c{-v value} \c{--verbose value}, i.e. the next
- argument is used as value (even if it starts with a \c{-}).
+ Passing values to options can be done by using the assignment operator (\c{-v=value},
+ \c{--verbose=value}), or with a space (\c{-v value}, \c{--verbose value}). This
+ works even if the the value starts with a \c{-}.
The parser does not support optional values - if an option is set to
require a value, one must be present. If such an option is placed last
@@ -190,13 +157,13 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
Example:
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
- If your compiler supports the C++11 standard, the three addOption() calls in
- the above example can be simplified:
+ The three addOption() calls in the above example can be made more compact
+ by using addOptions():
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp cxx11
Known limitation: the parsing of Qt options inside QCoreApplication and subclasses
happens before QCommandLineParser exists, so it can't take it into account. This
- means any option value that looks like a builtin Qt option, will be treated by
+ means any option value that looks like a builtin Qt option will be treated by
QCoreApplication as a builtin Qt option. Example: \c{--profile -reverse} will
lead to QGuiApplication seeing the -reverse option set, and removing it from
QCoreApplication::arguments() before QCommandLineParser defines the \c{profile}
@@ -209,7 +176,7 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
It is then advisable to introduce a function to do the command line parsing
which takes a struct or class receiving the option values returning an
- enumeration representing the result. The dnslookup example of the QtNetwork
+ object representing the result. The dnslookup example of the QtNetwork
module illustrates this:
\snippet dnslookup.h 0
@@ -237,20 +204,22 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
\code
- switch (parseCommandLine(parser, &query, &errorMessage)) {
- case CommandLineOk:
+ switch (parseResult.statusCode) {
+ case Status::Ok:
break;
- case CommandLineError:
+ case Status::Error: {
+ QString errorMessage = parseResult.errorString.value_or(u"Unknown error occurred"_qs);
QMessageBox::warning(0, QGuiApplication::applicationDisplayName(),
"<html><head/><body><h2>" + errorMessage + "</h2><pre>"
+ parser.helpText() + "</pre></body></html>");
return 1;
- case CommandLineVersionRequested:
+ }
+ case Status::VersionRequested:
QMessageBox::information(0, QGuiApplication::applicationDisplayName(),
QGuiApplication::applicationDisplayName() + ' '
+ QCoreApplication::applicationVersion());
return 0;
- case CommandLineHelpRequested:
+ case Status::HelpRequested:
QMessageBox::warning(0, QGuiApplication::applicationDisplayName(),
"<html><head/><body><pre>"
+ parser.helpText() + "</pre></body></html>");
@@ -284,7 +253,7 @@ QCommandLineParser::~QCommandLineParser()
\enum QCommandLineParser::SingleDashWordOptionMode
This enum describes the way the parser interprets command-line
- options that use a single dash followed by multiple letters, as as \c{-abc}.
+ options that use a single dash followed by multiple letters, as \c{-abc}.
\value ParseAsCompactedShortOptions \c{-abc} is interpreted as \c{-a -b -c},
i.e. as three short options that have been compacted on the command-line,
@@ -372,7 +341,7 @@ bool QCommandLineParser::addOption(const QCommandLineOption &option)
d->commandLineOptionList.append(option);
- const int offset = d->commandLineOptionList.size() - 1;
+ const qsizetype offset = d->commandLineOptionList.size() - 1;
for (const QString &name : optionNames)
d->nameHash.insert(name, offset);
@@ -420,13 +389,17 @@ QCommandLineOption QCommandLineParser::addVersionOption()
}
/*!
- Adds the help option (\c{-h}, \c{--help} and \c{-?} on Windows)
- as well as an option \c{--help-all} to include Qt-specific options in the output.
+ Adds help options to the command-line parser.
+
+ The options specified for this command-line are described by \c{-h} or
+ \c{--help}. On Windows, the alternative \c{-?} is also supported. The option
+ \c{--help-all} extends that to include generic Qt options, not defined by
+ this command, in the output.
These options are handled automatically by QCommandLineParser.
- Remember to use setApplicationDescription to set the application description,
- which will be displayed when this option is used.
+ Remember to use setApplicationDescription() to set the application
+ description, which will be displayed when this option is used.
Example:
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
@@ -442,7 +415,8 @@ QCommandLineOption QCommandLineParser::addHelpOption()
<< QStringLiteral("h")
<< QStringLiteral("help"), tr("Displays help on commandline options."));
addOption(opt);
- QCommandLineOption optHelpAll(QStringLiteral("help-all"), tr("Displays help including Qt specific options."));
+ QCommandLineOption optHelpAll(QStringLiteral("help-all"),
+ tr("Displays help, including generic Qt options."));
addOption(optHelpAll);
d->builtinHelpOption = true;
return opt;
@@ -533,9 +507,9 @@ QString QCommandLineParser::errorText() const
{
if (!d->errorText.isEmpty())
return d->errorText;
- if (d->unknownOptionNames.count() == 1)
- return tr("Unknown option '%1'.").arg(d->unknownOptionNames.first());
- if (d->unknownOptionNames.count() > 1)
+ if (d->unknownOptionNames.size() == 1)
+ return tr("Unknown option '%1'.").arg(d->unknownOptionNames.constFirst());
+ if (d->unknownOptionNames.size() > 1)
return tr("Unknown options: %1.").arg(d->unknownOptionNames.join(QStringLiteral(", ")));
return QString();
}
@@ -547,7 +521,8 @@ enum MessageType { UsageMessage, ErrorMessage };
// or we are run with redirected handles (for example, by QProcess).
static inline bool displayMessageBox()
{
- if (GetConsoleWindow())
+ if (GetConsoleWindow()
+ || qEnvironmentVariableIsSet("QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES"))
return false;
STARTUPINFO startupInfo;
startupInfo.cb = sizeof(STARTUPINFO);
@@ -592,7 +567,7 @@ static void showParserMessage(const QString &message, MessageType type)
void QCommandLineParser::process(const QStringList &arguments)
{
if (!d->parse(arguments)) {
- showParserMessage(QCoreApplication::applicationName() + QLatin1String(": ") + errorText() + QLatin1Char('\n'), ErrorMessage);
+ showParserMessage(QCoreApplication::applicationName() + ": "_L1 + errorText() + u'\n', ErrorMessage);
qt_call_post_routines();
::exit(EXIT_FAILURE);
}
@@ -659,7 +634,7 @@ bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, cons
const QLatin1Char assignChar('=');
const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
if (nameHashIt != nameHash.constEnd()) {
- const int assignPos = argument.indexOf(assignChar);
+ const qsizetype assignPos = argument.indexOf(assignChar);
const NameHash_t::mapped_type optionOffset = *nameHashIt;
const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
if (withValue) {
@@ -699,7 +674,6 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
needsParsing = false;
bool error = false;
- const QString doubleDashString(QStringLiteral("--"));
const QLatin1Char dashChar('-');
const QLatin1Char assignChar('=');
@@ -723,8 +697,8 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
if (forcePositional) {
positionalArgumentList.append(argument);
- } else if (argument.startsWith(doubleDashString)) {
- if (argument.length() > 2) {
+ } else if (argument.startsWith("--"_L1)) {
+ if (argument.size() > 2) {
QString optionName = argument.mid(2).section(assignChar, 0, 0);
if (registerFoundOption(optionName)) {
if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
@@ -812,7 +786,7 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
Returns \c true if the option \a name was set, false otherwise.
The name provided can be any long or short name of any option that was
- added with \c addOption(). All the options names are treated as being
+ added with addOption(). All the options names are treated as being
equivalent. If the name is not recognized or that option was not present,
false is returned.
@@ -826,7 +800,7 @@ bool QCommandLineParser::isSet(const QString &name) const
if (d->optionNames.contains(name))
return true;
const QStringList aliases = d->aliases(name);
- for (const QString &optionName : qAsConst(d->optionNames)) {
+ for (const QString &optionName : std::as_const(d->optionNames)) {
if (aliases.contains(optionName))
return true;
}
@@ -838,7 +812,7 @@ bool QCommandLineParser::isSet(const QString &name) const
an empty string if not found.
The name provided can be any long or short name of any option that was
- added with \c addOption(). All the option names are treated as being
+ added with addOption(). All the option names are treated as being
equivalent. If the name is not recognized or that option was not present, an
empty string is returned.
@@ -846,7 +820,7 @@ bool QCommandLineParser::isSet(const QString &name) const
that option is returned. If the option wasn't specified on the command line,
the default value is returned.
- An empty string is returned if the option does not take a value.
+ If the option does not take a value, a warning is printed, and an empty string is returned.
\sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
*/
@@ -867,7 +841,7 @@ QString QCommandLineParser::value(const QString &optionName) const
optionName, or an empty list if not found.
The name provided can be any long or short name of any option that was
- added with \c addOption(). All the options names are treated as being
+ added with addOption(). All the options names are treated as being
equivalent. If the name is not recognized or that option was not present, an
empty list is returned.
@@ -883,12 +857,18 @@ QString QCommandLineParser::value(const QString &optionName) const
QStringList QCommandLineParser::values(const QString &optionName) const
{
d->checkParsed("values");
- const NameHash_t::const_iterator it = d->nameHash.constFind(optionName);
+ auto it = d->nameHash.constFind(optionName);
if (it != d->nameHash.cend()) {
- const int optionOffset = *it;
+ const qsizetype optionOffset = *it;
QStringList values = d->optionValuesHash.value(optionOffset);
- if (values.isEmpty())
- values = d->commandLineOptionList.at(optionOffset).defaultValues();
+ if (values.isEmpty()) {
+ const auto &option = d->commandLineOptionList.at(optionOffset);
+ if (option.valueName().isEmpty()) {
+ qWarning("QCommandLineParser: option not expecting values: \"%ls\"",
+ qUtf16Printable(optionName));
+ }
+ values = option.defaultValues();
+ }
return values;
}
@@ -975,8 +955,8 @@ QStringList QCommandLineParser::positionalArguments() const
Names may appear more than once in this list if they were encountered
more than once by the parser.
- Any entry in the list can be used with \c value() or with
- \c values() to get any relevant option values.
+ Any entry in the list can be used with value() or with
+ values() to get any relevant option values.
*/
QStringList QCommandLineParser::optionNames() const
@@ -1017,8 +997,8 @@ QStringList QCommandLineParser::unknownOptionNames() const
*/
Q_NORETURN void QCommandLineParser::showVersion()
{
- showParserMessage(QCoreApplication::applicationName() + QLatin1Char(' ')
- + QCoreApplication::applicationVersion() + QLatin1Char('\n'),
+ showParserMessage(QCoreApplication::applicationName() + u' '
+ + QCoreApplication::applicationVersion() + u'\n',
UsageMessage);
qt_call_post_routines();
::exit(EXIT_SUCCESS);
@@ -1059,8 +1039,8 @@ QString QCommandLineParser::helpText() const
static QString wrapText(const QString &names, int optionNameMaxWidth, const QString &description)
{
- const QLatin1Char nl('\n');
- const QLatin1String indentation(" ");
+ const auto nl = u'\n';
+ const auto indentation = " "_L1;
// In case the list of option names is very long, wrap it as well
int nameIndex = 0;
@@ -1071,20 +1051,20 @@ static QString wrapText(const QString &names, int optionNameMaxWidth, const QStr
};
QString text;
- int lineStart = 0;
- int lastBreakable = -1;
+ qsizetype lineStart = 0;
+ qsizetype lastBreakable = -1;
const int max = 79 - (indentation.size() + optionNameMaxWidth + 1);
int x = 0;
- const int len = description.length();
+ const qsizetype len = description.size();
- for (int i = 0; i < len; ++i) {
+ for (qsizetype i = 0; i < len; ++i) {
++x;
const QChar c = description.at(i);
if (c.isSpace())
lastBreakable = i;
- int breakAt = -1;
- int nextLineStart = -1;
+ qsizetype breakAt = -1;
+ qsizetype nextLineStart = -1;
if (x > max && lastBreakable != -1) {
// time to break and we know where
breakAt = lastBreakable;
@@ -1100,9 +1080,9 @@ static QString wrapText(const QString &names, int optionNameMaxWidth, const QStr
}
if (breakAt != -1) {
- const int numChars = breakAt - lineStart;
+ const qsizetype numChars = breakAt - lineStart;
//qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars);
- text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + QLatin1Char(' ');
+ text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + u' ';
text += QStringView{description}.mid(lineStart, numChars) + nl;
x = 0;
lastBreakable = -1;
@@ -1126,14 +1106,15 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
QString text;
QString usage;
// executable name
- usage += qApp ? QCoreApplication::arguments().constFirst() : QStringLiteral("<executable_name>");
+ usage += qApp ? QStringView(QCoreApplication::arguments().constFirst())
+ : QStringView(u"<executable_name>");
QList<QCommandLineOption> options = commandLineOptionList;
if (includeQtOptions && qApp)
qApp->d_func()->addQtOptions(&options);
if (!options.isEmpty())
- usage += QLatin1Char(' ') + QCommandLineParser::tr("[options]");
+ usage += u' ' + QCommandLineParser::tr("[options]");
for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
- usage += QLatin1Char(' ') + arg.syntax;
+ usage += u' ' + arg.syntax;
text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl;
if (!description.isEmpty())
text += description + nl;
@@ -1142,28 +1123,28 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
text += QCommandLineParser::tr("Options:") + nl;
QStringList optionNameList;
optionNameList.reserve(options.size());
- int longestOptionNameString = 0;
- for (const QCommandLineOption &option : qAsConst(options)) {
+ qsizetype longestOptionNameString = 0;
+ for (const QCommandLineOption &option : std::as_const(options)) {
if (option.flags() & QCommandLineOption::HiddenFromHelp)
continue;
const QStringList optionNames = option.names();
QString optionNamesString;
for (const QString &optionName : optionNames) {
- const int numDashes = optionName.length() == 1 ? 1 : 2;
- optionNamesString += QLatin1String("--", numDashes) + optionName + QLatin1String(", ");
+ const int numDashes = optionName.size() == 1 ? 1 : 2;
+ optionNamesString += QLatin1StringView("--", numDashes) + optionName + ", "_L1;
}
if (!optionNames.isEmpty())
optionNamesString.chop(2); // remove trailing ", "
const auto valueName = option.valueName();
if (!valueName.isEmpty())
- optionNamesString += QLatin1String(" <") + valueName + QLatin1Char('>');
+ optionNamesString += " <"_L1 + valueName + u'>';
optionNameList.append(optionNamesString);
- longestOptionNameString = qMax(longestOptionNameString, optionNamesString.length());
+ longestOptionNameString = qMax(longestOptionNameString, optionNamesString.size());
}
++longestOptionNameString;
- const int optionNameMaxWidth = qMin(50, longestOptionNameString);
+ const int optionNameMaxWidth = qMin(50, int(longestOptionNameString));
auto optionNameIterator = optionNameList.cbegin();
- for (const QCommandLineOption &option : qAsConst(options)) {
+ for (const QCommandLineOption &option : std::as_const(options)) {
if (option.flags() & QCommandLineOption::HiddenFromHelp)
continue;
text += wrapText(*optionNameIterator, optionNameMaxWidth, option.description());
diff --git a/src/corelib/tools/qcommandlineparser.h b/src/corelib/tools/qcommandlineparser.h
index 4584c384cc..332a2f9568 100644
--- a/src/corelib/tools/qcommandlineparser.h
+++ b/src/corelib/tools/qcommandlineparser.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOMMANDLINEPARSER_H
#define QCOMMANDLINEPARSER_H
diff --git a/src/corelib/tools/qcontainerfwd.h b/src/corelib/tools/qcontainerfwd.h
index 673e3c3de2..d5590553fa 100644
--- a/src/corelib/tools/qcontainerfwd.h
+++ b/src/corelib/tools/qcontainerfwd.h
@@ -1,49 +1,20 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtCore/qglobal.h>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCONTAINERFWD_H
#define QCONTAINERFWD_H
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtypes.h>
+
+#if 0
+#pragma qt_class(QtContainerFwd)
+#endif
+
// std headers can unfortunately not be forward declared
+#include <cstddef> // std::size_t
#include <utility>
+#include <limits>
QT_BEGIN_NAMESPACE
@@ -52,16 +23,22 @@ template <typename Key, typename T> class QHash;
template <typename Key, typename T> class QMap;
template <typename Key, typename T> class QMultiHash;
template <typename Key, typename T> class QMultiMap;
+#ifndef QT_NO_QPAIR
template <typename T1, typename T2>
using QPair = std::pair<T1, T2>;
+#endif
template <typename T> class QQueue;
template <typename T> class QSet;
+template <typename T, std::size_t E = std::size_t(-1) /* = std::dynamic_extent*/> class QSpan;
template <typename T> class QStack;
-template <typename T, qsizetype Prealloc = 256> class QVarLengthArray;
+constexpr qsizetype QVarLengthArrayDefaultPrealloc = 256;
+template <typename T, qsizetype Prealloc = QVarLengthArrayDefaultPrealloc> class QVarLengthArray;
template <typename T> class QList;
-#ifndef Q_CLANG_QDOC
+class QString;
+#ifndef Q_QDOC
template<typename T> using QVector = QList<T>;
using QStringList = QList<QString>;
+class QByteArray;
using QByteArrayList = QList<QByteArray>;
#else
template<typename T> class QVector;
@@ -74,7 +51,13 @@ class QVariant;
using QVariantList = QList<QVariant>;
using QVariantMap = QMap<QString, QVariant>;
using QVariantHash = QHash<QString, QVariant>;
-using QVariantPair = QPair<QVariant, QVariant>;
+using QVariantPair = std::pair<QVariant, QVariant>;
+
+namespace QtPrivate
+{
+[[maybe_unused]]
+constexpr qsizetype MaxAllocSize = (std::numeric_limits<qsizetype>::max)();
+}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h
index 2053de6408..998bc292d4 100644
--- a/src/corelib/tools/qcontainertools_impl.h
+++ b/src/corelib/tools/qcontainertools_impl.h
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@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.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if 0
#pragma qt_sync_skip_header_check
@@ -50,6 +14,8 @@
#include <QtCore/qglobal.h>
#include <QtCore/qtypeinfo.h>
+#include <QtCore/qxptype_traits.h>
+
#include <cstring>
#include <iterator>
#include <memory>
@@ -73,22 +39,110 @@ static constexpr bool q_points_into_range(const T *p, const T *b, const T *e,
return !less(p, b) && less(p, e);
}
+/*!
+ \internal
+
+ Returns whether \a p is within container \a c. In its simplest form equivalent to:
+ c.data() <= p < c.data() + c.size()
+*/
+template <typename C, typename T>
+static constexpr bool q_points_into_range(const T &p, const C &c) noexcept
+{
+ static_assert(std::is_same_v<decltype(std::data(c)), T>);
+
+ // std::distance because QArrayDataPointer has a "qsizetype size"
+ // member but no size() function
+ return q_points_into_range(p, std::data(c),
+ std::data(c) + std::distance(std::begin(c), std::end(c)));
+}
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
+
+template <typename T, typename N>
+void q_uninitialized_move_if_noexcept_n(T* first, N n, T* out)
+{
+ if constexpr (std::is_nothrow_move_constructible_v<T> || !std::is_copy_constructible_v<T>)
+ std::uninitialized_move_n(first, n, out);
+ else
+ std::uninitialized_copy_n(first, n, out);
+}
+
template <typename T, typename N>
void q_uninitialized_relocate_n(T* first, N n, T* out)
{
if constexpr (QTypeInfo<T>::isRelocatable) {
- if (n != N(0)) { // even if N == 0, out == nullptr or first == nullptr are UB for memmove()
- std::memmove(static_cast<void*>(out),
- static_cast<const void*>(first),
- n * sizeof(T));
+ static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>,
+ "Refusing to relocate this non-copy/non-move-constructible type.");
+ if (n != N(0)) { // even if N == 0, out == nullptr or first == nullptr are UB for memcpy()
+ std::memcpy(static_cast<void *>(out),
+ static_cast<const void *>(first),
+ n * sizeof(T));
}
} else {
- std::uninitialized_move_n(first, n, out);
+ q_uninitialized_move_if_noexcept_n(first, n, out);
if constexpr (QTypeInfo<T>::isComplex)
std::destroy_n(first, n);
}
}
+QT_WARNING_POP
+
+/*!
+ \internal
+
+ A wrapper around std::rotate(), with an optimization for
+ Q_RELOCATABLE_TYPEs. We omit the return value, as it would be more work to
+ compute in the Q_RELOCATABLE_TYPE case and, unlike std::rotate on
+ ForwardIterators, callers can compute the result in constant time
+ themselves.
+*/
+template <typename T>
+void q_rotate(T *first, T *mid, T *last)
+{
+ if constexpr (QTypeInfo<T>::isRelocatable) {
+ const auto cast = [](T *p) { return reinterpret_cast<uchar*>(p); };
+ std::rotate(cast(first), cast(mid), cast(last));
+ } else {
+ std::rotate(first, mid, last);
+ }
+}
+
+/*!
+ \internal
+ Copies all elements, except the ones for which \a pred returns \c true, from
+ range [first, last), to the uninitialized memory buffer starting at \a out.
+
+ It's undefined behavior if \a out points into [first, last).
+
+ Returns a pointer one past the last copied element.
+
+ If an exception is thrown, all the already copied elements in the destination
+ buffer are destroyed.
+*/
+template <typename T, typename Predicate>
+T *q_uninitialized_remove_copy_if(T *first, T *last, T *out, Predicate &pred)
+{
+ static_assert(std::is_nothrow_destructible_v<T>,
+ "This algorithm requires that T has a non-throwing destructor");
+ Q_ASSERT(!q_points_into_range(out, first, last));
+
+ T *dest_begin = out;
+ QT_TRY {
+ while (first != last) {
+ if (!pred(*first)) {
+ new (std::addressof(*out)) T(*first);
+ ++out;
+ }
+ ++first;
+ }
+ } QT_CATCH (...) {
+ std::destroy(std::reverse_iterator(out), std::reverse_iterator(dest_begin));
+ QT_RETHROW;
+ }
+ return out;
+}
+
template<typename iterator, typename N>
void q_relocate_overlap_n_left_move(iterator first, N n, iterator d_first)
{
@@ -200,6 +254,13 @@ void q_relocate_overlap_n(T *first, N n, T *d_first)
}
}
+template <typename T>
+struct ArrowProxy
+{
+ T t;
+ T *operator->() noexcept { return &t; }
+};
+
template <typename Iterator>
using IfIsInputIterator = typename std::enable_if<
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>::value,
@@ -230,43 +291,38 @@ void reserveIfForwardIterator(Container *c, ForwardIterator f, ForwardIterator l
c->reserve(static_cast<typename Container::size_type>(std::distance(f, l)));
}
-template <typename Iterator, typename = std::void_t<>>
-struct AssociativeIteratorHasKeyAndValue : std::false_type
-{
-};
-
template <typename Iterator>
-struct AssociativeIteratorHasKeyAndValue<
- Iterator,
- std::void_t<decltype(std::declval<Iterator &>().key()),
- decltype(std::declval<Iterator &>().value())>
- >
- : std::true_type
-{
-};
-
-template <typename Iterator, typename = std::void_t<>, typename = std::void_t<>>
-struct AssociativeIteratorHasFirstAndSecond : std::false_type
-{
-};
+using KeyAndValueTest = decltype(
+ std::declval<Iterator &>().key(),
+ std::declval<Iterator &>().value()
+);
template <typename Iterator>
-struct AssociativeIteratorHasFirstAndSecond<
- Iterator,
- std::void_t<decltype(std::declval<Iterator &>()->first),
- decltype(std::declval<Iterator &>()->second)>
- >
- : std::true_type
-{
-};
+using FirstAndSecondTest = decltype(
+ std::declval<Iterator &>()->first,
+ std::declval<Iterator &>()->second
+);
template <typename Iterator>
using IfAssociativeIteratorHasKeyAndValue =
- typename std::enable_if<AssociativeIteratorHasKeyAndValue<Iterator>::value, bool>::type;
+ std::enable_if_t<qxp::is_detected_v<KeyAndValueTest, Iterator>, bool>;
template <typename Iterator>
using IfAssociativeIteratorHasFirstAndSecond =
- typename std::enable_if<AssociativeIteratorHasFirstAndSecond<Iterator>::value, bool>::type;
+ std::enable_if_t<
+ std::conjunction_v<
+ std::negation<qxp::is_detected<KeyAndValueTest, Iterator>>,
+ qxp::is_detected<FirstAndSecondTest, Iterator>
+ >, bool>;
+
+template <typename Iterator>
+using MoveBackwardsTest = decltype(
+ std::declval<Iterator &>().operator--()
+);
+
+template <typename Iterator>
+using IfIteratorCanMoveBackwards =
+ std::enable_if_t<qxp::is_detected_v<MoveBackwardsTest, Iterator>, bool>;
template <typename T, typename U>
using IfIsNotSame =
@@ -275,30 +331,56 @@ using IfIsNotSame =
template<typename T, typename U>
using IfIsNotConvertible = typename std::enable_if<!std::is_convertible<T, U>::value, bool>::type;
-template <typename Container, typename T>
-auto sequential_erase(Container &c, const T &t)
+template <typename Container, typename Predicate>
+auto sequential_erase_if(Container &c, Predicate &pred)
{
- // avoid a detach in case there is nothing to remove
+ // This is remove_if() modified to perform the find_if step on
+ // const_iterators to avoid shared container detaches if nothing needs to
+ // be removed. We cannot run remove_if after find_if: doing so would apply
+ // the predicate to the first matching element twice!
+
const auto cbegin = c.cbegin();
const auto cend = c.cend();
- const auto t_it = std::find(cbegin, cend, t);
+ const auto t_it = std::find_if(cbegin, cend, pred);
auto result = std::distance(cbegin, t_it);
if (result == c.size())
return result - result; // `0` of the right type
+ // now detach:
const auto e = c.end();
- const auto it = std::remove(std::next(c.begin(), result), e, t);
- result = std::distance(it, e);
- c.erase(it, e);
+
+ auto it = std::next(c.begin(), result);
+ auto dest = it;
+
+ // Loop Invariants:
+ // - it != e
+ // - [next(it), e[ still to be checked
+ // - [c.begin(), dest[ are result
+ while (++it != e) {
+ if (!pred(*it)) {
+ *dest = std::move(*it);
+ ++dest;
+ }
+ }
+
+ result = std::distance(dest, e);
+ c.erase(dest, e);
return result;
}
template <typename Container, typename T>
+auto sequential_erase(Container &c, const T &t)
+{
+ // use the equivalence relation from http://eel.is/c++draft/list.erasure#1
+ auto cmp = [&](auto &e) { return e == t; };
+ return sequential_erase_if(c, cmp); // can't pass rvalues!
+}
+
+template <typename Container, typename T>
auto sequential_erase_with_copy(Container &c, const T &t)
{
using CopyProxy = std::conditional_t<std::is_copy_constructible_v<T>, T, const T &>;
- const T &tCopy = CopyProxy(t);
- return sequential_erase(c, tCopy);
+ return sequential_erase(c, CopyProxy(t));
}
template <typename Container, typename T>
@@ -312,24 +394,6 @@ auto sequential_erase_one(Container &c, const T &t)
return true;
}
-template <typename Container, typename Predicate>
-auto sequential_erase_if(Container &c, Predicate &pred)
-{
- // avoid a detach in case there is nothing to remove
- const auto cbegin = c.cbegin();
- const auto cend = c.cend();
- const auto t_it = std::find_if(cbegin, cend, pred);
- auto result = std::distance(cbegin, t_it);
- if (result == c.size())
- return result - result; // `0` of the right type
-
- const auto e = c.end();
- const auto it = std::remove_if(std::next(c.begin(), result), e, pred);
- result = std::distance(it, e);
- c.erase(it, e);
- return result;
-}
-
template <typename T, typename Predicate>
qsizetype qset_erase_if(QSet<T> &set, Predicate &pred)
{
diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp
index 95537961f9..d28d1e7153 100644
--- a/src/corelib/tools/qcontiguouscache.cpp
+++ b/src/corelib/tools/qcontiguouscache.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcontiguouscache.h"
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
#include <QDebug>
#endif
+#include <QtCore/qmalloc.h>
+
QT_BEGIN_NAMESPACE
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 62ebfa0658..c01dbb9390 100644
--- a/src/corelib/tools/qcontiguouscache.h
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -1,47 +1,17 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCONTIGUOUSCACHE_H
#define QCONTIGUOUSCACHE_H
#include <QtCore/qatomic.h>
-#include <limits.h>
+#include <QtCore/qassert.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtcoreexports.h>
+#include <QtCore/qtypeinfo.h>
+
+#include <climits>
+#include <limits>
#include <new>
QT_BEGIN_NAMESPACE
@@ -97,9 +67,9 @@ public:
QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QContiguousCache)
- inline void swap(QContiguousCache<T> &other) noexcept { qSwap(d, other.d); }
+ void swap(QContiguousCache &other) noexcept { qt_ptr_swap(d, other.d); }
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template <typename U = T>
QTypeTraits::compare_eq_result<U> operator==(const QContiguousCache<T> &other) const
{
@@ -121,7 +91,7 @@ public:
#else
bool operator==(const QContiguousCache &other) const;
bool operator!=(const QContiguousCache &other) const;
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
inline qsizetype capacity() const {return d->alloc; }
inline qsizetype count() const { return d->count; }
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index e1f15d2b93..2e82a394ee 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -1,45 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2013 Richard J. Moore <rich@kde.org>.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
+// Copyright (C) 2013 Richard J. Moore <rich@kde.org>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qcryptographichash.h>
+#include <qmessageauthenticationcode.h>
+
#include <qiodevice.h>
+#include <qmutex.h>
+#include <qvarlengtharray.h>
+#include <private/qlocking_p.h>
+
+#include <array>
+#include <climits>
+#include <numeric>
#include "../../3rdparty/sha1/sha1.cpp"
@@ -47,12 +21,17 @@
# error "Are you sure you need the other hashing algorithms besides SHA-1?"
#endif
+// Header from rfc6234
+#include "../../3rdparty/rfc6234/sha.h"
+
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+#if !QT_CONFIG(openssl_hash)
// qdoc and qmake only need SHA-1
#include "../../3rdparty/md5/md5.h"
#include "../../3rdparty/md5/md5.cpp"
#include "../../3rdparty/md4/md4.h"
#include "../../3rdparty/md4/md4.cpp"
+#endif // !QT_CONFIG(openssl_hash)
typedef unsigned char BitSequence;
typedef unsigned long long DataLength;
@@ -79,23 +58,21 @@ typedef HashReturn (SHA3Final)(hashState *state, BitSequence *hashval);
#include "../../3rdparty/sha3/KeccakF-1600-opt64.c"
-static SHA3Init * const sha3Init = Init;
-static SHA3Update * const sha3Update = Update;
-static SHA3Final * const sha3Final = Final;
+Q_CONSTINIT static SHA3Init * const sha3Init = Init;
+Q_CONSTINIT static SHA3Update * const sha3Update = Update;
+Q_CONSTINIT static SHA3Final * const sha3Final = Final;
#else // 32 bit optimised fallback
#include "../../3rdparty/sha3/KeccakF-1600-opt32.c"
-static SHA3Init * const sha3Init = Init;
-static SHA3Update * const sha3Update = Update;
-static SHA3Final * const sha3Final = Final;
+Q_CONSTINIT static SHA3Init * const sha3Init = Init;
+Q_CONSTINIT static SHA3Update * const sha3Update = Update;
+Q_CONSTINIT static SHA3Final * const sha3Final = Final;
#endif
-// Header from rfc6234
-#include "../../3rdparty/rfc6234/sha.h"
-
+#if !QT_CONFIG(openssl_hash)
/*
These 2 functions replace macros of the same name in sha224-256.c and
sha384-512.c. Originally, these macros relied on a global static 'addTemp'
@@ -127,6 +104,9 @@ static inline int SHA384_512AddLength(SHA512Context *context, unsigned int lengt
uint64_t addTemp;
return SHA384_512AddLengthM(context, length);
}
+#endif // !QT_CONFIG(opensslv30)
+
+#include "qtcore-config_p.h"
#if QT_CONFIG(system_libb2)
#include <blake2.h>
@@ -136,17 +116,88 @@ static inline int SHA384_512AddLength(SHA512Context *context, unsigned int lengt
#endif
#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(openssl_hash)
+#define USING_OPENSSL30
+#include <openssl/evp.h>
+#include <openssl/provider.h>
+#endif
+
QT_BEGIN_NAMESPACE
-static constexpr qsizetype MaxHashLength = 64;
+template <size_t N>
+class QSmallByteArray
+{
+ std::array<quint8, N> m_data;
+ static_assert(N <= std::numeric_limits<std::uint8_t>::max());
+ quint8 m_size = 0;
+public:
+ QSmallByteArray() = default;
+ // all compiler-generated SMFs are ok!
+ template <std::size_t M, std::enable_if_t<M < N, bool> = true> // M == N is for copy ctor!
+ constexpr QSmallByteArray(const QSmallByteArray<M> &other) noexcept
+ {
+ assign(other);
+ }
+ template <std::size_t M, std::enable_if_t<M < N, bool> = true> // M == N is for copy-assignment op!
+ constexpr QSmallByteArray &operator=(const QSmallByteArray<M> &other) noexcept
+ {
+ assign(other);
+ return *this;
+ }
+
+ template <typename Container> // ### underconstrained
+ constexpr void assign(const Container &c)
+ {
+ const size_t otherSize = size_t(std::size(c));
+ Q_ASSERT(otherSize < N);
+ memcpy(data(), std::data(c), otherSize);
+ m_size = quint8(otherSize);
+ }
+
+ constexpr quint8 *data() noexcept { return m_data.data(); }
+ constexpr const quint8 *data() const noexcept { return m_data.data(); }
+ constexpr qsizetype size() const noexcept { return qsizetype{m_size}; }
+ constexpr quint8 &operator[](qsizetype n)
+ {
+ Q_ASSERT(n < size());
+ return data()[n];
+ }
+ constexpr const quint8 &operator[](qsizetype n) const
+ {
+ Q_ASSERT(n < size());
+ return data()[n];
+ }
+ constexpr bool isEmpty() const noexcept { return size() == 0; }
+ constexpr void clear() noexcept { m_size = 0; }
+ constexpr void resizeForOverwrite(qsizetype s)
+ {
+ Q_ASSERT(s >= 0);
+ Q_ASSERT(size_t(s) <= N);
+ m_size = std::uint8_t(s);
+ }
+ constexpr void resize(qsizetype s, quint8 v)
+ {
+ const auto oldSize = size();
+ resizeForOverwrite(s);
+ if (s > oldSize)
+ memset(data() + oldSize, v, size() - oldSize);
+ }
+ constexpr QByteArrayView toByteArrayView() const noexcept
+ { return *this; }
+
+ constexpr auto begin() noexcept { return data(); }
+ constexpr auto begin() const noexcept { return data(); }
+ constexpr auto cbegin() const noexcept { return begin(); }
+ constexpr auto end() noexcept { return data() + size(); }
+ constexpr auto end() const noexcept { return data() + size(); }
+ constexpr auto cend() const noexcept { return end(); }
+};
static constexpr int hashLengthInternal(QCryptographicHash::Algorithm method) noexcept
{
switch (method) {
#define CASE(Enum, Size) \
case QCryptographicHash:: Enum : \
- /* if this triggers, then increase MaxHashLength accordingly */ \
- static_assert(MaxHashLength >= qsizetype(Size) ); \
return Size \
/*end*/
CASE(Sha1, 20);
@@ -160,95 +211,184 @@ static constexpr int hashLengthInternal(QCryptographicHash::Algorithm method) no
CASE(Blake2s_128, 128 / 8);
case QCryptographicHash::Blake2b_160:
case QCryptographicHash::Blake2s_160:
- static_assert(160 / 8 <= MaxHashLength);
return 160 / 8;
case QCryptographicHash::RealSha3_224:
case QCryptographicHash::Keccak_224:
case QCryptographicHash::Blake2s_224:
- static_assert(224 / 8 <= MaxHashLength);
return 224 / 8;
case QCryptographicHash::RealSha3_256:
case QCryptographicHash::Keccak_256:
case QCryptographicHash::Blake2b_256:
case QCryptographicHash::Blake2s_256:
- static_assert(256 / 8 <= MaxHashLength);
return 256 / 8;
case QCryptographicHash::RealSha3_384:
case QCryptographicHash::Keccak_384:
case QCryptographicHash::Blake2b_384:
- static_assert(384 / 8 <= MaxHashLength);
return 384 / 8;
case QCryptographicHash::RealSha3_512:
case QCryptographicHash::Keccak_512:
case QCryptographicHash::Blake2b_512:
- static_assert(512 / 8 <= MaxHashLength);
return 512 / 8;
#endif
#undef CASE
+ case QCryptographicHash::NumAlgorithms: ;
+ // fall through
+ // Q_UNREACHABLE() would be BiC here, as hashLength(~~invalid~~) worked in 6.4
}
return 0;
}
+static constexpr int maxHashLength()
+{
+ int result = 0;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms; ++i)
+ result = std::max(result, hashLengthInternal(A(i)));
+ return result;
+}
+
+using HashResult = QSmallByteArray<maxHashLength()>;
+
+#ifdef USING_OPENSSL30
+static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept
+{
+ switch (method) {
+#define CASE(Enum, Name) \
+ case QCryptographicHash:: Enum : \
+ return Name \
+ /*end*/
+ CASE(Sha1, "SHA1");
+ CASE(Md4, "MD4");
+ CASE(Md5, "MD5");
+ CASE(Sha224, "SHA224");
+ CASE(Sha256, "SHA256");
+ CASE(Sha384, "SHA384");
+ CASE(Sha512, "SHA512");
+ CASE(RealSha3_224, "SHA3-224");
+ CASE(RealSha3_256, "SHA3-256");
+ CASE(RealSha3_384, "SHA3-384");
+ CASE(RealSha3_512, "SHA3-512");
+ CASE(Blake2b_512, "BLAKE2B512");
+ CASE(Blake2s_256, "BLAKE2S256");
+#undef CASE
+ default: return nullptr;
+ }
+}
+
+/*
+ Checks whether given method is not provided by OpenSSL and whether we will
+ have a fallback to non-OpenSSL implementation.
+*/
+static constexpr bool useNonOpenSSLFallback(QCryptographicHash::Algorithm method) noexcept
+{
+ if (method == QCryptographicHash::Keccak_224 || method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 || method == QCryptographicHash::Keccak_512 ||
+ method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384 || method == QCryptographicHash::Blake2s_128 ||
+ method == QCryptographicHash::Blake2s_160 || method == QCryptographicHash::Blake2s_224)
+ return true;
+
+ return false;
+}
+#endif // USING_OPENSSL30
+
class QCryptographicHashPrivate
{
public:
explicit QCryptographicHashPrivate(QCryptographicHash::Algorithm method) noexcept
- : method(method)
+ : state(method), method(method)
+ {
+ }
+ ~QCryptographicHashPrivate()
{
- reset();
+ state.destroy(method);
}
void reset() noexcept;
void addData(QByteArrayView bytes) noexcept;
+ bool addData(QIODevice *dev);
void finalize() noexcept;
+ // when not called from the static hash() function, this function needs to be
+ // called with finalizeMutex held (finalize() will do that):
+ void finalizeUnchecked() noexcept;
+ // END functions that need to be called with finalizeMutex held
QByteArrayView resultView() const noexcept { return result.toByteArrayView(); }
+ static bool supportsAlgorithm(QCryptographicHash::Algorithm method);
+
+#ifdef USING_OPENSSL30
+ struct EVP_MD_CTX_deleter {
+ void operator()(EVP_MD_CTX *ctx) const noexcept {
+ EVP_MD_CTX_free(ctx);
+ }
+ };
+ struct EVP_MD_deleter {
+ void operator()(EVP_MD *md) const noexcept {
+ EVP_MD_free(md);
+ }
+ };
+ struct OSSL_PROVIDER_deleter {
+ void operator()(OSSL_PROVIDER *provider) const noexcept {
+ OSSL_PROVIDER_unload(provider);
+ }
+ };
+
+ using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, EVP_MD_CTX_deleter>;
+ using EVP_MD_ptr = std::unique_ptr<EVP_MD, EVP_MD_deleter>;
+ using OSSL_PROVIDER_ptr = std::unique_ptr<OSSL_PROVIDER, OSSL_PROVIDER_deleter>;
+ struct EVP {
+ EVP_MD_ptr algorithm;
+ EVP_MD_CTX_ptr context;
+ OSSL_PROVIDER_ptr defaultProvider;
+ OSSL_PROVIDER_ptr legacyProvider;
+ bool initializationFailed;
+
+ explicit EVP(QCryptographicHash::Algorithm method);
+ void reset() noexcept;
+ void finalizeUnchecked(HashResult &result) noexcept;
+ };
+#endif
+
+ union State {
+ explicit State(QCryptographicHash::Algorithm method);
+ void destroy(QCryptographicHash::Algorithm method);
+#ifdef USING_OPENSSL30
+ ~State() {}
+#endif
+
+ void reset(QCryptographicHash::Algorithm method) noexcept;
+ void addData(QCryptographicHash::Algorithm method, QByteArrayView data) noexcept;
+ void finalizeUnchecked(QCryptographicHash::Algorithm method, HashResult &result) noexcept;
- const QCryptographicHash::Algorithm method;
- union {
Sha1State sha1Context;
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+#ifdef USING_OPENSSL30
+ EVP evp;
+#else
MD5Context md5Context;
md4_context md4Context;
SHA224Context sha224Context;
SHA256Context sha256Context;
SHA384Context sha384Context;
SHA512Context sha512Context;
+#endif
SHA3Context sha3Context;
+
+ enum class Sha3Variant { Sha3, Keccak };
+ void sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant);
blake2b_state blake2bContext;
blake2s_state blake2sContext;
#endif
- };
-#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- enum class Sha3Variant
- {
- Sha3,
- Keccak
- };
- void sha3Finish(int bitCount, Sha3Variant sha3Variant);
-#endif
- class SmallByteArray {
- std::array<char, MaxHashLength> m_data;
- static_assert(MaxHashLength <= std::numeric_limits<std::uint8_t>::max());
- std::uint8_t m_size;
- public:
- char *data() noexcept { return m_data.data(); }
- const char *data() const noexcept { return m_data.data(); }
- qsizetype size() const noexcept { return qsizetype{m_size}; }
- bool isEmpty() const noexcept { return size() == 0; }
- void clear() noexcept { m_size = 0; }
- void resize(qsizetype s) {
- Q_ASSERT(s >= 0);
- Q_ASSERT(s <= MaxHashLength);
- m_size = std::uint8_t(s);
- }
- QByteArrayView toByteArrayView() const noexcept
- { return QByteArrayView{data(), size()}; }
- };
- SmallByteArray result;
+ } state;
+ // protects result in finalize()
+ QBasicMutex finalizeMutex;
+ HashResult result;
+
+ const QCryptographicHash::Algorithm method;
};
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
-void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant)
+void QCryptographicHashPrivate::State::sha3Finish(HashResult &result, int bitCount,
+ Sha3Variant sha3Variant)
{
/*
FIPS 202 §6.1 defines SHA-3 in terms of calculating the Keccak function
@@ -272,7 +412,7 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
*/
static const unsigned char sha3FinalSuffix = 0x80;
- result.resize(bitCount / 8);
+ result.resizeForOverwrite(bitCount / 8);
SHA3Context copy = sha3Context;
@@ -284,7 +424,7 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
break;
}
- sha3Final(&copy, reinterpret_cast<BitSequence *>(result.data()));
+ sha3Final(&copy, result.data());
}
#endif
@@ -341,6 +481,7 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
\omitvalue RealSha3_256
\omitvalue RealSha3_384
\omitvalue RealSha3_512
+ \omitvalue NumAlgorithms
*/
/*!
@@ -352,6 +493,18 @@ QCryptographicHash::QCryptographicHash(Algorithm method)
}
/*!
+ \fn QCryptographicHash::QCryptographicHash(QCryptographicHash &&other)
+
+ Move-constructs a new QCryptographicHash from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 6.5
+*/
+
+/*!
Destroys the object.
*/
QCryptographicHash::~QCryptographicHash()
@@ -360,6 +513,27 @@ QCryptographicHash::~QCryptographicHash()
}
/*!
+ \fn QCryptographicHash &QCryptographicHash::operator=(QCryptographicHash &&other)
+
+ Move-assigns \a other to this QCryptographicHash instance.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 6.5
+*/
+
+/*!
+ \fn void QCryptographicHash::swap(QCryptographicHash &other)
+
+ Swaps cryptographic hash \a other with this cryptographic hash. This
+ operation is very fast and never fails.
+
+ \since 6.5
+*/
+
+/*!
Resets the object.
*/
void QCryptographicHash::reset() noexcept
@@ -367,12 +541,101 @@ void QCryptographicHash::reset() noexcept
d->reset();
}
-void QCryptographicHashPrivate::reset() noexcept
+/*!
+ Returns the algorithm used to generate the cryptographic hash.
+
+ \since 6.5
+*/
+QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept
+{
+ return d->method;
+}
+
+#ifdef USING_OPENSSL30
+
+QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method)
+{
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ new (&sha3Context) SHA3Context;
+ reset(method);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
+ new (&blake2bContext) blake2b_state;
+ reset(method);
+ } else if (method == QCryptographicHash::Blake2s_128 ||
+ method == QCryptographicHash::Blake2s_160 ||
+ method == QCryptographicHash::Blake2s_224) {
+ new (&blake2sContext) blake2s_state;
+ reset(method);
+ } else {
+ new (&evp) EVP(method);
+ }
+}
+
+void QCryptographicHashPrivate::State::destroy(QCryptographicHash::Algorithm method)
+{
+ if (method != QCryptographicHash::Keccak_224 &&
+ method != QCryptographicHash::Keccak_256 &&
+ method != QCryptographicHash::Keccak_384 &&
+ method != QCryptographicHash::Keccak_512 &&
+ method != QCryptographicHash::Blake2b_160 &&
+ method != QCryptographicHash::Blake2b_256 &&
+ method != QCryptographicHash::Blake2b_384 &&
+ method != QCryptographicHash::Blake2s_128 &&
+ method != QCryptographicHash::Blake2s_160 &&
+ method != QCryptographicHash::Blake2s_224) {
+ evp.~EVP();
+ }
+}
+
+QCryptographicHashPrivate::EVP::EVP(QCryptographicHash::Algorithm method)
+ : initializationFailed{true}
+{
+ if (method == QCryptographicHash::Md4) {
+ /*
+ * We need to load the legacy provider in order to have the MD4
+ * algorithm available.
+ */
+ legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
+
+ if (!legacyProvider)
+ return;
+ }
+
+ defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
+ if (!defaultProvider)
+ return;
+
+ context = EVP_MD_CTX_ptr(EVP_MD_CTX_new());
+
+ if (!context) {
+ return;
+ }
+
+ /*
+ * Using the "-fips" option will disable the global "fips=yes" for
+ * this one lookup and the algorithm can be fetched from any provider
+ * that implements the algorithm (including the FIPS provider).
+ */
+ algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), "-fips"));
+ if (!algorithm) {
+ return;
+ }
+
+ initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr);
+}
+
+#else // USING_OPENSSL30
+
+QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method)
{
switch (method) {
case QCryptographicHash::Sha1:
new (&sha1Context) Sha1State;
- sha1InitState(&sha1Context);
break;
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
default:
@@ -382,27 +645,21 @@ void QCryptographicHashPrivate::reset() noexcept
#else
case QCryptographicHash::Md4:
new (&md4Context) md4_context;
- md4_init(&md4Context);
break;
case QCryptographicHash::Md5:
new (&md5Context) MD5Context;
- MD5Init(&md5Context);
break;
case QCryptographicHash::Sha224:
new (&sha224Context) SHA224Context;
- SHA224Reset(&sha224Context);
break;
case QCryptographicHash::Sha256:
new (&sha256Context) SHA256Context;
- SHA256Reset(&sha256Context);
break;
case QCryptographicHash::Sha384:
new (&sha384Context) SHA384Context;
- SHA384Reset(&sha384Context);
break;
case QCryptographicHash::Sha512:
new (&sha512Context) SHA512Context;
- SHA512Reset(&sha512Context);
break;
case QCryptographicHash::RealSha3_224:
case QCryptographicHash::Keccak_224:
@@ -413,27 +670,134 @@ void QCryptographicHashPrivate::reset() noexcept
case QCryptographicHash::RealSha3_512:
case QCryptographicHash::Keccak_512:
new (&sha3Context) SHA3Context;
- sha3Init(&sha3Context, hashLengthInternal(method) * 8);
break;
case QCryptographicHash::Blake2b_160:
case QCryptographicHash::Blake2b_256:
case QCryptographicHash::Blake2b_384:
case QCryptographicHash::Blake2b_512:
new (&blake2bContext) blake2b_state;
- blake2b_init(&blake2bContext, hashLengthInternal(method));
break;
case QCryptographicHash::Blake2s_128:
case QCryptographicHash::Blake2s_160:
case QCryptographicHash::Blake2s_224:
case QCryptographicHash::Blake2s_256:
new (&blake2sContext) blake2s_state;
- blake2s_init(&blake2sContext, hashLengthInternal(method));
break;
#endif
+ case QCryptographicHash::NumAlgorithms:
+ Q_UNREACHABLE();
}
+ reset(method);
+}
+
+void QCryptographicHashPrivate::State::destroy(QCryptographicHash::Algorithm)
+{
+ static_assert(std::is_trivially_destructible_v<State>); // so nothing to do here
+}
+#endif // !USING_OPENSSL30
+
+void QCryptographicHashPrivate::reset() noexcept
+{
result.clear();
+ state.reset(method);
+}
+
+#ifdef USING_OPENSSL30
+
+void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept
+{
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ sha3Init(&sha3Context, hashLengthInternal(method) * 8);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
+ blake2b_init(&blake2bContext, hashLengthInternal(method));
+ } else if (method == QCryptographicHash::Blake2s_128 ||
+ method == QCryptographicHash::Blake2s_160 ||
+ method == QCryptographicHash::Blake2s_224) {
+ blake2s_init(&blake2sContext, hashLengthInternal(method));
+ } else {
+ evp.reset();
+ }
}
+void QCryptographicHashPrivate::EVP::reset() noexcept
+{
+ if (!initializationFailed) {
+ Q_ASSERT(context);
+ Q_ASSERT(algorithm);
+ // everything already set up - just reset the context
+ EVP_MD_CTX_reset(context.get());
+ initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr);
+ }
+ // if initializationFailed first time around, it will not succeed this time, either
+}
+
+#else // USING_OPENSSL30
+
+void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept
+{
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ sha1InitState(&sha1Context);
+ break;
+#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ default:
+ Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
+ Q_UNREACHABLE();
+ break;
+#else
+ case QCryptographicHash::Md4:
+ md4_init(&md4Context);
+ break;
+ case QCryptographicHash::Md5:
+ MD5Init(&md5Context);
+ break;
+ case QCryptographicHash::Sha224:
+ SHA224Reset(&sha224Context);
+ break;
+ case QCryptographicHash::Sha256:
+ SHA256Reset(&sha256Context);
+ break;
+ case QCryptographicHash::Sha384:
+ SHA384Reset(&sha384Context);
+ break;
+ case QCryptographicHash::Sha512:
+ SHA512Reset(&sha512Context);
+ break;
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::Keccak_224:
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::Keccak_256:
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::Keccak_384:
+ case QCryptographicHash::RealSha3_512:
+ case QCryptographicHash::Keccak_512:
+ sha3Init(&sha3Context, hashLengthInternal(method) * 8);
+ break;
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ blake2b_init(&blake2bContext, hashLengthInternal(method));
+ break;
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+ blake2s_init(&blake2sContext, hashLengthInternal(method));
+ break;
+#endif
+ case QCryptographicHash::NumAlgorithms:
+ Q_UNREACHABLE();
+ }
+}
+
+#endif // USING_OPENSSL30
+
#if QT_DEPRECATED_SINCE(6, 4)
/*!
Adds the first \a length chars of \a data to the cryptographic
@@ -462,6 +826,43 @@ void QCryptographicHash::addData(QByteArrayView bytes) noexcept
void QCryptographicHashPrivate::addData(QByteArrayView bytes) noexcept
{
+ state.addData(method, bytes);
+ result.clear();
+}
+
+#ifdef USING_OPENSSL30
+
+void QCryptographicHashPrivate::State::addData(QCryptographicHash::Algorithm method,
+ QByteArrayView bytes) noexcept
+{
+ const char *data = bytes.data();
+ auto length = bytes.size();
+ // all functions take size_t length, so we don't need to loop around them:
+ {
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
+ blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
+ } else if (method == QCryptographicHash::Blake2s_128 ||
+ method == QCryptographicHash::Blake2s_160 ||
+ method == QCryptographicHash::Blake2s_224) {
+ blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
+ } else if (!evp.initializationFailed) {
+ EVP_DigestUpdate(evp.context.get(), (const unsigned char *)data, length);
+ }
+ }
+}
+
+#else // USING_OPENSSL30
+
+void QCryptographicHashPrivate::State::addData(QCryptographicHash::Algorithm method,
+ QByteArrayView bytes) noexcept
+{
const char *data = bytes.data();
auto length = bytes.size();
@@ -525,10 +926,12 @@ void QCryptographicHashPrivate::addData(QByteArrayView bytes) noexcept
blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
break;
#endif
+ case QCryptographicHash::NumAlgorithms:
+ Q_UNREACHABLE();
}
}
- result.clear();
}
+#endif // !USING_OPENSSL30
/*!
Reads the data from the open QIODevice \a device until it ends
@@ -537,6 +940,11 @@ void QCryptographicHashPrivate::addData(QByteArrayView bytes) noexcept
*/
bool QCryptographicHash::addData(QIODevice *device)
{
+ return d->addData(device);
+}
+
+bool QCryptographicHashPrivate::addData(QIODevice *device)
+{
if (!device->isReadable())
return false;
@@ -544,10 +952,10 @@ bool QCryptographicHash::addData(QIODevice *device)
return false;
char buffer[1024];
- int length;
+ qint64 length;
while ((length = device->read(buffer, sizeof(buffer))) > 0)
- d->addData({buffer, length});
+ addData({buffer, qsizetype(length)}); // length always <= 1024
return device->atEnd();
}
@@ -575,21 +983,86 @@ QByteArray QCryptographicHash::result() const
*/
QByteArrayView QCryptographicHash::resultView() const noexcept
{
+ // resultView() is a const function, so concurrent calls are allowed; protect:
d->finalize();
+ // resultView() remains(!) valid even after we dropped the mutex in finalize()
return d->resultView();
}
+/*!
+ \internal
+
+ Calls finalizeUnchecked(), if needed, under finalizeMutex protection.
+*/
void QCryptographicHashPrivate::finalize() noexcept
{
+ const auto lock = qt_scoped_lock(finalizeMutex);
+ // check that no other thread already finalizeUnchecked()'ed before us:
if (!result.isEmpty())
return;
+ finalizeUnchecked();
+}
+
+/*!
+ \internal
+ Must be called with finalizeMutex held (except from static hash() function,
+ where no sharing can take place).
+*/
+void QCryptographicHashPrivate::finalizeUnchecked() noexcept
+{
+ state.finalizeUnchecked(method, result);
+}
+
+#ifdef USING_OPENSSL30
+void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method,
+ HashResult &result) noexcept
+{
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
+ const auto length = hashLengthInternal(method);
+ blake2b_state copy = blake2bContext;
+ result.resizeForOverwrite(length);
+ blake2b_final(&copy, result.data(), length);
+ } else if (method == QCryptographicHash::Blake2s_128 ||
+ method == QCryptographicHash::Blake2s_160 ||
+ method == QCryptographicHash::Blake2s_224) {
+ const auto length = hashLengthInternal(method);
+ blake2s_state copy = blake2sContext;
+ result.resizeForOverwrite(length);
+ blake2s_final(&copy, result.data(), length);
+ } else {
+ evp.finalizeUnchecked(result);
+ }
+}
+
+void QCryptographicHashPrivate::EVP::finalizeUnchecked(HashResult &result) noexcept
+{
+ if (!initializationFailed) {
+ EVP_MD_CTX_ptr copy = EVP_MD_CTX_ptr(EVP_MD_CTX_new());
+ EVP_MD_CTX_copy_ex(copy.get(), context.get());
+ result.resizeForOverwrite(EVP_MD_get_size(algorithm.get()));
+ EVP_DigestFinal_ex(copy.get(), result.data(), nullptr);
+ }
+}
+
+#else // USING_OPENSSL30
+
+void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method,
+ HashResult &result) noexcept
+{
switch (method) {
case QCryptographicHash::Sha1: {
Sha1State copy = sha1Context;
- result.resize(20);
+ result.resizeForOverwrite(20);
sha1FinalizeState(&copy);
- sha1ToHash(&copy, (unsigned char *)result.data());
+ sha1ToHash(&copy, result.data());
break;
}
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
@@ -600,52 +1073,52 @@ void QCryptographicHashPrivate::finalize() noexcept
#else
case QCryptographicHash::Md4: {
md4_context copy = md4Context;
- result.resize(MD4_RESULTLEN);
- md4_final(&copy, (unsigned char *)result.data());
+ result.resizeForOverwrite(MD4_RESULTLEN);
+ md4_final(&copy, result.data());
break;
}
case QCryptographicHash::Md5: {
MD5Context copy = md5Context;
- result.resize(16);
- MD5Final(&copy, (unsigned char *)result.data());
+ result.resizeForOverwrite(16);
+ MD5Final(&copy, result.data());
break;
}
case QCryptographicHash::Sha224: {
SHA224Context copy = sha224Context;
- result.resize(SHA224HashSize);
- SHA224Result(&copy, reinterpret_cast<unsigned char *>(result.data()));
+ result.resizeForOverwrite(SHA224HashSize);
+ SHA224Result(&copy, result.data());
break;
}
case QCryptographicHash::Sha256: {
SHA256Context copy = sha256Context;
- result.resize(SHA256HashSize);
- SHA256Result(&copy, reinterpret_cast<unsigned char *>(result.data()));
+ result.resizeForOverwrite(SHA256HashSize);
+ SHA256Result(&copy, result.data());
break;
}
case QCryptographicHash::Sha384: {
SHA384Context copy = sha384Context;
- result.resize(SHA384HashSize);
- SHA384Result(&copy, reinterpret_cast<unsigned char *>(result.data()));
+ result.resizeForOverwrite(SHA384HashSize);
+ SHA384Result(&copy, result.data());
break;
}
case QCryptographicHash::Sha512: {
SHA512Context copy = sha512Context;
- result.resize(SHA512HashSize);
- SHA512Result(&copy, reinterpret_cast<unsigned char *>(result.data()));
+ result.resizeForOverwrite(SHA512HashSize);
+ SHA512Result(&copy, result.data());
break;
}
case QCryptographicHash::RealSha3_224:
case QCryptographicHash::RealSha3_256:
case QCryptographicHash::RealSha3_384:
case QCryptographicHash::RealSha3_512: {
- sha3Finish(8 * hashLengthInternal(method), Sha3Variant::Sha3);
+ sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Sha3);
break;
}
case QCryptographicHash::Keccak_224:
case QCryptographicHash::Keccak_256:
case QCryptographicHash::Keccak_384:
case QCryptographicHash::Keccak_512: {
- sha3Finish(8 * hashLengthInternal(method), Sha3Variant::Keccak);
+ sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
break;
}
case QCryptographicHash::Blake2b_160:
@@ -654,8 +1127,8 @@ void QCryptographicHashPrivate::finalize() noexcept
case QCryptographicHash::Blake2b_512: {
const auto length = hashLengthInternal(method);
blake2b_state copy = blake2bContext;
- result.resize(length);
- blake2b_final(&copy, reinterpret_cast<uint8_t *>(result.data()), length);
+ result.resizeForOverwrite(length);
+ blake2b_final(&copy, result.data(), length);
break;
}
case QCryptographicHash::Blake2s_128:
@@ -664,13 +1137,16 @@ void QCryptographicHashPrivate::finalize() noexcept
case QCryptographicHash::Blake2s_256: {
const auto length = hashLengthInternal(method);
blake2s_state copy = blake2sContext;
- result.resize(length);
- blake2s_final(&copy, reinterpret_cast<uint8_t *>(result.data()), length);
+ result.resizeForOverwrite(length);
+ blake2s_final(&copy, result.data(), length);
break;
}
#endif
+ case QCryptographicHash::NumAlgorithms:
+ Q_UNREACHABLE();
}
}
+#endif // !USING_OPENSSL30
/*!
Returns the hash of \a data using \a method.
@@ -682,7 +1158,7 @@ QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method)
{
QCryptographicHashPrivate hash(method);
hash.addData(data);
- hash.finalize();
+ hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash'
return hash.resultView().toByteArray();
}
@@ -696,6 +1172,480 @@ int QCryptographicHash::hashLength(QCryptographicHash::Algorithm method)
return hashLengthInternal(method);
}
+/*!
+ Returns whether the selected algorithm \a method is supported and if
+ result() will return a value when the \a method is used.
+
+ \note OpenSSL will be responsible for providing this information when
+ used as a provider, otherwise \c true will be returned as the non-OpenSSL
+ implementation doesn't have any restrictions.
+ We return \c false if we fail to query OpenSSL.
+
+ \since 6.5
+*/
+
+
+bool QCryptographicHash::supportsAlgorithm(QCryptographicHash::Algorithm method)
+{
+ return QCryptographicHashPrivate::supportsAlgorithm(method);
+}
+
+bool QCryptographicHashPrivate::supportsAlgorithm(QCryptographicHash::Algorithm method)
+{
+#ifdef USING_OPENSSL30
+ // OpenSSL doesn't support Blake2b{60,236,384} and Blake2s{128,160,224}
+ // and these would automatically return FALSE in that case, while they are
+ // actually supported by our non-OpenSSL implementation.
+ if (useNonOpenSSLFallback(method))
+ return true;
+
+ auto legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
+ auto defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
+
+ const char *restriction = "-fips";
+ EVP_MD_ptr algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), restriction));
+
+ return algorithm != nullptr;
+#else
+ switch (method) {
+ case QCryptographicHash::Sha1:
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ case QCryptographicHash::Md4:
+ case QCryptographicHash::Md5:
+ case QCryptographicHash::Sha224:
+ case QCryptographicHash::Sha256:
+ case QCryptographicHash::Sha384:
+ case QCryptographicHash::Sha512:
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::Keccak_224:
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::Keccak_256:
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::Keccak_384:
+ case QCryptographicHash::RealSha3_512:
+ case QCryptographicHash::Keccak_512:
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+#endif
+ return true;
+ case QCryptographicHash::NumAlgorithms: ;
+ };
+ return false;
+#endif // !USING_OPENSSL3
+}
+
+static constexpr int qt_hash_block_size(QCryptographicHash::Algorithm method)
+{
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ return SHA1_Message_Block_Size;
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ case QCryptographicHash::Md4:
+ return 64;
+ case QCryptographicHash::Md5:
+ return 64;
+ case QCryptographicHash::Sha224:
+ return SHA224_Message_Block_Size;
+ case QCryptographicHash::Sha256:
+ return SHA256_Message_Block_Size;
+ case QCryptographicHash::Sha384:
+ return SHA384_Message_Block_Size;
+ case QCryptographicHash::Sha512:
+ return SHA512_Message_Block_Size;
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::Keccak_224:
+ return 144;
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::Keccak_256:
+ return 136;
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::Keccak_384:
+ return 104;
+ case QCryptographicHash::RealSha3_512:
+ case QCryptographicHash::Keccak_512:
+ return 72;
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ return BLAKE2B_BLOCKBYTES;
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+ return BLAKE2S_BLOCKBYTES;
+#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ case QCryptographicHash::NumAlgorithms:
+#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 900
+ // GCC 8 has trouble with Q_UNREACHABLE() in constexpr functions
+ Q_UNREACHABLE();
+#endif
+ break;
+ }
+ return 0;
+}
+
+constexpr int maxHashBlockSize()
+{
+ int result = 0;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms ; ++i)
+ result = std::max(result, qt_hash_block_size(A(i)));
+ return result;
+}
+
+[[maybe_unused]]
+constexpr int minHashBlockSize()
+{
+ int result = INT_MAX;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms ; ++i)
+ result = std::min(result, qt_hash_block_size(A(i)));
+ return result;
+}
+
+[[maybe_unused]]
+constexpr int gcdHashBlockSize()
+{
+ int result = 0;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms ; ++i)
+ result = std::gcd(result, qt_hash_block_size(A(i)));
+ return result;
+}
+
+using HashBlock = QSmallByteArray<maxHashBlockSize()>;
+
+static HashBlock xored(const HashBlock &block, quint8 val) noexcept
+{
+ // some hints for the optimizer:
+ Q_ASSERT(block.size() >= minHashBlockSize());
+ Q_ASSERT(block.size() <= maxHashBlockSize());
+ Q_ASSERT(block.size() % gcdHashBlockSize() == 0);
+ HashBlock result;
+ result.resizeForOverwrite(block.size());
+ for (qsizetype i = 0; i < block.size(); ++i)
+ result[i] = block[i] ^ val;
+ return result;
+}
+
+class QMessageAuthenticationCodePrivate
+{
+public:
+ QMessageAuthenticationCodePrivate(QCryptographicHash::Algorithm m)
+ : messageHash(m)
+ {
+ }
+
+ HashBlock key;
+ QCryptographicHashPrivate messageHash;
+
+ void setKey(QByteArrayView k) noexcept;
+ void initMessageHash() noexcept;
+ void finalize();
+
+ // when not called from the static hash() function, this function needs to be
+ // called with messageHash.finalizeMutex held:
+ void finalizeUnchecked() noexcept;
+ // END functions that need to be called with finalizeMutex held
+};
+
+/*!
+ \internal
+
+ Transforms key \a newKey into a block-sized format and stores it in member
+ \c key.
+
+ This function assumes it can use messageHash (i.e. it's in its initial
+ state (reset() has been called)).
+*/
+void QMessageAuthenticationCodePrivate::setKey(QByteArrayView newKey) noexcept
+{
+ const int blockSize = qt_hash_block_size(messageHash.method);
+
+ if (newKey.size() > blockSize) {
+ messageHash.addData(newKey);
+ messageHash.finalizeUnchecked();
+ static_assert([] {
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms; ++i) {
+ if (hashLengthInternal(A(i)) > qt_hash_block_size(A(i)))
+ return false;
+ }
+ return true;
+ }(), "this code assumes that a hash's result always fits into that hash's block size");
+ key = messageHash.result;
+ messageHash.reset();
+ } else {
+ key.assign(newKey);
+ }
+
+ if (key.size() < blockSize)
+ key.resize(blockSize, '\0');
+
+ initMessageHash();
+}
+
+/*!
+ \internal
+
+ Seeds messageHash from \c key.
+
+ This function assumes that messageHash is in its initial state (reset() has
+ been called).
+*/
+void QMessageAuthenticationCodePrivate::initMessageHash() noexcept
+{
+ messageHash.addData(xored(key, 0x36));
+}
+
+/*!
+ \class QMessageAuthenticationCode
+ \inmodule QtCore
+
+ \brief The QMessageAuthenticationCode class provides a way to generate
+ hash-based message authentication codes.
+
+ \since 5.1
+
+ \ingroup tools
+ \reentrant
+
+ Use the QMessageAuthenticationCode class to generate hash-based message
+ authentication codes (HMACs). The class supports all cryptographic
+ hash algorithms from \l QCryptographicHash (see also
+ \l{QCryptographicHash::Algorithm}).
+
+ To generate a message authentication code, pass a suitable hash
+ algorithm and secret key to the constructor. Then process the message
+ data by calling \l addData() one or more times. After the full
+ message has been processed, get the final authentication code
+ via the \l result() function:
+
+ \snippet qmessageauthenticationcode/main.cpp 0
+ \dots
+ \snippet qmessageauthenticationcode/main.cpp 1
+
+ For simple cases like above, you can also use the static
+ \l hash() function:
+
+ \snippet qmessageauthenticationcode/main.cpp 2
+
+
+ \note The cryptographic strength of the HMAC depends upon the
+ size of the secret key, and the security of the
+ underlying hash function.
+
+ \sa QCryptographicHash, QCryptographicHash::Algorithm
+*/
+
+/*!
+ Constructs an object that can be used to create a cryptographic hash from data
+ using method \a method and key \a key.
+
+//! [qba-to-qbav-6.6]
+ \note In Qt versions prior to 6.6, this function took its arguments as
+ QByteArray, not QByteArrayView. If you experience compile errors, it's
+ because your code is passing objects that are implicitly convertible to
+ QByteArray, but not QByteArrayView. Wrap the corresponding argument in
+ \c{QByteArray{~~~}} to make the cast explicit. This is backwards-compatible
+ with old Qt versions.
+//! [qba-to-qbav-6.6]
+*/
+QMessageAuthenticationCode::QMessageAuthenticationCode(QCryptographicHash::Algorithm method,
+ QByteArrayView key)
+ : d(new QMessageAuthenticationCodePrivate(method))
+{
+ d->setKey(key);
+}
+
+/*!
+ Destroys the object.
+*/
+QMessageAuthenticationCode::~QMessageAuthenticationCode()
+{
+ delete d;
+}
+
+/*!
+ \fn QMessageAuthenticationCode::QMessageAuthenticationCode(QMessageAuthenticationCode &&other)
+
+ Move-constructs a new QMessageAuthenticationCode from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new object.
+
+ \since 6.6
+*/
+
+/*!
+ \fn QMessageAuthenticationCode &QMessageAuthenticationCode::operator=(QMessageAuthenticationCode &&other)
+
+ Move-assigns \a other to this QMessageAuthenticationCode instance.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new object.
+
+ \since 6.6
+*/
+
+/*!
+ \fn void QMessageAuthenticationCode::swap(QMessageAuthenticationCode &other)
+
+ Swaps message authentication code \a other with this message authentication
+ code. This operation is very fast and never fails.
+
+ \since 6.6
+*/
+
+/*!
+ Resets message data. Calling this function doesn't affect the key.
+*/
+void QMessageAuthenticationCode::reset() noexcept
+{
+ d->messageHash.reset();
+ d->initMessageHash();
+}
+
+/*!
+ Sets secret \a key. Calling this function automatically resets the object state.
+
+ For optimal performance, call this function only to \e change the active key,
+ not to set an \e initial key, as in
+
+ \code
+ QMessageAuthenticationCode mac(method);
+ mac.setKey(key); // does extra work
+ use(mac);
+ \endcode
+
+ Prefer to pass initial keys as the constructor argument:
+
+ \code
+ QMessageAuthenticationCode mac(method, key); // OK, optimal
+ use(mac);
+ \endcode
+
+ You can use std::optional to delay construction of a
+ QMessageAuthenticationCode until you know the key:
+
+ \code
+ std::optional<QMessageAuthenticationCode> mac;
+ ~~~
+ key = ~~~;
+ mac.emplace(method, key);
+ use(*mac);
+ \endcode
+
+ \include qcryptographichash.cpp {qba-to-qbav-6.6}
+*/
+void QMessageAuthenticationCode::setKey(QByteArrayView key) noexcept
+{
+ d->messageHash.reset();
+ d->setKey(key);
+}
+
+/*!
+ \overload
+ Adds the first \a length chars of \a data to the message.
+*/
+void QMessageAuthenticationCode::addData(const char *data, qsizetype length)
+{
+ d->messageHash.addData({data, length});
+}
+
+/*!
+ Adds \a data to the message.
+
+ \include qcryptographichash.cpp {qba-to-qbav-6.6}
+
+ \sa resultView(), result()
+*/
+void QMessageAuthenticationCode::addData(QByteArrayView data) noexcept
+{
+ d->messageHash.addData(data);
+}
+
+/*!
+ Reads the data from the open QIODevice \a device until it ends
+ and adds it to message. Returns \c true if reading was successful.
+
+ \note \a device must be already opened.
+ */
+bool QMessageAuthenticationCode::addData(QIODevice *device)
+{
+ return d->messageHash.addData(device);
+}
+
+/*!
+ \since 6.6
+
+ Returns the final hash value.
+
+ Note that the returned view remains valid only as long as the
+ QMessageAuthenticationCode object is not modified by other means.
+
+ \sa result()
+*/
+QByteArrayView QMessageAuthenticationCode::resultView() const noexcept
+{
+ d->finalize();
+ return d->messageHash.resultView();
+}
+
+/*!
+ Returns the final authentication code.
+
+ \sa resultView(), QByteArray::toHex()
+*/
+QByteArray QMessageAuthenticationCode::result() const
+{
+ return resultView().toByteArray();
+}
+
+void QMessageAuthenticationCodePrivate::finalize()
+{
+ const auto lock = qt_scoped_lock(messageHash.finalizeMutex);
+ if (!messageHash.result.isEmpty())
+ return;
+ finalizeUnchecked();
+}
+
+void QMessageAuthenticationCodePrivate::finalizeUnchecked() noexcept
+{
+ messageHash.finalizeUnchecked();
+ const HashResult hashedMessage = messageHash.result;
+
+ messageHash.reset();
+ messageHash.addData(xored(key, 0x5c));
+ messageHash.addData(hashedMessage);
+ messageHash.finalizeUnchecked();
+}
+
+/*!
+ Returns the authentication code for the message \a message using
+ the key \a key and the method \a method.
+
+ \include qcryptographichash.cpp {qba-to-qbav-6.6}
+*/
+QByteArray QMessageAuthenticationCode::hash(QByteArrayView message, QByteArrayView key,
+ QCryptographicHash::Algorithm method)
+{
+ QMessageAuthenticationCodePrivate mac(method);
+ mac.setKey(key);
+ mac.messageHash.addData(message);
+ mac.finalizeUnchecked();
+ return mac.messageHash.resultView().toByteArray();
+}
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h
index 83aed7c64c..294453adce 100644
--- a/src/corelib/tools/qcryptographichash.h
+++ b/src/corelib/tools/qcryptographichash.h
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2013 Richard J. Moore <rich@kde.org>.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2013 Richard J. Moore <rich@kde.org>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCRYPTOGRAPHICHASH_H
#define QCRYPTOGRAPHICHASH_H
@@ -96,19 +60,25 @@ public:
Blake2s_224,
Blake2s_256,
#endif
+ NumAlgorithms
};
Q_ENUM(Algorithm)
explicit QCryptographicHash(Algorithm method);
+ QCryptographicHash(QCryptographicHash &&other) noexcept : d(std::exchange(other.d, nullptr)) {}
~QCryptographicHash();
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QCryptographicHash)
+ void swap(QCryptographicHash &other) noexcept { qt_ptr_swap(d, other.d); }
+
void reset() noexcept;
+ [[nodiscard]] Algorithm algorithm() const noexcept;
#if QT_DEPRECATED_SINCE(6, 4)
QT_DEPRECATED_VERSION_X_6_4("Use the QByteArrayView overload instead")
void addData(const char *data, qsizetype length);
#endif
-#if QT_REMOVED_SINCE(6, 3)
+#if QT_CORE_REMOVED_SINCE(6, 3)
void addData(const QByteArray &data);
#endif
void addData(QByteArrayView data) noexcept;
@@ -117,11 +87,12 @@ public:
QByteArray result() const;
QByteArrayView resultView() const noexcept;
-#if QT_REMOVED_SINCE(6, 3)
+#if QT_CORE_REMOVED_SINCE(6, 3)
static QByteArray hash(const QByteArray &data, Algorithm method);
#endif
static QByteArray hash(QByteArrayView data, Algorithm method);
static int hashLength(Algorithm method);
+ static bool supportsAlgorithm(Algorithm method);
private:
Q_DISABLE_COPY(QCryptographicHash)
QCryptographicHashPrivate *d;
diff --git a/src/corelib/tools/qduplicatetracker_p.h b/src/corelib/tools/qduplicatetracker_p.h
index 19f69161a6..23465ecffe 100644
--- a/src/corelib/tools/qduplicatetracker_p.h
+++ b/src/corelib/tools/qduplicatetracker_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDUPLICATETRACKER_P_H
#define QDUPLICATETRACKER_P_H
@@ -50,9 +14,9 @@
// We mean it.
//
-#include <qglobal.h>
+#include <private/qglobal_p.h>
-#if __has_include(<memory_resource>)
+#ifdef __cpp_lib_memory_resource
# include <unordered_set>
# include <memory_resource>
# include <qhash.h> // for the hashing helpers
@@ -92,13 +56,13 @@ class QDuplicateTracker {
auto insert(const T &e) {
auto it = QSet<T>::insert(e);
const auto n = this->size();
- return std::pair{it, qExchange(setSize, n) != n};
+ return std::pair{it, std::exchange(setSize, n) != n};
}
auto insert(T &&e) {
auto it = QSet<T>::insert(std::move(e));
const auto n = this->size();
- return std::pair{it, qExchange(setSize, n) != n};
+ return std::pair{it, std::exchange(setSize, n) != n};
}
};
Set set{Prealloc};
@@ -148,6 +112,11 @@ public:
return appendTo(c); // lvalue version
}
}
+
+ void clear()
+ {
+ set.clear();
+ }
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index 4839fc839e..d8b3367de3 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*
@@ -483,7 +447,7 @@ struct BezierEase : public QEasingCurveFunction
{
if (_bezierCurves.constLast() == QPointF(1.0, 1.0)) {
_init = true;
- _curveCount = _bezierCurves.count() / 3;
+ _curveCount = _bezierCurves.size() / 3;
for (int i=0; i < _curveCount; i++) {
_intervals[i] = _bezierCurves.at(i * 3 + 2).x();
@@ -502,17 +466,17 @@ struct BezierEase : public QEasingCurveFunction
_curves[0].p3y = _bezierCurves.at(2).y();
} else if (i == (_curveCount - 1)) {
- _curves[i].p0x = _bezierCurves.at(_bezierCurves.count() - 4).x();
- _curves[i].p0y = _bezierCurves.at(_bezierCurves.count() - 4).y();
+ _curves[i].p0x = _bezierCurves.at(_bezierCurves.size() - 4).x();
+ _curves[i].p0y = _bezierCurves.at(_bezierCurves.size() - 4).y();
- _curves[i].p1x = _bezierCurves.at(_bezierCurves.count() - 3).x();
- _curves[i].p1y = _bezierCurves.at(_bezierCurves.count() - 3).y();
+ _curves[i].p1x = _bezierCurves.at(_bezierCurves.size() - 3).x();
+ _curves[i].p1y = _bezierCurves.at(_bezierCurves.size() - 3).y();
- _curves[i].p2x = _bezierCurves.at(_bezierCurves.count() - 2).x();
- _curves[i].p2y = _bezierCurves.at(_bezierCurves.count() - 2).y();
+ _curves[i].p2x = _bezierCurves.at(_bezierCurves.size() - 2).x();
+ _curves[i].p2y = _bezierCurves.at(_bezierCurves.size() - 2).y();
- _curves[i].p3x = _bezierCurves.at(_bezierCurves.count() - 1).x();
- _curves[i].p3y = _bezierCurves.at(_bezierCurves.count() - 1).y();
+ _curves[i].p3x = _bezierCurves.at(_bezierCurves.size() - 1).x();
+ _curves[i].p3y = _bezierCurves.at(_bezierCurves.size() - 1).y();
} else {
_curves[i].p0x = _bezierCurves.at(i * 3 - 1).x();
_curves[i].p0y = _bezierCurves.at(i * 3 - 1).y();
@@ -571,7 +535,7 @@ struct BezierEase : public QEasingCurveFunction
qreal value(qreal x) override
{
- Q_ASSERT(_bezierCurves.count() % 3 == 0);
+ Q_ASSERT(_bezierCurves.size() % 3 == 0);
if (_bezierCurves.isEmpty()) {
return x;
@@ -905,7 +869,7 @@ struct TCBEase : public BezierEase
qreal value(qreal x) override
{
- Q_ASSERT(_bezierCurves.count() % 3 == 0);
+ Q_ASSERT(_bezierCurves.size() % 3 == 0);
if (_bezierCurves.isEmpty()) {
qWarning("QEasingCurve: Invalid tcb curve");
@@ -1310,7 +1274,7 @@ void QEasingCurve::addCubicBezierSegment(const QPointF & c1, const QPointF & c2,
QList<QPointF> static inline tcbToBezier(const TCBPoints &tcbPoints)
{
- const int count = tcbPoints.count();
+ const int count = tcbPoints.size();
QList<QPointF> bezierPoints;
bezierPoints.reserve(3 * (count - 1));
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index 7e50743bf1..5b112d7d7d 100644
--- a/src/corelib/tools/qeasingcurve.h
+++ b/src/corelib/tools/qeasingcurve.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEASINGCURVE_H
#define QEASINGCURVE_H
@@ -81,7 +45,7 @@ public:
QEasingCurve(QEasingCurve &&other) noexcept : d_ptr(other.d_ptr) { other.d_ptr = nullptr; }
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QEasingCurve)
- void swap(QEasingCurve &other) noexcept { qSwap(d_ptr, other.d_ptr); }
+ void swap(QEasingCurve &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); }
bool operator==(const QEasingCurve &other) const;
inline bool operator!=(const QEasingCurve &other) const
diff --git a/src/corelib/tools/qflatmap_p.h b/src/corelib/tools/qflatmap_p.h
index 1b3eaea01c..d2c0d45b79 100644
--- a/src/corelib/tools/qflatmap_p.h
+++ b/src/corelib/tools/qflatmap_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFLATMAP_P_H
#define QFLATMAP_P_H
@@ -52,6 +16,7 @@
//
#include "qlist.h"
+#include "private/qglobal_p.h"
#include <algorithm>
#include <functional>
@@ -77,6 +42,19 @@ QT_BEGIN_NAMESPACE
QFlatMap<float, int, std::less<float>, std::vector<float>, std::vector<int>>
*/
+// Qt 6.4:
+// - removed QFlatMap API which was incompatible with STL semantics
+// - will be released with said API disabled, to catch any out-of-tree users
+// - also allows opting in to the new API using QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
+// Qt 6.5
+// - will make QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT the default:
+
+#ifndef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
+# if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+# define QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
+# endif
+#endif
+
namespace Qt {
struct OrderedUniqueRange_t {};
@@ -96,7 +74,7 @@ public:
using value_type = std::pair<const Key, T>;
static constexpr bool is_comparator_noexcept = noexcept(
- std::declval<Compare>()(std::declval<Key>(), std::declval<Key>()));
+ std::declval<Compare>()(std::declval<const Key &>(), std::declval<const Key &>()));
bool operator()(const value_type &lhs, const value_type &rhs) const
noexcept(is_comparator_noexcept)
@@ -105,29 +83,34 @@ public:
}
};
+namespace qflatmap {
+namespace detail {
+template <class T>
+class QFlatMapMockPointer
+{
+ T ref;
+public:
+ QFlatMapMockPointer(T r)
+ : ref(r)
+ {
+ }
+
+ T *operator->()
+ {
+ return &ref;
+ }
+};
+} // namespace detail
+} // namespace qflatmap
+
template<class Key, class T, class Compare = std::less<Key>, class KeyContainer = QList<Key>,
class MappedContainer = QList<T>>
class QFlatMap : private QFlatMapValueCompare<Key, T, Compare>
{
static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
- 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;
- }
- };
+ template<class U>
+ using mock_pointer = qflatmap::detail::QFlatMapMockPointer<U>;
public:
using key_type = Key;
@@ -161,12 +144,12 @@ public:
{
}
- reference operator*()
+ reference operator*() const
{
return { c->keys[i], c->values[i] };
}
- pointer operator->()
+ pointer operator->() const
{
return { operator*() };
}
@@ -191,7 +174,7 @@ public:
{
iterator r = *this;
- i++;
+ ++*this;
return r;
}
@@ -204,7 +187,7 @@ public:
iterator operator--(int)
{
iterator r = *this;
- i--;
+ --*this;
return r;
}
@@ -242,7 +225,7 @@ public:
return b.i - a.i;
}
- reference operator[](size_type n)
+ reference operator[](size_type n) const
{
size_type k = i + n;
return { c->keys[k], c->values[k] };
@@ -269,12 +252,12 @@ public:
}
const Key &key() const { return c->keys[i]; }
- T &value() { return c->values[i]; }
+ T &value() const { return c->values[i]; }
private:
containers *c = nullptr;
size_type i = 0;
- friend full_map_t;
+ friend QFlatMap;
};
class const_iterator
@@ -298,12 +281,12 @@ public:
{
}
- reference operator*()
+ reference operator*() const
{
return { c->keys[i], c->values[i] };
}
- pointer operator->()
+ pointer operator->() const
{
return { operator*() };
}
@@ -328,7 +311,7 @@ public:
{
const_iterator r = *this;
- i++;
+ ++*this;
return r;
}
@@ -341,7 +324,7 @@ public:
const_iterator operator--(int)
{
const_iterator r = *this;
- i--;
+ --*this;
return r;
}
@@ -379,7 +362,7 @@ public:
return b.i - a.i;
}
- reference operator[](size_type n)
+ reference operator[](size_type n) const
{
size_type k = i + n;
return { c->keys[k], c->values[k] };
@@ -406,12 +389,12 @@ public:
}
const Key &key() const { return c->keys[i]; }
- const T &value() { return c->values[i]; }
+ const T &value() const { return c->values[i]; }
private:
const containers *c = nullptr;
size_type i = 0;
- friend full_map_t;
+ friend QFlatMap;
};
private:
@@ -419,7 +402,7 @@ private:
struct is_marked_transparent_type : std::false_type { };
template <class X>
- struct is_marked_transparent_type<X, typename X::is_transparent> : std::true_type { };
+ struct is_marked_transparent_type<X, std::void_t<typename X::is_transparent>> : std::true_type { };
template <class X>
using is_marked_transparent = typename std::enable_if<
@@ -432,6 +415,7 @@ private:
public:
QFlatMap() = default;
+#ifdef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
explicit QFlatMap(const key_container_type &keys, const mapped_container_type &values)
: c{keys, values}
{
@@ -439,23 +423,20 @@ public:
}
explicit QFlatMap(key_container_type &&keys, const mapped_container_type &values)
+ : c{std::move(keys), values}
{
- c.keys = std::move(keys);
- c.values = values;
ensureOrderedUnique();
}
explicit QFlatMap(const key_container_type &keys, mapped_container_type &&values)
+ : c{keys, std::move(values)}
{
- c.keys = keys;
- c.values = std::move(values);
ensureOrderedUnique();
}
explicit QFlatMap(key_container_type &&keys, mapped_container_type &&values)
+ : c{std::move(keys), std::move(values)}
{
- c.keys = std::move(keys);
- c.values = std::move(values);
ensureOrderedUnique();
}
@@ -470,37 +451,34 @@ public:
initWithRange(first, last);
ensureOrderedUnique();
}
+#endif
explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
const mapped_container_type &values)
+ : c{keys, values}
{
- c.keys = keys;
- c.values = values;
}
explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
const mapped_container_type &values)
+ : c{std::move(keys), 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, std::move(values)}
{
- c.keys = keys;
- c.values = std::move(values);
}
explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
mapped_container_type &&values)
+ : c{std::move(keys), std::move(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())
+ : QFlatMap(Qt::OrderedUniqueRange, lst.begin(), lst.end())
{
}
@@ -515,6 +493,7 @@ public:
{
}
+#ifdef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
explicit QFlatMap(const key_container_type &keys, const mapped_container_type &values,
const Compare &compare)
: value_compare(compare), c{keys, values}
@@ -555,6 +534,7 @@ public:
initWithRange(first, last);
ensureOrderedUnique();
}
+#endif
explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
const mapped_container_type &values, const Compare &compare)
@@ -616,13 +596,13 @@ public:
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;
+ return do_remove(find(key));
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ bool remove(const X &key)
+ {
+ return do_remove(find(key));
}
iterator erase(iterator it)
@@ -633,50 +613,60 @@ public:
T take(const Key &key)
{
- auto it = binary_find(key);
- if (it != end()) {
- T result = std::move(it.value());
- erase(it);
- return result;
- }
- return {};
+ return do_take(find(key));
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ T take(const X &key)
+ {
+ return do_take(find(key));
}
bool contains(const Key &key) const
{
- return binary_find(key) != end();
+ return find(key) != end();
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ bool contains(const X &key) const
+ {
+ return find(key) != end();
}
T value(const Key &key, const T &defaultValue) const
{
- auto it = binary_find(key);
+ auto it = find(key);
+ return it == end() ? defaultValue : it.value();
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ T value(const X &key, const T &defaultValue) const
+ {
+ auto it = find(key);
return it == end() ? defaultValue : it.value();
}
T value(const Key &key) const
{
- auto it = binary_find(key);
+ auto it = find(key);
+ return it == end() ? T() : it.value();
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ T value(const X &key) const
+ {
+ auto it = 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();
+ return try_emplace(key).first.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();
+ return try_emplace(std::move(key)).first.value();
}
T operator[](const Key &key) const
@@ -684,55 +674,71 @@ public:
return value(key);
}
+#ifdef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
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};
- }
+ return try_emplace(key, value);
}
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};
- }
+ return try_emplace(std::move(key), value);
}
std::pair<iterator, bool> insert(const Key &key, T &&value)
{
+ return try_emplace(key, std::move(value));
+ }
+
+ std::pair<iterator, bool> insert(Key &&key, T &&value)
+ {
+ return try_emplace(std::move(key), std::move(value));
+ }
+#endif
+
+ template <typename...Args>
+ std::pair<iterator, bool> try_emplace(const Key &key, Args&&...args)
+ {
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 };
+ c.values.emplace(toValuesIterator(it), std::forward<Args>(args)...);
+ return { fromKeysIterator(c.keys.insert(toKeysIterator(it), key)), true };
} else {
- *toValuesIterator(it) = std::move(value);
return {it, false};
}
}
- std::pair<iterator, bool> insert(Key &&key, T &&value)
+ template <typename...Args>
+ std::pair<iterator, bool> try_emplace(Key &&key, Args&&...args)
{
auto it = lower_bound(key);
if (it == end() || key_compare::operator()(key, it.key())) {
- c.values.insert(toValuesIterator(it), std::move(value));
+ c.values.emplace(toValuesIterator(it), std::forward<Args>(args)...);
return { fromKeysIterator(c.keys.insert(toKeysIterator(it), std::move(key))), true };
} else {
- *toValuesIterator(it) = std::move(value);
return {it, false};
}
}
+ template <typename M>
+ std::pair<iterator, bool> insert_or_assign(const Key &key, M &&obj)
+ {
+ auto r = try_emplace(key, std::forward<M>(obj));
+ if (!r.second)
+ *toValuesIterator(r.first) = std::forward<M>(obj);
+ return r;
+ }
+
+ template <typename M>
+ std::pair<iterator, bool> insert_or_assign(Key &&key, M &&obj)
+ {
+ auto r = try_emplace(std::move(key), std::forward<M>(obj));
+ if (!r.second)
+ *toValuesIterator(r.first) = std::forward<M>(obj);
+ return r;
+ }
+
+#ifdef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
void insert(InputIt first, InputIt last)
{
@@ -758,6 +764,7 @@ public:
{
insertOrderedUniqueRange(first, last);
}
+#endif
iterator begin() { return { &c, 0 }; }
const_iterator begin() const { return { &c, 0 }; }
@@ -784,14 +791,14 @@ public:
iterator lower_bound(const Key &key)
{
- auto cit = const_cast<const full_map_t *>(this)->lower_bound(key);
+ auto cit = std::as_const(*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);
+ auto cit = std::as_const(*this).lower_bound(key);
return { &c, cit.i };
}
@@ -806,14 +813,112 @@ public:
return fromKeysIterator(std::lower_bound(c.keys.begin(), c.keys.end(), key, key_comp()));
}
- iterator find(const key_type &k)
+ iterator find(const Key &key)
+ {
+ return { &c, std::as_const(*this).find(key).i };
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ iterator find(const X &key)
+ {
+ return { &c, std::as_const(*this).find(key).i };
+ }
+
+ const_iterator find(const Key &key) const
{
- return binary_find(k);
+ auto it = lower_bound(key);
+ if (it != end()) {
+ if (!key_compare::operator()(key, it.key()))
+ return it;
+ it = end();
+ }
+ return it;
}
- const_iterator find(const key_type &k) const
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ const_iterator find(const X &key) const
{
- return binary_find(k);
+ auto it = lower_bound(key);
+ if (it != end()) {
+ if (!key_compare::operator()(key, it.key()))
+ return it;
+ it = end();
+ }
+ return it;
+ }
+
+ template <typename Predicate>
+ size_type remove_if(Predicate pred)
+ {
+ const auto indirect_call_to_pred = [pred = std::move(pred)](iterator it) {
+ using Pair = decltype(*it);
+ using K = decltype(it.key());
+ using V = decltype(it.value());
+ using P = Predicate;
+ if constexpr (std::is_invocable_v<P, K, V>) {
+ return pred(it.key(), it.value());
+ } else if constexpr (std::is_invocable_v<P, Pair> && !std::is_invocable_v<P, K>) {
+ return pred(*it);
+ } else if constexpr (std::is_invocable_v<P, K> && !std::is_invocable_v<P, Pair>) {
+ return pred(it.key());
+ } else {
+ static_assert(QtPrivate::type_dependent_false<Predicate>(),
+ "Don't know how to call the predicate.\n"
+ "Options:\n"
+ "- pred(*it)\n"
+ "- pred(it.key(), it.value())\n"
+ "- pred(it.key())");
+ }
+ };
+
+ auto first = begin();
+ const auto last = end();
+
+ // find_if prefix loop
+ while (first != last && !indirect_call_to_pred(first))
+ ++first;
+
+ if (first == last)
+ return 0; // nothing to do
+
+ // we know that we need to remove *first
+
+ auto kdest = toKeysIterator(first);
+ auto vdest = toValuesIterator(first);
+
+ ++first;
+
+ auto k = std::next(kdest);
+ auto v = std::next(vdest);
+
+ // Main Loop
+ // - first is used only for indirect_call_to_pred
+ // - operations are done on k, v
+ // Loop invariants:
+ // - first, k, v are pointing to the same element
+ // - [begin(), first[, [c.keys.begin(), k[, [c.values.begin(), v[: already processed
+ // - [first, end()[, [k, c.keys.end()[, [v, c.values.end()[: still to be processed
+ // - [c.keys.begin(), kdest[ and [c.values.begin(), vdest[ are keepers
+ // - [kdest, k[, [vdest, v[ are considered removed
+ // - kdest is not c.keys.end()
+ // - vdest is not v.values.end()
+ while (first != last) {
+ if (!indirect_call_to_pred(first)) {
+ // keep *first, aka {*k, *v}
+ *kdest = std::move(*k);
+ *vdest = std::move(*v);
+ ++kdest;
+ ++vdest;
+ }
+ ++k;
+ ++v;
+ ++first;
+ }
+
+ const size_type r = std::distance(kdest, c.keys.end());
+ c.keys.erase(kdest, c.keys.end());
+ c.values.erase(vdest, c.values.end());
+ return r;
}
key_compare key_comp() const noexcept
@@ -827,6 +932,25 @@ public:
}
private:
+ bool do_remove(iterator it)
+ {
+ if (it != end()) {
+ erase(it);
+ return true;
+ }
+ return false;
+ }
+
+ T do_take(iterator it)
+ {
+ if (it != end()) {
+ T result = std::move(it.value());
+ erase(it);
+ return result;
+ }
+ return {};
+ }
+
template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
void initWithRange(InputIt first, InputIt last)
{
@@ -874,7 +998,7 @@ private:
class IndexedKeyComparator
{
public:
- IndexedKeyComparator(const full_map_t *am)
+ IndexedKeyComparator(const QFlatMap *am)
: m(am)
{
}
@@ -885,7 +1009,7 @@ private:
}
private:
- const full_map_t *m;
+ const QFlatMap *m;
};
template <class InputIt>
@@ -906,22 +1030,6 @@ private:
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()));
@@ -953,31 +1061,49 @@ private:
void makeUnique()
{
- if (c.keys.size() < 2)
+ // std::unique, but over two ranges
+ auto equivalent = [this](const auto &lhs, const auto &rhs) {
+ return !key_compare::operator()(lhs, rhs) && !key_compare::operator()(rhs, lhs);
+ };
+ const auto kb = c.keys.begin();
+ const auto ke = c.keys.end();
+ auto k = std::adjacent_find(kb, ke, equivalent);
+ if (k == ke)
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;
+
+ // equivalent keys found, we need to do actual work:
+ auto v = std::next(c.values.begin(), std::distance(kb, k));
+
+ auto kdest = k;
+ auto vdest = v;
+
+ ++k;
+ ++v;
+
+ // Loop Invariants:
+ //
+ // - [keys.begin(), kdest] and [values.begin(), vdest] are unique
+ // - k is not keys.end(), v is not values.end()
+ // - [next(k), keys.end()[ and [next(v), values.end()[ still need to be checked
+ while ((++v, ++k) != ke) {
+ if (!equivalent(*kdest, *k)) {
+ *++kdest = std::move(*k);
+ *++vdest = std::move(*v);
}
}
- c.keys.shrink_to_fit();
- c.values.shrink_to_fit();
+
+ c.keys.erase(std::next(kdest), ke);
+ c.values.erase(std::next(vdest), c.values.end());
}
containers c;
};
+template <class Key, class T,
+ qsizetype N = QVarLengthArrayDefaultPrealloc,
+ class Compare = std::less<Key>>
+using QVarLengthFlatMap = QFlatMap<Key, T, Compare, QVarLengthArray<Key, N>, QVarLengthArray<T, N>>;
+
QT_END_NAMESPACE
#endif // QFLATMAP_P_H
diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp
index 38ad13a1ee..db15fac5d6 100644
--- a/src/corelib/tools/qfreelist.cpp
+++ b/src/corelib/tools/qfreelist.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfreelist_p.h"
QT_BEGIN_NAMESPACE
// default sizes and offsets (no need to define these when customizing)
+namespace QFreeListDefaultConstantsPrivate {
enum {
Offset0 = 0x00000000,
Offset1 = 0x00008000,
@@ -53,12 +18,13 @@ enum {
Size2 = Offset3 - Offset2,
Size3 = QFreeListDefaultConstants::MaxIndex - Offset3
};
+}
-const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = {
- Size0,
- Size1,
- Size2,
- Size3
+Q_CONSTINIT const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = {
+ QFreeListDefaultConstantsPrivate::Size0,
+ QFreeListDefaultConstantsPrivate::Size1,
+ QFreeListDefaultConstantsPrivate::Size2,
+ QFreeListDefaultConstantsPrivate::Size3
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h
index f54e5aad65..6bbde5b4b6 100644
--- a/src/corelib/tools/qfreelist_p.h
+++ b/src/corelib/tools/qfreelist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFREELIST_P_H
#define QFREELIST_P_H
@@ -160,8 +124,7 @@ class QFreeList
return i;
x -= size;
}
- Q_ASSERT(false);
- return -1;
+ Q_UNREACHABLE_RETURN(-1);
}
// allocate a block of the given \a size, initialized starting with the given \a offset
diff --git a/src/corelib/tools/qfunctionaltools_impl.cpp b/src/corelib/tools/qfunctionaltools_impl.cpp
new file mode 100644
index 0000000000..28148c39a2
--- /dev/null
+++ b/src/corelib/tools/qfunctionaltools_impl.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qfunctionaltools_impl.h>
+
+// Remove this file once we have tests that implicitly test all aspects of
+// CompactStorage
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+#define FOR_EACH_CVREF(op) \
+ op(&) \
+ op(const &) \
+ op(&&) \
+ op(const &&) \
+ /* end */
+
+namespace _testing {
+ struct empty {};
+ struct final final {};
+ static_assert(std::is_same_v<CompactStorage<empty>,
+ detail::StorageEmptyBaseClassOptimization<empty>>);
+ static_assert(std::is_same_v<CompactStorage<final>,
+ detail::StorageByValue<final>>);
+ static_assert(std::is_same_v<CompactStorage<int>,
+ detail::StorageByValue<int>>);
+#define CHECK1(Obj, cvref) \
+ static_assert(std::is_same_v<decltype(std::declval<CompactStorage< Obj > cvref>().object()), \
+ Obj cvref>);
+#define CHECK(cvref) \
+ CHECK1(empty, cvref) \
+ CHECK1(final, cvref) \
+ CHECK1(int, cvref) \
+ /* end */
+
+ FOR_EACH_CVREF(CHECK)
+#undef CHECK
+#undef CHECK1
+} // namespace _testing
+
+} // namespace QtPrivate
+
+#undef FOR_EACH_CVREF
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qfunctionaltools_impl.h b/src/corelib/tools/qfunctionaltools_impl.h
new file mode 100644
index 0000000000..0942d5fe7d
--- /dev/null
+++ b/src/corelib/tools/qfunctionaltools_impl.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#if 0
+#pragma qt_sync_skip_header_check
+#pragma qt_sync_stop_processing
+#endif
+
+#ifndef QFUNCTIONALTOOLS_IMPL_H
+#define QFUNCTIONALTOOLS_IMPL_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <type_traits>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+namespace detail {
+
+#define FOR_EACH_CVREF(op) \
+ op(&) \
+ op(const &) \
+ op(&&) \
+ op(const &&) \
+ /* end */
+
+
+template <typename Object, typename = void>
+struct StorageByValue
+{
+ Object o;
+#define MAKE_GETTER(cvref) \
+ constexpr Object cvref object() cvref noexcept \
+ { return static_cast<Object cvref>(o); }
+ FOR_EACH_CVREF(MAKE_GETTER)
+#undef MAKE_GETTER
+};
+
+template <typename Object, typename Tag = void>
+struct StorageEmptyBaseClassOptimization : Object
+{
+ StorageEmptyBaseClassOptimization() = default;
+ StorageEmptyBaseClassOptimization(Object &&o)
+ : Object(std::move(o))
+ {}
+ StorageEmptyBaseClassOptimization(const Object &o)
+ : Object(o)
+ {}
+
+#define MAKE_GETTER(cvref) \
+ constexpr Object cvref object() cvref noexcept \
+ { return static_cast<Object cvref>(*this); }
+ FOR_EACH_CVREF(MAKE_GETTER)
+#undef MAKE_GETTER
+};
+} // namespace detail
+
+template <typename Object, typename Tag = void>
+using CompactStorage = typename std::conditional_t<
+ std::conjunction_v<
+ std::is_empty<Object>,
+ std::negation<std::is_final<Object>>
+ >,
+ detail::StorageEmptyBaseClassOptimization<Object, Tag>,
+ detail::StorageByValue<Object, Tag>
+ >;
+
+} // namespace QtPrivate
+
+#undef FOR_EACH_CVREF
+
+QT_END_NAMESPACE
+
+#endif // QFUNCTIONALTOOLS_IMPL_H
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 62c84a0820..12e90daecf 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2021 Intel Corporation.
-** Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2021 Intel Corporation.
+// Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// for rand_s, _CRT_RAND_S must be #defined before #including stdlib.h.
// put it at the beginning so some indirect inclusion doesn't break it
@@ -66,22 +30,155 @@
#ifndef QT_BOOTSTRAPPED
#include <qcoreapplication.h>
#include <qrandom.h>
+#include <private/qlocale_tools_p.h>
#endif // QT_BOOTSTRAPPED
+#include <array>
#include <limits.h>
+#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
+# define NDEBUG
+#endif
+#include <assert.h>
+
+#ifdef Q_CC_GNU
+# define Q_DECL_HOT_FUNCTION __attribute__((hot))
+#else
+# define Q_DECL_HOT_FUNCTION
+#endif
+
QT_BEGIN_NAMESPACE
+void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept; // qstring.cpp
+
// 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.");
+namespace {
+struct HashSeedStorage
+{
+ static constexpr int SeedCount = 2;
+ QBasicAtomicInteger<quintptr> seeds[SeedCount] = { Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) };
+
+#if !QT_SUPPORTS_INIT_PRIORITY || defined(QT_BOOTSTRAPPED)
+ constexpr HashSeedStorage() = default;
+#else
+ HashSeedStorage() { initialize(0); }
+#endif
+
+ enum State {
+ OverriddenByEnvironment = -1,
+ JustInitialized,
+ AlreadyInitialized
+ };
+ struct StateResult {
+ quintptr requestedSeed;
+ State state;
+ };
+
+ StateResult state(int which = -1);
+ Q_DECL_HOT_FUNCTION QHashSeed currentSeed(int which)
+ {
+ return { state(which).requestedSeed };
+ }
+
+ void resetSeed()
+ {
+#ifndef QT_BOOTSTRAPPED
+ if (state().state < AlreadyInitialized)
+ return;
+
+ // update the public seed
+ QRandomGenerator *generator = QRandomGenerator::system();
+ seeds[0].storeRelaxed(sizeof(size_t) > sizeof(quint32)
+ ? generator->generate64() : generator->generate());
+#endif
+ }
+
+ void clearSeed()
+ {
+ state();
+ seeds[0].storeRelaxed(0); // always write (smaller code)
+ }
+
+private:
+ Q_DECL_COLD_FUNCTION Q_NEVER_INLINE StateResult initialize(int which) noexcept;
+};
+
+[[maybe_unused]] HashSeedStorage::StateResult HashSeedStorage::initialize(int which) noexcept
+{
+ StateResult result = { 0, OverriddenByEnvironment };
+#ifdef QT_BOOTSTRAPPED
+ Q_UNUSED(which);
+ Q_UNREACHABLE_RETURN(result);
+#else
+ // can't use qEnvironmentVariableIntValue (reentrancy)
+ const char *seedstr = getenv("QT_HASH_SEED");
+ if (seedstr) {
+ auto r = qstrntoll(seedstr, strlen(seedstr), 10);
+ if (r.used > 0 && size_t(r.used) == strlen(seedstr)) {
+ if (r.result) {
+ // can't use qWarning here (reentrancy)
+ fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
+ }
+
+ // we don't have to store to the seed, since it's pre-initialized by
+ // the compiler to zero
+ return result;
+ }
+ }
+
+ // update the full seed
+ auto x = qt_initial_random_value();
+ for (int i = 0; i < SeedCount; ++i) {
+ seeds[i].storeRelaxed(x.data[i]);
+ if (which == i)
+ result.requestedSeed = x.data[i];
+ }
+ result.state = JustInitialized;
+ return result;
+#endif
+}
+
+inline HashSeedStorage::StateResult HashSeedStorage::state(int which)
+{
+ constexpr quintptr BadSeed = quintptr(Q_UINT64_C(0x5555'5555'5555'5555));
+ StateResult result = { BadSeed, AlreadyInitialized };
+
+#if defined(QT_BOOTSTRAPPED)
+ result = { 0, OverriddenByEnvironment };
+#elif !QT_SUPPORTS_INIT_PRIORITY
+ // dynamic initialization
+ static auto once = [&]() {
+ result = initialize(which);
+ return true;
+ }();
+ Q_UNUSED(once);
+#endif
+
+ if (result.state == AlreadyInitialized && which >= 0)
+ return { seeds[which].loadRelaxed(), AlreadyInitialized };
+ return result;
+}
+} // unnamed namespace
+
+/*
+ The QHash seed itself.
+*/
+#ifdef Q_DECL_INIT_PRIORITY
+Q_DECL_INIT_PRIORITY(05)
+#else
+Q_CONSTINIT
+#endif
+static HashSeedStorage qt_qhash_seed;
+
/*
* Hashing for memory segments is based on the public domain MurmurHash2 by
* Austin Appleby. See http://murmurhash.googlepages.com/
*/
#if QT_POINTER_SIZE == 4
-
+Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
static inline uint murmurhash(const void *key, uint len, uint seed) noexcept
{
// 'm' and 'r' are mixing constants generated offline.
@@ -139,7 +236,7 @@ static inline uint murmurhash(const void *key, uint len, uint seed) noexcept
}
#else
-
+Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed) noexcept
{
const uint64_t m = 0xc6a4a7935bd1e995ULL;
@@ -188,20 +285,11 @@ static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed)
#endif
-#if QT_POINTER_SIZE == 8
+namespace {
// 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 ROTL(x, b) (((x) << (b)) | ((x) >> (sizeof(x) * 8 - (b))))
#define SIPROUND \
do { \
@@ -221,8 +309,7 @@ static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed)
v2 = ROTL(v2, 32); \
} while (0)
-
-static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
+template <int cROUNDS = 2, int dROUNDS = 4> struct SipHash64
{
/* "somepseudorandomlygeneratedbytes" */
uint64_t v0 = 0x736f6d6570736575ULL;
@@ -230,17 +317,32 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
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;
+ uint64_t k0;
+ uint64_t k1;
+
+ inline SipHash64(uint64_t fulllen, uint64_t seed, uint64_t seed2);
+ inline void addBlock(const uint8_t *in, size_t inlen);
+ inline uint64_t finalize(const uint8_t *in, size_t left);
+};
+
+template <int cROUNDS, int dROUNDS>
+SipHash64<cROUNDS, dROUNDS>::SipHash64(uint64_t inlen, uint64_t seed, uint64_t seed2)
+{
b = inlen << 56;
+ k0 = seed;
+ k1 = seed2;
v3 ^= k1;
v2 ^= k0;
v1 ^= k1;
v0 ^= k0;
+}
+template <int cROUNDS, int dROUNDS> Q_DECL_HOT_FUNCTION void
+SipHash64<cROUNDS, dROUNDS>::addBlock(const uint8_t *in, size_t inlen)
+{
+ Q_ASSERT((inlen & 7ULL) == 0);
+ int i;
+ const uint8_t *end = in + inlen;
for (; in != end; in += 8) {
uint64_t m = qFromUnaligned<uint64_t>(in);
v3 ^= m;
@@ -250,24 +352,31 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
v0 ^= m;
}
+}
-
-#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
- QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
-#endif
+template <int cROUNDS, int dROUNDS> Q_DECL_HOT_FUNCTION uint64_t
+SipHash64<cROUNDS, dROUNDS>::finalize(const uint8_t *in, size_t left)
+{
+ int i;
switch (left) {
case 7:
b |= ((uint64_t)in[6]) << 48;
+ Q_FALLTHROUGH();
case 6:
b |= ((uint64_t)in[5]) << 40;
+ Q_FALLTHROUGH();
case 5:
b |= ((uint64_t)in[4]) << 32;
+ Q_FALLTHROUGH();
case 4:
b |= ((uint64_t)in[3]) << 24;
+ Q_FALLTHROUGH();
case 3:
b |= ((uint64_t)in[2]) << 16;
+ Q_FALLTHROUGH();
case 2:
b |= ((uint64_t)in[1]) << 8;
+ Q_FALLTHROUGH();
case 1:
b |= ((uint64_t)in[0]);
break;
@@ -290,7 +399,8 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
b = v0 ^ v1 ^ v2 ^ v3;
return b;
}
-#else
+#undef SIPROUND
+
// 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.
@@ -301,12 +411,6 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
//
// 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 { \
@@ -326,8 +430,7 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, const uint64_t seed)
v2 = ROTL(v2, 16); \
} while (0)
-
-static uint siphash(const uint8_t *in, uint inlen, const uint seed)
+template <int cROUNDS = 2, int dROUNDS = 4> struct SipHash32
{
/* "somepseudorandomlygeneratedbytes" */
uint v0 = 0x736f6d65U;
@@ -335,17 +438,32 @@ static uint siphash(const uint8_t *in, uint inlen, const uint seed)
uint v2 = 0x6c796765U;
uint v3 = 0x74656462U;
uint b;
+ uint k0;
+ uint k1;
+
+ inline SipHash32(size_t fulllen, uint seed, uint seed2);
+ inline void addBlock(const uint8_t *in, size_t inlen);
+ inline uint finalize(const uint8_t *in, size_t left);
+};
+
+template <int cROUNDS, int dROUNDS> inline
+SipHash32<cROUNDS, dROUNDS>::SipHash32(size_t inlen, uint seed, uint seed2)
+{
uint k0 = seed;
- uint k1 = seed ^ inlen;
- int i;
- const uint8_t *end = in + (inlen & ~3ULL);
- const int left = inlen & 3;
+ uint k1 = seed2;
b = inlen << 24;
v3 ^= k1;
v2 ^= k0;
v1 ^= k1;
v0 ^= k0;
+}
+template <int cROUNDS, int dROUNDS> inline Q_DECL_HOT_FUNCTION void
+SipHash32<cROUNDS, dROUNDS>::addBlock(const uint8_t *in, size_t inlen)
+{
+ Q_ASSERT((inlen & 3ULL) == 0);
+ int i;
+ const uint8_t *end = in + inlen;
for (; in != end; in += 4) {
uint m = qFromUnaligned<uint>(in);
v3 ^= m;
@@ -355,15 +473,19 @@ static uint siphash(const uint8_t *in, uint inlen, const uint seed)
v0 ^= m;
}
+}
-#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
- QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
-#endif
+template <int cROUNDS, int dROUNDS> inline Q_DECL_HOT_FUNCTION uint
+SipHash32<cROUNDS, dROUNDS>::finalize(const uint8_t *in, size_t left)
+{
+ int i;
switch (left) {
case 3:
b |= ((uint)in[2]) << 16;
+ Q_FALLTHROUGH();
case 2:
b |= ((uint)in[1]) << 8;
+ Q_FALLTHROUGH();
case 1:
b |= ((uint)in[0]);
break;
@@ -386,7 +508,70 @@ static uint siphash(const uint8_t *in, uint inlen, const uint seed)
b = v0 ^ v1 ^ v2 ^ v3;
return b;
}
-#endif
+#undef SIPROUND
+#undef ROTL
+
+// Use SipHash-1-2, which has similar performance characteristics as
+// stablehash() above, instead of the SipHash-2-4 default
+template <int cROUNDS = 1, int dROUNDS = 2>
+using SipHash = std::conditional_t<sizeof(void *) == 8,
+ SipHash64<cROUNDS, dROUNDS>, SipHash32<cROUNDS, dROUNDS>>;
+} // unnamed namespace
+
+Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
+static size_t siphash(const uint8_t *in, size_t inlen, size_t seed, size_t seed2)
+{
+ constexpr size_t TailSizeMask = sizeof(void *) - 1;
+ SipHash<> hasher(inlen, seed, seed2);
+ hasher.addBlock(in, inlen & ~TailSizeMask);
+ return hasher.finalize(in + (inlen & ~TailSizeMask), inlen & TailSizeMask);
+}
+
+enum ZeroExtension {
+ None = 0,
+ ByteToWord = 1,
+};
+
+template <ZeroExtension = None> static size_t
+qHashBits_fallback(const uchar *p, size_t size, size_t seed, size_t seed2) noexcept;
+template <> size_t qHashBits_fallback<None>(const uchar *p, size_t size, size_t seed, size_t seed2) noexcept
+{
+ if (size <= QT_POINTER_SIZE)
+ return murmurhash(p, size, seed);
+
+ return siphash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
+}
+
+template <> size_t qHashBits_fallback<ByteToWord>(const uchar *data, size_t size, size_t seed, size_t seed2) noexcept
+{
+ auto quick_from_latin1 = [](char16_t *dest, const uchar *data, size_t size) {
+ // Quick, "inlined" version for very short blocks
+ std::copy_n(data, size, dest);
+ };
+ if (size <= QT_POINTER_SIZE / 2) {
+ std::array<char16_t, QT_POINTER_SIZE / 2> buf;
+ quick_from_latin1(buf.data(), data, size);
+ return murmurhash(buf.data(), size * 2, seed);
+ }
+
+ constexpr size_t TailSizeMask = sizeof(void *) / 2 - 1;
+ std::array<char16_t, 256> buf;
+ SipHash<> siphash(size * 2, seed, seed2);
+ ptrdiff_t offset = 0;
+ for ( ; offset + buf.size() < size; offset += buf.size()) {
+ qt_from_latin1(buf.data(), reinterpret_cast<const char *>(data) + offset, buf.size());
+ siphash.addBlock(reinterpret_cast<uint8_t *>(buf.data()), sizeof(buf));
+ }
+ if (size_t n = size - offset; n > TailSizeMask) {
+ n &= ~TailSizeMask;
+ qt_from_latin1(buf.data(), reinterpret_cast<const char *>(data) + offset, n);
+ siphash.addBlock(reinterpret_cast<uint8_t *>(buf.data()), n * 2);
+ offset += n;
+ }
+
+ quick_from_latin1(buf.data(), data + offset, size - offset);
+ return siphash.finalize(reinterpret_cast<uint8_t *>(buf.data()), (size - offset) * 2);
+}
#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__) // GCC
# define QHASH_AES_SANITIZER_BUILD
@@ -402,29 +587,30 @@ static uint siphash(const uint8_t *in, uint inlen, const uint seed)
#if QT_COMPILER_SUPPORTS_HERE(AES) && QT_COMPILER_SUPPORTS_HERE(SSE4_2) && \
!defined(QHASH_AES_SANITIZER_BUILD)
# define AESHASH
+# define QT_FUNCTION_TARGET_STRING_AES_AVX2 "avx2,aes"
+# define QT_FUNCTION_TARGET_STRING_AES_AVX512 \
+ QT_FUNCTION_TARGET_STRING_ARCH_SKYLAKE_AVX512 "," \
+ QT_FUNCTION_TARGET_STRING_AES
+# define QT_FUNCTION_TARGET_STRING_VAES_AVX512 \
+ QT_FUNCTION_TARGET_STRING_ARCH_SKYLAKE_AVX512 "," \
+ QT_FUNCTION_TARGET_STRING_VAES
+# undef QHASH_AES_SANITIZER_BUILD
+# if QT_POINTER_SIZE == 8
+# define mm_set1_epz _mm_set1_epi64x
+# define mm_cvtsz_si128 _mm_cvtsi64_si128
+# define mm_cvtsi128_sz _mm_cvtsi128_si64
+# define mm256_set1_epz _mm256_set1_epi64x
+# else
+# define mm_set1_epz _mm_set1_epi32
+# define mm_cvtsz_si128 _mm_cvtsi32_si128
+# define mm_cvtsi128_sz _mm_cvtsi128_si32
+# define mm256_set1_epz _mm256_set1_epi32
+# endif
-#undef QHASH_AES_SANITIZER_BUILD
-
-QT_FUNCTION_TARGET(AES)
-static size_t aeshash(const uchar *p, size_t len, size_t seed) noexcept
-{
- __m128i key;
- if (sizeof(size_t) == 8) {
-#ifdef Q_PROCESSOR_X86_64
- quint64 seededlen = seed ^ len;
- __m128i mseed = _mm_cvtsi64_si128(seed);
- key = _mm_insert_epi64(mseed, seededlen, 1);
-#endif
- } else {
- quint32 replicated_len = quint16(len) | (quint32(quint16(len)) << 16);
- __m128i mseed = _mm_cvtsi32_si128(int(seed));
- key = _mm_insert_epi32(mseed, replicated_len, 1);
- key = _mm_unpacklo_epi64(key, key);
- }
-
+namespace {
// This is inspired by the algorithm in the Go language. See:
- // https://github.com/golang/go/blob/894abb5f680c040777f17f9f8ee5a5ab3a03cb94/src/runtime/asm_386.s#L902
- // https://github.com/golang/go/blob/894abb5f680c040777f17f9f8ee5a5ab3a03cb94/src/runtime/asm_amd64.s#L903
+ // https://github.com/golang/go/blob/01b6cf09fc9f272d9db3d30b4c93982f4911d120/src/runtime/asm_amd64.s#L1105
+ // https://github.com/golang/go/blob/01b6cf09fc9f272d9db3d30b4c93982f4911d120/src/runtime/asm_386.s#L908
//
// Even though we're using the AESENC instruction from the CPU, this code
// is not encryption and this routine makes no claim to be
@@ -432,115 +618,354 @@ static size_t aeshash(const uchar *p, size_t len, size_t seed) noexcept
// the scrambling round (step 3 in [1]) because it's just very good at
// spreading the bits around.
//
+ // Note on Latin-1 hashing (ZX == ByteToWord): for simplicity of the
+ // algorithm, we pass sizes equivalent to the UTF-16 content (ZX == None).
+ // That means we must multiply by 2 on entry, divide by 2 on pointer
+ // advancing, and load half as much data from memory (though we produce
+ // exactly as much data in registers). The compilers appear to optimize
+ // this out.
+ //
// [1] https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#High-level_description_of_the_algorithm
+ template <ZeroExtension ZX, typename T> static const T *advance(const T *ptr, ptrdiff_t n)
+ {
+ if constexpr (ZX == None)
+ return ptr + n;
+
+ // see note above on ZX == ByteToWord hashing
+ auto p = reinterpret_cast<const uchar *>(ptr);
+ n *= sizeof(T);
+ return reinterpret_cast<const T *>(p + n/2);
+ }
+
+ template <ZeroExtension> static __m128i loadu128(const void *ptr);
+ template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(AES) __m128i loadu128<None>(const void *ptr)
+ {
+ return _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ }
+ template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(AES) __m128i loadu128<ByteToWord>(const void *ptr)
+ {
+ // use a MOVQ followed by PMOVZXBW
+ // the compiler usually combines them as a single, loading PMOVZXBW
+ __m128i data = _mm_loadl_epi64(static_cast<const __m128i *>(ptr));
+ return _mm_cvtepu8_epi16(data);
+ }
+
// hash 16 bytes, running 3 scramble rounds of AES on itself (like label "final1")
- const auto hash16bytes = [](__m128i &state0, __m128i data) QT_FUNCTION_TARGET(AES) {
+ static void Q_ALWAYS_INLINE QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+ hash16bytes(__m128i &state0, __m128i data)
+ {
state0 = _mm_xor_si128(state0, data);
state0 = _mm_aesenc_si128(state0, state0);
state0 = _mm_aesenc_si128(state0, state0);
state0 = _mm_aesenc_si128(state0, state0);
+ }
+
+ // hash twice 16 bytes, running 2 scramble rounds of AES on itself
+ template <ZeroExtension ZX>
+ static void QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+ hash2x16bytes(__m128i &state0, __m128i &state1, const __m128i *src0, const __m128i *src1)
+ {
+ __m128i data0 = loadu128<ZX>(src0);
+ __m128i data1 = loadu128<ZX>(src1);
+ state0 = _mm_xor_si128(data0, state0);
+ state1 = _mm_xor_si128(data1, state1);
+ state0 = _mm_aesenc_si128(state0, state0);
+ state1 = _mm_aesenc_si128(state1, state1);
+ state0 = _mm_aesenc_si128(state0, state0);
+ state1 = _mm_aesenc_si128(state1, state1);
+ }
+
+ struct AESHashSeed
+ {
+ __m128i state0;
+ __m128i mseed2;
+ AESHashSeed(size_t seed, size_t seed2) QT_FUNCTION_TARGET(AES);
+ __m128i state1() const QT_FUNCTION_TARGET(AES);
+ __m256i state0_256() const QT_FUNCTION_TARGET(AES_AVX2)
+ { return _mm256_set_m128i(state1(), state0); }
};
+} // unnamed namespace
- __m128i state0 = key;
- auto src = reinterpret_cast<const __m128i *>(p);
+Q_ALWAYS_INLINE AESHashSeed::AESHashSeed(size_t seed, size_t seed2)
+{
+ __m128i mseed = mm_cvtsz_si128(seed);
+ mseed2 = mm_set1_epz(seed2);
- if (len < 16)
- goto lt16;
- if (len < 32)
- goto lt32;
+ // mseed (epi16) = [ seed, seed >> 16, seed >> 32, seed >> 48, len, 0, 0, 0 ]
+ mseed = _mm_insert_epi16(mseed, short(seed), 4);
+ // mseed (epi16) = [ seed, seed >> 16, seed >> 32, seed >> 48, len, len, len, len ]
+ mseed = _mm_shufflehi_epi16(mseed, 0);
- // rounds of 32 bytes
+ // merge with the process-global seed
+ __m128i key = _mm_xor_si128(mseed, mseed2);
+
+ // scramble the key
+ __m128i state0 = _mm_aesenc_si128(key, key);
+ this->state0 = state0;
+}
+
+Q_ALWAYS_INLINE __m128i AESHashSeed::state1() const
+{
{
- // Make state1 = ~state0:
- __m128i one = _mm_cmpeq_epi64(key, key);
- __m128i state1 = _mm_xor_si128(state0, one);
+ // unlike the Go code, we don't have more per-process seed
+ __m128i state1 = _mm_aesenc_si128(state0, mseed2);
+ return state1;
+ }
+}
- // do simplified rounds of 32 bytes: unlike the Go code, we only
- // scramble twice and we keep 256 bits of state
- const auto srcend = src + (len / 32);
- while (src < srcend) {
- __m128i data0 = _mm_loadu_si128(src);
- __m128i data1 = _mm_loadu_si128(src + 1);
- state0 = _mm_xor_si128(data0, state0);
- state1 = _mm_xor_si128(data1, state1);
- state0 = _mm_aesenc_si128(state0, state0);
- state1 = _mm_aesenc_si128(state1, state1);
- state0 = _mm_aesenc_si128(state0, state0);
- state1 = _mm_aesenc_si128(state1, state1);
- src += 2;
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+aeshash128_16to32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
+{
+ {
+ const __m128i *src2 = advance<ZX>(srcend, -1);
+ if (advance<ZX>(src, 1) < srcend) {
+ // epilogue: between 16 and 31 bytes
+ hash2x16bytes<ZX>(state0, state1, src, src2);
+ } else if (src != srcend) {
+ // epilogue: between 1 and 16 bytes, overlap with the end
+ __m128i data = loadu128<ZX>(src2);
+ hash16bytes(state0, data);
}
+
+ // combine results:
state0 = _mm_xor_si128(state0, state1);
}
- len &= 0x1f;
- // do we still have 16 or more bytes?
- if (len & 0x10) {
-lt32:
- __m128i data = _mm_loadu_si128(src);
- hash16bytes(state0, data);
- ++src;
- }
- len &= 0xf;
+ return mm_cvtsi128_sz(state0);
+}
-lt16:
+// load all 16 bytes and mask off the bytes past the end of the source
+static const qint8 maskarray[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+// load 16 bytes ending at the data end, then shuffle them to the beginning
+static const qint8 shufflecontrol[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+aeshash128_lt16(__m128i state0, const __m128i *src, const __m128i *srcend, size_t len)
+{
if (len) {
- // load the last chunk of data
// We're going to load 16 bytes and mask zero the part we don't care
// (the hash of a short string is different from the hash of a longer
// including NULLs at the end because the length is in the key)
// WARNING: this may produce valgrind warnings, but it's safe
+ constexpr quintptr CachelineSize = 64;
__m128i data;
- if (Q_LIKELY(quintptr(src + 1) & 0xff0)) {
- // same page, we definitely can't fault:
- // load all 16 bytes and mask off the bytes past the end of the source
- static const qint8 maskarray[] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
+ if ((quintptr(src) & (CachelineSize / 2)) == 0) {
+ // lower half of the cacheline:
__m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(maskarray + 15 - len));
- data = _mm_loadu_si128(src);
+ data = loadu128<ZX>(src);
data = _mm_and_si128(data, mask);
} else {
- // too close to the end of the page, it could fault:
- // load 16 bytes ending at the data end, then shuffle them to the beginning
- static const qint8 shufflecontrol[] = {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- };
+ // upper half of the cacheline:
__m128i control = _mm_loadu_si128(reinterpret_cast<const __m128i *>(shufflecontrol + 15 - len));
- p = reinterpret_cast<const uchar *>(src - 1);
- data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p + len));
+ data = loadu128<ZX>(advance<ZX>(srcend, -1));
data = _mm_shuffle_epi8(data, control);
}
hash16bytes(state0, data);
}
+ return mm_cvtsi128_sz(state0);
+}
- // extract state0
-# if QT_POINTER_SIZE == 8
- return _mm_cvtsi128_si64(state0);
-# else
- return _mm_cvtsi128_si32(state0);
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+aeshash128_ge32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
+{
+ // main loop: scramble two 16-byte blocks
+ for ( ; advance<ZX>(src, 2) < srcend; src = advance<ZX>(src, 2))
+ hash2x16bytes<ZX>(state0, state1, src, advance<ZX>(src, 1));
+
+ return aeshash128_16to32<ZX>(state0, state1, src, srcend);
+}
+
+# if QT_COMPILER_SUPPORTS_HERE(VAES)
+template <ZeroExtension> static __m256i loadu256(const void *ptr);
+template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(VAES) __m256i loadu256<None>(const void *ptr)
+{
+ return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
+}
+template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(VAES) __m256i loadu256<ByteToWord>(const void *ptr)
+{
+ // VPMOVZXBW xmm, ymm
+ __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ return _mm256_cvtepu8_epi16(data);
+}
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(VAES_AVX512) QT_VECTORCALL
+aeshash256_lt32_avx256(__m256i state0, const uchar *p, size_t len)
+{
+ __m128i state0_128 = _mm256_castsi256_si128(state0);
+ if (len) {
+ __m256i data;
+ if constexpr (ZX == None) {
+ __mmask32 mask = _bzhi_u32(-1, unsigned(len));
+ data = _mm256_maskz_loadu_epi8(mask, p);
+ } else {
+ __mmask16 mask = _bzhi_u32(-1, unsigned(len) / 2);
+ __m128i data0 = _mm_maskz_loadu_epi8(mask, p);
+ data = _mm256_cvtepu8_epi16(data0);
+ }
+ __m128i data0 = _mm256_castsi256_si128(data);
+ if (len >= sizeof(__m128i)) {
+ state0 = _mm256_xor_si256(state0, data);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ // we're XOR'ing the two halves so we skip the third AESENC
+ // state0 = _mm256_aesenc_epi128(state0, state0);
+
+ // XOR the two halves and extract
+ __m128i low = _mm256_extracti128_si256(state0, 0);
+ __m128i high = _mm256_extracti128_si256(state0, 1);
+ state0_128 = _mm_xor_si128(low, high);
+ } else {
+ hash16bytes(state0_128, data0);
+ }
+ }
+ return mm_cvtsi128_sz(state0_128);
+}
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(VAES) QT_VECTORCALL
+aeshash256_ge32(__m256i state0, const __m128i *s, const __m128i *end, size_t len)
+{
+ static const auto hash32bytes = [](__m256i &state0, __m256i data) QT_FUNCTION_TARGET(VAES) {
+ state0 = _mm256_xor_si256(state0, data);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ };
+
+ // hash twice 32 bytes, running 2 scramble rounds of AES on itself
+ const auto hash2x32bytes = [](__m256i &state0, __m256i &state1, const void *src0,
+ const void *src1) QT_FUNCTION_TARGET(VAES) {
+ __m256i data0 = loadu256<ZX>(src0);
+ __m256i data1 = loadu256<ZX>(src1);
+ state0 = _mm256_xor_si256(data0, state0);
+ state1 = _mm256_xor_si256(data1, state1);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ state1 = _mm256_aesenc_epi128(state1, state1);
+ state0 = _mm256_aesenc_epi128(state0, state0);
+ state1 = _mm256_aesenc_epi128(state1, state1);
+ };
+
+ const __m256i *src = reinterpret_cast<const __m256i *>(s);
+ const __m256i *srcend = reinterpret_cast<const __m256i *>(end);
+
+ __m256i state1 = _mm256_aesenc_epi128(state0, mm256_set1_epz(len));
+
+ // main loop: scramble two 32-byte blocks
+ for ( ; advance<ZX>(src, 2) < srcend; src = advance<ZX>(src, 2))
+ hash2x32bytes(state0, state1, src, advance<ZX>(src, 1));
+
+ const __m256i *src2 = advance<ZX>(srcend, -1);
+ if (advance<ZX>(src, 1) < srcend) {
+ // epilogue: between 32 and 31 bytes
+ hash2x32bytes(state0, state1, src, src2);
+ } else if (src != srcend) {
+ // epilogue: between 1 and 32 bytes, overlap with the end
+ __m256i data = loadu256<ZX>(src2);
+ hash32bytes(state0, data);
+ }
+
+ // combine results:
+ state0 = _mm256_xor_si256(state0, state1);
+
+ // XOR the two halves and extract
+ __m128i low = _mm256_extracti128_si256(state0, 0);
+ __m128i high = _mm256_extracti128_si256(state0, 1);
+ return mm_cvtsi128_sz(_mm_xor_si128(low, high));
+}
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(VAES)
+aeshash256(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
+{
+ AESHashSeed state(seed, seed2);
+ auto src = reinterpret_cast<const __m128i *>(p);
+ const auto srcend = reinterpret_cast<const __m128i *>(advance<ZX>(p, len));
+
+ if (len < sizeof(__m128i))
+ return aeshash128_lt16<ZX>(state.state0, src, srcend, len);
+
+ if (len <= sizeof(__m256i))
+ return aeshash128_16to32<ZX>(state.state0, state.state1(), src, srcend);
+
+ return aeshash256_ge32<ZX>(state.state0_256(), src, srcend, len);
+}
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(VAES_AVX512)
+aeshash256_avx256(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
+{
+ AESHashSeed state(seed, seed2);
+ auto src = reinterpret_cast<const __m128i *>(p);
+ const auto srcend = reinterpret_cast<const __m128i *>(advance<ZX>(p, len));
+
+ if (len <= sizeof(__m256i))
+ return aeshash256_lt32_avx256<ZX>(state.state0_256(), p, len);
+
+ return aeshash256_ge32<ZX>(state.state0_256(), src, srcend, len);
+}
+# endif // VAES
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(AES)
+aeshash128(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
+{
+ AESHashSeed state(seed, seed2);
+ auto src = reinterpret_cast<const __m128i *>(p);
+ const auto srcend = reinterpret_cast<const __m128i *>(advance<ZX>(p, len));
+
+ if (len < sizeof(__m128i))
+ return aeshash128_lt16<ZX>(state.state0, src, srcend, len);
+
+ if (len <= sizeof(__m256i))
+ return aeshash128_16to32<ZX>(state.state0, state.state1(), src, srcend);
+
+ return aeshash128_ge32<ZX>(state.state0, state.state1(), src, srcend);
+}
+
+template <ZeroExtension ZX = None>
+static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
+{
+ if constexpr (ZX == ByteToWord)
+ len *= 2; // see note above on ZX == ByteToWord hashing
+
+# if QT_COMPILER_SUPPORTS_HERE(VAES)
+ if (qCpuHasFeature(VAES)) {
+ if (qCpuHasFeature(AVX512VL))
+ return aeshash256_avx256<ZX>(p, len, seed, seed2);
+ return aeshash256<ZX>(p, len, seed, seed2);
+ }
# endif
+ return aeshash128<ZX>(p, len, seed, seed2);
}
-#endif
+#endif // x86 AESNI
#if defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
QT_FUNCTION_TARGET(AES)
-static size_t aeshash(const uchar *p, size_t len, size_t seed) noexcept
+static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
{
uint8x16_t key;
# if QT_POINTER_SIZE == 8
- quint64 seededlen = seed ^ len;
- uint64x2_t vseed = vcombine_u64(vcreate_u64(seed), vcreate_u64(seededlen));
+ uint64x2_t vseed = vcombine_u64(vcreate_u64(seed), vcreate_u64(seed2));
key = vreinterpretq_u8_u64(vseed);
# else
- quint32 replicated_len = quint16(len) | (quint32(quint16(len)) << 16);
+
uint32x2_t vseed = vmov_n_u32(seed);
- vseed = vset_lane_u32(replicated_len, vseed, 1);
+ vseed = vset_lane_u32(seed2, vseed, 1);
key = vreinterpretq_u8_u32(vcombine_u32(vseed, vseed));
# endif
@@ -668,31 +1093,25 @@ size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
// so help the compiler do dead code elimination
seed = 0;
#endif
+ // mix in the length as a secondary seed. For seed == 0, seed2 must be
+ // size, to match what we used to do prior to Qt 6.2.
+ size_t seed2 = size;
+ if (seed)
+ seed2 = qt_qhash_seed.currentSeed(1);
+
+ auto data = reinterpret_cast<const uchar *>(p);
#ifdef AESHASH
if (seed && qCpuHasFeature(AES) && qCpuHasFeature(SSE4_2))
- return aeshash(reinterpret_cast<const uchar *>(p), size, seed);
+ return aeshash(data, size, seed, seed2);
#elif defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
-# if defined(Q_OS_LINUX)
- // Do specific runtime-only check as Yocto hard enables Crypto extension for
- // all armv8 configs
- if (seed && (qCpuFeatures() & CpuFeatureAES))
-# else
if (seed && qCpuHasFeature(AES))
-# endif
- return aeshash(reinterpret_cast<const uchar *>(p), size, seed);
+ return aeshash(data, size, seed, seed2);
#endif
- if (size <= QT_POINTER_SIZE)
- return murmurhash(p, size, seed);
- return siphash(reinterpret_cast<const uchar *>(p), size, seed);
+ return qHashBits_fallback<>(data, size, seed, seed2);
}
-size_t qHash(const QByteArray &key, size_t seed) noexcept
-{
- return qHashBits(key.constData(), size_t(key.size()), seed);
-}
-
-size_t qHash(const QByteArrayView &key, size_t seed) noexcept
+size_t qHash(QByteArrayView key, size_t seed) noexcept
{
return qHashBits(key.constData(), size_t(key.size()), seed);
}
@@ -702,6 +1121,7 @@ size_t qHash(QStringView key, size_t seed) noexcept
return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
}
+#ifndef QT_BOOTSTRAPPED
size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
{
qsizetype m = bitArray.d.size() - 1;
@@ -714,72 +1134,35 @@ size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
result = ((result << 4) + bitArray.d.at(m)) & ((1 << n) - 1);
return result;
}
+#endif
-size_t qHash(QLatin1String key, size_t seed) noexcept
-{
- return qHashBits(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
-}
-
-/*!
- \internal
-
- Note: not \c{noexcept}, but called from a \c{noexcept} function and thus
- will cause termination if any of the functions here throw.
-*/
-enum HashCreationMode { Initial, Reseed };
-static size_t qt_create_qhash_seed(HashCreationMode mode)
+size_t qHash(QLatin1StringView key, size_t seed) noexcept
{
- size_t seed = 0;
-
#ifdef QT_BOOTSTRAPPED
- Q_UNUSED(mode)
-#else
- bool ok;
- seed = qEnvironmentVariableIntValue("QT_HASH_SEED", &ok);
- if (ok) {
- if (seed) {
- // can't use qWarning here (reentrancy)
- fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
- }
- seed = 1; // QHashSeed::globalSeed subtracts 1
- } else if (mode == Initial) {
- auto data = qt_initial_random_value();
- seed = data.data[0] ^ data.data[1];
- } else if (sizeof(seed) > sizeof(uint)) {
- seed = QRandomGenerator::system()->generate64();
- } else {
- seed = QRandomGenerator::system()->generate();
- }
-#endif // QT_BOOTSTRAPPED
+ // the seed is always 0 in bootstrapped mode (no seed generation code),
+ // so help the compiler do dead code elimination
+ seed = 0;
+#endif
- return seed;
-}
+ auto data = reinterpret_cast<const uchar *>(key.data());
+ size_t size = key.size();
-/*
- The QHash seed itself.
-
- We store the seed value plus one, so the value zero is used to indicate the
- seed is not initialized. This is corrected before passing to the user.
-*/
-static QBasicAtomicInteger<size_t> qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(0);
+ // Mix in the length as a secondary seed.
+ // Multiplied by 2 to match the byte size of the equiavlent UTF-16 string.
+ size_t seed2 = size * 2;
+ if (seed)
+ seed2 = qt_qhash_seed.currentSeed(1);
-/*!
- \internal
- \threadsafe
-
- Initializes the seed and returns it.
-*/
-static size_t qt_initialize_qhash_seed()
-{
- size_t theirSeed; // another thread's seed
- size_t ourSeed = qt_create_qhash_seed(Initial);
- if (qt_qhash_seed.testAndSetRelaxed(0, ourSeed, theirSeed))
- return ourSeed;
- return theirSeed;
+#if defined(AESHASH)
+ if (seed && qCpuHasFeature(AES) && qCpuHasFeature(SSE4_2))
+ return aeshash<ByteToWord>(data, size, seed, seed2);
+#endif
+ return qHashBits_fallback<ByteToWord>(data, size, seed, seed2);
}
/*!
\class QHashSeed
+ \inmodule QtCore
\since 6.2
The QHashSeed class is used to convey the QHash seed. This is used
@@ -832,11 +1215,7 @@ static size_t qt_initialize_qhash_seed()
*/
QHashSeed QHashSeed::globalSeed() noexcept
{
- size_t seed = qt_qhash_seed.loadRelaxed();
- if (Q_UNLIKELY(seed == 0))
- seed = qt_initialize_qhash_seed();
-
- return { seed - 1 };
+ return qt_qhash_seed.currentSeed(0);
}
/*!
@@ -850,7 +1229,7 @@ QHashSeed QHashSeed::globalSeed() noexcept
*/
void QHashSeed::setDeterministicGlobalSeed()
{
- qt_qhash_seed.storeRelease(1);
+ qt_qhash_seed.clearSeed();
}
/*!
@@ -870,8 +1249,7 @@ void QHashSeed::setDeterministicGlobalSeed()
*/
void QHashSeed::resetRandomGlobalSeed()
{
- size_t seed = qt_create_qhash_seed(Reseed);
- qt_qhash_seed.storeRelaxed(seed + 1);
+ qt_qhash_seed.resetSeed();
}
#if QT_DEPRECATED_SINCE(6,6)
@@ -1184,6 +1562,26 @@ uint qt_hash(QStringView key, uint chained) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
+/*! \fn size_t qHash(quint128 key, size_t seed = 0)
+ \relates QHash
+ \since 6.8
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+
+ \note This function is only available on platforms that support a native
+ 128-bit integer type.
+*/
+
+/*! \fn size_t qHash(qint128 key, size_t seed = 0)
+ \relates QHash
+ \since 6.8
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+
+ \note This function is only available on platforms that support a native
+ 128-bit integer type.
+ */
+
/*! \fn size_t qHash(char8_t key, size_t seed = 0)
\relates QHash
\since 6.0
@@ -1212,7 +1610,7 @@ uint qt_hash(QStringView key, uint chained) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn size_t qHash(float key, size_t seed) noexcept
+/*! \fn size_t qHash(float key, size_t seed = 0) noexcept
\relates QHash
\since 5.3
@@ -1237,7 +1635,6 @@ size_t qHash(double key, size_t seed) noexcept
}
}
-#if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
/*! \relates QHash
\since 5.3
@@ -1255,7 +1652,6 @@ size_t qHash(long double key, size_t seed) noexcept
return murmurhash(&key, sizeof(key), seed);
}
}
-#endif
/*! \fn size_t qHash(const QChar key, size_t seed = 0)
\relates QHash
@@ -1299,7 +1695,7 @@ size_t qHash(long double key, size_t seed) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn size_t qHash(QLatin1String key, size_t seed = 0)
+/*! \fn size_t qHash(QLatin1StringView key, size_t seed = 0)
\relates QHash
\since 5.0
@@ -1313,7 +1709,7 @@ size_t qHash(long double key, size_t seed) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn template <class T> size_t qHash(std::nullptr_t key, size_t seed = 0)
+/*! \fn size_t qHash(std::nullptr_t key, size_t seed = 0)
\relates QHash
\since 6.0
@@ -1441,7 +1837,7 @@ size_t qHash(long double key, size_t seed) noexcept
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}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qhash.cpp 12
@@ -1480,10 +1876,15 @@ size_t qHash(long double key, size_t seed) noexcept
The two-arguments overloads take an unsigned integer that should be used to
seed the calculation of the hash function. This seed is provided by QHash
- in order to prevent a family of \l{algorithmic complexity attacks}. If both
- a one-argument and a two-arguments overload are defined for a key type,
- the latter is used by QHash (note that you can simply define a
- two-arguments version, and use a default value for the seed parameter).
+ in order to prevent a family of \l{algorithmic complexity attacks}.
+
+ \note In Qt 6 it is possible to define a \c{qHash()} overload
+ taking only one argument; support for this is deprecated. Starting
+ with Qt 7, it will be mandatory to use a two-arguments overload. If
+ both a one-argument and a two-arguments overload are defined for a
+ key type, the latter is used by QHash (note that you can simply
+ define a two-arguments version, and use a default value for the
+ seed parameter).
The second way to provide a hashing function is by specializing
the \c{std::hash} class for the key type \c{K}, and providing a
@@ -1579,8 +1980,8 @@ size_t qHash(long double key, size_t seed) noexcept
Constructs a hash with a copy of each of the elements in the iterator range
[\a begin, \a end). Either the elements iterated by the range must be
- objects with \c{first} and \c{second} data members (like \c{QPair},
- \c{std::pair}, etc.) convertible to \c Key and to \c T respectively; or the
+ objects with \c{first} and \c{second} data members (like \c{std::pair}),
+ convertible to \c Key and to \c T respectively; or the
iterators must have \c{key()} and \c{value()} member functions, returning a
key convertible to \c Key and a value convertible to \c T respectively.
*/
@@ -1656,7 +2057,7 @@ size_t qHash(long double key, size_t seed) noexcept
\sa operator==()
*/
-/*! \fn template <class Key, class T> int QHash<Key, T>::size() const
+/*! \fn template <class Key, class T> qsizetype QHash<Key, T>::size() const
Returns the number of items in the hash.
@@ -1671,7 +2072,7 @@ size_t qHash(long double key, size_t seed) noexcept
\sa size()
*/
-/*! \fn template <class Key, class T> int QHash<Key, T>::capacity() const
+/*! \fn template <class Key, class T> qsizetype QHash<Key, T>::capacity() const
Returns the number of buckets in the QHash's internal hash table.
@@ -1815,17 +2216,18 @@ size_t qHash(long double key, size_t seed) noexcept
Returns \c true if the hash contains an item with the \a key;
otherwise returns \c false.
- \sa count(), QMultiHash::contains()
+ \sa count()
*/
-/*! \fn template <class Key, class T> T QHash<Key, T>::value(const Key &key, const T &defaultValue = T()) const
+/*! \fn template <class Key, class T> 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) 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.
+ returns \a defaultValue, or a \l{default-constructed value} if this
+ parameter has not been supplied.
*/
/*! \fn template <class Key, class T> T &QHash<Key, T>::operator[](const Key &key)
@@ -1837,6 +2239,12 @@ size_t qHash(long double key, size_t seed) noexcept
a \l{default-constructed value} into the hash with the \a key, and
returns a reference to it.
+//! [qhash-iterator-invalidation-func-desc]
+ \warning Returned iterators/references should be considered invalidated
+ the next time you call a non-const function on the hash, or when the
+ hash is destroyed.
+//! [qhash-iterator-invalidation-func-desc]
+
\sa insert(), value()
*/
@@ -1888,25 +2296,27 @@ size_t qHash(long double key, size_t seed) noexcept
*/
/*!
- \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value, const Key &defaultKey = Key()) const
+ \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value) const
+ \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value, const Key &defaultKey) 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.
+ Returns the first key mapped to \a value. If the hash contains no item
+ mapped to \a value, returns \a defaultKey, or a \l{default-constructed
+ value}{default-constructed key} if this parameter has not been supplied.
This function can be slow (\l{linear time}), because QHash's
internal data structure is optimized for fast lookup by key, not
by value.
*/
-/*! \fn template <class Key, class T> int QHash<Key, T>::count(const Key &key) const
+/*! \fn template <class Key, class T> qsizetype QHash<Key, T>::count(const Key &key) const
Returns the number of items associated with the \a key.
\sa contains()
*/
-/*! \fn template <class Key, class T> int QHash<Key, T>::count() const
+/*! \fn template <class Key, class T> qsizetype QHash<Key, T>::count() const
\overload
@@ -1918,12 +2328,16 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::begin() const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::cbegin() const
@@ -1932,6 +2346,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), cend()
*/
@@ -1940,6 +2356,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -1949,6 +2367,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyEnd()
*/
@@ -1957,12 +2377,16 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::end() const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::constEnd() const
@@ -1970,6 +2394,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
@@ -1979,6 +2405,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa cbegin(), end()
*/
@@ -1988,6 +2416,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last key in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyBegin()
*/
@@ -1997,6 +2427,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -2006,6 +2438,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -2015,6 +2449,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -2024,6 +2460,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -2033,6 +2471,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -2042,9 +2482,32 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QHash<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this hash as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qhash.cpp 34
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the hash. Specifically, mutating the value
+ will modify the hash itself.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::erase(const_iterator pos)
\since 5.7
@@ -2059,6 +2522,8 @@ size_t qHash(long double key, size_t seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 15
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa remove(), take(), find()
*/
@@ -2078,12 +2543,16 @@ size_t qHash(long double key, size_t seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 16
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa value(), values()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &key) const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::constFind(const Key &key) const
@@ -2095,6 +2564,8 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains no item with the \a key, the function
returns constEnd().
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa find()
*/
@@ -2104,6 +2575,10 @@ size_t qHash(long double key, size_t seed) noexcept
If there is already an item with the \a key, that item's value
is replaced with \a value.
+
+ Returns an iterator pointing to the new/updated element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
@@ -2115,6 +2590,8 @@ size_t qHash(long double key, size_t seed) noexcept
construction.
Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
@@ -2125,9 +2602,6 @@ size_t qHash(long double key, size_t seed) noexcept
If a key is common to both hashes, its value will be replaced with the
value stored in \a other.
-
- \note If \a other contains multiple entries with the same key then the
- final value of the key is undefined.
*/
/*! \fn template <class Key, class T> bool QHash<Key, T>::empty() const
@@ -2137,17 +2611,21 @@ size_t qHash(long double key, size_t seed) noexcept
returns \c false.
*/
-/*! \fn template <class Key, class T> QPair<iterator, iterator> QMultiHash<Key, T>::equal_range(const Key &key)
+/*! \fn template <class Key, class T> std::pair<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
are stored under \a key. If the range is empty then both iterators will be equal to end().
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
- \fn template <class Key, class T> QPair<const_iterator, const_iterator> QMultiHash<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> std::pair<const_iterator, const_iterator> QMultiHash<Key, T>::equal_range(const Key &key) const
\overload
\since 5.7
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \typedef QHash::ConstIterator
@@ -2244,12 +2722,6 @@ size_t qHash(long double key, size_t seed) noexcept
\inmodule QtCore
\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
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
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,
@@ -2270,31 +2742,15 @@ size_t qHash(long double key, size_t seed) noexcept
Unlike QMap, which orders its items by key, QHash stores its
items in an arbitrary order.
- Let's see a few examples of things we can do with a
- QHash::iterator that we cannot do with a QHash::const_iterator.
Here's an example that increments every value stored in the QHash
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 QHash::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:
+ To remove elements from a QHash you can use erase_if(QHash\<Key, T\> &map, Predicate pred):
\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.
@@ -2305,10 +2761,6 @@ size_t qHash(long double key, size_t seed) noexcept
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.
@@ -2317,7 +2769,7 @@ size_t qHash(long double key, size_t seed) noexcept
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QHash::const_iterator, QHash::key_iterator, QMutableHashIterator
+ \sa QHash::const_iterator, QHash::key_iterator, QHash::key_value_iterator
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator::iterator()
@@ -2413,12 +2865,6 @@ size_t qHash(long double key, size_t seed) noexcept
\inmodule QtCore
\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
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QHash\<Key, T\>::const_iterator allows you to iterate over a
QHash. If you want to modify the QHash as you
iterate over it, you must use QHash::iterator instead. It is
@@ -2429,8 +2875,8 @@ size_t qHash(long double key, size_t seed) noexcept
The default QHash::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QHash
- function like QHash::constBegin(), QHash::constEnd(), or
- QHash::find() before you can start iterating. Here's a typical
+ function like QHash::cbegin(), QHash::cend(), or
+ QHash::constFind() 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
@@ -2451,12 +2897,16 @@ size_t qHash(long double key, size_t seed) noexcept
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.
+
\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 QHash::iterator, QHashIterator
+ \sa QHash::iterator, QHash::key_iterator, QHash::const_key_value_iterator
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator::const_iterator()
@@ -2742,9 +3192,6 @@ size_t qHash(long double key, size_t seed) noexcept
Constructs a multi-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> QMultiHash<Key, T>::QMultiHash(const QHash<Key, T> &other)
@@ -2758,8 +3205,8 @@ size_t qHash(long double key, size_t seed) noexcept
Constructs a multi-hash with a copy of each of the elements in the iterator range
[\a begin, \a end). Either the elements iterated by the range must be
- objects with \c{first} and \c{second} data members (like \c{QPair},
- \c{std::pair}, etc.) convertible to \c Key and to \c T respectively; or the
+ objects with \c{first} and \c{second} data members (like \c{std::pair}),
+ convertible to \c Key and to \c T respectively; or the
iterators must have \c{key()} and \c{value()} member functions, returning a
key convertible to \c Key and a value convertible to \c T respectively.
*/
@@ -2774,6 +3221,10 @@ size_t qHash(long double key, size_t seed) noexcept
If there are multiple items with the \a key, the most
recently inserted item's value is replaced with \a value.
+ Returns an iterator pointing to the new/updated element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa insert()
*/
@@ -2786,6 +3237,10 @@ size_t qHash(long double key, size_t seed) noexcept
different from replace(), which overwrites the value of an
existing item.)
+ Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa replace()
*/
@@ -2804,6 +3259,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an iterator pointing to the new element.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa insert
*/
@@ -2820,6 +3277,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an iterator pointing to the new element.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa replace, emplace
*/
@@ -2852,14 +3311,14 @@ size_t qHash(long double key, size_t 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
+/*! \fn template <class Key, class T> T QMultiHash<Key, T>::value(const Key &key) const
+ \fn template <class Key, class T> T QMultiHash<Key, T>::value(const Key &key, const T &defaultValue) const
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.
+ returns \a defaultValue, or a \l{default-constructed value} if this
+ parameter has not been supplied.
If there are multiple
items for the \a key in the hash, the value of the most recently
@@ -2886,6 +3345,8 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains multiple items with the \a key, this function returns
a reference to the most recently inserted value.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa insert(), value()
*/
@@ -2917,7 +3378,17 @@ size_t qHash(long double key, size_t seed) noexcept
*/
/*!
- \fn template <class Key, class T> int QMultiHash<Key, T>::remove(const Key &key, const T &value)
+ \fn template <class Key, class T> qsizetype QMultiHash<Key, T>::remove(const Key &key)
+ \since 4.3
+
+ Removes all the items that have the \a key from the hash.
+ Returns the number of items removed.
+
+ \sa remove()
+*/
+
+/*!
+ \fn template <class Key, class T> qsizetype QMultiHash<Key, T>::remove(const Key &key, const T &value)
\since 4.3
Removes all the items that have the \a key and the value \a
@@ -2997,11 +3468,13 @@ size_t qHash(long double key, size_t seed) noexcept
*/
/*!
- \fn template <class Key, class T> Key QMultiHash<Key, T>::key(const T &value, const Key &defaultKey = Key()) const
+ \fn template <class Key, class T> Key QMultiHash<Key, T>::key(const T &value) const
+ \fn template <class Key, class T> Key QMultiHash<Key, T>::key(const T &value, const Key &defaultKey) 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.
+ Returns the first key mapped to \a value. If the hash contains no item
+ mapped to \a value, returns \a defaultKey, or a \l{default-constructed
+ value}{default-constructed key} if this parameter has not been supplied.
This function can be slow (\l{linear time}), because QMultiHash's
internal data structure is optimized for fast lookup by key, not
@@ -3009,7 +3482,7 @@ size_t qHash(long double key, size_t seed) noexcept
*/
/*!
- \fn template <class Key, class T> int QMultiHash<Key, T>::count(const Key &key, const T &value) const
+ \fn template <class Key, class T> qsizetype QMultiHash<Key, T>::count(const Key &key, const T &value) const
\since 4.3
Returns the number of items with the \a key and \a value.
@@ -3026,12 +3499,16 @@ size_t qHash(long double key, size_t 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.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
\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
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
@@ -3043,6 +3520,8 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains no such item, the function returns
constEnd().
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::begin()
@@ -3050,12 +3529,16 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::begin() const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::cbegin() const
@@ -3064,6 +3547,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), cend()
*/
@@ -3072,6 +3557,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -3081,6 +3568,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyEnd()
*/
@@ -3089,6 +3578,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -3102,6 +3593,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
@@ -3111,6 +3604,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa cbegin(), end()
*/
@@ -3120,6 +3615,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last key in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyBegin()
*/
@@ -3129,6 +3626,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -3138,6 +3637,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -3147,6 +3648,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -3156,6 +3659,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -3165,6 +3670,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -3174,20 +3681,36 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QMultiHash<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this hash as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qhash.cpp 35
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the hash. Specifically, mutating the value
+ will modify the hash itself.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa QKeyValueIterator
+*/
/*! \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,
@@ -3208,31 +3731,15 @@ size_t qHash(long double key, size_t seed) noexcept
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:
+ To remove elements from a QMultiHash you can use erase_if(QMultiHash\<Key, T\> &map, Predicate pred):
\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.
@@ -3243,10 +3750,6 @@ size_t qHash(long double key, size_t seed) noexcept
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.
@@ -3255,7 +3758,7 @@ size_t qHash(long double key, size_t seed) noexcept
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiHash::const_iterator, QMultiHash::key_iterator, QMutableHashIterator
+ \sa QMultiHash::const_iterator, QMultiHash::key_iterator, QMultiHash::key_value_iterator
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator::iterator()
@@ -3351,12 +3854,6 @@ size_t qHash(long double key, size_t seed) noexcept
\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
@@ -3367,8 +3864,8 @@ size_t qHash(long double key, size_t seed) noexcept
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
+ function like QMultiHash::cbegin(), QMultiHash::cend(), or
+ QMultiHash::constFind() 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
@@ -3380,28 +3877,24 @@ size_t qHash(long double key, size_t 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 (inserting and
+ that any modification performed directly on the QMultiHash (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
+ Inserting items into the hash or calling methods such as QMultiHash::reserve()
+ or QMultiHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QMultiHash 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.
+ that you use QMultiMap rather than QMultiHash.
\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
+ \sa QMultiHash::iterator, QMultiHash::key_iterator, QMultiHash::const_key_value_iterator
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator()
@@ -3665,4 +4158,36 @@ size_t qHash(long double key, size_t seed) noexcept
Returns the number of elements removed, if any.
*/
+#ifdef QT_HAS_CONSTEXPR_BITOPS
+namespace QHashPrivate {
+static_assert(qPopulationCount(SpanConstants::NEntries) == 1,
+ "NEntries must be a power of 2 for bucketForHash() to work.");
+
+// ensure the size of a Span does not depend on the template parameters
+using Node1 = Node<int, int>;
+static_assert(sizeof(Span<Node1>) == sizeof(Span<Node<char, void *>>));
+static_assert(sizeof(Span<Node1>) == sizeof(Span<Node<qsizetype, QHashDummyValue>>));
+static_assert(sizeof(Span<Node1>) == sizeof(Span<Node<QString, QVariant>>));
+static_assert(sizeof(Span<Node1>) > SpanConstants::NEntries);
+static_assert(qNextPowerOfTwo(sizeof(Span<Node1>)) == SpanConstants::NEntries * 2);
+
+// ensure allocations are always a power of two, at a minimum NEntries,
+// obeying the fomula
+// qNextPowerOfTwo(2 * N);
+// without overflowing
+static constexpr size_t NEntries = SpanConstants::NEntries;
+static_assert(GrowthPolicy::bucketsForCapacity(1) == NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries / 2 + 0) == NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries / 2 + 1) == 2 * NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 1 - 1) == 2 * NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 1 + 0) == 4 * NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 1 + 1) == 4 * NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 2 - 1) == 4 * NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(NEntries * 2 + 0) == 8 * NEntries);
+static_assert(GrowthPolicy::bucketsForCapacity(SIZE_MAX / 4) == SIZE_MAX / 2 + 1);
+static_assert(GrowthPolicy::bucketsForCapacity(SIZE_MAX / 2) == SIZE_MAX);
+static_assert(GrowthPolicy::bucketsForCapacity(SIZE_MAX) == SIZE_MAX);
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index fb4b3f3198..e7cd4123fb 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHASH_H
#define QHASH_H
+#include <QtCore/qalgorithms.h>
#include <QtCore/qcontainertools_impl.h>
#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qlist.h>
-#include <QtCore/qmath.h>
#include <QtCore/qrefcount.h>
#include <initializer_list>
@@ -208,7 +172,7 @@ struct MultiNode
MultiNode(MultiNode &&other)
: key(other.key),
- value(qExchange(other.value, nullptr))
+ value(std::exchange(other.value, nullptr))
{
}
@@ -239,7 +203,7 @@ struct MultiNode
void insertMulti(Args &&... args)
{
Chain *e = new Chain{ T(std::forward<Args>(args)...), nullptr };
- e->next = qExchange(value, e);
+ e->next = std::exchange(value, e);
}
template<typename ...Args>
void emplaceValue(Args &&... args)
@@ -254,6 +218,15 @@ constexpr bool isRelocatable()
return QTypeInfo<typename Node::KeyType>::isRelocatable && QTypeInfo<typename Node::ValueType>::isRelocatable;
}
+struct SpanConstants {
+ static constexpr size_t SpanShift = 7;
+ static constexpr size_t NEntries = (1 << SpanShift);
+ static constexpr size_t LocalBucketMask = (NEntries - 1);
+ static constexpr size_t UnusedEntry = 0xff;
+
+ static_assert ((NEntries & LocalBucketMask) == 0, "NEntries must be a power of two.");
+};
+
// 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.
@@ -264,13 +237,6 @@ constexpr bool isRelocatable()
// 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
@@ -278,19 +244,19 @@ struct Span {
// 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;
+ struct { alignas(Node) unsigned char data[sizeof(Node)]; } storage;
unsigned char &nextFree() { return *reinterpret_cast<unsigned char *>(&storage); }
Node &node() { return *reinterpret_cast<Node *>(&storage); }
};
- unsigned char offsets[NEntries];
+ unsigned char offsets[SpanConstants::NEntries];
Entry *entries = nullptr;
unsigned char allocated = 0;
unsigned char nextFree = 0;
Span() noexcept
{
- memset(offsets, UnusedEntry, sizeof(offsets));
+ memset(offsets, SpanConstants::UnusedEntry, sizeof(offsets));
}
~Span()
{
@@ -301,7 +267,7 @@ struct Span {
if (entries) {
if constexpr (!std::is_trivially_destructible<Node>::value) {
for (auto o : offsets) {
- if (o != UnusedEntry)
+ if (o != SpanConstants::UnusedEntry)
entries[o].node().~Node();
}
}
@@ -311,8 +277,8 @@ struct Span {
}
Node *insert(size_t i)
{
- Q_ASSERT(i <= NEntries);
- Q_ASSERT(offsets[i] == UnusedEntry);
+ Q_ASSERT(i < SpanConstants::NEntries);
+ Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
if (nextFree == allocated)
addStorage();
unsigned char entry = nextFree;
@@ -323,11 +289,11 @@ struct Span {
}
void erase(size_t bucket) noexcept(std::is_nothrow_destructible<Node>::value)
{
- Q_ASSERT(bucket <= NEntries);
- Q_ASSERT(offsets[bucket] != UnusedEntry);
+ Q_ASSERT(bucket < SpanConstants::NEntries);
+ Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
unsigned char entry = offsets[bucket];
- offsets[bucket] = UnusedEntry;
+ offsets[bucket] = SpanConstants::UnusedEntry;
entries[entry].node().~Node();
entries[entry].nextFree() = nextFree;
@@ -339,19 +305,19 @@ struct Span {
}
bool hasNode(size_t i) const noexcept
{
- return (offsets[i] != UnusedEntry);
+ return (offsets[i] != SpanConstants::UnusedEntry);
}
Node &at(size_t i) noexcept
{
- Q_ASSERT(i <= NEntries);
- Q_ASSERT(offsets[i] != UnusedEntry);
+ Q_ASSERT(i < SpanConstants::NEntries);
+ Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
return entries[offsets[i]].node();
}
const Node &at(size_t i) const noexcept
{
- Q_ASSERT(i <= NEntries);
- Q_ASSERT(offsets[i] != UnusedEntry);
+ Q_ASSERT(i < SpanConstants::NEntries);
+ Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
return entries[offsets[i]].node();
}
@@ -369,17 +335,17 @@ struct Span {
}
void moveLocal(size_t from, size_t to) noexcept
{
- Q_ASSERT(offsets[from] != UnusedEntry);
- Q_ASSERT(offsets[to] == UnusedEntry);
+ Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
+ Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
offsets[to] = offsets[from];
- offsets[from] = UnusedEntry;
+ offsets[from] = SpanConstants::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);
+ Q_ASSERT(to < SpanConstants::NEntries);
+ Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
+ Q_ASSERT(fromIndex < SpanConstants::NEntries);
+ Q_ASSERT(fromSpan.offsets[fromIndex] != SpanConstants::UnusedEntry);
if (nextFree == allocated)
addStorage();
Q_ASSERT(nextFree < allocated);
@@ -388,7 +354,7 @@ struct Span {
nextFree = toEntry.nextFree();
size_t fromOffset = fromSpan.offsets[fromIndex];
- fromSpan.offsets[fromIndex] = UnusedEntry;
+ fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
Entry &fromEntry = fromSpan.entries[fromOffset];
if constexpr (isRelocatable<Node>()) {
@@ -403,15 +369,28 @@ struct Span {
void addStorage()
{
- Q_ASSERT(allocated < NEntries);
+ Q_ASSERT(allocated < SpanConstants::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;
+ // in here. More exactly, we have a binominal distribution of the amount of
+ // occupied entries.
+ // For a 25% filled table, the average is 32 entries, with a 95% chance that we have between
+ // 23 and 41 entries.
+ // For a 50% filled table, the average is 64 entries, with a 95% chance that we have between
+ // 53 and 75 entries.
+ // Since we only resize the table once it's 50% filled and we want to avoid copies of
+ // data where possible, we initially allocate 48 entries, then resize to 80 entries, after that
+ // resize by increments of 16. That way, we usually only get one resize of the table
+ // while filling it.
+ size_t alloc;
+ static_assert(SpanConstants::NEntries % 8 == 0);
+ if (!allocated)
+ alloc = SpanConstants::NEntries / 8 * 3;
+ else if (allocated == SpanConstants::NEntries / 8 * 3)
+ alloc = SpanConstants::NEntries / 8 * 5;
+ else
+ alloc = allocated + SpanConstants::NEntries/8;
Entry *newEntries = new Entry[alloc];
// we only add storage if the previous storage was fully filled, so
// simply copy the old data over
@@ -424,7 +403,7 @@ struct Span {
entries[i].node().~Node();
}
}
- for (size_t i = allocated; i < allocated + increment; ++i) {
+ for (size_t i = allocated; i < alloc; ++i) {
newEntries[i].nextFree() = uchar(i + 1);
}
delete[] entries;
@@ -435,28 +414,25 @@ struct Span {
// QHash uses a power of two growth policy.
namespace GrowthPolicy {
-inline constexpr size_t maxNumBuckets() noexcept
-{
- // ensure the size of a Span does not depend on the template parameters
- using Node1 = Node<int, int>;
- using Node2 = Node<char, void *>;
- using Node3 = Node<qsizetype, QHashDummyValue>;
- static_assert(sizeof(Span<Node1>) == sizeof(Span<Node2>));
- static_assert(sizeof(Span<Node1>) == sizeof(Span<Node3>));
- static_assert(int(Span<Node1>::NEntries) == int(Span<Node2>::NEntries));
- static_assert(int(Span<Node1>::NEntries) == int(Span<Node3>::NEntries));
-
- // Maximum is 2^31-1 or 2^63-1 bytes (limited by qsizetype and ptrdiff_t)
- size_t max = (std::numeric_limits<ptrdiff_t>::max)();
- return max / sizeof(Span<Node1>) * Span<Node1>::NEntries;
-}
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));
+ constexpr int SizeDigits = std::numeric_limits<size_t>::digits;
+
+ // We want to use at minimum a full span (128 entries), so we hardcode it for any requested
+ // capacity <= 64. Any capacity above that gets rounded to a later power of two.
+ if (requestedCapacity <= 64)
+ return SpanConstants::NEntries;
+
+ // Same as
+ // qNextPowerOfTwo(2 * requestedCapacity);
+ //
+ // but ensuring neither our multiplication nor the function overflow.
+ // Additionally, the maximum memory allocation is 2^31-1 or 2^63-1 bytes
+ // (limited by qsizetype and ptrdiff_t).
+ int count = qCountLeadingZeroBits(requestedCapacity);
+ if (count < 2)
+ return (std::numeric_limits<size_t>::max)(); // will cause std::bad_alloc
+ return size_t(1) << (SizeDigits - count + 1);
}
inline constexpr size_t bucketForHash(size_t nBuckets, size_t hash) noexcept
{
@@ -479,43 +455,148 @@ struct Data
size_t size = 0;
size_t numBuckets = 0;
size_t seed = 0;
+ Span *spans = nullptr;
+ static constexpr size_t maxNumBuckets() noexcept
+ {
+ return (std::numeric_limits<ptrdiff_t>::max)() / sizeof(Span);
+ }
- Span *spans = nullptr;
+ struct Bucket {
+ Span *span;
+ size_t index;
+
+ Bucket(Span *s, size_t i) noexcept
+ : span(s), index(i)
+ {}
+ Bucket(const Data *d, size_t bucket) noexcept
+ : span(d->spans + (bucket >> SpanConstants::SpanShift)),
+ index(bucket & SpanConstants::LocalBucketMask)
+ {}
+ Bucket(iterator it) noexcept
+ : Bucket(it.d, it.bucket)
+ {}
+
+ size_t toBucketIndex(const Data *d) const noexcept
+ {
+ return ((span - d->spans) << SpanConstants::SpanShift) | index;
+ }
+ iterator toIterator(const Data *d) const noexcept { return iterator{d, toBucketIndex(d)}; }
+ void advanceWrapped(const Data *d) noexcept
+ {
+ advance_impl(d, d->spans);
+ }
+ void advance(const Data *d) noexcept
+ {
+ advance_impl(d, nullptr);
+ }
+ bool isUnused() const noexcept
+ {
+ return !span->hasNode(index);
+ }
+ size_t offset() const noexcept
+ {
+ return span->offset(index);
+ }
+ Node &nodeAtOffset(size_t offset)
+ {
+ return span->atOffset(offset);
+ }
+ Node *node()
+ {
+ return &span->at(index);
+ }
+ Node *insert() const
+ {
+ return span->insert(index);
+ }
+
+ private:
+ friend bool operator==(Bucket lhs, Bucket rhs) noexcept
+ {
+ return lhs.span == rhs.span && lhs.index == rhs.index;
+ }
+ friend bool operator!=(Bucket lhs, Bucket rhs) noexcept { return !(lhs == rhs); }
+
+ void advance_impl(const Data *d, Span *whenAtEnd) noexcept
+ {
+ Q_ASSERT(span);
+ ++index;
+ if (Q_UNLIKELY(index == SpanConstants::NEntries)) {
+ index = 0;
+ ++span;
+ if (span - d->spans == ptrdiff_t(d->numBuckets >> SpanConstants::SpanShift))
+ span = whenAtEnd;
+ }
+ }
+ };
+
+ static auto allocateSpans(size_t numBuckets)
+ {
+ struct R {
+ Span *spans;
+ size_t nSpans;
+ };
+
+ constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() / sizeof(Span);
+ constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
+
+ if (numBuckets > MaxBucketCount) {
+ Q_CHECK_PTR(false);
+ Q_UNREACHABLE(); // no exceptions and no assertions -> no error reporting
+ }
+
+ size_t nSpans = numBuckets >> SpanConstants::SpanShift;
+ return R{ new Span[nSpans], nSpans };
+ }
Data(size_t reserve = 0)
{
numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
- size_t nSpans = (numBuckets + Span::LocalBucketMask) / Span::NEntries;
- spans = new Span[nSpans];
+ spans = allocateSpans(numBuckets).spans;
seed = QHashSeed::globalSeed();
}
- 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];
+ void reallocationHelper(const Data &other, size_t nSpans, bool resized)
+ {
for (size_t s = 0; s < nSpans; ++s) {
const Span &span = other.spans[s];
- for (size_t index = 0; index < Span::NEntries; ++index) {
+ for (size_t index = 0; index < SpanConstants::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 };
+ auto it = resized ? findBucket(n.key) : Bucket { spans + s, index };
Q_ASSERT(it.isUnused());
- Node *newNode = spans[it.span()].insert(it.index());
+ Node *newNode = it.insert();
new (newNode) Node(n);
}
}
}
- static Data *detached(Data *d, size_t size = 0)
+ Data(const Data &other) : size(other.size), numBuckets(other.numBuckets), seed(other.seed)
+ {
+ auto r = allocateSpans(numBuckets);
+ spans = r.spans;
+ reallocationHelper(other, r.nSpans, false);
+ }
+ Data(const Data &other, size_t reserved) : size(other.size), seed(other.seed)
+ {
+ numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
+ spans = allocateSpans(numBuckets).spans;
+ size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
+ reallocationHelper(other, otherNSpans, numBuckets != other.numBuckets);
+ }
+
+ static Data *detached(Data *d)
+ {
+ if (!d)
+ return new Data;
+ Data *dd = new Data(*d);
+ if (!d->ref.deref())
+ delete d;
+ return dd;
+ }
+ static Data *detached(Data *d, size_t size)
{
if (!d)
return new Data(size);
@@ -559,20 +640,19 @@ struct Data
Span *oldSpans = spans;
size_t oldBucketCount = numBuckets;
- size_t nSpans = (newBucketCount + Span::LocalBucketMask) / Span::NEntries;
- spans = new Span[nSpans];
+ spans = allocateSpans(newBucketCount).spans;
numBuckets = newBucketCount;
- size_t oldNSpans = (oldBucketCount + Span::LocalBucketMask) / Span::NEntries;
+ size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
for (size_t s = 0; s < oldNSpans; ++s) {
Span &span = oldSpans[s];
- for (size_t index = 0; index < Span::NEntries; ++index) {
+ for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
if (!span.hasNode(index))
continue;
Node &n = span.at(index);
- iterator it = find(n.key);
+ auto it = findBucket(n.key);
Q_ASSERT(it.isUnused());
- Node *newNode = spans[it.span()].insert(it.index());
+ Node *newNode = it.insert();
new (newNode) Node(std::move(n));
}
span.freeData();
@@ -597,39 +677,34 @@ struct Data
return size >= (numBuckets >> 1);
}
- iterator find(const Key &key) const noexcept
+ template <typename K> Bucket findBucket(const K &key) const noexcept
{
+ static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
+ QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
Q_ASSERT(numBuckets > 0);
size_t hash = QHashPrivate::calculateHash(key, seed);
- size_t bucket = GrowthPolicy::bucketForHash(numBuckets, hash);
+ Bucket bucket(this, 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 };
+ size_t offset = bucket.offset();
+ if (offset == SpanConstants::UnusedEntry) {
+ return bucket;
} else {
- Node &n = s.atOffset(offset);
+ Node &n = bucket.nodeAtOffset(offset);
if (qHashEquals(n.key, key))
- return iterator{ this, bucket };
+ return bucket;
}
- bucket = nextBucket(bucket);
+ bucket.advanceWrapped(this);
}
}
- Node *findNode(const Key &key) const noexcept
+ template <typename K> Node *findNode(const K &key) const noexcept
{
- if (!size)
- return nullptr;
- iterator it = find(key);
- if (it.isUnused())
+ auto bucket = findBucket(key);
+ if (bucket.isUnused())
return nullptr;
- return it.node();
+ return bucket.node();
}
struct InsertionResult
@@ -638,64 +713,58 @@ struct Data
bool initialized;
};
- InsertionResult findOrInsert(const Key &key) noexcept
+ template <typename K> InsertionResult findOrInsert(const K &key) noexcept
{
- if (shouldGrow())
+ Bucket it(static_cast<Span *>(nullptr), 0);
+ if (numBuckets > 0) {
+ it = findBucket(key);
+ if (!it.isUnused())
+ return { it.toIterator(this), true };
+ }
+ if (shouldGrow()) {
rehash(size + 1);
- iterator it = find(key);
- if (it.isUnused()) {
- spans[it.span()].insert(it.index());
- ++size;
- return { it, false };
+ it = findBucket(key); // need to get a new iterator after rehashing
}
- return { it, true };
+ Q_ASSERT(it.span != nullptr);
+ Q_ASSERT(it.isUnused());
+ it.insert();
+ ++size;
+ return { it.toIterator(this), false };
}
- iterator erase(iterator it) noexcept(std::is_nothrow_destructible<Node>::value)
+ void erase(Bucket bucket) 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);
+ Q_ASSERT(bucket.span->hasNode(bucket.index));
+ bucket.span->erase(bucket.index);
--size;
// re-insert the following entries to avoid holes
- size_t hole = bucket;
- size_t next = bucket;
+ Bucket 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 = QHashPrivate::calculateHash(spans[nextSpan].at(nextIndex).key, seed);
- size_t newBucket = GrowthPolicy::bucketForHash(numBuckets, hash);
+ next.advanceWrapped(this);
+ size_t offset = next.offset();
+ if (offset == SpanConstants::UnusedEntry)
+ return;
+ size_t hash = QHashPrivate::calculateHash(next.nodeAtOffset(offset).key, seed);
+ Bucket newBucket(this, 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 if (newBucket == bucket) {
+ // move into the hole we created earlier
+ if (next.span == bucket.span) {
+ bucket.span->moveLocal(next.index, bucket.index);
} else {
// move between spans, more expensive
- spans[holeSpan].moveFromSpan(spans[nextSpan], nextIndex, holeIndex);
+ bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
}
- hole = next;
+ bucket = next;
break;
}
- newBucket = nextBucket(newBucket);
+ newBucket.advanceWrapped(this);
}
}
-
- // return correct position of the next element
- if (bucket == numBuckets - 1 || !spans[span].hasNode(index))
- ++it;
- return it;
}
~Data()
@@ -711,8 +780,8 @@ struct iterator {
const Data<Node> *d = nullptr;
size_t bucket = 0;
- size_t span() const noexcept { return bucket / Span::NEntries; }
- size_t index() const noexcept { return bucket & Span::LocalBucketMask; }
+ size_t span() const noexcept { return bucket >> SpanConstants::SpanShift; }
+ size_t index() const noexcept { return bucket & SpanConstants::LocalBucketMask; }
inline bool isUnused() const noexcept { return !d->spans[span()].hasNode(index()); }
inline Node *node() const noexcept
@@ -828,11 +897,11 @@ public:
insert(f->first, f->second);
}
#endif
- void swap(QHash &other) noexcept { qSwap(d, other.d); }
+ void swap(QHash &other) noexcept { qt_ptr_swap(d, other.d); }
-#ifndef Q_CLANG_QDOC
- template <typename U = T>
- QTypeTraits::compare_eq_result_container<QHash, U> operator==(const QHash &other) const noexcept
+#ifndef Q_QDOC
+ template <typename AKey = Key, typename AT = T>
+ QTypeTraits::compare_eq_result_container<QHash, AKey, AT> operator==(const QHash &other) const noexcept
{
if (d == other.d)
return true;
@@ -847,13 +916,13 @@ public:
// all values must be the same as size is the same
return true;
}
- template <typename U = T>
- QTypeTraits::compare_eq_result_container<QHash, U> operator!=(const QHash &other) const noexcept
+ template <typename AKey = Key, typename AT = T>
+ QTypeTraits::compare_eq_result_container<QHash, AKey, AT> operator!=(const QHash &other) const noexcept
{ return !(*this == other); }
#else
bool operator==(const QHash &other) const;
bool operator!=(const QHash &other) const;
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
inline qsizetype size() const noexcept { return d ? qsizetype(d->size) : 0; }
inline bool isEmpty() const noexcept { return !d || d->size == 0; }
@@ -861,6 +930,9 @@ public:
inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
void reserve(qsizetype size)
{
+ // reserve(0) is used in squeeze()
+ if (size && (this->capacity() >= size))
+ return;
if (isDetached())
d->rehash(size);
else
@@ -885,28 +957,45 @@ public:
bool remove(const Key &key)
{
+ return removeImpl(key);
+ }
+private:
+ template <typename K> bool removeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return false;
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
- auto it = d->find(key);
if (it.isUnused())
return false;
d->erase(it);
return true;
}
+
+public:
template <typename Predicate>
qsizetype removeIf(Predicate pred)
{
return QtPrivate::associative_erase_if(*this, pred);
}
+
T take(const Key &key)
{
+ return takeImpl(key);
+ }
+private:
+ template <typename K> T takeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return T();
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
- auto it = d->find(key);
if (it.isUnused())
return T();
T value = it.node()->takeValue();
@@ -914,6 +1003,7 @@ public:
return value;
}
+public:
bool contains(const Key &key) const noexcept
{
if (!d)
@@ -925,7 +1015,8 @@ public:
return contains(key) ? 1 : 0;
}
- Key key(const T &value, const Key &defaultKey = Key()) const noexcept
+private:
+ template <typename Fn> Key keyImpl(const T &value, Fn &&defaultFn) const noexcept
{
if (d) {
const_iterator i = begin();
@@ -936,27 +1027,57 @@ public:
}
}
- return defaultKey;
+ return defaultFn();
+ }
+
+public:
+ Key key(const T &value) const noexcept
+ {
+ return keyImpl(value, [] { return Key(); });
+ }
+ Key key(const T &value, const Key &defaultKey) const noexcept
+ {
+ return keyImpl(value, [&] { return defaultKey; });
}
- T value(const Key &key, const T &defaultValue = T()) const noexcept
+
+private:
+ template <typename K, typename Fn> T valueImpl(const K &key, Fn &&defaultValue) const noexcept
{
if (d) {
Node *n = d->findNode(key);
if (n)
return n->value;
}
- return defaultValue;
+ return defaultValue();
}
+public:
+ T value(const Key &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+
+ T value(const Key &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
+ }
+
T &operator[](const Key &key)
{
+ return operatorIndexImpl(key);
+ }
+private:
+ template <typename K> T &operatorIndexImpl(const K &key)
+ {
+ const auto copy = isDetached() ? QHash() : *this; // keep 'key' alive across the detach
detach();
auto result = d->findOrInsert(key);
Q_ASSERT(!result.it.atEnd());
if (!result.initialized)
- Node::createInPlace(result.it.node(), key, T());
+ Node::createInPlace(result.it.node(), Key(key), T());
return result.it.node()->value;
}
+public:
const T operator[](const Key &key) const noexcept
{
return value(key);
@@ -1104,6 +1225,10 @@ public:
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()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator erase(const_iterator it)
{
@@ -1111,50 +1236,65 @@ public:
detach();
// ensure a valid iterator across the detach:
iterator i = iterator{d->detachedIterator(it.i)};
+ typename Data::Bucket bucket(i.i);
- i.i = d->erase(i.i);
+ d->erase(bucket);
+ if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
+ ++i;
return i;
}
- QPair<iterator, iterator> equal_range(const Key &key)
+ std::pair<iterator, iterator> equal_range(const Key &key)
{
- auto first = find(key);
- auto second = first;
- if (second != iterator())
- ++second;
- return qMakePair(first, second);
+ return equal_range_impl(*this, key);
}
-
- QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
{
- auto first = find(key);
+ return equal_range_impl(*this, key);
+ }
+private:
+ template <typename Hash, typename K> static auto equal_range_impl(Hash &self, const K &key)
+ {
+ auto first = self.find(key);
auto second = first;
- if (second != iterator())
+ if (second != decltype(first){})
++second;
- return qMakePair(first, second);
+ return std::make_pair(first, second);
}
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
- iterator find(const Key &key)
+ template <typename K> iterator findImpl(const K &key)
{
if (isEmpty()) // prevents detaching shared null
return end();
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
- auto it = d->find(key);
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
if (it.isUnused())
- it = d->end();
- return iterator(it);
+ return end();
+ return iterator(it.toIterator(d));
}
- const_iterator find(const Key &key) const noexcept
+ template <typename K> const_iterator constFindImpl(const K &key) const noexcept
{
if (isEmpty())
return end();
- auto it = d->find(key);
+ auto it = d->findBucket(key);
if (it.isUnused())
- it = d->end();
- return const_iterator(it);
+ return end();
+ return const_iterator({d, it.toBucketIndex(d)});
+ }
+
+public:
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
+ iterator find(const Key &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator find(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
}
const_iterator constFind(const Key &key) const noexcept
{
@@ -1190,8 +1330,28 @@ public:
template <typename ...Args>
iterator emplace(Key &&key, Args &&... args)
{
+ if (isDetached()) {
+ if (d->shouldGrow()) // Construct the value now so that no dangling references are used
+ return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
+ return emplace_helper(std::move(key), std::forward<Args>(args)...);
+ }
+ // else: we must detach
+ const auto copy = *this; // keep 'args' alive across the detach/growth
detach();
+ return emplace_helper(std::move(key), std::forward<Args>(args)...);
+ }
+
+ 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 Data::maxNumBuckets(); }
+ inline bool empty() const noexcept { return isEmpty(); }
+
+private:
+ template <typename ...Args>
+ iterator emplace_helper(Key &&key, Args &&... args)
+ {
auto result = d->findOrInsert(key);
if (!result.initialized)
Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
@@ -1200,16 +1360,66 @@ public:
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(); }
+public:
+#ifdef __cpp_concepts
+ bool remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
+ }
+ T take(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return takeImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return d ? d->findNode(key) != nullptr : false;
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return contains(key) ? 1 : 0;
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
+ }
+ T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return operatorIndexImpl(key);
+ }
+ const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return value(key);
+ }
+ std::pair<iterator, iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return equal_range_impl(*this, key);
+ }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return equal_range_impl(*this, key);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return find(key);
+ }
+#endif // __cpp_concepts
};
-
template <typename Key, typename T>
class QMultiHash
{
@@ -1285,8 +1495,8 @@ public:
return *this;
}
QMultiHash(QMultiHash &&other) noexcept
- : d(qExchange(other.d, nullptr)),
- m_size(qExchange(other.m_size, 0))
+ : d(std::exchange(other.d, nullptr)),
+ m_size(std::exchange(other.m_size, 0))
{
}
QMultiHash &operator=(QMultiHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
@@ -1304,9 +1514,16 @@ public:
{
unite(std::move(other));
}
- void swap(QMultiHash &other) noexcept { qSwap(d, other.d); qSwap(m_size, other.m_size); }
- bool operator==(const QMultiHash &other) const noexcept
+ void swap(QMultiHash &other) noexcept
+ {
+ qt_ptr_swap(d, other.d);
+ std::swap(m_size, other.m_size);
+ }
+
+#ifndef Q_QDOC
+ template <typename AKey = Key, typename AT = T>
+ QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> operator==(const QMultiHash &other) const noexcept
{
if (d == other.d)
return true;
@@ -1320,12 +1537,12 @@ public:
if (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())
+ auto *n = d->findNode(it.node()->key);
+ if (!n)
return false;
Chain *e = it.node()->value;
while (e) {
- Chain *oe = i.node()->value;
+ Chain *oe = n->value;
while (oe) {
if (oe->value == e->value)
break;
@@ -1339,7 +1556,13 @@ public:
// all values must be the same as size is the same
return true;
}
- bool operator!=(const QMultiHash &other) const noexcept { return !(*this == other); }
+ template <typename AKey = Key, typename AT = T>
+ QTypeTraits::compare_eq_result_container<QMultiHash, AKey, AT> operator!=(const QMultiHash &other) const noexcept
+ { return !(*this == other); }
+#else
+ bool operator==(const QMultiHash &other) const;
+ bool operator!=(const QMultiHash &other) const;
+#endif // Q_QDOC
inline qsizetype size() const noexcept { return m_size; }
@@ -1348,6 +1571,9 @@ public:
inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
void reserve(qsizetype size)
{
+ // reserve(0) is used in squeeze()
+ if (size && (this->capacity() >= size))
+ return;
if (isDetached())
d->rehash(size);
else
@@ -1369,11 +1595,18 @@ public:
qsizetype remove(const Key &key)
{
+ return removeImpl(key);
+ }
+private:
+ template <typename K> qsizetype removeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return 0;
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
- auto it = d->find(key);
if (it.isUnused())
return 0;
qsizetype n = Node::freeChain(it.node());
@@ -1382,18 +1615,28 @@ public:
d->erase(it);
return n;
}
+
+public:
template <typename Predicate>
qsizetype removeIf(Predicate pred)
{
return QtPrivate::associative_erase_if(*this, pred);
}
+
T take(const Key &key)
{
+ return takeImpl(key);
+ }
+private:
+ template <typename K> T takeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return T();
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
- auto it = d->find(key);
if (it.isUnused())
return T();
Chain *e = it.node()->value;
@@ -1411,6 +1654,7 @@ public:
return t;
}
+public:
bool contains(const Key &key) const noexcept
{
if (!d)
@@ -1418,7 +1662,8 @@ public:
return d->findNode(key) != nullptr;
}
- Key key(const T &value, const Key &defaultKey = Key()) const noexcept
+private:
+ template <typename Fn> Key keyImpl(const T &value, Fn &&defaultValue) const noexcept
{
if (d) {
auto i = d->begin();
@@ -1430,9 +1675,20 @@ public:
}
}
- return defaultKey;
+ return defaultValue();
+ }
+public:
+ Key key(const T &value) const noexcept
+ {
+ return keyImpl(value, [] { return Key(); });
+ }
+ Key key(const T &value, const Key &defaultKey) const noexcept
+ {
+ return keyImpl(value, [&] { return defaultKey; });
}
- T value(const Key &key, const T &defaultValue = T()) const noexcept
+
+private:
+ template <typename K, typename Fn> T valueImpl(const K &key, Fn &&defaultValue) const noexcept
{
if (d) {
Node *n = d->findNode(key);
@@ -1441,19 +1697,37 @@ public:
return n->value->value;
}
}
- return defaultValue;
+ return defaultValue();
+ }
+public:
+ T value(const Key &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+ T value(const Key &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
}
T &operator[](const Key &key)
{
+ return operatorIndexImpl(key);
+ }
+private:
+ template <typename K> T &operatorIndexImpl(const K &key)
+ {
+ const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
detach();
auto result = d->findOrInsert(key);
Q_ASSERT(!result.it.atEnd());
- if (!result.initialized)
- Node::createInPlace(result.it.node(), key, T());
+ if (!result.initialized) {
+ Node::createInPlace(result.it.node(), Key(key), T());
+ ++m_size;
+ }
return result.it.node()->value->value;
}
+public:
const T operator[](const Key &key) const noexcept
{
return value(key);
@@ -1484,9 +1758,15 @@ public:
}
return res;
}
+
QList<T> values() const { return QList<T>(begin(), end()); }
QList<T> values(const Key &key) const
{
+ return valuesImpl(key);
+ }
+private:
+ template <typename K> QList<T> valuesImpl(const K &key) const
+ {
QList<T> values;
if (d) {
Node *n = d->findNode(key);
@@ -1501,6 +1781,7 @@ public:
return values;
}
+public:
class const_iterator;
class iterator
@@ -1650,6 +1931,10 @@ public:
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()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator detach(const_iterator it)
{
@@ -1680,7 +1965,8 @@ public:
iterator erase(const_iterator it)
{
Q_ASSERT(d);
- iterator i = detach(it);
+ iterator iter = detach(it);
+ iterator i = iter;
Chain *e = *i.e;
Chain *next = e->next;
*i.e = next;
@@ -1688,9 +1974,14 @@ public:
if (!next) {
if (i.e == &i.i.node()->value) {
// last remaining entry, erase
- i = iterator(d->erase(i.i));
+ typename Data::Bucket bucket(i.i);
+ d->erase(bucket);
+ if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
+ i = iterator(++iter.i);
+ else // 'i' currently has a nullptr chain. So, we must recreate it
+ i = iterator(bucket.toIterator(d));
} else {
- i = iterator(++it.i);
+ i = iterator(++iter.i);
}
}
--m_size;
@@ -1702,29 +1993,44 @@ public:
typedef iterator Iterator;
typedef const_iterator ConstIterator;
inline qsizetype count() const noexcept { return size(); }
- iterator find(const Key &key)
+
+private:
+ template <typename K> iterator findImpl(const K &key)
{
if (isEmpty())
return end();
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
- auto it = d->find(key);
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
+
if (it.isUnused())
- it = d->end();
- return iterator(it);
- }
- const_iterator find(const Key &key) const noexcept
- {
- return constFind(key);
+ return end();
+ return iterator(it.toIterator(d));
}
- const_iterator constFind(const Key &key) const noexcept
+ template <typename K> const_iterator constFindImpl(const K &key) const noexcept
{
if (isEmpty())
return end();
- auto it = d->find(key);
+ auto it = d->findBucket(key);
if (it.isUnused())
- it = d->end();
- return const_iterator(it);
+ return constEnd();
+ return const_iterator(it.toIterator(d));
+ }
+public:
+ iterator find(const Key &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator constFind(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator find(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
}
+
iterator insert(const Key &key, const T &value)
{
return emplace(key, value);
@@ -1739,22 +2045,22 @@ public:
template <typename ...Args>
iterator emplace(Key &&key, Args &&... args)
{
+ if (isDetached()) {
+ if (d->shouldGrow()) // Construct the value now so that no dangling references are used
+ return emplace_helper(std::move(key), T(std::forward<Args>(args)...));
+ return emplace_helper(std::move(key), std::forward<Args>(args)...);
+ }
+ // else: we must detach
+ const auto copy = *this; // keep 'args' alive across the detach/growth
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);
+ return emplace_helper(std::move(key), std::forward<Args>(args)...);
}
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(); }
+ static size_t max_bucket_count() noexcept { return Data::maxNumBuckets(); }
inline bool empty() const noexcept { return isEmpty(); }
@@ -1772,16 +2078,15 @@ public:
template <typename ...Args>
iterator emplaceReplace(Key &&key, Args &&... args)
{
- detach();
-
- 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)...);
+ if (isDetached()) {
+ if (d->shouldGrow()) // Construct the value now so that no dangling references are used
+ return emplaceReplace_helper(std::move(key), T(std::forward<Args>(args)...));
+ return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
}
- return iterator(result.it);
+ // else: we must detach
+ const auto copy = *this; // keep 'args' alive across the detach/growth
+ detach();
+ return emplaceReplace_helper(std::move(key), std::forward<Args>(args)...);
}
inline QMultiHash &operator+=(const QMultiHash &other)
@@ -1791,6 +2096,11 @@ public:
bool contains(const Key &key, const T &value) const noexcept
{
+ return containsImpl(key, value);
+ }
+private:
+ template <typename K> bool containsImpl(const K &key, const T &value) const noexcept
+ {
if (isEmpty())
return false;
auto n = d->findNode(key);
@@ -1799,13 +2109,21 @@ public:
return n->value->contains(value);
}
+public:
qsizetype remove(const Key &key, const T &value)
{
+ return removeImpl(key, value);
+ }
+private:
+ template <typename K> qsizetype removeImpl(const K &key, const T &value)
+ {
if (isEmpty()) // prevents detaching shared null
return 0;
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
detach();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
- auto it = d->find(key);
if (it.isUnused())
return 0;
qsizetype n = 0;
@@ -1827,11 +2145,17 @@ public:
return n;
}
+public:
qsizetype count(const Key &key) const noexcept
{
+ return countImpl(key);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key) const noexcept
+ {
if (!d)
return 0;
- auto it = d->find(key);
+ auto it = d->findBucket(key);
if (it.isUnused())
return 0;
qsizetype n = 0;
@@ -1844,11 +2168,17 @@ public:
return n;
}
+public:
qsizetype count(const Key &key, const T &value) const noexcept
{
+ return countImpl(key, value);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key, const T &value) const noexcept
+ {
if (!d)
return 0;
- auto it = d->find(key);
+ auto it = d->findBucket(key);
if (it.isUnused())
return 0;
qsizetype n = 0;
@@ -1862,19 +2192,16 @@ public:
return n;
}
- iterator find(const Key &key, const T &value)
+ template <typename K> iterator findImpl(const K &key, const T &value)
{
if (isEmpty())
return end();
+ const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key'/'value' alive across the detach
detach();
auto it = constFind(key, value);
return iterator(it.i, it.e);
}
- 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
+ template <typename K> const_iterator constFindImpl(const K &key, const T &value) const noexcept
{
const_iterator i(constFind(key));
const_iterator end(constEnd());
@@ -1886,6 +2213,21 @@ public:
return end;
}
+public:
+ iterator find(const Key &key, const T &value)
+ {
+ return findImpl(key, value);
+ }
+
+ const_iterator constFind(const Key &key, const T &value) const noexcept
+ {
+ return constFindImpl(key, value);
+ }
+ const_iterator find(const Key &key, const T &value) const noexcept
+ {
+ return constFind(key, value);
+ }
+
QMultiHash &unite(const QMultiHash &other)
{
if (isEmpty()) {
@@ -1921,27 +2263,39 @@ public:
return *this;
}
- QPair<iterator, iterator> equal_range(const Key &key)
+ std::pair<iterator, iterator> equal_range(const Key &key)
+ {
+ return equal_range_impl(key);
+ }
+private:
+ template <typename K> std::pair<iterator, iterator> equal_range_impl(const K &key)
{
+ const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
detach();
- auto pair = qAsConst(*this).equal_range(key);
- return qMakePair(iterator(pair.first.i), iterator(pair.second.i));
+ auto pair = std::as_const(*this).equal_range(key);
+ return {iterator(pair.first.i), iterator(pair.second.i)};
}
- QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+public:
+ std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ {
+ return equal_range_impl(key);
+ }
+private:
+ template <typename K> std::pair<const_iterator, const_iterator> equal_range_impl(const K &key) const noexcept
{
if (!d)
- return qMakePair(end(), end());
+ return {end(), end()};
- auto it = d->find(key);
- if (it.isUnused())
- return qMakePair(end(), end());
+ auto bucket = d->findBucket(key);
+ if (bucket.isUnused())
+ return {end(), end()};
+ auto it = bucket.toIterator(d);
auto end = it;
++end;
- return qMakePair(const_iterator(it), const_iterator(end));
+ return {const_iterator(it), const_iterator(end)};
}
-private:
void detach_helper()
{
if (!d) {
@@ -1953,6 +2307,119 @@ private:
delete d;
d = dd;
}
+
+ template<typename... Args>
+ iterator emplace_helper(Key &&key, Args &&...args)
+ {
+ 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);
+ }
+
+ template<typename... Args>
+ iterator emplaceReplace_helper(Key &&key, Args &&...args)
+ {
+ auto result = d->findOrInsert(key);
+ if (!result.initialized) {
+ Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
+ ++m_size;
+ } else {
+ result.it.node()->emplaceValue(std::forward<Args>(args)...);
+ }
+ return iterator(result.it);
+ }
+
+public:
+#ifdef __cpp_concepts
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
+ }
+ T take(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return takeImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
+ }
+ T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return operatorIndexImpl(key);
+ }
+ const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return value(key);
+ }
+ QList<T> values(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return valuesImpl(key);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return containsImpl(key, value);
+ }
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
+ {
+ return removeImpl(key, value);
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return countImpl(key);
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return countImpl(key, value);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
+ {
+ return findImpl(key, value);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return constFindImpl(key, value);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return constFind(key, value);
+ }
+ std::pair<iterator, iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return equal_range_impl(key);
+ }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return equal_range_impl(key);
+ }
+#endif // __cpp_concepts
};
Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index 4f8e4066ee..90a269deaa 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -1,51 +1,21 @@
-/****************************************************************************
-**
-** 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>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHASHFUNCTIONS_H
#define QHASHFUNCTIONS_H
#include <QtCore/qstring.h>
-#include <QtCore/qpair.h>
+#include <QtCore/qstringfwd.h>
#include <numeric> // for std::accumulate
#include <functional> // for std::hash
+#include <utility> // For std::pair
+
+#ifdef __cpp_concepts
+# include <concepts>
+#endif
#if 0
#pragma qt_class(QHashFunctions)
@@ -60,9 +30,6 @@
QT_BEGIN_NAMESPACE
class QBitArray;
-class QByteArray;
-class QString;
-class QLatin1String;
#if QT_DEPRECATED_SINCE(6,6)
QT_DEPRECATED_VERSION_X_6_6("Use QHashSeed instead")
@@ -76,13 +43,28 @@ struct QHashSeed
constexpr QHashSeed(size_t d = 0) : data(d) {}
constexpr operator size_t() const noexcept { return data; }
- static Q_CORE_EXPORT QHashSeed globalSeed() noexcept Q_DECL_PURE_FUNCTION;
+ static Q_CORE_EXPORT QHashSeed globalSeed() noexcept;
static Q_CORE_EXPORT void setDeterministicGlobalSeed();
static Q_CORE_EXPORT void resetRandomGlobalSeed();
private:
size_t data;
};
+// Whether, ∀ t of type T && ∀ seed, qHash(Key(t), seed) == qHash(t, seed)
+template <typename Key, typename T> struct QHashHeterogeneousSearch : std::false_type {};
+
+// Specializations
+template <> struct QHashHeterogeneousSearch<QString, QStringView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QStringView, QString> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QByteArray, QByteArrayView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QByteArrayView, QByteArray> : std::true_type {};
+#ifndef Q_PROCESSOR_ARM
+template <> struct QHashHeterogeneousSearch<QString, QLatin1StringView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QStringView, QLatin1StringView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QLatin1StringView, QString> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QLatin1StringView, QStringView> : std::true_type {};
+#endif
+
namespace QHashPrivate {
Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
@@ -106,14 +88,6 @@ Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
}
}
-template <typename T, typename = void>
-constexpr inline bool HasQHashSingleArgOverload = false;
-
-template <typename T>
-constexpr inline bool HasQHashSingleArgOverload<T, std::enable_if_t<
- std::is_convertible_v<decltype(qHash(std::declval<const T &>())), size_t>
->> = true;
-
template <typename T1, typename T2> static constexpr bool noexceptPairHash();
}
@@ -148,7 +122,39 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(quint64 key, size_t seed = 0
key ^= (key >> 32);
return QHashPrivate::hash(size_t(key), seed);
}
-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 constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept
+{
+ if constexpr (sizeof(qint64) > sizeof(size_t)) {
+ // Avoid QTBUG-116080: we XOR the top half with its own sign bit:
+ // - if the qint64 is in range of qint32, then signmask ^ high == 0
+ // (for Qt 7 only)
+ // - if the qint64 is in range of quint32, then signmask == 0 and we
+ // do the same as the quint64 overload above
+ quint32 high = quint32(quint64(key) >> 32);
+ quint32 low = quint32(quint64(key));
+ quint32 signmask = qint32(high) >> 31; // all zeroes or all ones
+ signmask = QT_VERSION_MAJOR > 6 ? signmask : 0;
+ low ^= signmask ^ high;
+ return qHash(low, seed);
+ }
+ return qHash(quint64(key), seed);
+}
+#if QT_SUPPORTS_INT128
+constexpr size_t qHash(quint128 key, size_t seed = 0) noexcept
+{
+ return qHash(quint64(key + (key >> 64)), seed);
+}
+constexpr size_t qHash(qint128 key, size_t seed = 0) noexcept
+{
+ // Avoid QTBUG-116080: same as above, but with double the sizes and without
+ // the need for compatibility
+ quint64 high = quint64(quint128(key) >> 64);
+ quint64 low = quint64(quint128(key));
+ quint64 signmask = qint64(high) >> 63; // all zeroes or all ones
+ low += signmask ^ high;
+ return qHash(low, seed);
+}
+#endif // QT_SUPPORTS_INT128
Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
{
// ensure -0 gets mapped to 0
@@ -158,9 +164,7 @@ Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
return QHashPrivate::hash(k, seed);
}
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 size_t qHash(long double key, size_t seed = 0) noexcept;
-#endif
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(wchar_t key, size_t seed = 0) noexcept
{ return QHashPrivate::hash(size_t(key), seed); }
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char16_t key, size_t seed = 0) noexcept
@@ -179,18 +183,30 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed
{
return seed;
}
+template <class Enum, std::enable_if_t<std::is_enum_v<Enum>, bool> = true>
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(Enum e, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(qToUnderlying(e), seed); }
// (some) Qt types
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(const QChar key, size_t seed = 0) noexcept { return qHash(key.unicode(), seed); }
+
+#if QT_CORE_REMOVED_SINCE(6, 4)
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0) noexcept;
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QByteArrayView &key, size_t seed = 0) noexcept;
+#else
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QByteArrayView key, size_t seed = 0) noexcept;
+inline Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0
+ QT6_DECL_NEW_OVERLOAD_TAIL) noexcept
+{ return qHash(qToByteArrayViewIgnoringNull(key), seed); }
+#endif
+
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept;
-#if QT_STRINGVIEW_LEVEL < 2
inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept
{ return qHash(QStringView{key}, seed); }
-#endif
+#ifndef QT_BOOTSTRAPPED
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;
+#endif
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1StringView key, size_t seed = 0) noexcept;
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QKeyCombination key, size_t seed = 0) noexcept
{ return qHash(key.toCombined(), seed); }
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) noexcept;
@@ -199,9 +215,42 @@ template <typename Enum>
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QFlags<Enum> flags, size_t seed = 0) noexcept
{ return qHash(flags.toInt(), seed); }
-template <typename T, std::enable_if_t<QHashPrivate::HasQHashSingleArgOverload<T>, bool> = true>
+// ### Qt 7: remove this "catch-all" overload logic, and require users
+// to provide the two-argument version of qHash.
+#if (QT_VERSION < QT_VERSION_CHECK(7, 0, 0))
+// Beware of moving this code from here. It needs to see all the
+// declarations of qHash overloads for C++ fundamental types *before*
+// its own declaration.
+namespace QHashPrivate {
+template <typename T, typename = void>
+constexpr inline bool HasQHashSingleArgOverload = false;
+
+template <typename T>
+constexpr inline bool HasQHashSingleArgOverload<T, std::enable_if_t<
+ std::is_convertible_v<decltype(qHash(std::declval<const T &>())), size_t>
+>> = true;
+}
+
+template <typename T, std::enable_if_t<QHashPrivate::HasQHashSingleArgOverload<T> && !std::is_enum_v<T>, bool> = true>
size_t qHash(const T &t, size_t seed) noexcept(noexcept(qHash(t)))
{ return qHash(t) ^ seed; }
+#endif // < Qt 7
+
+namespace QHashPrivate {
+#ifdef __cpp_concepts
+template <typename Key, typename T> concept HeterogeneouslySearchableWithHelper =
+ // if Key and T are not the same (member already exists)
+ !std::is_same_v<Key, T>
+ // but are comparable amongst each other
+ && std::equality_comparable_with<Key, T>
+ // and supports heteregenous hashing
+ && QHashHeterogeneousSearch<Key, T>::value;
+template <typename Key, typename T> concept HeterogeneouslySearchableWith =
+ HeterogeneouslySearchableWithHelper<q20::remove_cvref_t<Key>, q20::remove_cvref_t<T>>;
+#else
+template <typename Key, typename T> constexpr bool HeterogeneouslySearchableWith = false;
+#endif
+}
template<typename T>
bool qHashEquals(const T &a, const T &b)
@@ -209,6 +258,13 @@ bool qHashEquals(const T &a, const T &b)
return a == b;
}
+template <typename T1, typename T2>
+std::enable_if_t<QHashPrivate::HeterogeneouslySearchableWith<T1, T2>, bool>
+qHashEquals(const T1 &a, const T2 &b)
+{
+ return a == b;
+}
+
namespace QtPrivate {
struct QHashCombine
@@ -251,6 +307,9 @@ struct QNothrowHashable : std::false_type {};
template <typename T>
struct QNothrowHashable<T, std::enable_if_t<QNothrowHashableHelper_v<T>>> : std::true_type {};
+template <typename T>
+constexpr inline bool QNothrowHashable_v = QNothrowHashable<T>::value;
+
} // namespace QtPrivate
template <typename... T>
@@ -317,15 +376,15 @@ template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2>
using argument_type = QT_PREPEND_NAMESPACE(Class); \
using result_type = size_t; \
size_t operator()(Arguments s) const \
- noexcept(noexcept(QT_PREPEND_NAMESPACE(qHash)(s))) \
+ noexcept(QT_PREPEND_NAMESPACE( \
+ QtPrivate::QNothrowHashable_v)<argument_type>) \
{ \
/* this seeds qHash with the result of */ \
/* std::hash applied to an int, to reap */ \
/* any protection against predictable hash */ \
/* values the std implementation may provide */ \
- return QT_PREPEND_NAMESPACE(qHash)(s, \
- QT_PREPEND_NAMESPACE(qHash)( \
- std::hash<int>{}(0))); \
+ using QT_PREPEND_NAMESPACE(qHash); \
+ return qHash(s, qHash(std::hash<int>{}(0))); \
} \
}; \
} \
@@ -339,9 +398,12 @@ template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2>
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QString)
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QStringView)
-QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QLatin1String)
+QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QLatin1StringView)
+QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QByteArrayView)
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QByteArray)
+#ifndef QT_BOOTSTRAPPED
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QBitArray)
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h
index 8922f34758..8a2b493ef4 100644
--- a/src/corelib/tools/qiterator.h
+++ b/src/corelib/tools/qiterator.h
@@ -1,51 +1,23 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QITERATOR_H
#define QITERATOR_H
#include <QtCore/qglobal.h>
+#include <QtCore/qcontainertools_impl.h>
QT_BEGIN_NAMESPACE
#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
+#ifdef Q_QDOC
+#define Q_DISABLE_BACKWARD_ITERATOR
+#else
+#define Q_DISABLE_BACKWARD_ITERATOR \
+ template<typename It = decltype(i), QtPrivate::IfIteratorCanMoveBackwards<It> = true>
+#endif
+
#define Q_DECLARE_SEQUENTIAL_ITERATOR(C) \
\
template <class T> \
@@ -64,11 +36,15 @@ public: \
inline bool hasNext() const { return i != c.constEnd(); } \
inline const T &next() { return *i++; } \
inline const T &peekNext() const { return *i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return i != c.constBegin(); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline const T &previous() { return *--i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline const T &peekPrevious() const { const_iterator p = i; return *--p; } \
inline bool findNext(const T &t) \
{ while (i != c.constEnd()) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (i != c.constBegin()) if (*(--i) == t) return true; \
return false; } \
@@ -95,8 +71,11 @@ public: \
inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
inline T &next() { n = i++; return *n; } \
inline T &peekNext() const { return *i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline T &previous() { n = --i; return *n; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline T &peekPrevious() const { iterator p = i; return *--p; } \
inline void remove() \
{ if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } } \
@@ -106,6 +85,7 @@ public: \
inline void insert(const T &t) { n = i = c->insert(i, t); ++i; } \
inline bool findNext(const T &t) \
{ while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true; \
n = c->end(); return false; } \
@@ -131,13 +111,17 @@ public: \
inline bool hasNext() const { return i != c.constEnd(); } \
inline Item next() { n = i++; return n; } \
inline Item peekNext() const { return i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return i != c.constBegin(); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item previous() { n = --i; return n; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item peekPrevious() const { const_iterator p = i; return --p; } \
inline const T &value() const { Q_ASSERT(item_exists()); return *n; } \
inline const Key &key() const { Q_ASSERT(item_exists()); return n.key(); } \
inline bool findNext(const T &t) \
{ while ((n = i) != c.constEnd()) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (i != c.constBegin()) if (*(n = --i) == t) return true; \
n = c.constEnd(); return false; } \
@@ -165,8 +149,11 @@ public: \
inline bool hasNext() const { return const_iterator(i) != c->constEnd(); } \
inline Item next() { n = i++; return n; } \
inline Item peekNext() const { return i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return const_iterator(i) != c->constBegin(); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item previous() { n = --i; return n; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item peekPrevious() const { iterator p = i; return --p; } \
inline void remove() \
{ if (const_iterator(n) != c->constEnd()) { i = c->erase(n); n = c->end(); } } \
@@ -176,6 +163,7 @@ public: \
inline const Key &key() const { Q_ASSERT(item_exists()); return n.key(); } \
inline bool findNext(const T &t) \
{ while (const_iterator(n = i) != c->constEnd()) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (const_iterator(i) != c->constBegin()) if (*(n = --i) == t) return true; \
n = c->end(); return false; } \
@@ -266,26 +254,10 @@ public:
return std::pair<Key, T>(i.key(), i.value());
}
- struct pointer
- {
- pointer(value_type &&r_) : r(std::move(r_)) { }
-
- pointer() = default;
- pointer(const pointer &other) = default;
- pointer(pointer &&other) = default;
- pointer &operator=(const pointer &other) = default;
- pointer &operator=(pointer &&other) = default;
-
- value_type &operator*() const { return r; }
-
- value_type r;
- const value_type *operator->() const {
- return &r;
- }
- };
+ using pointer = QtPrivate::ArrowProxy<value_type>;
pointer operator->() const {
- return pointer(std::pair<Key, T>(i.key(), i.value()));
+ return pointer{std::pair<Key, T>(i.key(), i.value())};
}
friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i == rhs.i; }
@@ -301,6 +273,47 @@ private:
Iterator i;
};
+namespace QtPrivate {
+
+template <typename Map>
+class QKeyValueRangeStorage
+{
+protected:
+ Map m_map;
+public:
+ explicit QKeyValueRangeStorage(const Map &map) : m_map(map) {}
+ explicit QKeyValueRangeStorage(Map &&map) : m_map(std::move(map)) {}
+};
+
+template <typename Map>
+class QKeyValueRangeStorage<Map &>
+{
+protected:
+ Map &m_map;
+public:
+ explicit QKeyValueRangeStorage(Map &map) : m_map(map) {}
+};
+
+template <typename Map>
+class QKeyValueRange : public QKeyValueRangeStorage<Map>
+{
+public:
+ using QKeyValueRangeStorage<Map>::QKeyValueRangeStorage;
+ auto begin() { return this->m_map.keyValueBegin(); }
+ auto begin() const { return this->m_map.keyValueBegin(); }
+ auto end() { return this->m_map.keyValueEnd(); }
+ auto end() const { return this->m_map.keyValueEnd(); }
+};
+
+template <typename Map>
+QKeyValueRange(Map &) -> QKeyValueRange<Map &>;
+
+template <typename Map, std::enable_if_t<!std::is_reference_v<Map>, bool> = false>
+QKeyValueRange(Map &&) -> QKeyValueRange<std::remove_const_t<Map>>;
+
+} // namespace QtPrivate
+
+
QT_END_NAMESPACE
#endif // QITERATOR_H
diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc
index 1ba5b66318..041fb0701d 100644
--- a/src/corelib/tools/qiterator.qdoc
+++ b/src/corelib/tools/qiterator.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! \class QKeyValueIterator
\inmodule QtCore
@@ -108,7 +84,7 @@
/*!
\fn template<typename Key, typename T, class Iterator> QKeyValueIterator &QKeyValueIterator<Key, T, Iterator>::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the container and returns the iterator.
\note Advancing the iterator past its container's end() constitutes
@@ -121,7 +97,7 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} operator (\c{i++}) advances the iterator to the
next item in the container and returns the iterator's prior value.
\note Advancing the iterator past its container's end() constitutes
@@ -130,7 +106,7 @@
/*! \fn template<typename Key, typename T, class Iterator> QKeyValueIterator &QKeyValueIterator<Key, T, Iterator>::operator--()
- The prefix -- operator (\c{--i}) backs the iterator up to the previous item
+ The prefix c{--} operator (\c{--i}) backs the iterator up to the previous item
in the container and returns the iterator.
\note Backing up an iterator to before its container's begin() constitutes
@@ -143,7 +119,7 @@
\overload
- The postfix -- operator (\c{i--}) backs the iterator up to the previous item
+ The postfix c{--} operator (\c{i--}) backs the iterator up to the previous item
in the container and returns the iterator's prior value.
\note Backing up an iterator to before its container's begin() constitutes
@@ -237,12 +213,8 @@
\image javaiterators1.png
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 7
-
If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
+ findNext() in a loop.
Multiple iterators can be used on the same set. If the set
is modified while a QSetIterator is active, the QSetIterator
@@ -413,15 +385,21 @@
*/
/*! \fn template <class T> void QListIterator<T>::toBack()
- \fn template <class T> void QSetIterator<T>::toBack()
\fn template <class T> void QMutableListIterator<T>::toBack()
+//! [toBack]
Moves the iterator to the back of the container (after the last
item).
+//! [toBack]
\sa toFront(), previous()
*/
+/*! \fn template <class T> void QSetIterator<T>::toBack()
+ \include qiterator.qdoc toBack
+ \sa toFront()
+*/
+
/*! \fn template <class T> void QMutableSetIterator<T>::toBack()
Moves the iterator to the back of the container (after the last
@@ -431,16 +409,22 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasNext() const
- \fn template <class T> bool QSetIterator<T>::hasNext() const
\fn template <class T> bool QMutableListIterator<T>::hasNext() const
+//! [hasNext]
Returns \c true if there is at least one item ahead of the iterator,
i.e. the iterator is \e not at the back of the container;
otherwise returns \c false.
+//! [hasNext]
\sa hasPrevious(), next()
*/
+/*! \fn template <class T> bool QSetIterator<T>::hasNext() const
+ \include qiterator.qdoc hasNext
+ \sa next()
+*/
+
/*! \fn template <class T> bool QMutableSetIterator<T>::hasNext() const
Returns \c true if there is at least one item ahead of the iterator,
@@ -451,16 +435,23 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::next()
- \fn template <class T> const T &QSetIterator<T>::next()
+//! [next]
Returns the next item and advances the iterator by one position.
Calling this function on an iterator located at the back of the
container leads to undefined results.
+//! [next]
\sa hasNext(), peekNext(), previous()
*/
+/*!
+ \fn template <class T> const T &QSetIterator<T>::next()
+ \include qiterator.qdoc next
+ \sa hasNext(), peekNext()
+*/
+
/* \fn template <class T> const T &QMutableSetIterator<T>::next()
Returns the next item and advances the iterator by one position.
@@ -492,17 +483,24 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekNext() const
- \fn template <class T> const T &QSetIterator<T>::peekNext() const
+//! [peekNext]
Returns the next item without moving the iterator.
Calling this function on an iterator located at the back of the
container leads to undefined results.
+//! [peekNext]
\sa hasNext(), next(), peekPrevious()
*/
/*!
+ \fn template <class T> const T &QSetIterator<T>::peekNext() const
+ \include qiterator.qdoc peekNext
+ \sa hasNext(), next()
+*/
+
+/*!
\fn template <class T> const T &QMutableSetIterator<T>::peekNext() const
Returns the next item without moving the iterator.
@@ -524,7 +522,6 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasPrevious() const
- \fn template <class T> bool QSetIterator<T>::hasPrevious() const
\fn template <class T> bool QMutableListIterator<T>::hasPrevious() const
Returns \c true if there is at least one item behind the iterator,
@@ -535,7 +532,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::previous()
- \fn template <class T> const T &QSetIterator<T>::previous()
Returns the previous item and moves the iterator back by one
position.
@@ -558,7 +554,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekPrevious() const
- \fn template <class T> const T &QSetIterator<T>::peekPrevious() const
Returns the previous item without moving the iterator.
@@ -590,21 +585,25 @@
*/
/*! \fn template <class T> bool QListIterator<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)
+//! [findNext]
Searches for \a value starting from the current iterator position
forward. Returns \c true if \a value is found; otherwise returns \c false.
After the call, if \a value was found, the iterator is positioned
just after the matching item; otherwise, the iterator is
positioned at the back of the container.
+//! [findNext]
\sa findPrevious()
*/
+/*! \fn template <class T> bool QSetIterator<T>::findNext(const T &value)
+ \include qiterator.qdoc findNext
+*/
+
/*! \fn template <class T> bool QListIterator<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)
Searches for \a value starting from the current iterator position
@@ -974,9 +973,8 @@
be preferred.
QMutableHashIterator\<Key, T\> allows you to iterate over a QHash
- (or a QMultiHash) and modify the hash. If you don't want to modify
- the hash (or have a const QHash), use the slightly faster
- QHashIterator instead.
+ and modify the hash. If you don't want to modify the hash (or have
+ a const QHash), use the slightly faster QHashIterator instead.
The QMutableHashIterator constructor takes a QHash as argument.
After construction, the iterator is located at the very beginning
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index bbedfa948e..9216b8875b 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qline.h"
@@ -263,6 +227,15 @@ QT_BEGIN_NAMESPACE
\sa setP1(), setP2(), p1(), p2()
*/
+/*!
+ \fn QLine::toLineF() const
+ \since 6.4
+
+ Returns this line as a line with floating point accuracy.
+
+ \sa QLineF::toLine()
+*/
+
#ifndef QT_NO_DEBUG_STREAM
@@ -423,7 +396,7 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
Construct a QLineF object from the given integer-based \a line.
- \sa toLine()
+ \sa toLine(), QLine::toLineF()
*/
/*!
@@ -463,7 +436,7 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
Note that the returned line's start and end points are rounded to
the nearest integer.
- \sa QLineF()
+ \sa QLineF(), QLine::toLineF()
*/
/*!
\fn qreal QLineF::x1() const
diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h
index 426d69cd6d..e23ffbe9d5 100644
--- a/src/corelib/tools/qline.h
+++ b/src/corelib/tools/qline.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINE_H
#define QLINE_H
@@ -44,6 +8,7 @@
QT_BEGIN_NAMESPACE
+class QLineF;
/*******************************************************************************
* class QLine
@@ -86,10 +51,12 @@ public:
constexpr inline bool operator==(const QLine &d) const noexcept;
constexpr inline bool operator!=(const QLine &d) const noexcept { return !(*this == d); }
+ [[nodiscard]] constexpr inline QLineF toLineF() const noexcept;
+
private:
QPoint pt1, pt2;
};
-Q_DECLARE_TYPEINFO(QLine, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QLine, Q_PRIMITIVE_TYPE);
/*******************************************************************************
* class QLine inline members
@@ -274,7 +241,7 @@ public:
private:
QPointF pt1, pt2;
};
-Q_DECLARE_TYPEINFO(QLineF, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QLineF, Q_PRIMITIVE_TYPE);
/*******************************************************************************
* class QLineF inline members
@@ -386,6 +353,8 @@ constexpr inline QPointF QLineF::pointAt(qreal t) const
return QPointF(pt1.x() + (pt2.x() - pt1.x()) * t, pt1.y() + (pt2.y() - pt1.y()) * t);
}
+constexpr inline QLineF QLine::toLineF() const noexcept { return *this; }
+
constexpr inline QLine QLineF::toLine() const
{
return QLine(pt1.toPoint(), pt2.toPoint());
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 9b2a56a66a..89e0e3f380 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2019 Intel Corporation
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLIST_H
#define QLIST_H
@@ -46,12 +10,15 @@
#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qnamespace.h>
#include <functional>
#include <limits>
#include <initializer_list>
#include <type_traits>
+class tst_QList;
+
QT_BEGIN_NAMESPACE
namespace QtPrivate {
@@ -111,10 +78,15 @@ class QList
using DataPointer = QArrayDataPointer<T>;
class DisableRValueRefs {};
+ friend class ::tst_QList;
+
DataPointer d;
template <typename V, typename U> friend qsizetype QtPrivate::indexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
template <typename V, typename U> friend qsizetype QtPrivate::lastIndexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
+ // This alias prevents the QtPrivate namespace from being exposed into the docs.
+ template <typename InputIterator>
+ using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
public:
using Type = T;
@@ -145,14 +117,11 @@ public:
public:
using difference_type = qsizetype;
using value_type = T;
- // libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
-#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
- using iterator_category = std::contiguous_iterator_tag;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using iterator_concept = std::contiguous_iterator_tag;
using element_type = value_type;
-#else
- using iterator_category = std::random_access_iterator_tag;
#endif
-
+ using iterator_category = std::random_access_iterator_tag;
using pointer = T *;
using reference = T &;
@@ -218,13 +187,11 @@ public:
public:
using difference_type = qsizetype;
using value_type = T;
- // libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
-#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
- using iterator_category = std::contiguous_iterator_tag;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using iterator_concept = std::contiguous_iterator_tag;
using element_type = const value_type;
-#else
- using iterator_category = std::random_access_iterator_tag;
#endif
+ using iterator_category = std::random_access_iterator_tag;
using pointer = const T *;
using reference = const T &;
@@ -291,6 +258,14 @@ private:
const std::less<const T*> less = {};
return !less(d->end(), i.i) && !less(i.i, d->begin());
}
+
+ void verify([[maybe_unused]] qsizetype pos = 0, [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
public:
QList(DataPointer dd) noexcept
: d(dd)
@@ -300,20 +275,20 @@ public:
public:
QList() = default;
explicit QList(qsizetype size)
- : d(Data::allocate(size))
+ : d(size)
{
if (size)
d->appendInitialize(size);
}
QList(qsizetype size, parameter_type t)
- : d(Data::allocate(size))
+ : d(size)
{
if (size)
d->copyAppend(size, t);
}
inline QList(std::initializer_list<T> args)
- : d(Data::allocate(args.size()))
+ : d(qsizetype(args.size()))
{
if (args.size())
d->copyAppend(args.begin(), args.end());
@@ -321,20 +296,18 @@ public:
QList<T> &operator=(std::initializer_list<T> args)
{
- d = DataPointer(Data::allocate(args.size()));
- if (args.size())
- d->copyAppend(args.begin(), args.end());
- return *this;
+ return assign(args);
}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
+
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
QList(InputIterator i1, InputIterator i2)
{
- if constexpr (!std::is_convertible_v<typename std::iterator_traits<Iterator>::iterator_category, std::forward_iterator_tag>) {
+ if constexpr (!std::is_convertible_v<typename std::iterator_traits<InputIterator>::iterator_category, std::forward_iterator_tag>) {
std::copy(i1, i2, std::back_inserter(*this));
} else {
const auto distance = std::distance(i1, i2);
if (distance) {
- d = DataPointer(Data::allocate(distance));
+ d = DataPointer(qsizetype(distance));
// appendIteratorRange can deal with contiguous iterators on its own,
// this is an optimization for C++17 code.
if constexpr (std::is_same_v<std::decay_t<InputIterator>, iterator> ||
@@ -352,11 +325,18 @@ public:
inline explicit QList(const String &str)
{ append(str); }
+ QList(qsizetype size, Qt::Initialization)
+ : d(size)
+ {
+ if (size)
+ d->appendUninitialized(size);
+ }
+
// compiler-generated special member functions are fine!
- void swap(QList<T> &other) noexcept { qSwap(d, other.d); }
+ void swap(QList &other) noexcept { d.swap(other.d); }
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template <typename U = T>
QTypeTraits::compare_eq_result_container<QList, U> operator==(const QList &other) const
{
@@ -412,7 +392,7 @@ public:
bool operator>(const QList &other) const;
bool operator<=(const QList &other) const;
bool operator>=(const QList &other) const;
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
qsizetype size() const noexcept { return d->size; }
qsizetype count() const noexcept { return size(); }
@@ -432,6 +412,12 @@ public:
if (size > this->size())
d->copyAppend(size - this->size(), c);
}
+ void resizeForOverwrite(qsizetype size)
+ {
+ resize_internal(size);
+ if (size > this->size())
+ d->appendUninitialized(size);
+ }
inline qsizetype capacity() const { return qsizetype(d->constAllocatedCapacity()); }
void reserve(qsizetype size);
@@ -450,7 +436,7 @@ public:
return;
if (d->needsDetach()) {
// must allocate memory
- DataPointer detached(Data::allocate(d.allocatedCapacity()));
+ DataPointer detached(d.allocatedCapacity());
d.swap(detached);
} else {
d->truncate(0);
@@ -465,7 +451,7 @@ public:
reference operator[](qsizetype i)
{
Q_ASSERT_X(size_t(i) < size_t(d->size), "QList::operator[]", "index out of range");
- detach();
+ // don't detach() here, we detach in data below:
return data()[i];
}
const_reference operator[](qsizetype i) const noexcept { return at(i); }
@@ -527,6 +513,19 @@ public:
}
}
+ QList &assign(qsizetype n, parameter_type t)
+ {
+ Q_ASSERT(n >= 0);
+ return fill(t, n);
+ }
+
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
+ QList &assign(InputIterator first, InputIterator last)
+ { d.assign(first, last); return *this; }
+
+ QList &assign(std::initializer_list<T> l)
+ { return assign(l.begin(), l.end()); }
+
template <typename ...Args>
iterator emplace(const_iterator before, Args&&... args)
{
@@ -585,7 +584,7 @@ public:
template <typename AT = T>
qsizetype count(const AT &t) const noexcept
{
- return qsizetype(std::count(&*cbegin(), &*cend(), t));
+ return qsizetype(std::count(data(), data() + size(), t));
}
void removeAt(qsizetype i) { remove(i); }
@@ -654,27 +653,13 @@ public:
QList<T> mid(qsizetype pos, qsizetype len = -1) const;
QList<T> first(qsizetype n) const
- {
- Q_ASSERT(size_t(n) <= size_t(size()));
- return QList<T>(begin(), begin() + n);
- }
+ { verify(0, n); return QList<T>(begin(), begin() + n); }
QList<T> last(qsizetype n) const
- {
- Q_ASSERT(size_t(n) <= size_t(size()));
- return QList<T>(end() - n, end());
- }
+ { verify(0, n); return QList<T>(end() - n, end()); }
QList<T> sliced(qsizetype pos) const
- {
- Q_ASSERT(size_t(pos) <= size_t(size()));
- return QList<T>(begin() + pos, end());
- }
+ { verify(pos, 0); return QList<T>(begin() + pos, end()); }
QList<T> sliced(qsizetype pos, qsizetype n) const
- {
- Q_ASSERT(size_t(pos) <= size_t(size()));
- Q_ASSERT(n >= 0);
- Q_ASSERT(pos + n <= size());
- return QList<T>(begin() + pos, begin() + pos + n);
- }
+ { verify(pos, n); return QList<T>(begin() + pos, begin() + pos + n); }
T value(qsizetype i) const { return value(i, T()); }
T value(qsizetype i, parameter_type defaultValue) const;
@@ -704,14 +689,22 @@ public:
inline reference back() { return last(); }
inline const_reference back() const noexcept { return last(); }
void shrink_to_fit() { squeeze(); }
+ static qsizetype max_size() noexcept
+ {
+ return Data::max_size();
+ }
// comfort
QList<T> &operator+=(const QList<T> &l) { append(l); return *this; }
QList<T> &operator+=(QList<T> &&l) { append(std::move(l)); return *this; }
- inline QList<T> operator+(const QList<T> &l) const
+ inline QList<T> operator+(const QList<T> &l) const &
{ QList n = *this; n += l; return n; }
- inline QList<T> operator+(QList<T> &&l) const
+ QList<T> operator+(const QList<T> &l) &&
+ { return std::move(*this += l); }
+ inline QList<T> operator+(QList<T> &&l) const &
{ QList n = *this; n += std::move(l); return n; }
+ QList<T> operator+(QList<T> &&l) &&
+ { return std::move(*this += std::move(l)); }
inline QList<T> &operator+=(parameter_type t)
{ append(t); return *this; }
inline QList<T> &operator<< (parameter_type t)
@@ -770,7 +763,7 @@ void QList<T>::reserve(qsizetype asize)
}
}
- DataPointer detached(Data::allocate(qMax(asize, size())));
+ DataPointer detached(qMax(asize, size()));
detached->copyAppend(d->begin(), d->end());
if (detached.d_ptr())
detached->setFlag(Data::CapacityReserved);
@@ -784,7 +777,7 @@ inline void QList<T>::squeeze()
return;
if (d->needsDetach() || size() < capacity()) {
// must allocate memory
- DataPointer detached(Data::allocate(size()));
+ DataPointer detached(size());
if (size()) {
if (d.needsDetach())
detached->copyAppend(d.data(), d.data() + d.size);
@@ -913,7 +906,7 @@ inline QList<T> &QList<T>::fill(parameter_type t, qsizetype newSize)
newSize = size();
if (d->needsDetach() || newSize > capacity()) {
// must allocate memory
- DataPointer detached(Data::allocate(d->detachCapacity(newSize)));
+ DataPointer detached(d->detachCapacity(newSize));
detached->copyAppend(newSize, t);
d.swap(detached);
} else {
@@ -995,7 +988,7 @@ inline QList<T> QList<T>::mid(qsizetype pos, qsizetype len) const
}
// Allocate memory
- DataPointer copied(Data::allocate(l));
+ DataPointer copied(l);
copied->copyAppend(data() + p, data() + p + l);
return copied;
}
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
index 4e92e2c047..e07b74cd53 100644
--- a/src/corelib/tools/qlist.qdoc
+++ b/src/corelib/tools/qlist.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QVector
@@ -153,21 +129,7 @@
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, iterators are
- handy when working with generic algorithms provided by \l{generic
- algorithms}{Qt} and the C++ standard library. \l{Java-style iterators} are
- provided for backwards compatibility, prefer \l{STL-style iterators} when
- writing C++ code.
-
- \note Iterators over a QList, and references to individual elements
- within one, cannot be relied on to remain valid when any non-const method
- of the QList is called. Accessing such an iterator or reference after
- the call to a non-const method leads to undefined behavior. When stability
- for iterator-like functionality is required, you should use indexes instead
- of iterators as they are not tied to QList's internal state and thus do
- not get invalidated.
+ For iterating over the items, see \l {Iterating over Containers}.
In addition to QList, Qt also provides QVarLengthArray, a very
low-level class with little functionality that is optimized for
@@ -285,6 +247,31 @@
\sa resize()
*/
+/*! \fn template <typename T> QList<T>::QList(qsizetype size, Qt::Initialization)
+ \since 6.8
+
+ Constructs a list with an initial size of \a size elements.
+
+ QList will make an attempt at \b{not initializing} the elements.
+
+//! [qlist-uninitialized-strategy]
+ Specifically:
+
+ \list
+
+ \li if \c{T} has a constructor that accepts \c{Qt::Uninitialized},
+ that constructor will be used to initialize the elements;
+
+ \li otherwise, each element is default constructed. For
+ trivially constructible types (such as \c{int}, \c{float}, etc.)
+ this is equivalent to not initializing them.
+
+ \endlist
+//! [qlist-uninitialized-strategy]
+
+ \sa resizeForOverwrite()
+*/
+
/*! \fn template <typename T> QList<T>::QList(qsizetype size, parameter_type value)
Constructs a list with an initial size of \a size elements.
@@ -312,11 +299,15 @@
Constructs a list from the std::initializer_list given by \a args.
*/
-/*! \fn template <typename T> template<typename InputIterator> QList<T>::QList(InputIterator first, InputIterator last)
+/*! \fn template<typename T> template <typename InputIterator, QList<T>::if_input_iterator<InputIterator> = true> QList<T>::QList(InputIterator first, InputIterator last)
\since 5.14
Constructs a list with the contents in the iterator range [\a first, \a last).
+ \note This constructor only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
The value type of \c InputIterator must be convertible to \c T.
*/
@@ -460,18 +451,35 @@
*/
/*! \fn template <typename T> void QList<T>::resize(qsizetype size)
+ \fn template <typename T> void QList<T>::resize(qsizetype size, parameter_type c)
+ \since 6.0
Sets the size of the list to \a size. If \a size is greater than the
current size, elements are added to the end; the new elements are
- initialized with a \l{default-constructed value}. If \a size is less
- than the current size, elements are removed from the end.
+ initialized with either a \l{default-constructed value} or \a c. If \a size
+ is less than the current size, elements are removed from the end.
- Since Qt 5.6, resize() doesn't shrink the capacity anymore.
- To shed excess capacity, use squeeze().
+ If this list is not shared, the capacity() is preserved. Use squeeze()
+ to shed excess capacity.
+
+ \note In Qt versions prior to 5.7 (for QVector; QList lacked a resize()
+ until 6.0), this function released the memory used by the list instead of
+ preserving the capacity.
\sa size()
*/
+/*! \fn template <typename T> void QList<T>::resizeForOverwrite(qsizetype size)
+ \since 6.8
+
+ Sets the size of the list to \a size. If \a size is less than the
+ current size, elements are removed from the end. If \a size is
+ greater than the current size, elements are added to the end; QList
+ will make an attempt at \b{not initializing} these new elements.
+
+ \include qlist.qdoc qlist-uninitialized-strategy
+*/
+
/*! \fn template <typename T> qsizetype QList<T>::capacity() const
Returns the maximum number of items that can be stored in the
@@ -587,17 +595,14 @@
Removes all the elements from the list.
- \note Until Qt 5.6, this also released the memory used by
- the list. From Qt 5.7, the capacity is preserved. To shed
- all capacity, swap with a default-constructed list:
- \code
- QList<T> l ...;
- QList<T>().swap(l);
- Q_ASSERT(l.capacity() == 0);
- \endcode
- or call squeeze().
+ If this list is not shared, the capacity() is preserved. Use squeeze() to
+ shed excess capacity.
+
+ \note In Qt versions prior to 5.7 (for QVector) and 6.0 (for QList), this
+ function released the memory used by the list instead of preserving the
+ capacity.
- \sa squeeze()
+ \sa resize(), squeeze()
*/
/*! \fn template <typename T> const T &QList<T>::at(qsizetype i) const
@@ -1324,6 +1329,15 @@
returns \c false.
*/
+/*! \fn template <typename T> qsizetype QList<T>::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the list can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn template <typename T> QList<T> &QList<T>::operator+=(const QList<T> &other)
Appends the items of the \a other list to this list and
@@ -1357,7 +1371,11 @@
\sa append(), operator<<()
*/
-/*! \fn template <typename T> QList<T> QList<T>::operator+(const QList<T> &other) const
+/*!
+ \fn template <typename T> QList<T> QList<T>::operator+(const QList<T> &other) const &
+ \fn template <typename T> QList<T> QList<T>::operator+(const QList<T> &other) &&
+ \fn template <typename T> QList<T> QList<T>::operator+(QList<T> &&other) const &
+ \fn template <typename T> QList<T> QList<T>::operator+(QList<T> &&other) &&
Returns a list that contains all the items in this list
followed by all the items in the \a other list.
@@ -1365,14 +1383,6 @@
\sa operator+=()
*/
-/*! \fn template <typename T> QList<T> QList<T>::operator+(QList<T> &&other) const
- \since 6.0
-
- \overload
-
- \sa operator+=()
-*/
-
/*! \fn template <typename T> QList<T> &QList<T>::operator<<(parameter_type value)
Appends \a value to the list and returns a reference to this list.
@@ -1573,3 +1583,47 @@
\sa erase
*/
+
+/*! \fn template <typename T> QList<T>& QList<T>::assign(qsizetype n, parameter_type t)
+ \since 6.6
+
+ Replaces the contents of this list with \a n copies of \a t.
+
+ The size of this list will be equal to \a n.
+
+ This function will only allocate memory if \a n exceeds the capacity of the
+ list or this list is shared.
+*/
+
+/*! \fn template <typename T> template <typename InputIterator, QList<T>::if_input_iterator<InputIterator>> QList<T>& QList<T>::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this list with a copy of the elements in the
+ iterator range [\a first, \a last).
+
+ The size of this list will be equal to the number of elements in the
+ range [\a first, \a last).
+
+ This function will only allocate memory if the number of elements in the
+ range exceeds the capacity of this list or this list is shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
+ \note The behavior is undefined if either argument is an iterator into
+ *this.
+*/
+
+/*! \fn template <typename T> QList<T>& QList<T>::assign(std::initializer_list<T> l)
+ \since 6.6
+
+ Replaces the contents of this list with a copy of the elements of
+ \a l.
+
+ The size of this list will be equal to the number of elements in
+ \a l.
+
+ This function only allocates memory if the number of elements in \a l
+ exceeds the capacity of this list or this list is shared.
+*/
diff --git a/src/corelib/tools/qmakearray_p.h b/src/corelib/tools/qmakearray_p.h
index 4ed8c16234..17014c23b9 100644
--- a/src/corelib/tools/qmakearray_p.h
+++ b/src/corelib/tools/qmakearray_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMAKEARRAY_P_H
#define QMAKEARRAY_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include "QtCore/qglobal.h"
+#include "QtCore/private/qglobal_p.h"
#include <array>
#include <type_traits>
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 7fd6e4d705..7ee0be1e51 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMAP_H
#define QMAP_H
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qlist.h>
#include <QtCore/qrefcount.h>
@@ -238,7 +203,7 @@ public:
void swap(QMap<Key, T> &other) noexcept
{
- qSwap(d, other.d);
+ d.swap(other.d);
}
QMap(std::initializer_list<std::pair<Key, T>> list)
@@ -276,7 +241,7 @@ public:
return {};
}
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template <typename AKey = Key, typename AT = T> friend
QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator==(const QMap &lhs, const QMap &rhs)
{
@@ -297,7 +262,7 @@ public:
#else
friend bool operator==(const QMap &lhs, const QMap &rhs);
friend bool operator!=(const QMap &lhs, const QMap &rhs);
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
@@ -359,6 +324,7 @@ public:
if (!d)
return T();
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
// TODO: improve. There is no need of copying all the
// elements (the one to be removed can be skipped).
detach();
@@ -400,6 +366,7 @@ public:
T &operator[](const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
auto i = d->m.find(key);
if (i == d->m.end())
@@ -644,6 +611,10 @@ public:
const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator erase(const_iterator it)
{
@@ -669,6 +640,7 @@ public:
iterator find(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.find(key));
}
@@ -687,6 +659,7 @@ public:
iterator lowerBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.lower_bound(key));
}
@@ -700,6 +673,7 @@ public:
iterator upperBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.upper_bound(key));
}
@@ -713,6 +687,7 @@ public:
iterator insert(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
// TODO: improve. In case of assignment, why copying first?
detach();
return iterator(d->m.insert_or_assign(key, value).first);
@@ -722,6 +697,7 @@ public:
{
// TODO: improve. In case of assignment, why copying first?
typename Map::const_iterator dpos;
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key`/`value` alive across the detach
if (!d || d.isShared()) {
auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
detach();
@@ -787,20 +763,46 @@ public:
return isEmpty();
}
- QPair<iterator, iterator> equal_range(const Key &akey)
+ std::pair<iterator, iterator> equal_range(const Key &akey)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
auto result = d->m.equal_range(akey);
return {iterator(result.first), iterator(result.second)};
}
- QPair<const_iterator, const_iterator> equal_range(const Key &akey) const
+ std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
{
if (!d)
return {};
auto result = d->m.equal_range(akey);
return {const_iterator(result.first), const_iterator(result.second)};
}
+
+private:
+#ifdef Q_QDOC
+ friend size_t qHash(const QMap &key, size_t seed = 0);
+#else
+# if defined(Q_CC_GHS) || defined (Q_CC_MSVC)
+ // GHS and MSVC tries to intantiate qHash() for the noexcept running into a
+ // non-SFINAE'ed hard error... Create an artificial SFINAE context as a
+ // work-around:
+ template <typename M, std::enable_if_t<std::is_same_v<M, QMap>, bool> = true>
+ friend QtPrivate::QHashMultiReturnType<typename M::key_type, typename M::mapped_type>
+# else
+ using M = QMap;
+ friend size_t
+# endif
+ qHash(const M &key, size_t seed = 0)
+ noexcept(QHashPrivate::noexceptPairHash<typename M::key_type, typename M::mapped_type>())
+ {
+ if (!key.d)
+ return seed;
+ // don't use qHashRange to avoid its compile-time overhead:
+ return std::accumulate(key.d->m.begin(), key.d->m.end(), seed,
+ QtPrivate::QHashCombine{});
+ }
+#endif // !Q_QDOC
};
Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
@@ -812,6 +814,7 @@ qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
return QtPrivate::associative_erase_if(map, pred);
}
+
//
// QMultiMap
//
@@ -841,7 +844,7 @@ public:
void swap(QMultiMap<Key, T> &other) noexcept
{
- qSwap(d, other.d);
+ d.swap(other.d);
}
explicit QMultiMap(const QMap<Key, T> &other)
@@ -909,7 +912,7 @@ public:
return {};
}
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template <typename AKey = Key, typename AT = T> friend
QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator==(const QMultiMap &lhs, const QMultiMap &rhs)
{
@@ -930,7 +933,7 @@ public:
#else
friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs);
friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs);
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
@@ -986,15 +989,15 @@ public:
if (!d)
return 0;
- // TODO: improve. Copy over only the elements not to be removed.
- detach();
-
// key and value may belong to this map. As such, we need to copy
// them to ensure they stay valid throughout the iteration below
// (which may destroy them)
const Key keyCopy = key;
const T valueCopy = value;
+ // TODO: improve. Copy over only the elements not to be removed.
+ detach();
+
size_type result = 0;
const auto &keyCompare = d->m.key_comp();
@@ -1024,6 +1027,8 @@ public:
if (!d)
return T();
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
+
// TODO: improve. There is no need of copying all the
// elements (the one to be removed can be skipped).
detach();
@@ -1331,6 +1336,10 @@ public:
const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
+ auto asKeyValueRange() & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() const & { return QtPrivate::QKeyValueRange(*this); }
+ auto asKeyValueRange() && { return QtPrivate::QKeyValueRange(std::move(*this)); }
+ auto asKeyValueRange() const && { return QtPrivate::QKeyValueRange(std::move(*this)); }
iterator erase(const_iterator it)
{
@@ -1361,6 +1370,7 @@ public:
iterator find(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.find(key));
}
@@ -1379,6 +1389,8 @@ public:
iterator find(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
+
detach();
auto range = d->m.equal_range(key);
@@ -1411,6 +1423,7 @@ public:
iterator lowerBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.lower_bound(key));
}
@@ -1424,6 +1437,7 @@ public:
iterator upperBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.upper_bound(key));
}
@@ -1437,6 +1451,7 @@ public:
iterator insert(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
detach();
// note that std::multimap inserts at the end of an equal_range for a key,
// QMultiMap at the beginning.
@@ -1446,6 +1461,7 @@ public:
iterator insert(const_iterator pos, const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
typename Map::const_iterator dpos;
if (!d || d.isShared()) {
auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
@@ -1484,6 +1500,8 @@ public:
iterator replace(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
+
// TODO: improve. No need of copying and then overwriting.
detach();
@@ -1501,14 +1519,15 @@ public:
// STL compatibility
inline bool empty() const { return isEmpty(); }
- QPair<iterator, iterator> equal_range(const Key &akey)
+ std::pair<iterator, iterator> equal_range(const Key &akey)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
auto result = d->m.equal_range(akey);
return {iterator(result.first), iterator(result.second)};
}
- QPair<const_iterator, const_iterator> equal_range(const Key &akey) const
+ std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
{
if (!d)
return {};
diff --git a/src/corelib/tools/qmap.qdoc b/src/corelib/tools/qmap.qdoc
index 55c2bcb5d9..0cabf3df38 100644
--- a/src/corelib/tools/qmap.qdoc
+++ b/src/corelib/tools/qmap.qdoc
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QMap
@@ -123,27 +87,17 @@
The items are traversed in ascending key order.
- Normally, a QMap allows only one value per key. If you call
+ A QMap allows only one value per key. If you call
insert() with a key that already exists in the QMap, the
previous value will be erased. For example:
\snippet code/src_corelib_tools_qmap.cpp 9
However, you can store multiple values per key by using
- QMultiMap. If you want
- to retrieve all the values for a single key, you can use
- values(const Key &key), which returns a QList<T>:
-
- \snippet code/src_corelib_tools_qmap.cpp 10
-
- Another approach is to call
- find() to get the STL-style iterator for the first item with a
- key and iterate from there:
-
- \snippet code/src_corelib_tools_qmap.cpp 11
+ QMultiMap.
If you only need to extract the values from a map (not the keys),
- you can also use \l{foreach}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qmap.cpp 12
@@ -243,11 +197,20 @@
\sa toStdMap()
*/
-/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() const
+/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() const &
Returns an STL map equivalent to this QMap.
*/
+/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() &&
+
+ \overload
+ \since 6.0
+
+ \note Calling this function will leave this QMap in the partially-formed state, in which
+ the only valid operations are destruction or assignment of a new value.
+*/
+
/*! \fn template <class Key, class T> bool QMap<Key, T>::operator==(const QMap<Key, T> &lhs, const QMap<Key, T> &rhs)
Returns \c true if \a lhs is equal to \a rhs; otherwise returns
@@ -354,9 +317,7 @@
the value associated with it.
If the item does not exist in the map, the function simply
- returns a \l{default-constructed value}. If there are multiple
- items for \a key in the map, only the most recently inserted one
- is removed and returned.
+ returns a \l{default-constructed value}.
If you don't use the return value, remove() is more efficient.
@@ -406,9 +367,7 @@
If the map contains no item with key \a key, the function inserts
a \l{default-constructed value} into the map with key \a key, and
- returns a reference to it. If the map contains multiple items
- with key \a key, this function returns a reference to the most
- recently inserted value.
+ returns a reference to it.
\sa insert(), value()
*/
@@ -431,7 +390,7 @@
use that entails can be avoided by iterating from \l keyBegin() to
\l keyEnd().
- \sa QMultiMap::uniqueKeys(), values(), key()
+ \sa values(), key()
*/
/*! \fn template <class Key, class T> QList<Key> QMap<Key, T>::keys(const T &value) const
@@ -449,9 +408,7 @@
/*! \fn template <class Key, class T> QList<T> QMap<Key, T>::values() const
Returns a list containing all the values in the map, in ascending
- order of their keys. 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.
+ order of their keys.
This function creates a new list, in \l {linear time}. The time and memory
use that entails can be avoided by iterating from \l keyValueBegin() to
@@ -663,6 +620,25 @@
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QMap<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this map as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qmap.cpp 28
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the map. Specifically, mutating the value
+ will modify the map itself.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::erase(const_iterator pos)
Removes the (key, value) pair pointed to by the iterator \a pos
@@ -754,7 +730,7 @@
If there is already an item with the key \a key, that item's value
is replaced with \a value.
- \sa QMultiMap::insert()
+ Returns an iterator pointing to the new/updated element.
*/
/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::insert(const_iterator pos, const Key &key, const T &value)
@@ -780,7 +756,7 @@
\b {Note:} Be careful with the hint. Providing an iterator from an older shared instance might
crash but there is also a risk that it will silently corrupt both the map and the \a pos map.
- \sa QMultiMap::insert()
+ Returns an iterator pointing to the new/updated element.
*/
/*! \fn template <class Key, class T> void QMap<Key, T>::insert(const QMap<Key, T> &map)
@@ -790,11 +766,6 @@
If a key is common to both maps, its value will be replaced with
the value stored in \a map.
-
- \note If \a map contains multiple entries with the same key then the
- final value of the key is undefined.
-
- \sa QMultiMap::insert()
*/
/*! \fn template <class Key, class T> void QMap<Key, T>::insert(QMap<Key, T> &&map)
@@ -810,12 +781,12 @@
/*! \typedef QMap::Iterator
- Qt-style synonym for QMap<Key, T>::iterator.
+ Qt-style synonym for QMap::iterator.
*/
/*! \typedef QMap::ConstIterator
- Qt-style synonym for QMap<Key, T>::const_iterator.
+ Qt-style synonym for QMap::const_iterator.
*/
/*! \typedef QMap::difference_type
@@ -847,14 +818,14 @@
*/
/*!
- \fn template <class Key, class T> QPair<typename QMap<Key, T>::iterator, typename QMap<Key, T>::iterator> QMap<Key, T>::equal_range(const Key &key)
+ \fn template <class Key, class T> std::pair<typename QMap<Key, T>::iterator, typename QMap<Key, T>::iterator> QMap<Key, T>::equal_range(const Key &key)
Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
are stored under \a key.
*/
/*!
- \fn template <class Key, class T> QPair<typename QMap<Key, T>::const_iterator, typename QMap<Key, T>::const_iterator> QMap<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> std::pair<typename QMap<Key, T>::const_iterator, typename QMap<Key, T>::const_iterator> QMap<Key, T>::equal_range(const Key &key) const
\overload
\since 5.6
*/
@@ -864,12 +835,6 @@
\inmodule QtCore
\brief The QMap::iterator class provides an STL-style non-const iterator for QMap.
- QMap 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.
-
QMap\<Key, T\>::iterator allows you to iterate over a QMap
and to modify the value (but not the key) stored under
a particular key. If you want to iterate over a const QMap, you
@@ -889,31 +854,15 @@
Unlike QHash, which stores its items in an arbitrary order, QMap
stores its items ordered by key.
- Let's see a few examples of things we can do with a
- QMap::iterator that we cannot do with a QMap::const_iterator.
Here's an example that increments every value stored in the QMap
by 2:
\snippet code/src_corelib_tools_qmap.cpp 19
- 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_qmap.cpp 20
-
- The call to QMap::erase() removes the item pointed to by the
- iterator from the map, and returns an iterator to the next item.
- Here's another way of removing an item while iterating:
+ To remove elements from a QMap you can use erase_if(QMap\<Key, T\> &map, Predicate pred):
\snippet code/src_corelib_tools_qmap.cpp 21
- It might be tempting to write code like this:
-
- \snippet code/src_corelib_tools_qmap.cpp 22
-
- 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 map. If you add items
to the map, existing iterators will remain valid. If you remove
items from the map, iterators that point to the removed items
@@ -924,7 +873,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMap::const_iterator, QMap::key_iterator, QMutableMapIterator
+ \sa QMap::const_iterator, QMap::key_iterator, QMap::key_value_iterator
*/
/*! \typedef QMap::iterator::difference_type
@@ -1025,7 +974,7 @@
/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the map and returns an iterator to the new current
item.
@@ -1038,14 +987,14 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} operator (\c{i++}) advances the iterator to the
next item in the map and returns an iterator to the previously
current item.
*/
/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator--()
- The prefix -- operator (\c{--i}) makes the preceding item
+ The prefix \c{--} operator (\c{--i}) makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QMap::begin() leads to undefined
@@ -1058,7 +1007,7 @@
\overload
- The postfix -- operator (\c{i--}) makes the preceding item
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
current and returns an iterator pointing to the previously
current item.
*/
@@ -1084,12 +1033,6 @@
\inmodule QtCore
\brief The QMap::const_iterator class provides an STL-style const iterator for QMap.
- QMap 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.
-
QMap\<Key, T\>::const_iterator allows you to iterate over a QMap.
If you want to modify the QMap as you iterate
over it, you must use QMap::iterator instead. It is generally
@@ -1100,12 +1043,20 @@
The default QMap::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QMap
- function like QMap::constBegin(), QMap::constEnd(), or
- QMap::find() before you can start iterating. Here's a typical
+ function like QMap::cbegin(), QMap::cend(), or
+ QMap::constFind() before you can start iterating. Here's a typical
loop that prints all the (key, value) pairs stored in a map:
\snippet code/src_corelib_tools_qmap.cpp 24
+ Here's an example that removes all the items whose value is greater than 10:
+
+ \snippet code/src_corelib_tools_qmap.cpp 20
+
+ And here the same behavior with erase_if()
+
+ \snippet code/src_corelib_tools_qmap.cpp 21
+
Unlike QHash, which stores its items in an arbitrary order, QMap
stores its items ordered by key.
@@ -1119,7 +1070,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMap::iterator, QMap::key_iterator, QMapIterator
+ \sa QMap::iterator, QMap::key_iterator, QMap::const_key_value_iterator
*/
/*! \typedef QMap::const_iterator::difference_type
@@ -1196,7 +1147,7 @@
/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the map and returns an iterator to the new current
item.
@@ -1209,14 +1160,14 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} operator (\c{i++}) advances the iterator to the
next item in the map and returns an iterator to the previously
current item.
*/
/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator--()
- The prefix -- operator (\c{--i}) makes the preceding item
+ The prefix \c{--} operator (\c{--i}) makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QMap::begin() leads to undefined
@@ -1229,7 +1180,7 @@
\overload
- The postfix -- operator (\c{i--}) makes the preceding item
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
current and returns an iterator pointing to the previously
current item.
*/
@@ -1337,7 +1288,7 @@
/*!
\fn template <class Key, class T> QMap<Key, T>::key_iterator &QMap<Key, T>::key_iterator::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the hash and returns an iterator to the new current
item.
@@ -1350,14 +1301,14 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} 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> QMap<Key, T>::key_iterator &QMap<Key, T>::key_iterator::operator--()
- The prefix -- operator (\c{--i}) makes the preceding item
+ The prefix \c{--} operator (\c{--i}) makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QMap::keyBegin() leads to undefined
@@ -1370,7 +1321,7 @@
\overload
- The postfix -- operator (\c{i--}) makes the preceding item
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
current and returns an iterator pointing to the previous
item.
*/
@@ -1438,3 +1389,12 @@
Returns the number of elements removed, if any.
*/
+
+/*!
+ \fn template <class Key, class T> size_t QMap<Key, T>::qHash(const QMap &key, size_t seed) noexcept
+ \since 6.8
+
+ Returns the hash value for \a key, using \a seed to seed the calculation.
+
+ Types \c Key and \c T must be supported by qHash().
+*/
diff --git a/src/corelib/tools/qmargins.cpp b/src/corelib/tools/qmargins.cpp
index 8f18528ce2..1d2cb7d6e5 100644
--- a/src/corelib/tools/qmargins.cpp
+++ b/src/corelib/tools/qmargins.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmargins.h"
#include "qdatastream.h"
@@ -406,6 +370,15 @@ QT_BEGIN_NAMESPACE
\since 5.1
*/
+/*!
+ \fn QMargins::toMarginsF() const
+ \since 6.4
+
+ Returns these margins as margins with floating point accuracy.
+
+ \sa QMarginsF::toMargins()
+*/
+
/*****************************************************************************
QMargins stream functions
*****************************************************************************/
@@ -500,7 +473,9 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
/*!
\fn QMarginsF::QMarginsF(const QMargins &margins)
- Constructs margins copied from the given \a margins
+ Constructs margins copied from the given \a margins.
+
+ \sa QMargins::toMarginsF()
*/
/*!
@@ -509,7 +484,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
Returns \c true if all margins are very close to 0; otherwise returns
false.
- \sa {<QtGlobal>::}{qFuzzyIsNull}
+ \sa {<QtNumeric>::}{qFuzzyIsNull()}
*/
@@ -768,7 +743,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
Note that the components in the returned margins will be rounded to
the nearest integer.
- \sa QMarginsF()
+ \sa QMarginsF(), QMargins::toMarginsF()
*/
/*****************************************************************************
diff --git a/src/corelib/tools/qmargins.h b/src/corelib/tools/qmargins.h
index cf40b89ee0..f8d7150dfd 100644
--- a/src/corelib/tools/qmargins.h
+++ b/src/corelib/tools/qmargins.h
@@ -1,49 +1,20 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMARGINS_H
#define QMARGINS_H
#include <QtCore/qnamespace.h>
+#include <QtCore/q20type_traits.h>
+#include <QtCore/q23utility.h>
+
QT_BEGIN_NAMESPACE
+QT_ENABLE_P0846_SEMANTICS_FOR(get)
+
+class QMarginsF;
+
/*****************************************************************************
QMargins class
*****************************************************************************/
@@ -75,6 +46,8 @@ public:
constexpr QMargins &operator*=(qreal) noexcept;
constexpr QMargins &operator/=(qreal);
+ [[nodiscard]] constexpr inline QMarginsF toMarginsF() const noexcept;
+
private:
int m_left;
int m_top;
@@ -98,17 +71,17 @@ private:
template <std::size_t I,
typename M,
std::enable_if_t<(I < 4), bool> = true,
- std::enable_if_t<std::is_same_v<std::decay_t<M>, QMargins>, bool> = true>
+ std::enable_if_t<std::is_same_v<q20::remove_cvref_t<M>, QMargins>, bool> = true>
friend constexpr decltype(auto) get(M &&m) noexcept
{
if constexpr (I == 0)
- return (std::forward<M>(m).m_left);
+ return q23::forward_like<M>(m.m_left);
else if constexpr (I == 1)
- return (std::forward<M>(m).m_top);
+ return q23::forward_like<M>(m.m_top);
else if constexpr (I == 2)
- return (std::forward<M>(m).m_right);
+ return q23::forward_like<M>(m.m_right);
else if constexpr (I == 3)
- return (std::forward<M>(m).m_bottom);
+ return q23::forward_like<M>(m.m_bottom);
}
};
@@ -347,17 +320,17 @@ private:
template <std::size_t I,
typename M,
std::enable_if_t<(I < 4), bool> = true,
- std::enable_if_t<std::is_same_v<std::decay_t<M>, QMarginsF>, bool> = true>
+ std::enable_if_t<std::is_same_v<q20::remove_cvref_t<M>, QMarginsF>, bool> = true>
friend constexpr decltype(auto) get(M &&m) noexcept
{
if constexpr (I == 0)
- return (std::forward<M>(m).m_left);
+ return q23::forward_like<M>(m.m_left);
else if constexpr (I == 1)
- return (std::forward<M>(m).m_top);
+ return q23::forward_like<M>(m.m_top);
else if constexpr (I == 2)
- return (std::forward<M>(m).m_right);
+ return q23::forward_like<M>(m.m_right);
else if constexpr (I == 3)
- return (std::forward<M>(m).m_bottom);
+ return q23::forward_like<M>(m.m_bottom);
}
};
@@ -516,6 +489,8 @@ constexpr inline QMarginsF operator-(const QMarginsF &margins) noexcept
return QMarginsF(-margins.left(), -margins.top(), -margins.right(), -margins.bottom());
}
+constexpr QMarginsF QMargins::toMarginsF() const noexcept { return *this; }
+
constexpr inline QMargins QMarginsF::toMargins() const noexcept
{
return QMargins(qRound(m_left), qRound(m_top), qRound(m_right), qRound(m_bottom));
diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp
deleted file mode 100644
index 767a7a14d4..0000000000
--- a/src/corelib/tools/qmessageauthenticationcode.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
-** 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 "qmessageauthenticationcode.h"
-#include "qvarlengtharray.h"
-
-#include "qtcore-config_p.h"
-
-// Header from rfc6234
-#include "../../3rdparty/rfc6234/sha.h"
-
-#if QT_CONFIG(system_libb2)
-#include <blake2.h>
-#else
-#include "../../3rdparty/blake2/src/blake2.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-static int qt_hash_block_size(QCryptographicHash::Algorithm method)
-{
- switch (method) {
- case QCryptographicHash::Md4:
- return 64;
- case QCryptographicHash::Md5:
- return 64;
- case QCryptographicHash::Sha1:
- return SHA1_Message_Block_Size;
- case QCryptographicHash::Sha224:
- return SHA224_Message_Block_Size;
- case QCryptographicHash::Sha256:
- return SHA256_Message_Block_Size;
- case QCryptographicHash::Sha384:
- return SHA384_Message_Block_Size;
- case QCryptographicHash::Sha512:
- return SHA512_Message_Block_Size;
- case QCryptographicHash::RealSha3_224:
- case QCryptographicHash::Keccak_224:
- return 144;
- case QCryptographicHash::RealSha3_256:
- case QCryptographicHash::Keccak_256:
- return 136;
- case QCryptographicHash::RealSha3_384:
- case QCryptographicHash::Keccak_384:
- return 104;
- case QCryptographicHash::RealSha3_512:
- case QCryptographicHash::Keccak_512:
- return 72;
- case QCryptographicHash::Blake2b_160:
- case QCryptographicHash::Blake2b_256:
- case QCryptographicHash::Blake2b_384:
- case QCryptographicHash::Blake2b_512:
- return BLAKE2B_BLOCKBYTES;
- case QCryptographicHash::Blake2s_128:
- case QCryptographicHash::Blake2s_160:
- case QCryptographicHash::Blake2s_224:
- case QCryptographicHash::Blake2s_256:
- return BLAKE2S_BLOCKBYTES;
- }
- return 0;
-}
-
-class QMessageAuthenticationCodePrivate
-{
-public:
- QMessageAuthenticationCodePrivate(QCryptographicHash::Algorithm m)
- : messageHash(m), method(m), messageHashInited(false)
- {
- }
-
- QByteArray key;
- QByteArray result;
- QCryptographicHash messageHash;
- QCryptographicHash::Algorithm method;
- bool messageHashInited;
-
- void initMessageHash();
-};
-
-void QMessageAuthenticationCodePrivate::initMessageHash()
-{
- if (messageHashInited)
- return;
- messageHashInited = true;
-
- const int blockSize = qt_hash_block_size(method);
-
- if (key.size() > blockSize) {
- key = QCryptographicHash::hash(key, method);
- }
-
- if (key.size() < blockSize) {
- const int size = key.size();
- key.resize(blockSize);
- memset(key.data() + size, 0, blockSize - size);
- }
-
- QVarLengthArray<char> iKeyPad(blockSize);
- const char * const keyData = key.constData();
-
- for (int i = 0; i < blockSize; ++i)
- iKeyPad[i] = keyData[i] ^ 0x36;
-
- messageHash.addData(iKeyPad);
-}
-
-/*!
- \class QMessageAuthenticationCode
- \inmodule QtCore
-
- \brief The QMessageAuthenticationCode class provides a way to generate
- hash-based message authentication codes.
-
- \since 5.1
-
- \ingroup tools
- \reentrant
-
- QMessageAuthenticationCode supports all cryptographic hashes which are supported by
- QCryptographicHash.
-
- To generate message authentication code, pass hash algorithm QCryptographicHash::Algorithm
- to constructor, then set key and message by setKey() and addData() functions. Result
- can be acquired by result() function.
- \snippet qmessageauthenticationcode/main.cpp 0
- \dots
- \snippet qmessageauthenticationcode/main.cpp 1
-
- Alternatively, this effect can be achieved by providing message,
- key and method to hash() method.
- \snippet qmessageauthenticationcode/main.cpp 2
-
- \sa QCryptographicHash
-*/
-
-/*!
- Constructs an object that can be used to create a cryptographic hash from data
- using method \a method and key \a key.
-*/
-QMessageAuthenticationCode::QMessageAuthenticationCode(QCryptographicHash::Algorithm method,
- const QByteArray &key)
- : d(new QMessageAuthenticationCodePrivate(method))
-{
- d->key = key;
-}
-
-/*!
- Destroys the object.
-*/
-QMessageAuthenticationCode::~QMessageAuthenticationCode()
-{
- delete d;
-}
-
-/*!
- Resets message data. Calling this method doesn't affect the key.
-*/
-void QMessageAuthenticationCode::reset()
-{
- d->result.clear();
- d->messageHash.reset();
- d->messageHashInited = false;
-}
-
-/*!
- Sets secret \a key. Calling this method automatically resets the object state.
-*/
-void QMessageAuthenticationCode::setKey(const QByteArray &key)
-{
- reset();
- d->key = key;
-}
-
-/*!
- Adds the first \a length chars of \a data to the message.
-*/
-void QMessageAuthenticationCode::addData(const char *data, qsizetype length)
-{
- d->initMessageHash();
- d->messageHash.addData({data, length});
-}
-
-/*!
- \overload addData()
-*/
-void QMessageAuthenticationCode::addData(const QByteArray &data)
-{
- d->initMessageHash();
- d->messageHash.addData(data);
-}
-
-/*!
- Reads the data from the open QIODevice \a device until it ends
- and adds it to message. Returns \c true if reading was successful.
-
- \note \a device must be already opened.
- */
-bool QMessageAuthenticationCode::addData(QIODevice *device)
-{
- d->initMessageHash();
- return d->messageHash.addData(device);
-}
-
-/*!
- Returns the final authentication code.
-
- \sa QByteArray::toHex()
-*/
-QByteArray QMessageAuthenticationCode::result() const
-{
- if (!d->result.isEmpty())
- return d->result;
-
- d->initMessageHash();
-
- const int blockSize = qt_hash_block_size(d->method);
-
- QByteArrayView hashedMessage = d->messageHash.resultView();
-
- QVarLengthArray<char> oKeyPad(blockSize);
- const char * const keyData = d->key.constData();
-
- for (int i = 0; i < blockSize; ++i)
- oKeyPad[i] = keyData[i] ^ 0x5c;
-
- QCryptographicHash hash(d->method);
- hash.addData(oKeyPad);
- hash.addData(hashedMessage);
-
- d->result = hash.result();
- return d->result;
-}
-
-/*!
- Returns the authentication code for the message \a message using
- the key \a key and the method \a method.
-*/
-QByteArray QMessageAuthenticationCode::hash(const QByteArray &message, const QByteArray &key,
- QCryptographicHash::Algorithm method)
-{
- QMessageAuthenticationCode mac(method);
- mac.setKey(key);
- mac.addData(message);
- return mac.result();
-}
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qmessageauthenticationcode.h b/src/corelib/tools/qmessageauthenticationcode.h
index 343bf9d617..4e88138763 100644
--- a/src/corelib/tools/qmessageauthenticationcode.h
+++ b/src/corelib/tools/qmessageauthenticationcode.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMESSAGEAUTHENTICATIONCODE_H
#define QMESSAGEAUTHENTICATIONCODE_H
@@ -48,25 +12,48 @@ QT_BEGIN_NAMESPACE
class QMessageAuthenticationCodePrivate;
class QIODevice;
+// implemented in qcryptographichash.cpp
class Q_CORE_EXPORT QMessageAuthenticationCode
{
public:
+#if QT_CORE_REMOVED_SINCE(6, 6)
explicit QMessageAuthenticationCode(QCryptographicHash::Algorithm method,
- const QByteArray &key = QByteArray());
+ const QByteArray &key);
+#endif
+ explicit QMessageAuthenticationCode(QCryptographicHash::Algorithm method,
+ QByteArrayView key = {});
+
+ QMessageAuthenticationCode(QMessageAuthenticationCode &&other) noexcept
+ : d{std::exchange(other.d, nullptr)} {}
~QMessageAuthenticationCode();
- void reset();
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMessageAuthenticationCode)
+ void swap(QMessageAuthenticationCode &other) noexcept
+ { qt_ptr_swap(d, other.d); }
+
+ void reset() noexcept;
+#if QT_CORE_REMOVED_SINCE(6, 6)
void setKey(const QByteArray &key);
+#endif
+ void setKey(QByteArrayView key) noexcept;
void addData(const char *data, qsizetype length);
+#if QT_CORE_REMOVED_SINCE(6, 6)
void addData(const QByteArray &data);
+#endif
+ void addData(QByteArrayView data) noexcept;
bool addData(QIODevice *device);
+ QByteArrayView resultView() const noexcept;
QByteArray result() const;
+#if QT_CORE_REMOVED_SINCE(6, 6)
static QByteArray hash(const QByteArray &message, const QByteArray &key,
QCryptographicHash::Algorithm method);
+#endif
+ static QByteArray hash(QByteArrayView message, QByteArrayView key,
+ QCryptographicHash::Algorithm method);
private:
Q_DISABLE_COPY(QMessageAuthenticationCode)
diff --git a/src/corelib/tools/qminimalflatset_p.h b/src/corelib/tools/qminimalflatset_p.h
new file mode 100644
index 0000000000..6074688f6e
--- /dev/null
+++ b/src/corelib/tools/qminimalflatset_p.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTCORE_QMINIMALFLATSET_P_H
+#define QTCORE_QMINIMALFLATSET_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/qcontainerfwd.h>
+#include <QtCore/qfunctionaltools_impl.h> // CompactStorage
+#include <QtCore/private/qglobal_p.h>
+
+//#define QMINIMAL_FLAT_SET_DEBUG
+#ifdef QMINIMAL_FLAT_SET_DEBUG
+# include <QtCore/qscopeguard.h>
+# include <QtCore/qdebug.h>
+# define QMINIMAL_FLAT_SET_PRINT_AT_END \
+ const auto sg = qScopeGuard([&] { qDebug() << this << *this; });
+#else
+# define QMINIMAL_FLAT_SET_PRINT_AT_END
+#endif
+
+#include <algorithm> // for std::lower_bound
+#include <functional> // for std::less, std::ref
+
+QT_BEGIN_NAMESPACE
+
+/*
+ This is a minimal version of a QFlatSet, the std::set version of QFlatMap.
+ Like QFlatMap, it has linear insertion and removal, not logarithmic, like
+ real QMap and std::set, so it's only a good container if you either have
+ very few entries or lots, but with separate setup and lookup stages.
+ Because a full QFlatSet would be 10x the work on writing this minimal one,
+ we keep it here for now. When more users pop up and the class has matured a
+ bit, we can consider moving it as QFlatSet alongside QFlatMap.
+*/
+
+template <typename T, typename Container = QList<T>, typename Compare = std::less<T>>
+class QMinimalFlatSet : QtPrivate::CompactStorage<Compare>
+{
+ Container c;
+ using CompareStorage = QtPrivate::CompactStorage<Compare>;
+public:
+ QMinimalFlatSet() = default;
+ explicit QMinimalFlatSet(const Compare &cmp) : CompareStorage{cmp} {}
+ // Rule Of Zero applies
+
+ using const_iterator = typename Container::const_iterator;
+ using iterator = const_iterator;
+ using const_reverse_iterator = typename Container::const_reverse_iterator;
+ using reverse_iterator = const_reverse_iterator;
+ using value_type = T;
+ using key_compare = Compare;
+ using value_compare = Compare;
+
+ key_compare key_comp() const { return this->object(); }
+ value_compare value_comp() const { return key_comp(); }
+
+ iterator begin() const { return c.cbegin(); }
+ iterator end() const { return c.cend(); }
+ iterator cbegin() const { return begin(); }
+ iterator cend() const { return cend(); }
+
+ reverse_iterator rbegin() const { return c.crbegin(); }
+ reverse_iterator rend() const { return c.crend(); }
+ reverse_iterator crbegin() const { return rbegin(); }
+ reverse_iterator crend() const { return rend(); }
+
+ void clear() {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ c.clear();
+ }
+ auto size() const { return c.size(); }
+ auto count() const { return size(); }
+ bool isEmpty() const { return size() == 0; }
+
+ std::pair<iterator, bool> insert(value_type &&v)
+ {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ const auto r = lookup(v);
+ if (r.exists)
+ return {r.it, false};
+ else
+ return {c.insert(r.it, std::move(v)), true};
+ }
+
+ std::pair<iterator, bool> insert(const value_type &v)
+ {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ const auto r = lookup(v);
+ if (r.exists)
+ return {r.it, false};
+ else
+ return {c.insert(r.it, v), true};
+ }
+
+ void erase(const value_type &v)
+ {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ const auto r = lookup(v);
+ if (r.exists)
+ c.erase(r.it);
+ }
+ void remove(const value_type &v) { erase(v); }
+
+ bool contains(const value_type &v) const
+ {
+ return lookup(v).exists;
+ }
+
+ const Container &values() const & { return c; }
+ Container values() && { return std::move(c); }
+
+private:
+ auto lookup(const value_type &v) const
+ {
+ struct R {
+ iterator it;
+ bool exists;
+ };
+
+ auto cmp = std::ref(this->object()); // don't let std::lower_bound copy it
+
+ const auto it = std::lower_bound(c.cbegin(), c.cend(), v, cmp);
+ return R{it, it != c.cend() && !cmp(v, *it)};
+ }
+
+#ifdef QMINIMAL_FLAT_SET_DEBUG
+ friend QDebug operator<<(QDebug dbg, const QMinimalFlatSet &set)
+ {
+ const QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QMinimalFlatSet{";
+ for (auto &e : set)
+ dbg << e << ", ";
+ return dbg << "}";
+ }
+#endif
+};
+
+#undef QMINIMAL_FLAT_SET_PRINT_AT_END
+
+template <typename T, qsizetype N = QVarLengthArrayDefaultPrealloc>
+using QMinimalVarLengthFlatSet = QMinimalFlatSet<T, QVarLengthArray<T, N>>;
+
+QT_END_NAMESPACE
+
+#endif // QTCORE_QMINIMALFLATSET_P_H
diff --git a/src/corelib/tools/qmultimap.qdoc b/src/corelib/tools/qmultimap.qdoc
index 6bfc1515e6..0b05192817 100644
--- a/src/corelib/tools/qmultimap.qdoc
+++ b/src/corelib/tools/qmultimap.qdoc
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@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.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QMultiMap
@@ -128,7 +92,7 @@
\snippet code/src_corelib_tools_qmultimap.cpp 11
If you only need to extract the values from a map (not the keys),
- you can also use \l{foreach}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qmultimap.cpp 12
@@ -246,7 +210,7 @@
Returns an STL multi map equivalent to this QMultiMap.
*/
-/*! \fn template <class Key, class T> std::multimap<Key, T> QMultiMap<Key, T>::toStdMultiMap() const
+/*! \fn template <class Key, class T> std::multimap<Key, T> QMultiMap<Key, T>::toStdMultiMap() const &
Returns an STL multi map equivalent to this QMultiMap.
*/
@@ -693,6 +657,25 @@
\sa constKeyValueBegin()
*/
+/*! \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() &
+ \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() const &
+ \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() &&
+ \fn template <class Key, class T> auto QMultiMap<Key, T>::asKeyValueRange() const &&
+ \since 6.4
+
+ Returns a range object that allows iteration over this multi map as
+ key/value pairs. For instance, this range object can be used in a
+ range-based for loop, in combination with a structured binding declaration:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 26
+
+ Note that both the key and the value obtained this way are
+ references to the ones in the multi map. Specifically, mutating the value
+ will modify the map itself.
+
+ \sa QKeyValueIterator
+*/
+
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::erase(const_iterator pos)
Removes the (key, value) pair pointed to by the iterator \a pos
@@ -834,6 +817,8 @@
different from replace(), which overwrites the value of an
existing item.)
+ Returns an iterator pointing to the new element.
+
\sa replace()
*/
@@ -856,6 +841,8 @@
is faster than inserting in sorted order with constEnd(), since constEnd() - 1 (which is needed
to check if the hint is valid) needs \l{logarithmic time}.
+ Returns an iterator pointing to the new element.
+
\b {Note:} Be careful with the hint. Providing an iterator from an older shared instance might
crash but there is also a risk that it will silently corrupt both the multi map and the \a pos multi map.
*/
@@ -903,17 +890,19 @@
If there are multiple items with the key \a key, the most
recently inserted item's value is replaced with \a value.
+ Returns an iterator pointing to the new/updated element.
+
\sa insert()
*/
/*! \typedef QMultiMap::Iterator
- Qt-style synonym for QMultiMap<Key, T>::iterator.
+ Qt-style synonym for QMultiMap::iterator.
*/
/*! \typedef QMultiMap::ConstIterator
- Qt-style synonym for QMultiMap<Key, T>::const_iterator.
+ Qt-style synonym for QMultiMap::const_iterator.
*/
/*! \typedef QMultiMap::difference_type
@@ -945,14 +934,14 @@
*/
/*!
- \fn template <class Key, class T> QPair<typename QMultiMap<Key, T>::iterator, typename QMultiMap<Key, T>::iterator> QMultiMap<Key, T>::equal_range(const Key &key)
+ \fn template <class Key, class T> std::pair<typename QMultiMap<Key, T>::iterator, typename QMultiMap<Key, T>::iterator> QMultiMap<Key, T>::equal_range(const Key &key)
Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
are stored under \a key.
*/
/*!
- \fn template <class Key, class T> QPair<typename QMultiMap<Key, T>::const_iterator, typename QMultiMap<Key, T>::const_iterator> QMultiMap<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> std::pair<typename QMultiMap<Key, T>::const_iterator, typename QMultiMap<Key, T>::const_iterator> QMultiMap<Key, T>::equal_range(const Key &key) const
\overload
\since 5.6
*/
@@ -976,6 +965,7 @@
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
+ \relates QMultiMap
Inserts all the items in the \a rhs map into the \a lhs map and
returns the resulting map.
@@ -984,6 +974,7 @@
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
+ \relates QMultiMap
Returns a map that contains all the items in the \a lhs map in
addition to all the items in \a rhs. If a key is common to both
@@ -996,12 +987,6 @@
\inmodule QtCore
\brief The QMultiMap::iterator class provides an STL-style non-const iterator for QMultiMap.
- QMultiMap 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.
-
QMultiMap\<Key, T\>::iterator allows you to iterate over a QMultiMap
and to modify the value (but not the key) stored under
a particular key. If you want to iterate over a const QMultiMap, you
@@ -1016,38 +1001,20 @@
start iterating. Here's a typical loop that prints all the (key,
value) pairs stored in a map:
- \snippet code/src_corelib_tools_qmultimap.cpp 18
-
Unlike QMultiHash, which stores its items in an arbitrary order, QMultiMap
stores its items ordered by key. Items that share the same key
will appear consecutively,
from the most recently to the least recently inserted value.
- Let's see a few examples of things we can do with a
- QMultiMap::iterator that we cannot do with a QMultiMap::const_iterator.
Here's an example that increments every value stored in the QMultiMap
by 2:
\snippet code/src_corelib_tools_qmultimap.cpp 19
- 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_qmultimap.cpp 20
-
- The call to QMultiMap::erase() removes the item pointed to by the
- iterator from the map, and returns an iterator to the next item.
- Here's another way of removing an item while iterating:
+ To remove elements from a QMultiMap you can use erase_if(QMultiMap\<Key, T\> &map, Predicate pred):
\snippet code/src_corelib_tools_qmultimap.cpp 21
- It might be tempting to write code like this:
-
- \snippet code/src_corelib_tools_qmultimap.cpp 22
-
- 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 map. If you add items
to the map, existing iterators will remain valid. If you remove
items from the map, iterators that point to the removed items
@@ -1058,7 +1025,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiMap::const_iterator, QMultiMap::key_iterator, QMutableMultiMapIterator
+ \sa QMultiMap::const_iterator, QMultiMap::key_iterator, QMultiMap::key_value_iterator
*/
/*! \typedef QMultiMap::iterator::difference_type
@@ -1159,7 +1126,7 @@
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator &QMultiMap<Key, T>::iterator::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the multi map and returns an iterator to the new current
item.
@@ -1172,14 +1139,14 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} operator (\c{i++}) advances the iterator to the
next item in the multi map and returns an iterator to the previously
current item.
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator &QMultiMap<Key, T>::iterator::operator--()
- The prefix -- operator (\c{--i}) makes the preceding item
+ The prefix \c{--} operator (\c{--i}) makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QMultiMap::begin() leads to undefined
@@ -1192,7 +1159,7 @@
\overload
- The postfix -- operator (\c{i--}) makes the preceding item
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
current and returns an iterator pointing to the previously
current item.
*/
@@ -1219,12 +1186,6 @@
\inmodule QtCore
\brief The QMultiMap::const_iterator class provides an STL-style const iterator for QMultiMap.
- QMultiMap 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.
-
QMultiMap\<Key, T\>::const_iterator allows you to iterate over a QMultiMap.
If you want to modify the QMultiMap as you iterate
over it, you must use QMultiMap::iterator instead. It is generally
@@ -1235,12 +1196,16 @@
The default QMultiMap::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QMultiMap
- function like QMultiMap::constBegin(), QMultiMap::constEnd(), or
- QMultiMap::find() before you can start iterating. Here's a typical
+ function like QMultiMap::cbegin(), QMultiMap::cend(), or
+ QMultiMap::constFind() before you can start iterating. Here's a typical
loop that prints all the (key, value) pairs stored in a map:
\snippet code/src_corelib_tools_qmultimap.cpp 24
+ Here's an example that removes all the items whose value is greater than 10:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 20
+
Unlike QMultiHash, which stores its items in an arbitrary order, QMultiMap
stores its items ordered by key. Items that share the same key
will appear consecutively,
@@ -1256,7 +1221,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiMap::iterator, QMultiMap::key_iterator, QMultiMapIterator
+ \sa QMultiMap::iterator, QMultiMap::key_iterator, QMultiMap::const_key_value_iterator
*/
/*! \typedef QMultiMap::const_iterator::difference_type
@@ -1333,7 +1298,7 @@
/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator &QMultiMap<Key, T>::const_iterator::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the map and returns an iterator to the new current
item.
@@ -1346,14 +1311,14 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} operator (\c{i++}) advances the iterator to the
next item in the map and returns an iterator to the previously
current item.
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator &QMultiMap<Key, T>::const_iterator::operator--()
- The prefix -- operator (\c{--i}) makes the preceding item
+ The prefix \c{--} operator (\c{--i}) makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QMultiMap::begin() leads to undefined
@@ -1366,7 +1331,7 @@
\overload
- The postfix -- operator (\c{i--}) makes the preceding item
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
current and returns an iterator pointing to the previously
current item.
*/
@@ -1475,7 +1440,7 @@
/*!
\fn template <class Key, class T> QMultiMap<Key, T>::key_iterator &QMultiMap<Key, T>::key_iterator::operator++()
- The prefix ++ operator (\c{++i}) advances the iterator to the
+ The prefix \c{++} operator (\c{++i}) advances the iterator to the
next item in the hash and returns an iterator to the new current
item.
@@ -1488,14 +1453,14 @@
\overload
- The postfix ++ operator (\c{i++}) advances the iterator to the
+ The postfix \c{++} 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> QMultiMap<Key, T>::key_iterator &QMultiMap<Key, T>::key_iterator::operator--()
- The prefix -- operator (\c{--i}) makes the preceding item
+ The prefix \c{--} operator (\c{--i}) makes the preceding item
current and returns an iterator pointing to the new current item.
Calling this function on QMultiMap::keyBegin() leads to undefined
@@ -1508,7 +1473,7 @@
\overload
- The postfix -- operator (\c{i--}) makes the preceding item
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
current and returns an iterator pointing to the previous
item.
*/
diff --git a/src/corelib/tools/qoffsetstringarray_p.h b/src/corelib/tools/qoffsetstringarray_p.h
index 6e0cb1f30b..9103606a13 100644
--- a/src/corelib/tools/qoffsetstringarray_p.h
+++ b/src/corelib/tools/qoffsetstringarray_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2021 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2021 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOFFSETSTRINGARRAY_P_H
#define QOFFSETSTRINGARRAY_P_H
@@ -54,15 +18,24 @@
#include "private/qglobal_p.h"
+#include <QByteArrayView>
+
+#include <QtCore/q20algorithm.h>
#include <array>
#include <limits>
-#include <string>
+#include <string_view>
#include <tuple>
class tst_QOffsetStringArray;
QT_BEGIN_NAMESPACE
+QT_WARNING_PUSH
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1100
+// we usually don't overread, but GCC has a false positive
+QT_WARNING_DISABLE_GCC("-Wstringop-overread")
+#endif
+
template <typename StaticString, typename OffsetList>
class QOffsetStringArray
@@ -74,7 +47,7 @@ public:
constexpr const char *operator[](const int index) const noexcept
{
- return m_string.data() + m_offsets[qBound(int(0), index, count() - 1)];
+ return m_string.data() + m_offsets[qBound(int(0), index, count())];
}
constexpr const char *at(const int index) const noexcept
@@ -82,7 +55,22 @@ public:
return m_string.data() + m_offsets[index];
}
- constexpr int count() const { return int(m_offsets.size()); }
+ constexpr QByteArrayView viewAt(qsizetype index) const noexcept
+ {
+ return { m_string.data() + m_offsets[index],
+ qsizetype(m_offsets[index + 1]) - qsizetype(m_offsets[index]) - 1 };
+ }
+
+ constexpr int count() const { return int(m_offsets.size()) - 1; }
+
+ bool contains(QByteArrayView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ {
+ for (qsizetype i = 0; i < count(); ++i) {
+ if (viewAt(i).compare(needle, cs) == 0)
+ return true;
+ }
+ return false;
+ }
private:
StaticString m_string;
@@ -91,21 +79,13 @@ private:
};
namespace QtPrivate {
-// std::copy is not constexpr in C++17
-template <typename II, typename OO>
-static constexpr OO copyData(II input, qsizetype n, OO output)
-{
- using E = decltype(+*output);
- for (qsizetype i = 0; i < n; ++i)
- output[i] = E(input[i]);
- return output + n;
-}
-
template <size_t Highest> constexpr auto minifyValue()
{
- if constexpr (Highest <= std::numeric_limits<quint8>::max()) {
+ constexpr size_t max8 = (std::numeric_limits<quint8>::max)();
+ constexpr size_t max16 = (std::numeric_limits<quint16>::max)();
+ if constexpr (Highest <= max8) {
return quint8(Highest);
- } else if constexpr (Highest <= std::numeric_limits<quint16>::max()) {
+ } else if constexpr (Highest <= max16) {
return quint16(Highest);
} else {
// int is probably enough for everyone
@@ -122,7 +102,7 @@ constexpr auto makeStaticString(Extractor extract, const T &... entries)
const char *strings[] = { extract(entries).operator const char *()... };
size_t lengths[] = { sizeof(extract(T{}))... };
for (size_t i = 0; i < std::size(strings); ++i) {
- copyData(strings[i], lengths[i], result.begin() + offset);
+ q20::copy_n(strings[i], lengths[i], result.begin() + offset);
offset += lengths[i];
}
return result;
@@ -132,7 +112,7 @@ template <size_t N> struct StaticString
{
char value[N] = {};
constexpr StaticString() = default;
- constexpr StaticString(const char (&s)[N]) { copyData(s, N, value); }
+ constexpr StaticString(const char (&s)[N]) { q20::copy_n(s, N, value); }
constexpr operator const char *() const { return value; }
};
@@ -147,31 +127,34 @@ template <size_t KL, size_t VL> struct StaticMapEntry
};
template <typename StringExtractor, typename... T>
-constexpr auto qOffsetStringArray(StringExtractor extractString, const T &... entries)
+constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries)
{
constexpr size_t Count = sizeof...(T);
- constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...);
+ constexpr size_t StringLength = (sizeof(extractString(T{})) + ...);
using MinifiedOffsetType = decltype(QtPrivate::minifyValue<StringLength>());
size_t offset = 0;
std::array fullOffsetList = { offset += sizeof(extractString(T{}))... };
- // prepend zero, drop last element
- std::array<MinifiedOffsetType, Count> minifiedOffsetList = {};
- QtPrivate::copyData(fullOffsetList.begin(), Count - 1, minifiedOffsetList.begin() + 1);
+ // prepend zero
+ std::array<MinifiedOffsetType, Count + 1> minifiedOffsetList = {};
+ q20::transform(fullOffsetList.begin(), fullOffsetList.end(),
+ minifiedOffsetList.begin() + 1,
+ [] (auto e) { return MinifiedOffsetType(e); });
std::array staticString = QtPrivate::makeStaticString<StringLength>(extractString, entries...);
return QOffsetStringArray(staticString, minifiedOffsetList);
}
-}
+} // namespace QtPrivate
template<int ... Nx>
constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept
{
auto extractString = [](const auto &s) -> decltype(auto) { return s; };
- return QtPrivate::qOffsetStringArray(extractString, QtPrivate::StaticString(strings)...);
+ return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...);
}
+QT_WARNING_POP
QT_END_NAMESPACE
#endif // QOFFSETSTRINGARRAY_P_H
diff --git a/src/corelib/tools/qpair.h b/src/corelib/tools/qpair.h
index 6cb7fc5079..84f99075e1 100644
--- a/src/corelib/tools/qpair.h
+++ b/src/corelib/tools/qpair.h
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAIR_H
#define QPAIR_H
+#include <QtCore/qcontainerfwd.h>
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@@ -48,8 +13,7 @@ QT_BEGIN_NAMESPACE
#pragma qt_class(QPair)
#endif
-template <typename T1, typename T2>
-using QPair = std::pair<T1, T2>;
+#ifndef QT_NO_QPAIR
template <typename T1, typename T2>
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2)
@@ -58,8 +22,7 @@ constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2)
return std::make_pair(std::forward<T1>(value1), std::forward<T2>(value2));
}
-template<class T1, class T2>
-class QTypeInfo<std::pair<T1, T2>> : public QTypeInfoMerger<std::pair<T1, T2>, T1, T2> {};
+#endif // QT_NO_QPAIR
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc
index 3cd1beec18..3aaee157d4 100644
--- a/src/corelib/tools/qpair.qdoc
+++ b/src/corelib/tools/qpair.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\typealias QPair
diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp
index 80599a4caa..d1f3b12a68 100644
--- a/src/corelib/tools/qpoint.cpp
+++ b/src/corelib/tools/qpoint.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpoint.h"
#include "qdatastream.h"
@@ -381,6 +345,15 @@ QT_BEGIN_NAMESPACE
\sa QPoint::operator/=()
*/
+/*!
+ \fn QPoint::toPointF() const
+ \since 6.4
+
+ Returns this point as a point with floating point accuracy.
+
+ \sa QPointF::toPoint()
+*/
+
/*****************************************************************************
QPoint stream functions
*****************************************************************************/
@@ -532,7 +505,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
Constructs a copy of the given \a point.
- \sa toPoint()
+ \sa toPoint(), QPoint::toPointF()
*/
/*!
@@ -744,7 +717,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
Rounds the coordinates of this point to the nearest integer, and
returns a QPoint object with the rounded coordinates.
- \sa QPointF()
+ \sa QPointF(), QPoint::toPointF()
*/
/*!
diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h
index f2c562393a..7df4d49005 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -1,53 +1,24 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPOINT_H
#define QPOINT_H
#include <QtCore/qnamespace.h>
+#include <QtCore/q20type_traits.h>
+#include <QtCore/q23utility.h>
+
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
struct CGPoint;
#endif
QT_BEGIN_NAMESPACE
+QT_ENABLE_P0846_SEMANTICS_FOR(get)
+
+class QPointF;
+
class QPoint
{
public:
@@ -110,6 +81,7 @@ public:
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
[[nodiscard]] Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
#endif
+ [[nodiscard]] constexpr inline QPointF toPointF() const noexcept;
private:
friend class QTransform;
@@ -119,13 +91,13 @@ private:
template <std::size_t I,
typename P,
std::enable_if_t<(I < 2), bool> = true,
- std::enable_if_t<std::is_same_v<std::decay_t<P>, QPoint>, bool> = true>
+ std::enable_if_t<std::is_same_v<q20::remove_cvref_t<P>, QPoint>, bool> = true>
friend constexpr decltype(auto) get(P &&p) noexcept
{
if constexpr (I == 0)
- return (std::forward<P>(p).xp);
+ return q23::forward_like<P>(p.xp);
else if constexpr (I == 1)
- return (std::forward<P>(p).yp);
+ return q23::forward_like<P>(p.yp);
}
};
@@ -316,13 +288,13 @@ private:
template <std::size_t I,
typename P,
std::enable_if_t<(I < 2), bool> = true,
- std::enable_if_t<std::is_same_v<std::decay_t<P>, QPointF>, bool> = true>
+ std::enable_if_t<std::is_same_v<q20::remove_cvref_t<P>, QPointF>, bool> = true>
friend constexpr decltype(auto) get(P &&p) noexcept
{
if constexpr (I == 0)
- return (std::forward<P>(p).xp);
+ return q23::forward_like<P>(p.xp);
else if constexpr (I == 1)
- return (std::forward<P>(p).yp);
+ return q23::forward_like<P>(p.yp);
}
};
@@ -417,6 +389,8 @@ constexpr inline QPointF &QPointF::operator/=(qreal divisor)
return *this;
}
+constexpr QPointF QPoint::toPointF() const noexcept { return *this; }
+
constexpr inline QPoint QPointF::toPoint() const
{
return QPoint(qRound(xp), qRound(yp));
diff --git a/src/corelib/tools/qqueue.cpp b/src/corelib/tools/qqueue.cpp
index ffc48d6714..82095faa3d 100644
--- a/src/corelib/tools/qqueue.cpp
+++ b/src/corelib/tools/qqueue.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QQueue
diff --git a/src/corelib/tools/qqueue.h b/src/corelib/tools/qqueue.h
index 862aa2ae2c..4863499f2a 100644
--- a/src/corelib/tools/qqueue.h
+++ b/src/corelib/tools/qqueue.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQUEUE_H
#define QQUEUE_H
diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp
index 64ccdb20ff..6d345ce543 100644
--- a/src/corelib/tools/qrect.cpp
+++ b/src/corelib/tools/qrect.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrect.h"
#include "qdatastream.h"
@@ -1232,6 +1196,18 @@ bool QRect::intersects(const QRect &r) const noexcept
\since 6.0
*/
+/*!
+ \fn QRect::toRectF() const
+ \since 6.4
+
+ Returns this rectangle as a rectangle with floating point accuracy.
+
+ \note This function, like the QRectF(QRect) constructor, preserves the
+ size() of the rectangle, not its bottomRight() corner.
+
+ \sa QRectF::toRect()
+*/
+
/*****************************************************************************
QRect stream functions
*****************************************************************************/
@@ -1480,7 +1456,10 @@ QDebug operator<<(QDebug dbg, const QRect &r)
Constructs a QRectF rectangle from the given QRect \a rectangle.
- \sa toRect()
+ \note This function, like QRect::toRectF(), preserves the size() of
+ \a rectangle, not its bottomRight() corner.
+
+ \sa toRect(), QRect::toRectF()
*/
/*!
@@ -2334,7 +2313,7 @@ bool QRectF::intersects(const QRectF &r) const noexcept
Returns a QRect based on the values of this rectangle. Note that the
coordinates in the returned rectangle are rounded to the nearest integer.
- \sa QRectF(), toAlignedRect()
+ \sa QRectF(), toAlignedRect(), QRect::toRectF()
*/
/*!
diff --git a/src/corelib/tools/qrect.h b/src/corelib/tools/qrect.h
index 9e64f4d6e8..e69a217f48 100644
--- a/src/corelib/tools/qrect.h
+++ b/src/corelib/tools/qrect.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRECT_H
#define QRECT_H
@@ -52,9 +16,16 @@
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
struct CGRect;
#endif
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+namespace emscripten {
+class val;
+}
+#endif
QT_BEGIN_NAMESPACE
+class QRectF;
+
class Q_CORE_EXPORT QRect
{
public:
@@ -157,6 +128,7 @@ public:
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
[[nodiscard]] CGRect toCGRect() const noexcept;
#endif
+ [[nodiscard]] constexpr inline QRectF toRectF() const noexcept;
private:
int x1;
@@ -619,6 +591,11 @@ public:
[[nodiscard]] CGRect toCGRect() const noexcept;
#endif
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+ [[nodiscard]] static QRectF fromDOMRect(emscripten::val domRect);
+ [[nodiscard]] emscripten::val toDOMRect() const;
+#endif
+
private:
qreal xp;
qreal yp;
@@ -863,6 +840,8 @@ inline QRectF QRectF::united(const QRectF &r) const noexcept
return *this | r;
}
+constexpr QRectF QRect::toRectF() const noexcept { return *this; }
+
constexpr inline QRect QRectF::toRect() const noexcept
{
// This rounding is designed to minimize the maximum possible difference
diff --git a/src/corelib/tools/qrefcount.cpp b/src/corelib/tools/qrefcount.cpp
index 1986cce9ca..c33b34594b 100644
--- a/src/corelib/tools/qrefcount.cpp
+++ b/src/corelib/tools/qrefcount.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QtPrivate::RefCount
diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h
index 982a9c2bbf..9472716a72 100644
--- a/src/corelib/tools/qrefcount.h
+++ b/src/corelib/tools/qrefcount.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QREFCOUNT_H
#define QREFCOUNT_H
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index 09b0336145..0645759118 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -1,49 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2015 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2015 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qringbuffer_p.h"
-#include "private/qbytearray_p.h"
+
+#include <type_traits>
+
#include <string.h>
QT_BEGIN_NAMESPACE
+static_assert(std::is_nothrow_default_constructible_v<QRingChunk>);
+static_assert(std::is_nothrow_move_constructible_v<QRingChunk>);
+static_assert(std::is_nothrow_move_assignable_v<QRingChunk>);
+
void QRingChunk::allocate(qsizetype alloc)
{
Q_ASSERT(alloc > 0 && size() == 0);
@@ -57,31 +27,23 @@ void QRingChunk::detach()
Q_ASSERT(isShared());
const qsizetype chunkSize = size();
- QByteArray x(chunkSize, Qt::Uninitialized);
- ::memcpy(x.data(), chunk.constData() + headOffset, chunkSize);
- chunk = std::move(x);
+ chunk = QByteArray(std::as_const(*this).data(), chunkSize);
headOffset = 0;
tailOffset = chunkSize;
}
-QByteArray QRingChunk::toByteArray()
+QByteArray QRingChunk::toByteArray() &&
{
+ // ### Replace with std::move(chunk).sliced(head(), size()) once sliced()&& is available
if (headOffset != 0 || tailOffset != chunk.size()) {
if (isShared())
- return chunk.mid(headOffset, size());
-
- if (headOffset != 0) {
- char *ptr = chunk.data();
- ::memmove(ptr, ptr + headOffset, size());
- tailOffset -= headOffset;
- headOffset = 0;
- }
+ return chunk.sliced(head(), size());
- chunk.reserve(0); // avoid that resizing needlessly reallocates
chunk.resize(tailOffset);
+ chunk.remove(0, headOffset);
}
- return chunk;
+ return std::move(chunk);
}
/*!
@@ -128,7 +90,7 @@ void QRingBuffer::free(qint64 bytes)
clear(); // try to minify/squeeze us
}
} else {
- Q_ASSERT(bytes < MaxByteArraySize);
+ Q_ASSERT(bytes < QByteArray::max_size());
chunk.advance(bytes);
bufferSize -= bytes;
}
@@ -143,7 +105,7 @@ void QRingBuffer::free(qint64 bytes)
char *QRingBuffer::reserve(qint64 bytes)
{
- Q_ASSERT(bytes > 0 && bytes < MaxByteArraySize);
+ Q_ASSERT(bytes > 0 && bytes < QByteArray::max_size());
const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
qsizetype tail = 0;
@@ -173,7 +135,7 @@ char *QRingBuffer::reserve(qint64 bytes)
*/
char *QRingBuffer::reserveFront(qint64 bytes)
{
- Q_ASSERT(bytes > 0 && bytes < MaxByteArraySize);
+ Q_ASSERT(bytes > 0 && bytes < QByteArray::max_size());
const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
if (bufferSize == 0) {
@@ -219,7 +181,7 @@ void QRingBuffer::chop(qint64 bytes)
clear(); // try to minify/squeeze us
}
} else {
- Q_ASSERT(bytes < MaxByteArraySize);
+ Q_ASSERT(bytes < QByteArray::max_size());
chunk.grow(-bytes);
bufferSize -= bytes;
}
@@ -363,6 +325,21 @@ void QRingBuffer::append(const QByteArray &qba)
bufferSize += qba.size();
}
+/*!
+ \internal
+
+ Append a new buffer to the end
+*/
+void QRingBuffer::append(QByteArray &&qba)
+{
+ const auto qbaSize = qba.size();
+ if (bufferSize != 0 || buffers.isEmpty())
+ buffers.emplace_back(std::move(qba));
+ else
+ buffers.last().assign(std::move(qba));
+ bufferSize += qbaSize;
+}
+
qint64 QRingBuffer::readLine(char *data, qint64 maxLength)
{
Q_ASSERT(data != nullptr && maxLength > 1);
diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h
index bbab8df3e2..25113213c9 100644
--- a/src/corelib/tools/qringbuffer_p.h
+++ b/src/corelib/tools/qringbuffer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRINGBUFFER_P_H
#define QRINGBUFFER_P_H
@@ -65,36 +29,19 @@ class QRingChunk
{
public:
// initialization and cleanup
- inline QRingChunk() noexcept :
- headOffset(0), tailOffset(0)
- {
- }
- inline QRingChunk(const QRingChunk &other) noexcept :
- chunk(other.chunk), headOffset(other.headOffset), tailOffset(other.tailOffset)
- {
- }
+ QRingChunk() noexcept = default;
explicit inline QRingChunk(qsizetype alloc) :
- chunk(alloc, Qt::Uninitialized), headOffset(0), tailOffset(0)
+ chunk(alloc, Qt::Uninitialized), tailOffset(0)
{
}
explicit inline QRingChunk(const QByteArray &qba) noexcept :
- chunk(qba), headOffset(0), tailOffset(qba.size())
+ chunk(qba), tailOffset(qba.size())
{
}
-
- inline QRingChunk &operator=(const QRingChunk &other) noexcept
+ explicit QRingChunk(QByteArray &&qba) noexcept :
+ chunk(std::move(qba)), tailOffset(chunk.size())
{
- chunk = other.chunk;
- headOffset = other.headOffset;
- tailOffset = other.tailOffset;
- return *this;
}
- inline QRingChunk(QRingChunk &&other) noexcept :
- chunk(other.chunk), headOffset(other.headOffset), tailOffset(other.tailOffset)
- {
- other.headOffset = other.tailOffset = 0;
- }
- QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRingChunk)
inline void swap(QRingChunk &other) noexcept
{
@@ -110,7 +57,7 @@ public:
return !chunk.isDetached();
}
Q_CORE_EXPORT void detach();
- QByteArray toByteArray();
+ QByteArray toByteArray() &&;
// getters
inline qsizetype head() const
@@ -161,28 +108,38 @@ public:
headOffset = 0;
tailOffset = qba.size();
}
+ void assign(QByteArray &&qba)
+ {
+ chunk = std::move(qba);
+ headOffset = 0;
+ tailOffset = chunk.size();
+ }
inline void reset()
{
headOffset = tailOffset = 0;
}
inline void clear()
{
- assign(QByteArray());
+ *this = {};
}
private:
QByteArray chunk;
- qsizetype headOffset;
- qsizetype tailOffset;
+ qsizetype headOffset = 0;
+ qsizetype tailOffset = 0;
};
Q_DECLARE_SHARED(QRingChunk)
class QRingBuffer
{
+ Q_DISABLE_COPY(QRingBuffer)
public:
explicit inline QRingBuffer(int growth = QRINGBUFFER_CHUNKSIZE) :
bufferSize(0), basicBlockSize(growth) { }
+ QRingBuffer(QRingBuffer &&) noexcept = default;
+ QRingBuffer &operator=(QRingBuffer &&) noexcept = default;
+
inline void setChunkSize(int size) {
basicBlockSize = size;
}
@@ -248,6 +205,7 @@ public:
Q_CORE_EXPORT qint64 peek(char *data, qint64 maxLength, qint64 pos = 0) const;
Q_CORE_EXPORT void append(const char *data, qint64 size);
Q_CORE_EXPORT void append(const QByteArray &qba);
+ Q_CORE_EXPORT void append(QByteArray &&qba);
inline qint64 skip(qint64 length) {
qint64 bytesToSkip = qMin(length, bufferSize);
diff --git a/src/corelib/tools/qscopedpointer.cpp b/src/corelib/tools/qscopedpointer.cpp
index 1844013d46..515eb9dc75 100644
--- a/src/corelib/tools/qscopedpointer.cpp
+++ b/src/corelib/tools/qscopedpointer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qscopedpointer.h"
@@ -305,31 +269,37 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> template <typename D> QScopedArrayPointer<T, Cleanup>::QScopedArrayPointer(D * p)
+ \fn template <typename T, typename Cleanup> template <typename D, QScopedArrayPointer<T, Cleanup>::if_same_type<D> = true> QScopedArrayPointer<T, Cleanup>::QScopedArrayPointer(D * p)
Constructs a QScopedArrayPointer and stores the array of objects
pointed to by \a p.
*/
/*!
- \fn template <typename T, typename Cleanup> T *QScopedArrayPointer<T, Cleanup>::operator[](int i)
+ \fn template <typename T, typename Cleanup> T *QScopedArrayPointer<T, Cleanup>::operator[](qsizetype i)
Provides access to entry \a i of the scoped pointer's array of
objects.
If the contained pointer is \nullptr, behavior is undefined.
+ \note In Qt versions prior to 6.5, \a i was of type \c{int}, not
+ \c{qsizetype}, possibly causing truncation on 64-bit platforms.
+
\sa isNull()
*/
/*!
- \fn template <typename T, typename Cleanup> T *QScopedArrayPointer<T, Cleanup>::operator[](int i) const
+ \fn template <typename T, typename Cleanup> T *QScopedArrayPointer<T, Cleanup>::operator[](qsizetype i) const
Provides access to entry \a i of the scoped pointer's array of
objects.
If the contained pointer is \nullptr behavior is undefined.
+ \note In Qt versions prior to 6.5, \a i was of type \c{int}, not
+ \c{qsizetype}, possibly causing truncation on 64-bit platforms.
+
\sa isNull()
*/
diff --git a/src/corelib/tools/qscopedpointer.h b/src/corelib/tools/qscopedpointer.h
index c9afb248a1..59bae9b967 100644
--- a/src/corelib/tools/qscopedpointer.h
+++ b/src/corelib/tools/qscopedpointer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCOPEDPOINTER_H
#define QSCOPEDPOINTER_H
@@ -103,9 +67,10 @@ typedef QScopedPointerObjectDeleteLater<QObject> QScopedPointerDeleteLater;
#endif
template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
-class [[nodiscard]] QScopedPointer
+class QScopedPointer
{
public:
+ Q_NODISCARD_CTOR
explicit QScopedPointer(T *p = nullptr) noexcept : d(p)
{
}
@@ -156,7 +121,7 @@ public:
{
if (d == other)
return;
- T *oldD = qExchange(d, other);
+ T *oldD = std::exchange(d, other);
Cleanup::cleanup(oldD);
}
@@ -164,7 +129,7 @@ public:
QT_DEPRECATED_VERSION_X_6_1("Use std::unique_ptr instead, and call release().")
T *take() noexcept
{
- T *oldD = qExchange(d, nullptr);
+ T *oldD = std::exchange(d, nullptr);
return oldD;
}
#endif
@@ -173,7 +138,7 @@ public:
QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedPointer.")
void swap(QScopedPointer<T, Cleanup> &other) noexcept
{
- qSwap(d, other.d);
+ qt_ptr_swap(d, other.d);
}
#endif
@@ -223,26 +188,28 @@ private:
};
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
-class [[nodiscard]] QScopedArrayPointer : public QScopedPointer<T, Cleanup>
+class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
{
template <typename Ptr>
using if_same_type = typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, Ptr>::value, bool>::type;
public:
+ Q_NODISCARD_CTOR
inline QScopedArrayPointer() : QScopedPointer<T, Cleanup>(nullptr) {}
inline ~QScopedArrayPointer() = default;
template <typename D, if_same_type<D> = true>
+ Q_NODISCARD_CTOR
explicit QScopedArrayPointer(D *p)
: QScopedPointer<T, Cleanup>(p)
{
}
- inline T &operator[](int i)
+ T &operator[](qsizetype i)
{
return this->d[i];
}
- inline const T &operator[](int i) const
+ const T &operator[](qsizetype i) const
{
return this->d[i];
}
diff --git a/src/corelib/tools/qscopedvaluerollback.cpp b/src/corelib/tools/qscopedvaluerollback.cpp
index 0c1c43ac49..ce3c845cc3 100644
--- a/src/corelib/tools/qscopedvaluerollback.cpp
+++ b/src/corelib/tools/qscopedvaluerollback.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qscopedvaluerollback.h"
diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h
index 9b14308ec2..0ae3efd0c0 100644
--- a/src/corelib/tools/qscopedvaluerollback.h
+++ b/src/corelib/tools/qscopedvaluerollback.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCOPEDVALUEROLLBACK_H
#define QSCOPEDVALUEROLLBACK_H
@@ -45,17 +9,20 @@
QT_BEGIN_NAMESPACE
template <typename T>
-class [[nodiscard]] QScopedValueRollback
+class QScopedValueRollback
{
public:
+ Q_NODISCARD_CTOR
explicit constexpr QScopedValueRollback(T &var)
: varRef(var), oldValue(var)
{
}
+ Q_NODISCARD_CTOR
explicit constexpr QScopedValueRollback(T &var, T value)
- : varRef(var), oldValue(qExchange(var, std::move(value)))
+ : varRef(var), oldValue(std::move(var)) // ### C++20: std::exchange(var, std::move(value))
{
+ var = std::move(value);
}
#if __cpp_constexpr >= 201907L
@@ -75,7 +42,7 @@ private:
T &varRef;
T oldValue;
- Q_DISABLE_COPY(QScopedValueRollback)
+ Q_DISABLE_COPY_MOVE(QScopedValueRollback)
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qscopeguard.h b/src/corelib/tools/qscopeguard.h
index cc9e8db209..9be6634cc8 100644
--- a/src/corelib/tools/qscopeguard.h
+++ b/src/corelib/tools/qscopeguard.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCOPEGUARD_H
#define QSCOPEGUARD_H
@@ -49,22 +13,25 @@
QT_BEGIN_NAMESPACE
template <typename F>
-class [[nodiscard]] QScopeGuard
+class QScopeGuard
{
public:
+ Q_NODISCARD_CTOR
explicit QScopeGuard(F &&f) noexcept
: m_func(std::move(f))
{
}
+ Q_NODISCARD_CTOR
explicit QScopeGuard(const F &f) noexcept
: m_func(f)
{
}
+ Q_NODISCARD_CTOR
QScopeGuard(QScopeGuard &&other) noexcept
: m_func(std::move(other.m_func))
- , m_invoke(qExchange(other.m_invoke, false))
+ , m_invoke(std::exchange(other.m_invoke, false))
{
}
diff --git a/src/corelib/tools/qscopeguard.qdoc b/src/corelib/tools/qscopeguard.qdoc
index b36299d296..6d9874842a 100644
--- a/src/corelib/tools/qscopeguard.qdoc
+++ b/src/corelib/tools/qscopeguard.qdoc
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
#include "qscopeguard.h"
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index 299851bf8d..7330b5e91c 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSET_H
#define QSET_H
@@ -71,7 +35,7 @@ public:
inline void swap(QSet<T> &other) noexcept { q_hash.swap(other.q_hash); }
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template <typename U = T>
QTypeTraits::compare_eq_result_container<QSet, U> operator==(const QSet<T> &other) const
{ return q_hash == other.q_hash; }
@@ -187,7 +151,7 @@ public:
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
- inline qsizetype count() const { return q_hash.count(); }
+ inline qsizetype count() const { return q_hash.size(); }
inline iterator insert(const T &value)
{ return q_hash.insert(value, QHashDummyValue()); }
inline iterator insert(T &&value)
@@ -225,14 +189,18 @@ public:
inline QSet<T> &operator+=(const T &value) { insert(value); return *this; }
inline QSet<T> &operator-=(const QSet<T> &other) { subtract(other); return *this; }
inline QSet<T> &operator-=(const T &value) { remove(value); return *this; }
- inline QSet<T> operator|(const QSet<T> &other) const
- { QSet<T> result = *this; result |= other; return result; }
- inline QSet<T> operator&(const QSet<T> &other) const
- { QSet<T> result = *this; result &= other; return result; }
- inline QSet<T> operator+(const QSet<T> &other) const
- { QSet<T> result = *this; result += other; return result; }
- inline QSet<T> operator-(const QSet<T> &other) const
- { QSet<T> result = *this; result -= other; return result; }
+
+ friend QSet operator|(const QSet &lhs, const QSet &rhs) { return QSet(lhs) |= rhs; }
+ friend QSet operator|(QSet &&lhs, const QSet &rhs) { lhs |= rhs; return std::move(lhs); }
+
+ friend QSet operator&(const QSet &lhs, const QSet &rhs) { return QSet(lhs) &= rhs; }
+ friend QSet operator&(QSet &&lhs, const QSet &rhs) { lhs &= rhs; return std::move(lhs); }
+
+ friend QSet operator+(const QSet &lhs, const QSet &rhs) { return QSet(lhs) += rhs; }
+ friend QSet operator+(QSet &&lhs, const QSet &rhs) { lhs += rhs; return std::move(lhs); }
+
+ friend QSet operator-(const QSet &lhs, const QSet &rhs) { return QSet(lhs) -= rhs; }
+ friend QSet operator-(QSet &&lhs, const QSet &rhs) { lhs -= rhs; return std::move(lhs); }
QList<T> values() const;
@@ -260,10 +228,13 @@ Q_INLINE_TEMPLATE void QSet<T>::reserve(qsizetype asize) { q_hash.reserve(asize)
template <class T>
Q_INLINE_TEMPLATE QSet<T> &QSet<T>::unite(const QSet<T> &other)
{
- if (!q_hash.isSharedWith(other.q_hash)) {
- for (const T &e : other)
- insert(e);
- }
+ if (q_hash.isSharedWith(other.q_hash))
+ return *this;
+ QSet<T> tmp = other;
+ if (size() < other.size())
+ swap(tmp);
+ for (const auto &e : std::as_const(tmp))
+ insert(e);
return *this;
}
@@ -280,7 +251,7 @@ Q_INLINE_TEMPLATE QSet<T> &QSet<T>::intersect(const QSet<T> &other)
copy2 = *this;
*this = copy1;
}
- for (const auto &e : qAsConst(copy1)) {
+ for (const auto &e : std::as_const(copy1)) {
if (!copy2.contains(e))
remove(e);
}
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
index 137aa61502..4ef7a80a52 100644
--- a/src/corelib/tools/qset.qdoc
+++ b/src/corelib/tools/qset.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QSet
@@ -70,7 +46,7 @@
QSet is unordered, so an iterator's sequence cannot be assumed to
be predictable. If ordering by key is required, use a QMap.
- To navigate through a QSet, you can also use \l{foreach}:
+ To navigate through a QSet, you can also use range-based for:
\snippet code/doc_src_qset.cpp 6
@@ -110,7 +86,7 @@
initializer list \a list.
*/
-/*! \fn template <class T> template<typename InputIterator> QSet<T>::QSet(InputIterator first, InputIterator last)
+/*! \fn template <class T> template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> QSet<T>::QSet(InputIterator first, InputIterator last)
\since 5.14
Constructs a set with the contents in the iterator range [\a first, \a last).
@@ -459,7 +435,7 @@
*/
/*!
- \fn template <class T> QSet<T>::insert(const T &value)
+ \fn template <class T> QSet<T>::iterator QSet<T>::insert(const T &value)
Inserts item \a value into the set, if \a value isn't already
in the set, and returns an iterator pointing at the inserted
@@ -591,29 +567,30 @@
*/
/*!
- \fn template <class T> QSet<T> QSet<T>::operator|(const QSet<T> &other) const
- \fn template <class T> QSet<T> QSet<T>::operator+(const QSet<T> &other) const
+ \fn template <class T> QSet<T> QSet<T>::operator|(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator|(QSet &&lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator+(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator+(QSet &&lhs, const QSet &rhs)
- Returns a new QSet that is the union of this set and the
- \a other set.
+ Returns a new QSet that is the union of sets \a lhs and \a rhs.
\sa unite(), operator|=(), operator&(), operator-()
*/
/*!
- \fn template <class T> QSet<T> QSet<T>::operator&(const QSet<T> &other) const
+ \fn template <class T> QSet<T> QSet<T>::operator&(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator&(QSet &&lhs, const QSet &rhs)
- Returns a new QSet that is the intersection of this set and the
- \a other set.
+ Returns a new QSet that is the intersection of sets \a lhs and \a rhs.
\sa intersect(), operator&=(), operator|(), operator-()
*/
/*!
- \fn template <class T> QSet<T> QSet<T>::operator-(const QSet<T> &other) const
+ \fn template <class T> QSet<T> QSet<T>::operator-(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator-(QSet &&lhs, const QSet &rhs)
- Returns a new QSet that is the set difference of this set and
- the \a other set, i.e., this set - \a other set.
+ Returns a new QSet that is the set difference of sets \a lhs and \a rhs.
\sa subtract(), operator-=(), operator|(), operator&()
*/
@@ -910,3 +887,10 @@
from the set \a set. Returns the number of elements removed, if
any.
*/
+
+/*! \fn template <class T> template <class Pred> qsizetype QSet<T>::removeIf(Pred pred)
+ \since 6.1
+
+ Removes, from this set, all elements for which the predicate \a pred
+ returns \c true. Returns the number of elements removed, if any.
+*/
diff --git a/src/corelib/tools/qshareddata.cpp b/src/corelib/tools/qshareddata.cpp
index 16c10a58ac..8ef174ebfc 100644
--- a/src/corelib/tools/qshareddata.cpp
+++ b/src/corelib/tools/qshareddata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qshareddata.h>
diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h
index de11257db3..4c4153a506 100644
--- a/src/corelib/tools/qshareddata.h
+++ b/src/corelib/tools/qshareddata.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHAREDDATA_H
#define QSHAREDDATA_H
@@ -85,15 +49,19 @@ public:
const T *data() const noexcept { return d; }
const T *get() const noexcept { return d; }
const T *constData() const noexcept { return d; }
- T *take() noexcept { return qExchange(d, nullptr); }
+ T *take() noexcept { return std::exchange(d, nullptr); }
+ Q_NODISCARD_CTOR
QSharedDataPointer() noexcept : d(nullptr) { }
~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
+ Q_NODISCARD_CTOR
explicit QSharedDataPointer(T *data) noexcept : d(data)
{ if (d) d->ref.ref(); }
+ Q_NODISCARD_CTOR
QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
{}
+ Q_NODISCARD_CTOR
QSharedDataPointer(const QSharedDataPointer &o) noexcept : d(o.d)
{ if (d) d->ref.ref(); }
@@ -102,7 +70,7 @@ public:
if (ptr != d) {
if (ptr)
ptr->ref.ref();
- T *old = qExchange(d, ptr);
+ T *old = std::exchange(d, ptr);
if (old && !old->ref.deref())
delete old;
}
@@ -118,14 +86,15 @@ public:
reset(o);
return *this;
}
- QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(qExchange(o.d, nullptr)) {}
+ Q_NODISCARD_CTOR
+ QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer)
operator bool () const noexcept { return d != nullptr; }
bool operator!() const noexcept { return d == nullptr; }
void swap(QSharedDataPointer &other) noexcept
- { qSwap(d, other.d); }
+ { qt_ptr_swap(d, other.d); }
#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \
friend bool operator<(T1, T2) noexcept \
@@ -171,21 +140,26 @@ public:
T *data() const noexcept { return d; }
T *get() const noexcept { return d; }
const T *constData() const noexcept { return d; }
- T *take() noexcept { return qExchange(d, nullptr); }
+ T *take() noexcept { return std::exchange(d, nullptr); }
void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer() noexcept : d(nullptr) { }
~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
+ Q_NODISCARD_CTOR
explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data)
{ if (d) d->ref.ref(); }
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
{}
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : d(o.d)
{ if (d) d->ref.ref(); }
template<typename X>
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o) noexcept
#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
: d(static_cast<T *>(o.data()))
@@ -199,7 +173,7 @@ public:
if (ptr != d) {
if (ptr)
ptr->ref.ref();
- T *old = qExchange(d, ptr);
+ T *old = std::exchange(d, ptr);
if (old && !old->ref.deref())
delete old;
}
@@ -215,14 +189,15 @@ public:
reset(o);
return *this;
}
- QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(qExchange(o.d, nullptr)) {}
+ Q_NODISCARD_CTOR
+ QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QExplicitlySharedDataPointer)
operator bool () const noexcept { return d != nullptr; }
bool operator!() const noexcept { return d == nullptr; }
void swap(QExplicitlySharedDataPointer &other) noexcept
- { qSwap(d, other.d); }
+ { qt_ptr_swap(d, other.d); }
DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const QExplicitlySharedDataPointer &p2, p2.d)
DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const T *ptr, ptr)
diff --git a/src/corelib/tools/qshareddata_impl.h b/src/corelib/tools/qshareddata_impl.h
index cf1c534cdf..e0b4695e36 100644
--- a/src/corelib/tools/qshareddata_impl.h
+++ b/src/corelib/tools/qshareddata_impl.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if 0
#pragma qt_sync_skip_header_check
@@ -87,7 +51,7 @@ public:
}
QExplicitlySharedDataPointerV2(QExplicitlySharedDataPointerV2 &&other) noexcept
- : d(qExchange(other.d, nullptr))
+ : d(std::exchange(other.d, nullptr))
{
}
@@ -128,7 +92,7 @@ public:
constexpr T *take() noexcept
{
- return qExchange(d, nullptr);
+ return std::exchange(d, nullptr);
}
bool isShared() const noexcept
@@ -138,7 +102,7 @@ public:
constexpr void swap(QExplicitlySharedDataPointerV2 &other) noexcept
{
- qSwap(d, other.d);
+ qt_ptr_swap(d, other.d);
}
// important change from QExplicitlySharedDataPointer: deep const
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index bd4d6c906b..217a3a4ff4 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2020 Intel Corporation.
-** Copyright (C) 2019 Klarälvdalens Datakonsult AB.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2020 Intel Corporation.
+// Copyright (C) 2019 Klarälvdalens Datakonsult AB.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsharedpointer.h"
@@ -175,8 +139,7 @@
can also exceptionally be -1, indicating that there are no QSharedPointers
attached to an object, which is tracked too. The only case where this is
possible is that of QWeakPointers and QPointers tracking a QObject. Note
- that QWeakPointers tracking a QObject is a deprecated feature as of Qt 5.0,
- kept only for compatibility with Qt 4.x.
+ that QWeakPointers tracking a QObject is deprecated.
The weak reference count controls the lifetime of the d-pointer itself.
It can be thought of as an internal/intrusive reference count for
@@ -211,7 +174,7 @@
last QSharedPointer instance had.
This class is never instantiated directly: the constructors and
- destructor are private and, in C++11, deleted. Only the create() function
+ destructor are deleted. Only the create() function
may be called to return an object of this type. See below for construction
details.
@@ -250,8 +213,7 @@
Like ExternalRefCountWithCustomDeleter, this class is never instantiated
directly. This class also provides a create() member that returns the
- pointer, and hides its constructors and destructor. With C++11, they're
- deleted.
+ pointer, and deletes its constructors and destructor.
The size of this class depends on the size of \tt T.
@@ -479,6 +441,46 @@
*/
/*!
+ \fn template <class T> QSharedPointer<T>::QSharedPointer(QSharedPointer &&other)
+
+ Move-constructs a QSharedPointer instance, making it point at the same
+ object that \a other was pointing to.
+
+ \since 5.4
+*/
+
+/*!
+ \fn template <class T> QSharedPointer<T>::operator=(QSharedPointer &&other)
+
+ Move-assigns \a other to this QSharedPointer instance.
+
+ \since 5.0
+*/
+
+/*!
+ \fn template <class T> template <class X> QSharedPointer<T>::QSharedPointer(QSharedPointer<X> &&other)
+
+ Move-constructs a QSharedPointer instance, making it point at the same
+ object that \a other was pointing to.
+
+ This constructor participates in overload resolution only if \c{X*}
+ implicitly converts to \c{T*}.
+
+ \since 5.6
+*/
+
+/*!
+ \fn template <class T> template <class X> QSharedPointer<T>::operator=(QSharedPointer<X> &&other)
+
+ Move-assigns \a other to this QSharedPointer instance.
+
+ This assignment operator participates in overload resolution only if \c{X*}
+ implicitly converts to \c{T*}.
+
+ \since 5.6
+*/
+
+/*!
\fn template <class T> QSharedPointer<T>::QSharedPointer(const QWeakPointer<T> &other)
Creates a QSharedPointer by promoting the weak reference \a other
@@ -707,6 +709,49 @@
*/
/*!
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_before(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_before(const QWeakPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_before(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_before(const QWeakPointer<X> &other) const noexcept
+ \since 6.7
+
+ Returns \c true if and only if this smart pointer precedes \a other
+ in an implementation-defined owner-based ordering. The ordering is such
+ that two smart pointers are considered equivalent if they are both
+ empty or if they both own the same object (even if their apparent type
+ and pointer are different).
+
+ \sa owner_equal
+*/
+
+/*!
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_equal(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_equal(const QWeakPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_equal(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_equal(const QWeakPointer<X> &other) const noexcept
+
+ \since 6.7
+
+ Returns \c true if and only if this smart pointer and \a other
+ share ownership.
+
+ \sa owner_before, owner_hash
+*/
+
+/*!
+ \fn template <class T> size_t QSharedPointer<T>::owner_hash() const noexcept
+ \fn template <class T> size_t QWeakPointer<T>::owner_hash() const noexcept
+
+ \since 6.7
+
+ Returns a owner-based hash value for this smart pointer object.
+ Smart pointers that compare equal (as per \c{owner_equal}) will
+ have an identical owner-based hash.
+
+ \sa owner_equal
+*/
+
+/*!
\fn template <class T> QWeakPointer<T>::QWeakPointer()
Creates a QWeakPointer that points to nothing.
@@ -932,7 +977,16 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template <class T> qHash(const QSharedPointer<T> &key, size_t seed)
+ \relates QSharedPointer
+
+ Returns the hash value for \a key, using \a seed to seed the calculation.
+
+ \since 5.0
+*/
+
+/*!
+ \fn template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -945,7 +999,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -958,7 +1012,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2)
+ \fn template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -971,7 +1025,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QSharedPointer<T> &ptr1, const X *ptr2)
+ \fn template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const X *ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -984,7 +1038,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const T *ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const T *ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if the pointer \a ptr1 is the
@@ -998,7 +1052,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const T *ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const T *ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if the pointer \a ptr1 is not the
@@ -1012,7 +1066,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -1025,7 +1079,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -1038,7 +1092,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -1131,7 +1185,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -1144,7 +1198,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerCast(const QSharedPointer<T> &other)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerCast(const QSharedPointer<T> &other)
\relates QSharedPointer
Returns a shared pointer to the pointer held by \a other, cast to
@@ -1159,7 +1213,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerCast(const QWeakPointer<T> &other)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerCast(const QWeakPointer<T> &other)
\relates QSharedPointer
\relates QWeakPointer
@@ -1180,7 +1234,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src)
\relates QSharedPointer
Returns a shared pointer to the pointer held by \a src, using a
@@ -1196,7 +1250,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src)
\relates QSharedPointer
\relates QWeakPointer
@@ -1218,7 +1272,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src)
\relates QSharedPointer
Returns a shared pointer to the pointer held by \a src, cast to
@@ -1230,7 +1284,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src)
\relates QSharedPointer
\relates QWeakPointer
@@ -1248,7 +1302,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &src)
\relates QSharedPointer
\since 4.6
@@ -1320,7 +1374,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src)
\relates QSharedPointer
\relates QWeakPointer
\since 4.6
@@ -1346,7 +1400,7 @@
/*!
- \fn template <class X> template <class T> QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &src)
\relates QWeakPointer
Returns a weak pointer to the pointer held by \a src, cast to
@@ -1366,6 +1420,7 @@
QT_BEGIN_NAMESPACE
+QT6_ONLY(
/*!
\internal
This function is called for a just-created QObject \a obj, to enable
@@ -1373,7 +1428,9 @@ QT_BEGIN_NAMESPACE
*/
void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *, bool)
{}
+)
+QT6_ONLY(
/*!
\internal
This function is called when a QSharedPointer is created from a QWeakPointer
@@ -1386,6 +1443,7 @@ void QtSharedPointer::ExternalRefCountData::checkQObjectShared(const QObject *)
if (strongref.loadRelaxed() < 0)
qWarning("QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
}
+)
QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
{
@@ -1450,7 +1508,7 @@ QT_END_NAMESPACE
# ifdef QT_SHARED_POINTER_BACKTRACE_SUPPORT
# if defined(__GLIBC__) && (__GLIBC__ >= 2) && !defined(__UCLIBC__) && !defined(QT_LINUXBASE)
# define BACKTRACE_SUPPORTED
-# elif defined(Q_OS_MAC)
+# elif defined(Q_OS_DARWIN)
# define BACKTRACE_SUPPORTED
# endif
# endif
diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h
index 82eb80beff..116c9afa00 100644
--- a/src/corelib/tools/qsharedpointer.h
+++ b/src/corelib/tools/qsharedpointer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHAREDPOINTER_H
#define QSHAREDPOINTER_H
@@ -76,13 +40,20 @@ public:
template <typename Deleter> QSharedPointer(std::nullptr_t, Deleter d);
QSharedPointer(const QSharedPointer<T> &other);
QSharedPointer(const QWeakPointer<T> &other);
+ QSharedPointer(QSharedPointer<T> &&other) noexcept;
~QSharedPointer() { }
QSharedPointer<T> &operator=(const QSharedPointer<T> &other);
+ QSharedPointer<T> &operator=(QSharedPointer<T> &&other) noexcept;
QSharedPointer<T> &operator=(const QWeakPointer<T> &other);
- void swap(QSharedPointer<T> &other);
+ template <class X>
+ QSharedPointer(QSharedPointer<X> && other) noexcept;
+ template <class X>
+ QSharedPointer &operator=(QSharedPointer<X> && other) noexcept;
+
+ void swap(QSharedPointer<T> &other) noexcept;
QWeakPointer<T> toWeakRef() const;
@@ -101,9 +72,25 @@ public:
template <typename... Args>
static inline QSharedPointer<T> create(Args &&... args);
+
+ // owner-based comparisons
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept;
+
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept;
+
+ size_t owner_hash() const noexcept;
};
template <class T>
+size_t qHash(const QSharedPointer<T> &key, size_t seed = 0) noexcept;
+
+template <class T>
class QWeakPointer
{
public:
@@ -114,24 +101,39 @@ public:
// constructors:
QWeakPointer();
- QWeakPointer(const QWeakPointer<T> &other);
+ QWeakPointer(const QWeakPointer<T> &other) noexcept;
+ QWeakPointer(QWeakPointer<T> &&other) noexcept;
QWeakPointer(const QSharedPointer<T> &other);
~QWeakPointer();
- QWeakPointer<T> &operator=(const QWeakPointer<T> &other);
+ QWeakPointer<T> &operator=(const QWeakPointer<T> &other) noexcept;
+ QWeakPointer<T> &operator=(QWeakPointer<T> &&other) noexcept;
QWeakPointer<T> &operator=(const QSharedPointer<T> &other);
QWeakPointer(const QObject *other);
QWeakPointer<T> &operator=(const QObject *other);
- void swap(QWeakPointer<T> &other);
+ void swap(QWeakPointer<T> &other) noexcept;
T *data() const;
void clear();
QSharedPointer<T> toStrongRef() const;
QSharedPointer<T> lock() const;
+
+ // owner-based comparisons
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept;
+
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept;
+
+ size_t owner_hash() const noexcept;
};
template <class T>
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 0e69c18ca4..456be91d03 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2020 Intel Corporation.
-** Copyright (C) 2019 Klarälvdalens Datakonsult AB.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2019 Klarälvdalens Datakonsult AB.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef Q_QDOC
@@ -62,13 +26,18 @@ QT_END_NAMESPACE
#include <new>
#include <QtCore/qatomic.h>
-#include <QtCore/qobject.h> // for qobject_cast
#include <QtCore/qhashfunctions.h>
+#include <QtCore/qmetatype.h> // for IsPointerToTypeDerivedFromQObject
+#include <QtCore/qxptype_traits.h>
#include <memory>
QT_BEGIN_NAMESPACE
+class QObject;
+template <class T>
+T qobject_cast(const QObject *object);
+
//
// forward declarations
//
@@ -147,8 +116,10 @@ namespace QtSharedPointer {
#ifndef QT_NO_QOBJECT
Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
+ QT6_ONLY(
Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
- Q_CORE_EXPORT void checkQObjectShared(const QObject *);
+ )
+ QT6_ONLY(Q_CORE_EXPORT void checkQObjectShared(const QObject *);)
#endif
inline void checkQObjectShared(...) { }
inline void setQObjectShared(...) { }
@@ -308,23 +279,29 @@ public:
T &operator*() const { return *data(); }
T *operator->() const noexcept { return data(); }
+ Q_NODISCARD_CTOR
constexpr QSharedPointer() noexcept : value(nullptr), d(nullptr) { }
~QSharedPointer() { deref(); }
+ Q_NODISCARD_CTOR
constexpr QSharedPointer(std::nullptr_t) noexcept : value(nullptr), d(nullptr) { }
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept
{ internalConstruct(ptr, QtSharedPointer::NormalDeleter()); }
template <class X, typename Deleter, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws
{ internalConstruct(ptr, deleter); }
template <typename Deleter>
+ Q_NODISCARD_CTOR
QSharedPointer(std::nullptr_t, Deleter deleter) : value(nullptr)
{ internalConstruct(static_cast<T *>(nullptr), deleter); }
+ Q_NODISCARD_CTOR
QSharedPointer(const QSharedPointer &other) noexcept : value(other.value), d(other.d)
{ if (d) ref(); }
QSharedPointer &operator=(const QSharedPointer &other) noexcept
@@ -333,6 +310,7 @@ public:
swap(copy);
return *this;
}
+ Q_NODISCARD_CTOR
QSharedPointer(QSharedPointer &&other) noexcept
: value(other.value), d(other.d)
{
@@ -342,6 +320,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedPointer)
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
QSharedPointer(QSharedPointer<X> &&other) noexcept
: value(other.value), d(other.d)
{
@@ -358,6 +337,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
QSharedPointer(const QSharedPointer<X> &other) noexcept : value(other.value), d(other.d)
{ if (d) ref(); }
@@ -370,6 +350,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QSharedPointer(const QWeakPointer<X> &other) : value(nullptr), d(nullptr)
{ *this = other; }
@@ -415,10 +396,10 @@ public:
inline void clear() { QSharedPointer copy; swap(copy); }
- QWeakPointer<T> toWeakRef() const;
+ [[nodiscard]] QWeakPointer<T> toWeakRef() const;
template <typename... Args>
- static QSharedPointer create(Args && ...arguments)
+ [[nodiscard]] static QSharedPointer create(Args && ...arguments)
{
typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
@@ -465,7 +446,25 @@ public:
#undef DECLARE_TEMPLATE_COMPARE_SET
#undef DECLARE_COMPARE_SET
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept
+ { return d == other.d; }
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept
+ { return d == other.d; }
+
+ size_t owner_hash() const noexcept
+ { return std::hash<Data *>()(d); }
+
private:
+ Q_NODISCARD_CTOR
explicit QSharedPointer(Qt::Initialization) {}
void deref() noexcept
@@ -502,14 +501,13 @@ private:
#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
internalSafetyCheckAdd(d, ptr);
#endif
- d->setQObjectShared(ptr, true);
enableSharedFromThis(ptr);
}
void internalSwap(QSharedPointer &other) noexcept
{
- qSwap(d, other.d);
- qSwap(this->value, other.value);
+ qt_ptr_swap(d, other.d);
+ qt_ptr_swap(this->value, other.value);
}
template <class X> friend class QSharedPointer;
@@ -530,16 +528,14 @@ private:
tmp = o->strongref.loadRelaxed(); // failed, try again
}
- if (tmp > 0) {
+ if (tmp > 0)
o->weakref.ref();
- } else {
- o->checkQObjectShared(actual);
+ else
o = nullptr;
- }
}
- qSwap(d, o);
- qSwap(this->value, actual);
+ qt_ptr_swap(d, o);
+ qt_ptr_swap(this->value, actual);
if (!d || d->strongref.loadRelaxed() == 0)
this->value = nullptr;
@@ -558,6 +554,12 @@ class QWeakPointer
template <typename X>
using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type;
+ template <typename X>
+ using IfVirtualBase = typename std::enable_if<qxp::is_virtual_base_of_v<T, X>, bool>::type;
+
+ template <typename X>
+ using IfNotVirtualBase = typename std::enable_if<!qxp::is_virtual_base_of_v<T, X>, bool>::type;
+
public:
typedef T element_type;
typedef T value_type;
@@ -571,11 +573,14 @@ public:
explicit operator bool() const noexcept { return !isNull(); }
bool operator !() const noexcept { return isNull(); }
- inline QWeakPointer() noexcept : d(nullptr), value(nullptr) { }
+ Q_NODISCARD_CTOR
+ constexpr QWeakPointer() noexcept : d(nullptr), value(nullptr) { }
inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; }
+ Q_NODISCARD_CTOR
QWeakPointer(const QWeakPointer &other) noexcept : d(other.d), value(other.value)
{ if (d) d->weakref.ref(); }
+ Q_NODISCARD_CTOR
QWeakPointer(QWeakPointer &&other) noexcept
: d(other.d), value(other.value)
{
@@ -583,6 +588,32 @@ public:
other.value = nullptr;
}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QWeakPointer)
+
+ template <class X, IfCompatible<X> = true, IfNotVirtualBase<X> = true>
+ Q_NODISCARD_CTOR
+ QWeakPointer(QWeakPointer<X> &&other) noexcept
+ : d(std::exchange(other.d, nullptr)),
+ value(std::exchange(other.value, nullptr))
+ {
+ }
+
+ template <class X, IfCompatible<X> = true, IfVirtualBase<X> = true>
+ Q_NODISCARD_CTOR
+ QWeakPointer(QWeakPointer<X> &&other) noexcept
+ : d(other.d), value(other.toStrongRef().get()) // must go through QSharedPointer, see below
+ {
+ other.d = nullptr;
+ other.value = nullptr;
+ }
+
+ template <class X, IfCompatible<X> = true>
+ QWeakPointer &operator=(QWeakPointer<X> &&other) noexcept
+ {
+ QWeakPointer moved(std::move(other));
+ swap(moved);
+ return *this;
+ }
+
QWeakPointer &operator=(const QWeakPointer &other) noexcept
{
QWeakPointer copy(other);
@@ -592,10 +623,11 @@ public:
void swap(QWeakPointer &other) noexcept
{
- qSwap(this->d, other.d);
- qSwap(this->value, other.value);
+ qt_ptr_swap(this->d, other.d);
+ qt_ptr_swap(this->value, other.value);
}
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QSharedPointer<T> &o) : d(o.d), value(o.data())
{ if (d) d->weakref.ref();}
inline QWeakPointer &operator=(const QSharedPointer<T> &o)
@@ -605,6 +637,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr)
{ *this = o; }
@@ -618,6 +651,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr)
{ *this = o; }
@@ -630,9 +664,9 @@ public:
inline void clear() { *this = QWeakPointer(); }
- inline QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
+ [[nodiscard]] QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
// std::weak_ptr compatibility:
- inline QSharedPointer<T> lock() const { return toStrongRef(); }
+ [[nodiscard]] QSharedPointer<T> lock() const { return toStrongRef(); }
template <class X>
bool operator==(const QWeakPointer<X> &o) const noexcept
@@ -666,17 +700,36 @@ public:
friend bool operator!=(std::nullptr_t, const QWeakPointer &p)
{ return !p.isNull(); }
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept
+ { return d == other.d; }
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept
+ { return d == other.d; }
+
+ size_t owner_hash() const noexcept
+ { return std::hash<Data *>()(d); }
+
private:
friend struct QtPrivate::EnableInternalData;
template <class X> friend class QSharedPointer;
+ template <class X> friend class QWeakPointer;
template <class X> friend class QPointer;
template <class X>
inline QWeakPointer &assign(X *ptr)
- { return *this = QWeakPointer<X>(ptr, true); }
+ { return *this = QWeakPointer<T>(ptr, true); }
#ifndef QT_NO_QOBJECT
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
{ }
#endif
@@ -784,7 +837,7 @@ Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer<X> &ptr2)
template <class T>
Q_INLINE_TEMPLATE size_t qHash(const QSharedPointer<T> &ptr, size_t seed = 0)
{
- return QT_PREPEND_NAMESPACE(qHash)(ptr.data(), seed);
+ return qHash(ptr.data(), seed);
}
diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp
index 2779948aae..d5e8e4c71b 100644
--- a/src/corelib/tools/qsize.cpp
+++ b/src/corelib/tools/qsize.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsize.h"
#include "qdatastream.h"
@@ -403,6 +367,15 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept
\sa grownBy()
*/
+/*!
+ \fn QSize::toSizeF() const
+ \since 6.4
+
+ Returns this size as a size with floating point accuracy.
+
+ \sa QSizeF::toSize()
+*/
+
/*****************************************************************************
QSize stream functions
*****************************************************************************/
@@ -520,7 +493,7 @@ QDebug operator<<(QDebug dbg, const QSize &s)
Constructs a size with floating point accuracy from the given \a
size.
- \sa toSize()
+ \sa toSize(), QSize::toSizeF()
*/
/*!
@@ -596,7 +569,7 @@ QDebug operator<<(QDebug dbg, const QSize &s)
Note that the coordinates in the returned size will be rounded to
the nearest integer.
- \sa QSizeF()
+ \sa QSizeF(), QSize::toSizeF()
*/
/*!
diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h
index bab193031c..a5eaf34afe 100644
--- a/src/corelib/tools/qsize.h
+++ b/src/corelib/tools/qsize.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSIZE_H
#define QSIZE_H
@@ -44,12 +8,18 @@
#include <QtCore/qhashfunctions.h>
#include <QtCore/qmargins.h>
+#include <QtCore/q20type_traits.h>
+#include <QtCore/q23utility.h>
+
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
struct CGSize;
#endif
QT_BEGIN_NAMESPACE
+// QT_ENABLE_P0846_SEMANTICS_FOR(get) // from qmargins.h
+
+class QSizeF;
class Q_CORE_EXPORT QSize
{
@@ -109,6 +79,8 @@ public:
[[nodiscard]] CGSize toCGSize() const noexcept;
#endif
+ [[nodiscard]] inline constexpr QSizeF toSizeF() const noexcept;
+
private:
int wd;
int ht;
@@ -116,13 +88,13 @@ private:
template <std::size_t I,
typename S,
std::enable_if_t<(I < 2), bool> = true,
- std::enable_if_t<std::is_same_v<std::decay_t<S>, QSize>, bool> = true>
+ std::enable_if_t<std::is_same_v<q20::remove_cvref_t<S>, QSize>, bool> = true>
friend constexpr decltype(auto) get(S &&s) noexcept
{
if constexpr (I == 0)
- return (std::forward<S>(s).wd);
+ return q23::forward_like<S>(s.wd);
else if constexpr (I == 1)
- return (std::forward<S>(s).ht);
+ return q23::forward_like<S>(s.ht);
}
};
Q_DECLARE_TYPEINFO(QSize, Q_RELOCATABLE_TYPE);
@@ -305,13 +277,13 @@ private:
template <std::size_t I,
typename S,
std::enable_if_t<(I < 2), bool> = true,
- std::enable_if_t<std::is_same_v<std::decay_t<S>, QSizeF>, bool> = true>
+ std::enable_if_t<std::is_same_v<q20::remove_cvref_t<S>, QSizeF>, bool> = true>
friend constexpr decltype(auto) get(S &&s) noexcept
{
if constexpr (I == 0)
- return (std::forward<S>(s).wd);
+ return q23::forward_like<S>(s.wd);
else if constexpr (I == 1)
- return (std::forward<S>(s).ht);
+ return q23::forward_like<S>(s.ht);
}
};
Q_DECLARE_TYPEINFO(QSizeF, Q_RELOCATABLE_TYPE);
@@ -420,6 +392,8 @@ constexpr inline QSize QSizeF::toSize() const noexcept
return QSize(qRound(wd), qRound(ht));
}
+constexpr QSizeF QSize::toSizeF() const noexcept { return *this; }
+
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QSizeF &);
#endif
diff --git a/src/corelib/tools/qspan.h b/src/corelib/tools/qspan.h
new file mode 100644
index 0000000000..d6ae2570ae
--- /dev/null
+++ b/src/corelib/tools/qspan.h
@@ -0,0 +1,452 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSPAN_H
+#define QSPAN_H
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtypes.h>
+#include <QtCore/qcontainerfwd.h>
+
+#include <array>
+#include <cstddef>
+#include <cassert>
+#include <initializer_list>
+#include <QtCore/q20iterator.h>
+#include <QtCore/q20memory.h>
+#ifdef __cpp_lib_span
+#include <span>
+#endif
+#include <QtCore/q20type_traits.h>
+
+QT_BEGIN_NAMESPACE
+
+// like std::dynamic_extent
+namespace q20 {
+ inline constexpr auto dynamic_extent = std::size_t(-1);
+} // namespace q20
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#ifdef __cpp_lib_span
+#ifdef __cpp_lib_concepts
+namespace std::ranges {
+// Officially, these are defined in <ranges>, but that is a heavy-hitter header.
+// OTOH, <span> must specialize these variable templates, too, so we assume that
+// <span> includes some meaningful subset of <ranges> and just go ahead and use them:
+template <typename T, std::size_t E>
+constexpr inline bool enable_borrowed_range<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
+template <typename T, std::size_t E>
+constexpr inline bool enable_view<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
+} // namespace std::ranges
+#endif // __cpp_lib_concepts
+#endif // __cpp_lib_span
+QT_END_INCLUDE_NAMESPACE
+
+namespace QSpanPrivate {
+
+template <typename T, std::size_t E> class QSpanBase;
+
+template <typename T>
+struct is_qspan_helper : std::false_type {};
+template <typename T, std::size_t E>
+struct is_qspan_helper<QSpan<T, E>> : std::true_type {};
+template <typename T, std::size_t E>
+struct is_qspan_helper<QSpanBase<T, E>> : std::true_type {};
+template <typename T>
+using is_qspan = is_qspan_helper<q20::remove_cvref_t<T>>;
+
+template <typename T>
+struct is_std_span_helper : std::false_type {};
+#ifdef __cpp_lib_span
+template <typename T, std::size_t E>
+struct is_std_span_helper<std::span<T, E>> : std::true_type {};
+#endif // __cpp_lib_span
+template <typename T>
+using is_std_span = is_std_span_helper<q20::remove_cvref_t<T>>;
+
+template <typename T>
+struct is_std_array_helper : std::false_type {};
+template <typename T, std::size_t N>
+struct is_std_array_helper<std::array<T, N>> : std::true_type {};
+template <typename T>
+using is_std_array = is_std_array_helper<q20::remove_cvref_t<T>>;
+
+template <typename From, typename To>
+using is_qualification_conversion =
+ std::is_convertible<From(*)[], To(*)[]>; // https://eel.is/c++draft/span.cons#note-1
+template <typename From, typename To>
+constexpr inline bool is_qualification_conversion_v = is_qualification_conversion<From, To>::value;
+
+namespace AdlTester {
+#define MAKE_ADL_TEST(what) \
+ using std:: what; /* bring into scope */ \
+ template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
+ /* end */
+MAKE_ADL_TEST(begin)
+MAKE_ADL_TEST(data)
+MAKE_ADL_TEST(size)
+#undef MAKE_ADL_TEST
+}
+
+// Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s,
+// not doing the extra work C++20 requires
+template <typename Range>
+AdlTester::begin_result<Range> adl_begin(Range &&r) { using std::begin; return begin(r); }
+template <typename Range>
+AdlTester::data_result<Range> adl_data(Range &&r) { using std::data; return data(r); }
+template <typename Range>
+AdlTester::size_result<Range> adl_size(Range &&r) { using std::size; return size(r); }
+
+// Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin)
+// This one uses adl_begin() instead.
+template <typename Range>
+using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval<Range&>()));
+template <typename Range>
+using range_reference_t = q20::iter_reference_t<QSpanPrivate::iterator_t<Range>>;
+
+template <typename T>
+class QSpanCommon {
+protected:
+ template <typename Iterator>
+ using is_compatible_iterator = std::conjunction<
+ // ### C++20: extend to contiguous_iteratorss
+ std::is_base_of<
+ std::random_access_iterator_tag,
+ typename std::iterator_traits<Iterator>::iterator_category
+ >,
+ is_qualification_conversion<
+ std::remove_reference_t<q20::iter_reference_t<Iterator>>,
+ T
+ >
+ >;
+ template <typename Iterator, typename End>
+ using is_compatible_iterator_and_sentinel = std::conjunction<
+ // ### C++20: extend to contiguous_iterators and real sentinels
+ is_compatible_iterator<Iterator>,
+ std::negation<std::is_convertible<End, std::size_t>>
+ >;
+ template <typename Range, typename = void> // wrap use of SFINAE-unfriendly iterator_t:
+ struct is_compatible_range_helper : std::false_type {};
+ template <typename Range>
+ struct is_compatible_range_helper<Range, std::void_t<QSpanPrivate::iterator_t<Range>>>
+ : is_compatible_iterator<QSpanPrivate::iterator_t<Range>> {};
+ template <typename Range>
+ using is_compatible_range = std::conjunction<
+ // ### C++20: extend to contiguous_iterators
+ std::negation<is_qspan<Range>>,
+ std::negation<is_std_span<Range>>,
+ std::negation<is_std_array<Range>>,
+ std::negation<std::is_array<q20::remove_cvref_t<Range>>>,
+ is_compatible_range_helper<Range>
+ >;
+
+ // constraints
+ template <typename Iterator>
+ using if_compatible_iterator = std::enable_if_t<
+ is_compatible_iterator<Iterator>::value
+ , bool>;
+ template <typename Iterator, typename End>
+ using if_compatible_iterator_and_sentinel = std::enable_if_t<
+ is_compatible_iterator_and_sentinel<Iterator, End>::value
+ , bool>;
+ template <typename Range>
+ using if_compatible_range = std::enable_if_t<is_compatible_range<Range>::value, bool>;
+}; // class QSpanCommon
+
+template <typename T, std::size_t E>
+class QSpanBase : protected QSpanCommon<T>
+{
+ static_assert(E < size_t{(std::numeric_limits<qsizetype>::max)()},
+ "QSpan only supports extents that fit into the signed size type (qsizetype).");
+
+ struct Enabled_t { explicit Enabled_t() = default; };
+ static inline constexpr Enabled_t Enable{};
+
+ template <typename S, std::size_t N>
+ using if_compatible_array = std::enable_if_t<
+ N == E && is_qualification_conversion_v<S, T>
+ , bool>;
+
+ template <typename S>
+ using if_qualification_conversion = std::enable_if_t<
+ is_qualification_conversion_v<S, T>
+ , bool>;
+protected:
+ using Base = QSpanCommon<T>;
+
+ // data members:
+ T *m_data;
+ static constexpr qsizetype m_size = qsizetype(E);
+
+ // types and constants:
+ // (in QSpan only)
+
+ // constructors (need to be public d/t the way ctor inheriting works):
+public:
+ template <std::size_t E2 = E, std::enable_if_t<E2 == 0, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {}
+
+ template <typename It, typename Base::template if_compatible_iterator<It> = true>
+ explicit constexpr QSpanBase(It first, qsizetype count)
+ : m_data{q20::to_address(first)}
+ {
+ Q_ASSERT(count == m_size);
+ }
+
+ template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
+ explicit constexpr QSpanBase(It first, End last)
+ : QSpanBase(first, last - first) {}
+
+ template <size_t N, std::enable_if_t<N == E, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
+ : QSpanBase(arr, N) {}
+
+ template <typename S, size_t N, if_compatible_array<S, N> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename S, size_t N, if_compatible_array<S, N> = true>
+ Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename Range, typename Base::template if_compatible_range<Range> = true>
+ Q_IMPLICIT constexpr QSpanBase(Range &&r)
+ : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either)
+ qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
+ {}
+
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(QSpan<S, E> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(QSpan<S> other)
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il)
+ : QSpanBase(il.begin(), il.size())
+ {}
+
+#ifdef __cpp_lib_span
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::span<S, E> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::span<S> other)
+ : QSpanBase(other.data(), other.size())
+ {}
+#endif // __cpp_lib_span
+}; // class QSpanBase (fixed extent)
+
+template <typename T>
+class QSpanBase<T, q20::dynamic_extent> : protected QSpanCommon<T>
+{
+ template <typename S>
+ using if_qualification_conversion = std::enable_if_t<
+ is_qualification_conversion_v<S, T>
+ , bool>;
+protected:
+ using Base = QSpanCommon<T>;
+
+ // data members:
+ T *m_data;
+ qsizetype m_size;
+
+ // constructors (need to be public d/t the way ctor inheriting works):
+public:
+ Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {}
+
+ template <typename It, typename Base::template if_compatible_iterator<It> = true>
+ Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count)
+ : m_data{q20::to_address(first)}, m_size{count} {}
+
+ template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
+ Q_IMPLICIT constexpr QSpanBase(It first, End last)
+ : QSpanBase(first, last - first) {}
+
+ template <size_t N>
+ Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
+ : QSpanBase(arr, N) {}
+
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename Range, typename Base::template if_compatible_range<Range> = true>
+ Q_IMPLICIT constexpr QSpanBase(Range &&r)
+ : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either)
+ qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
+ {}
+
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(QSpan<S, N> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il) noexcept
+ : QSpanBase(il.begin(), il.size())
+ {}
+
+#ifdef __cpp_lib_span
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::span<S, N> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+#endif // __cpp_lib_span
+}; // class QSpanBase (dynamic extent)
+
+} // namespace QSpanPrivate
+
+template <typename T, std::size_t E>
+class QSpan
+#ifndef Q_QDOC
+ : private QSpanPrivate::QSpanBase<T, E>
+#endif
+{
+ using Base = QSpanPrivate::QSpanBase<T, E>;
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+
+ template <std::size_t N>
+ static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent;
+public:
+ // constants and types
+ using value_type = std::remove_cv_t<T>;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using iterator_concept = std::contiguous_iterator_tag;
+ using element_type = T;
+#endif
+ using size_type = qsizetype; // difference to std::span
+ using difference_type = qptrdiff; // difference to std::span
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using iterator = pointer; // implementation-defined choice
+ using const_iterator = const_pointer; // implementation-defined choice
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ static constexpr std::size_t extent = E;
+
+ // [span.cons], constructors, copy, and assignment
+ using Base::Base;
+#ifdef Q_QDOC
+ template <typename It> using if_compatible_iterator = bool;
+ template <typename S> using if_qualification_conversion = bool;
+ template <typename Range> using if_compatible_range = bool;
+ template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, qsizetype count);
+ template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, It last);
+ template <size_t N> constexpr QSpan(q20::type_identity_t<T> (&arr)[N]) noexcept;
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::array<S, N> &arr) noexcept;
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(const std::array<S, N> &arr) noexcept;
+ template <typename Range, if_compatible_range<Range> = true> constexpr QSpan(Range &&r);
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(QSpan<S, N> other) noexcept;
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::span<S, N> other) noexcept;
+ constexpr QSpan(std::initializer_list<value_type> il);
+#endif // Q_QDOC
+
+ // [span.obs]
+ [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; }
+ [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); }
+ [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
+
+ // [span.elem]
+ [[nodiscard]] constexpr reference operator[](size_type idx) const
+ { verify(idx); return data()[idx]; }
+ [[nodiscard]] constexpr reference front() const { verify(); return *data(); }
+ [[nodiscard]] constexpr reference back() const { verify(); return data()[size() - 1]; }
+ [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; }
+
+ // [span.iterators]
+ [[nodiscard]] constexpr iterator begin() const noexcept { return data(); }
+ [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); }
+ [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
+ [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
+ [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
+ [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
+ [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
+
+ // [span.sub]
+ template <std::size_t Count>
+ [[nodiscard]] constexpr QSpan<T, Count> first() const
+ noexcept(subspan_always_succeeds_v<Count>)
+ {
+ static_assert(Count <= E,
+ "Count cannot be larger than the span's extent.");
+ verify(0, Count);
+ return QSpan<T, Count>{data(), Count};
+ }
+
+ template <std::size_t Count>
+ [[nodiscard]] constexpr QSpan<T, Count> last() const
+ noexcept(subspan_always_succeeds_v<Count>)
+ {
+ static_assert(Count <= E,
+ "Count cannot be larger than the span's extent.");
+ verify(0, Count);
+ return QSpan<T, Count>{data() + (size() - Count), Count};
+ }
+
+ template <std::size_t Offset>
+ [[nodiscard]] constexpr auto subspan() const
+ noexcept(subspan_always_succeeds_v<Offset>)
+ {
+ static_assert(Offset <= E,
+ "Offset cannot be larger than the span's extent.");
+ verify(Offset, 0);
+ if constexpr (E == q20::dynamic_extent)
+ return QSpan<T>{data() + Offset, qsizetype(size() - Offset)};
+ else
+ return QSpan<T, E - Offset>{data() + Offset, qsizetype(E - Offset)};
+ }
+
+ template <std::size_t Offset, std::size_t Count>
+ [[nodiscard]] constexpr auto subspan() const
+ noexcept(subspan_always_succeeds_v<Offset + Count>)
+ { return subspan<Offset>().template first<Count>(); }
+
+ [[nodiscard]] constexpr QSpan<T> first(size_type n) const { verify(0, n); return {data(), n}; }
+ [[nodiscard]] constexpr QSpan<T> last(size_type n) const { verify(0, n); return {data() + (size() - n), n}; }
+ [[nodiscard]] constexpr QSpan<T> subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; }
+ [[nodiscard]] constexpr QSpan<T> subspan(size_type pos, size_type n) const { return subspan(pos).first(n); }
+
+ // Qt-compatibility API:
+ [[nodiscard]] bool isEmpty() const noexcept { return empty(); }
+ // nullary first()/last() clash with first<>() and last<>(), so they're not provided for QSpan
+ [[nodiscard]] constexpr QSpan<T> sliced(size_type pos) const { return subspan(pos); }
+ [[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
+
+}; // class QSpan
+
+// [span.deduct]
+template <class It, class EndOrSize>
+QSpan(It, EndOrSize) -> QSpan<std::remove_reference_t<q20::iter_reference_t<It>>>;
+template <class T, std::size_t N>
+QSpan(T (&)[N]) -> QSpan<T, N>;
+template <class T, std::size_t N>
+QSpan(std::array<T, N> &) -> QSpan<T, N>;
+template <class T, std::size_t N>
+QSpan(const std::array<T, N> &) -> QSpan<const T, N>;
+template <class R>
+QSpan(R&&) -> QSpan<std::remove_reference_t<QSpanPrivate::range_reference_t<R>>>;
+
+QT_END_NAMESPACE
+
+#endif // QSPAN_H
diff --git a/src/corelib/tools/qspan.qdoc b/src/corelib/tools/qspan.qdoc
new file mode 100644
index 0000000000..472f122877
--- /dev/null
+++ b/src/corelib/tools/qspan.qdoc
@@ -0,0 +1,651 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \class QSpan
+ \inmodule QtCore
+ \since 6.7
+ \brief A non-owning container over contiguous data.
+ \ingroup tools
+ \reentrant
+
+ A QSpan references a contiguous portion of another contiguous container.
+ It acts as an interface type for all kinds of contiguous containers,
+ without the need to construct an owning container such as QList or
+ std::vector first.
+
+ The data referenced by a QSpan may be represented as an array (or
+ array-compatible data-structure such as QList, std::vector,
+ QVarLengthArray, etc.). QSpan itself merely stores a pointer to the data,
+ so users must ensure that QSpan objects do not outlive the data they
+ reference.
+
+ Unlike views such as QStringView, QLatin1StringView and QUtf8StringView,
+ referenced data can be modified through a QSpan object. To prevent this,
+ construct a QSpan over a \c{const T}:
+
+ \code
+ int numbers[] = {0, 1, 2};
+ QSpan<int> span = numbers;
+ span[0] = 42;
+ // numbers == {42, 1, 2};
+ QSpan<const int> cspan = numbers;
+ cspan[0] = 0; // ERROR: cspan[0] is read-only
+ \endcode
+
+ A QSpan can be \e{fixed-size} or \e{variable-sized}.
+
+ A variable-sized span is formed by omitting the second template argument
+ (or setting it to \c{std::dynamic_extent}, which is, however, only
+ available in C++20 builds), as seen in the example above.
+
+ A fixed-size span is formed by passing a number as the second template
+ argument:
+
+ \code
+ int numbers[] = {0, 1, 2};
+ QSpan<int, 3> span = numbers;
+ QSpan<const int, 3> = numbers; // also OK
+ \endcode
+
+ As the name suggests, a fixed-size span's size() is fixed at compile-time
+ whereas the size() of a variable-sized span is determined only at run-time.
+
+ A fixed-size span is not default-constructible (unless its \l extent is zero
+ (0)). A variable-sized span \e{is} default-constructible and will have
+ \c{data() == nullptr} and \c{size() == 0}.
+
+ A fixed-size span can be implicitly converted into a variable-sized one.
+ The opposite direction (variable-length into fixed-length) has the
+ precondition that both span's sizes must match.
+
+ Unlike with owning containers, \c{const} is \e{shallow} in QSpan: you can
+ still modify the data through a const QSpan (but not through a
+ \c{QSpan<const T>}), and begin() and end() are not overloaded on
+ \c{const}/non-\c{const}. There are cbegin() and cend(), though, that return
+ const_iterators which prevent modification of the data even though \c{T} is
+ not const:
+ \code
+ int numbers[] = {0, 1, 2};
+ const QSpan<int> span = numbers;
+ span.front() = 42; // OK, numbers[0] == 42 now
+ *span.begin() = 31; // OK, numbers[0] == 31 now
+ *span.cbegin() = -1; // ERROR: cannot assign through a const_iterator
+ \endcode
+
+ QSpan should be passed by value, not by reference-to-const:
+
+ \code
+ void consume(QSpan<const int> data); // OK
+ void consume(const QSpan<const int> &data); // works, but is non-idiomatic and less efficient
+ \endcode
+
+ \c{QSpan<T,N>} is a \e{Literal Type}, regardless of whether \c{T} is a
+ Literal Type or not.
+
+ \section2 QSpan vs. std::span
+ \target span-STL
+
+ QSpan is closely modelled after
+ \l{https://en.cppreference.com/w/cpp/container/span}{std::span}, but has a
+ few differences which we'll discuss here. Since they both implicitly
+ convert into each other, you're free to choose whichever one you like best
+ in your own code.
+
+ \list
+ \li QSpan is using the signed qsizetype as \c{size_type}
+ whereas \c{std::span} uses \c{size_t}.
+ \li All QSpan constructors are implicit;
+ many \c{std::span} ones are \c{explicit}.
+ \li QSpan can be constructed from rvalue owning containers, \c{std::span} can not.
+ \endlist
+
+ The last two are required for source-compatibility when functions that took
+ owning containers are converted to take QSpan instead, which is a
+ vitally-important use-case in Qt. The use of qsizetype is for consistency
+ with the rest of Qt containers. QSpan template arguments still use size_t
+ to avoid introducing unnecessary error conditions (negative sizes).
+
+ \section2 Compatible Iterators
+ \target span-compatible-iterators
+
+ QSpan can be constructed from an iterator and size or from an
+ iterator pair, provided the iterators are \e{compatible} ones.
+ Eventually, this should mean C++20 \c{std::contiguous_iterator} and
+ \c{std::sentinel_for}, but while Qt still supports C++17, only raw pointers
+ are considered contiguous iterators.
+
+ \section2 Compatible Ranges
+ \target span-compatible-ranges
+
+ QSpan can also be constructed from a \e{compatible} range. A range is
+ compatible if it has \l{span-compatible-iterators}{compatible iterators}.
+
+ \sa QList, QStringView, QLatin1StringView, QUtf8StringView
+*/
+
+//
+// Nested types and constants
+//
+
+/*!
+ \typedef QSpan::element_type
+
+ An alias for \c{T}. Includes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa value_type, pointer
+*/
+
+/*!
+ \typedef QSpan::value_type
+
+ An alias for \c{T}. Excludes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type
+*/
+
+/*!
+ \typedef QSpan::size_type
+
+ An alias for qsizetype. This \l{span-STL}{differs from \c{std::span}}.
+
+ This alias is provided for compatbility with the STL.
+*/
+
+/*!
+ \typedef QSpan::difference_type
+
+ An alias for qptrdiff. This \l{span-STL}{differs from \c{std::span}}.
+
+ This alias is provided for compatbility with the STL.
+*/
+
+/*!
+ \typedef QSpan::pointer
+
+ An alias for \c{T*} and \c{element_type*}, respectively. Includes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, const_pointer, reference, iterator
+*/
+
+/*!
+ \typedef QSpan::const_pointer
+
+ An alias for \c{const T*} and \c{const element_type*}, respectively.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, pointer, const_reference, const_iterator
+*/
+
+/*!
+ \typedef QSpan::reference
+
+ An alias for \c{T&} and \c{element_type&}, respectively. Includes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, const_reference, pointer
+*/
+
+/*!
+ \typedef QSpan::const_reference
+
+ An alias for \c{const T&} and \c{const element_type&}, respectively.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, reference, const_pointer
+*/
+
+/*!
+ \typedef QSpan::iterator
+
+ An alias for \c{T*} and \c{pointer}, respectively. Includes the \c{const}, if any.
+
+ \sa pointer, const_iterator, reverse_iterator
+*/
+
+/*!
+ \typedef QSpan::const_iterator
+
+ An alias for \c{const T*} and \c{const_pointer}, respectively.
+
+ \sa const_pointer, iterator, const_reverse_iterator
+*/
+
+/*!
+ \typedef QSpan::reverse_iterator
+
+ An alias for \c{std::reverse_iterator<iterator>}. Includes the \c{const}, if any.
+
+ \sa iterator, const_reverse_iterator
+*/
+
+/*!
+ \typedef QSpan::const_reverse_iterator
+
+ An alias for \c{std::reverse_iterator<const_iterator>}.
+
+ \sa const_iterator, reverse_iterator
+*/
+
+/*!
+ \variable QSpan::extent
+
+ The second template argument of \c{QSpan<T, E>}, that is, \c{E}. This is
+ \c{std::dynamic_extent} for variable-sized spans.
+
+ \note While all other sizes and indexes in QSpan use qsizetype, this
+ variable, like \c{E}, is actually of type \c{size_t}, for compatibility with
+ \c{std::span} and \c{std::dynamic_extent}.
+
+ \sa size()
+*/
+
+//
+// Constructors and SMFs
+//
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T,E>::QSpan()
+
+ Default constructor.
+
+ This constructor is only present if \c{E} is either zero (0) or
+ \c{std::dynamic_extent}. In other words: only fixed-zero-sized or variable-sized spans
+ are default-constructible.
+
+ \sa extent
+*/
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T,E>::QSpan(const QSpan &other)
+ \fn template <typename T, size_t E> QSpan<T,E>::QSpan(QSpan &&other)
+ \fn template <typename T, size_t E> QSpan<T,E> &QSpan<T,E>::operator=(const QSpan &other)
+ \fn template <typename T, size_t E> QSpan<T,E> &QSpan<T,E>::operator=(QSpan &&other)
+ \fn template <typename T, size_t E> QSpan<T,E>::~QSpan()
+
+ These Special Member Functions are implicitly-defined.
+
+ \note Moves are equivalent to copies. Only data() and size() are copied
+ from span to span, not the referenced data.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename It, QSpan<T, E>::if_compatible_iterator<It>> QSpan<T,E>::QSpan(It first, qsizetype count)
+
+ Constructs a QSpan referencing the data starting at \a first and having length
+ \a count.
+
+ \c{[first, count)} must be a valid range.
+
+ \note This constructor participates in overload resolution only if \c{It}
+ is \l{span-compatible-iterators}{a compatible iterator}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename It, QSpan<T, E>::if_compatible_iterator<It>> QSpan<T,E>::QSpan(It first, It last)
+
+ Constructs a QSpan referencing the data starting at \a first and having length
+ (\a last - \a first).
+
+ \c{[first, last)} must be a valid range.
+
+ \note This constructor participates in overload resolution only if \c{It}
+ is \l{span-compatible-iterators}{a compatible iterator}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <size_t N> QSpan<T,E>::QSpan(q20::type_identity_t<T> (&arr)[N]);
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(std::array<S, N> &arr);
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(const std::array<S, N> &arr);
+
+ Constructs a QSpan referencing the data in the supplied array \a arr.
+
+ \note This constructor participates in overload resolution only if
+ \list
+ \li either \c{N} or \l{extent} are \c{std::dynamic_extent} or otherwise \l{extent} \c{==} \c{N}
+ \li and either \c{S} or \c{const S} are the same as \c{T}.
+ \endlist
+
+ \note \c{q20::type_identity_t} is a C++17 backport of C++20's
+ \l{https://en.cppreference.com/w/cpp/types/type_identity}{\c{std::type_identity_t}}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename Range, QSpan<T, E>::if_compatible_range<Range> = true> QSpan<T,E>::QSpan(Range &&r)
+
+ Constructs a QSpan referencing the data in the supplied range \a r.
+
+ \note This constructor participates in overload resolution only if \c{Range}
+ is \l{span-compatible-ranges}{a compatible range}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(QSpan<S, N> other);
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(std::span<S, N> other);
+
+ Constructs a QSpan referencing the data in the supplied span \a other.
+
+ \note This constructor participates in overload resolution only if
+ \list
+ \li either \c{N} or \l{extent} are \c{std::dynamic_extent} or \l{extent} \c{==} \c{N}
+ \li and either \c{S} or \c{const S} are the same as \c{T}.
+ \endlist
+*/
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T, E>::QSpan(std::initializer_list<value_type> il);
+
+ Constructs a QSpan referencing the data in the supplied initializer list \a il.
+
+ \note This constructor participates in overload resolution only if \c{T} is \c{const}-qualified.
+
+ \note This constructor is \c{noexcept} only if \c{E} is \c{std::dynamic_extent}.
+
+ \note If \c{E} is not \c{std::dynamic_extent} and the size of \a il is not \c{E}, the behavior is undefined.
+*/
+
+//
+// Member functions: sizes
+//
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::size() const
+
+ Returns the size of the span, that is, the number of elements it references.
+
+ \sa size_bytes(), empty(), isEmpty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::size_bytes() const
+
+ Returns the size of the span in bytes, that is, the number of elements
+ multiplied by \c{sizeof(T)}.
+
+ \sa size(), empty(), isEmpty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::empty() const
+ \fn template <typename T, size_t E> auto QSpan<T, E>::isEmpty() const
+
+ Returns whether the span is empty, that is, whether \c{size() == 0}.
+
+ These functions do the same thing: empty() is provided for STL
+ compatibility and isEmpty() is provided for Qt compatibility.
+
+ \sa size(), size_bytes()
+*/
+
+//
+// element access
+//
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T, E>::operator[](size_type idx) const
+
+ Returns a reference to the element at index \a idx in the span.
+
+ The index must be in range, that is, \a idx >= 0 and \a idx < size(),
+ otherwise the behavior is undefined.
+
+ \sa front(), back(), size(), empty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::front() const
+
+ Returns a reference to the first element in the span.
+
+ The span must not be empty, otherwise the behavior is undefined.
+
+ \sa operator[](), back(), size(), empty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::back() const
+
+ Returns a reference to the last element in the span.
+
+ The span must not be empty, otherwise the behavior is undefined.
+
+ \sa operator[](), front(), size(), empty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::data() const
+
+ Returns a pointer to the beginning of the span.
+
+ The same as calling begin().
+
+ \sa begin(), front()
+*/
+
+//
+// iterators
+//
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::begin() const
+
+ Returns an interator pointing at the beginning of the span.
+
+ Because QSpan iterators are just pointers, this is the same as calling
+ data().
+
+ \sa end(), cbegin(), rbegin(), crbegin(), data()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::end() const
+
+ Returns an iterator pointing to one past the end of the span.
+
+ Because QSpan iterators are just pointers, this it the same as calling
+ \c{data() + size()}.
+
+ \sa begin(), cend(), rend(), crend(), data(), size()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::cbegin() const
+
+ Returns a const_iterator pointing to the beginning of the span.
+
+ This will return a read-only iterator even if \c{T} is not \c{const}:
+ \code
+ QSpan<int> span = ~~~;
+ *span.begin() = 42; // OK
+ *span.cbegin() = 42; // ERROR: cannot assign through a const_iterator
+ \endcode
+
+ \sa cend(), begin(), crbegin(), rbegin(), data()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::cend() const
+
+ Returns a const_iterator pointing to one past the end of the span.
+
+ \sa cbegin(), end(), crend(), rend(), data(), size()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::rbegin() const
+
+ Returns a reverse_iterator pointing to the beginning of the reversed span.
+
+ \sa rend(), crbegin(), begin(), cbegin()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::rend() const
+
+ Returns a reverse_iterator pointing to one past the end of the reversed span.
+
+ \sa rbegin(), crend(), end(), cend()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::crbegin() const
+
+ Returns a const_reverse_iterator pointing to the beginning of the reversed span.
+
+ \sa crend(), rbegin(), cbegin(), begin()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::crend() const
+
+ Returns a const_reverse_iterator pointing to one past the end of the reversed span.
+
+ \sa crbegin(), rend(), cend(), end()
+*/
+
+//
+// compile-time subspans:
+//
+
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Count> auto QSpan<T, E>::first() const
+ \keyword first-t
+
+ Returns a fixed-sized span of size \c{Count} referencing the first \c{Count} elements of \c{*this}.
+
+ The span must hold at least \c{Count} elements (\c{E} >= \c{Count} \e{and}
+ size() >= \c{Count}), otherwise the behavior is undefined.
+
+ \sa first(QSpan<T,E>::size_type), last(), subspan()
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Count> auto QSpan<T, E>::last() const
+ \keyword last-t
+
+ Returns a fixed-sized span of size \c{Count} referencing the last \c{Count} elements of \c{*this}.
+
+ The span must hold at least \c{Count} elements (\c{E} >= \c{Count} \e{and}
+ size() >= \c{Count}), otherwise the behavior is undefined.
+
+ \sa last(QSpan<T,E>::size_type), first(), subspan()
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Offset> auto QSpan<T, E>::subspan() const
+ \keyword subspan-t1
+
+ Returns a span of size \c{E - Offset} referencing the remainder of this span
+ after dropping the first \c{Offset} elements.
+
+ If \c{*this} is a variable-sized span, the return type is a variable-sized
+ span, otherwise it is a fixed-sized span.
+
+ This span must hold at least \c{Offset} elements (\c{E} >= \c{Offset} \e{and}
+ size() >= \c{Offset}), otherwise the behavior is undefined.
+
+ \sa subspan(QSpan<T,E>::size_type), subspan(), first(), last()
+*/
+
+#if 0 // needs fix for QTBUG-118080 integrated into qt5.git
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Offset, std::size_t Count> auto QSpan<T, E>::subspan() const
+ \keyword subspan-t2
+
+ Returns a span of size \c{Count} referencing the \c{Count} elements of this
+ span starting at \c{Offset}.
+
+ If \c{*this} is a variable-sized span, the return type is a variable-sized
+ span, otherwise it is a fixed-sized span.
+
+ This span must hold at least \c{Offset + Count} elements (\c{E} >=
+ \c{Offset + Count} \e{and} size() >= \c{Offset + Count}), otherwise the
+ behavior is undefined.
+
+ \sa subspan(QSpan<T,E>::size_type, QSpan<T,E>::size_type), subspan(), first(), last()
+*/
+#endif
+
+//
+// runtime subspans:
+//
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::first(qsizetype n) const
+ \keyword first-n
+
+ Returns a variable-sized span of size \a n referencing the first \a n elements of \c{*this}.
+
+ \a n must be non-negative.
+
+ The span must hold at least \a n elements (\c{E} >= \a n \e{and} size() >=
+ \a n), otherwise the behavior is undefined.
+
+ \sa {first-t}{first<N>()}, last(QSpan<T,E>::size_type), subspan(QSpan<T,E>::size_type),
+ subspan(QSpan<T,E>::size_type, QSpan<T,E>::size_type)
+ \sa sliced()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::last(qsizetype n) const
+ \keyword last-n
+
+ Returns a variable-sized span of size \a n referencing the last \a n elements of \c{*this}.
+
+ \a n must be non-negative.
+
+ The span must hold at least \a n elements (\c{E} >= \a n \e{and}
+ size() >= \a n), otherwise the behavior is undefined.
+
+ \sa last(), first(QSpan<T,E>::size_type), subspan(QSpan<T,E>::size_type),
+ subspan(QSpan<T,E>::size_type, QSpan<T,E>::size_type), sliced()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::subspan(qsizetype pos) const
+ \fn template <typename T, size_t E> auto QSpan<T, E>::sliced(qsizetype pos) const
+ \keyword subspan-n1
+
+ Returns a variable-sized span of size \c{size() - pos} referencing the
+ remainder of this span after dropping the first \a pos elements.
+
+ \a pos must be non-negative.
+
+ This span must hold at least \a pos elements (\c{E} >= \a pos \e{and}
+ size() >= \a pos), otherwise the behavior is undefined.
+
+ These functions do the same thing: subspan() is provided for STL
+ compatibility and sliced() is provided for Qt compatibility.
+
+ \sa subspan(), first(QSpan<T,E>::size_type), last(QSpan<T,E>::size_type)
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::subspan(qsizetype pos, qsizetype n) const
+ \fn template <typename T, size_t E> auto QSpan<T, E>::sliced(qsizetype pos, qsizetype n) const
+ \keyword subspan-n2
+
+ Returns a variable-sized span of size \a n referencing the \a n elements of
+ this span starting at \a pos.
+
+ Both \a pos and \a n must be non-negative.
+
+ This span must hold at least \c{pos + n} elements (\c{E} >=
+ \c{pos + n} \e{and} size() >= \c{pos + n}), otherwise the
+ behavior is undefined.
+
+ These functions do the same thing: subspan() is provided for STL
+ compatibility and sliced() is provided for Qt compatibility.
+
+ \sa subspan(), first(QSpan<T,E>::size_type), last(QSpan<T,E>::size_type)
+*/
+
diff --git a/src/corelib/tools/qspan_p.h b/src/corelib/tools/qspan_p.h
new file mode 100644
index 0000000000..0072e3ef64
--- /dev/null
+++ b/src/corelib/tools/qspan_p.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSPAN_P_H
+#define QSPAN_P_H
+
+#include <QtCore/qspan.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
+
+QT_END_NAMESPACE
+
+#endif // QSPAN_P_H
diff --git a/src/corelib/tools/qstack.cpp b/src/corelib/tools/qstack.cpp
index 849a474d2c..5255e0e100 100644
--- a/src/corelib/tools/qstack.cpp
+++ b/src/corelib/tools/qstack.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QStack
diff --git a/src/corelib/tools/qstack.h b/src/corelib/tools/qstack.h
index a0e39f8ece..11ffb13328 100644
--- a/src/corelib/tools/qstack.h
+++ b/src/corelib/tools/qstack.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTACK_H
#define QSTACK_H
@@ -49,26 +13,13 @@ class QStack : public QList<T>
{
public:
// compiler-generated special member functions are fine!
- inline void swap(QStack<T> &other) noexcept { QList<T>::swap(other); } // prevent QList<->QStack swaps
- inline void push(const T &t) { QList<T>::append(t); }
- T pop();
- T &top();
- const T &top() const;
+ void swap(QStack<T> &other) noexcept { QList<T>::swap(other); } // prevent QList<->QStack swaps
+ void push(const T &t) { QList<T>::append(t); }
+ T pop() { return QList<T>::takeLast(); }
+ T &top() { return QList<T>::last(); }
+ const T &top() const { return QList<T>::last(); }
};
-template<class T>
-inline T QStack<T>::pop()
-{ Q_ASSERT(!this->isEmpty()); T t = this->data()[this->size() -1];
- this->resize(this->size()-1); return t; }
-
-template<class T>
-inline T &QStack<T>::top()
-{ Q_ASSERT(!this->isEmpty()); this->detach(); return this->data()[this->size()-1]; }
-
-template<class T>
-inline const T &QStack<T>::top() const
-{ Q_ASSERT(!this->isEmpty()); return this->data()[this->size()-1]; }
-
QT_END_NAMESPACE
#endif // QSTACK_H
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h
index f6ce85eebc..6c467d59f8 100644
--- a/src/corelib/tools/qtaggedpointer.h
+++ b/src/corelib/tools/qtaggedpointer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTAGGEDPOINTER_H
#define QTAGGEDPOINTER_H
@@ -48,7 +12,7 @@
QT_BEGIN_NAMESPACE
namespace QtPrivate {
- constexpr quint8 nextByteSize(quint8 bits) { return (bits + 7) / 8; }
+ constexpr quint8 nextByteSize(quint8 bits) { return quint8((bits + 7) / 8); }
template <typename T>
struct TagInfo
@@ -57,7 +21,7 @@ namespace QtPrivate {
static_assert((alignment & (alignment - 1)) == 0,
"Alignment of template parameter must be power of two");
- static constexpr quint8 tagBits = QtPrivate::qConstexprCountTrailingZeroBits(alignment);
+ static constexpr quint8 tagBits = quint8{QtPrivate::qConstexprCountTrailingZeroBits(alignment)};
static_assert(tagBits > 0,
"Alignment of template parameter does not allow any tags");
@@ -79,10 +43,10 @@ public:
static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
static constexpr quintptr pointerMask() { return ~tagMask(); }
- constexpr QTaggedPointer() noexcept : d(0) {}
- constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
+ Q_NODISCARD_CTOR constexpr QTaggedPointer() noexcept : d(0) {}
+ Q_NODISCARD_CTOR constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
- explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
+ Q_NODISCARD_CTOR explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
: d(quintptr(pointer) | quintptr(tag))
{
static_assert(sizeof(Type*) == sizeof(QTaggedPointer));
@@ -108,12 +72,31 @@ public:
return !isNull();
}
- QTaggedPointer &operator=(T *other) noexcept
+#ifdef Q_QDOC
+ QTaggedPointer &operator=(T *other) noexcept;
+#else
+ // Disables the usage of `ptr = {}`, which would go through this operator
+ // (rather than using the implicitly-generated assignment operator).
+ // The operators have different semantics: the ones here leave the tag intact,
+ // the implicitly-generated one overwrites it.
+ template <typename U,
+ std::enable_if_t<std::is_convertible_v<U *, T *>, bool> = false>
+ QTaggedPointer &operator=(U *other) noexcept
{
- d = reinterpret_cast<quintptr>(other) | (d & tagMask());
+ T *otherT = other;
+ d = reinterpret_cast<quintptr>(otherT) | (d & tagMask());
return *this;
}
+ template <typename U,
+ std::enable_if_t<std::is_null_pointer_v<U>, bool> = false>
+ QTaggedPointer &operator=(U) noexcept
+ {
+ d = reinterpret_cast<quintptr>(static_cast<T *>(nullptr)) | (d & tagMask());
+ return *this;
+ }
+#endif
+
static constexpr Tag maximumTag() noexcept
{
return TagType(typename QtPrivate::TagInfo<T>::TagType(tagMask()));
@@ -121,8 +104,10 @@ public:
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");
+ Q_ASSERT_X(
+ (static_cast<quintptr>(tag) & pointerMask()) == 0,
+ "QTaggedPointer<T, Tag>::setTag",
+ "Tag is larger than allowed by number of available tag bits");
d = (d & pointerMask()) | static_cast<quintptr>(tag);
}
@@ -144,7 +129,7 @@ public:
void swap(QTaggedPointer &other) noexcept
{
- qSwap(d, other.d);
+ std::swap(d, other.d);
}
friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
diff --git a/src/corelib/tools/qtaggedpointer.qdoc b/src/corelib/tools/qtaggedpointer.qdoc
index 36e20ecff0..f910e35b69 100644
--- a/src/corelib/tools/qtaggedpointer.qdoc
+++ b/src/corelib/tools/qtaggedpointer.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QTaggedPointer
@@ -211,7 +187,7 @@
*/
/*!
- \fn template <typename T, typename Tag> qHash(QTaggedPointer<T, Tag> key, std::size_t seed)
+ \fn template <typename T, typename Tag> qHash(QTaggedPointer<T, Tag> key, std::size_t seed = 0)
\relates QTaggedPointer
Returns the hash value for the \a key, using \a seed to seed the calculation.
diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp
index 8a01dbe685..5512da867f 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtimeline.h"
@@ -91,16 +55,16 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
{
Q_Q(QTimeLine);
currentTime.removeBindingUnlessInWrapper();
- auto previousCurrentTime = currentTime.value();
+ const auto previousCurrentTime = currentTime.valueBypassingBindings();
- qreal lastValue = q->currentValue();
- int lastFrame = q->currentFrame();
+ const qreal lastValue = q->valueForTime(previousCurrentTime);
+ const int lastFrame = q->frameForTime(previousCurrentTime);
// Determine if we are looping.
- int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
- int loopCountNow = elapsed / duration;
+ const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
+ const int loopCountNow = elapsed / duration;
- bool looping = (loopCountNow != currentLoopCount);
+ const bool looping = (loopCountNow != currentLoopCount);
#ifdef QTIMELINE_DEBUG
qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow"
<< loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping;
@@ -111,7 +75,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
// Normalize msecs to be between 0 and duration, inclusive.
currentTime.setValueBypassingBindings(elapsed % duration);
if (direction.value() == QTimeLine::Backward)
- currentTime.setValueBypassingBindings(duration - currentTime);
+ currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
// Check if we have reached the end of loopcount.
bool finished = false;
@@ -121,12 +85,14 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
currentLoopCount = loopCount - 1;
}
- int currentFrame = q->frameForTime(currentTime);
+ const int currentFrame = q->frameForTime(currentTime.valueBypassingBindings());
#ifdef QTIMELINE_DEBUG
- qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime" << currentTime << currentFrame;
+ qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime"
+ << currentTime.valueBypassingBindings() << currentFrame;
#endif
- if (!qFuzzyCompare(lastValue, q->currentValue()))
- emit q->valueChanged(q->currentValue(), QTimeLine::QPrivateSignal());
+ const qreal currentValue = q->valueForTime(currentTime.valueBypassingBindings());
+ if (!qFuzzyCompare(lastValue, currentValue))
+ emit q->valueChanged(currentValue, QTimeLine::QPrivateSignal());
if (lastFrame != currentFrame) {
const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
if (looping && !finished && transitionframe != currentFrame) {
@@ -159,7 +125,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
q->stop();
emit q->finished(QTimeLine::QPrivateSignal());
}
- if (currentTime.value() != previousCurrentTime)
+ if (currentTime.valueBypassingBindings() != previousCurrentTime)
currentTime.notify();
}
QBindable<int> QTimeLine::bindableCurrentTime()
@@ -326,7 +292,7 @@ QTimeLine::State QTimeLine::state() const
\property QTimeLine::loopCount
\brief the number of times the timeline should loop before it's finished.
- A loop count of of 0 means that the timeline will loop forever.
+ A loop count of 0 means that the timeline will loop forever.
By default, this property contains a value of 1.
*/
@@ -370,11 +336,12 @@ QTimeLine::Direction QTimeLine::direction() const
void QTimeLine::setDirection(Direction direction)
{
Q_D(QTimeLine);
- auto previousDirection = d->direction.value();
- d->direction.setValue(direction);
+ d->direction.removeBindingUnlessInWrapper();
+ const auto previousDirection = d->direction.valueBypassingBindings();
+ d->direction.setValueBypassingBindings(direction);
d->startTime = d->currentTime;
d->timer.start();
- if (previousDirection != d->direction.value())
+ if (previousDirection != d->direction.valueBypassingBindings())
d->direction.notify();
}
@@ -408,12 +375,11 @@ void QTimeLine::setDuration(int duration)
qWarning("QTimeLine::setDuration: cannot set duration <= 0");
return;
}
- if (duration == d->duration) {
- d->duration.removeBindingUnlessInWrapper();
- return;
+ d->duration.removeBindingUnlessInWrapper();
+ if (duration != d->duration.valueBypassingBindings()) {
+ d->duration.setValueBypassingBindings(duration);
+ d->duration.notify();
}
- d->duration.setValue(duration);
- d->duration.notify();
}
QBindable<int> QTimeLine::bindableDuration()
diff --git a/src/corelib/tools/qtimeline.h b/src/corelib/tools/qtimeline.h
index 464c4a8836..4bdcceaebd 100644
--- a/src/corelib/tools/qtimeline.h
+++ b/src/corelib/tools/qtimeline.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTIMELINE_H
#define QTIMELINE_H
diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h
index 8854ae8c48..105aa40c02 100644
--- a/src/corelib/tools/qtools_p.h
+++ b/src/corelib/tools/qtools_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTOOLS_P_H
#define QTOOLS_P_H
@@ -52,22 +16,32 @@
//
#include "QtCore/private/qglobal_p.h"
+
+#include <chrono>
#include <limits.h>
+#include <time.h>
QT_BEGIN_NAMESPACE
namespace QtMiscUtils {
-constexpr inline char toHexUpper(uint value) noexcept
+constexpr inline char toHexUpper(char32_t value) noexcept
{
return "0123456789ABCDEF"[value & 0xF];
}
-constexpr inline char toHexLower(uint value) noexcept
+constexpr inline char toHexLower(char32_t value) noexcept
{
return "0123456789abcdef"[value & 0xF];
}
-constexpr inline int fromHex(uint c) noexcept
+[[nodiscard]] constexpr inline bool isHexDigit(char32_t c) noexcept
+{
+ return (c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'F')
+ || (c >= 'a' && c <= 'f');
+}
+
+constexpr inline int fromHex(char32_t c) noexcept
{
return ((c >= '0') && (c <= '9')) ? int(c - '0') :
((c >= 'A') && (c <= 'F')) ? int(c - 'A' + 10) :
@@ -75,19 +49,71 @@ constexpr inline int fromHex(uint c) noexcept
/* otherwise */ -1;
}
-constexpr inline char toOct(uint value) noexcept
+constexpr inline char toOct(char32_t value) noexcept
{
return char('0' + (value & 0x7));
}
-constexpr inline int fromOct(uint c) noexcept
+[[nodiscard]] constexpr inline bool isOctalDigit(char32_t c) noexcept
{
- return ((c >= '0') && (c <= '7')) ? int(c - '0') : -1;
+ return c >= '0' && c <= '7';
}
+
+constexpr inline int fromOct(char32_t c) noexcept
+{
+ return isOctalDigit(c) ? int(c - '0') : -1;
+}
+
+[[nodiscard]] constexpr inline bool isAsciiDigit(char32_t c) noexcept
+{
+ return c >= '0' && c <= '9';
+}
+
+constexpr inline bool isAsciiUpper(char32_t c) noexcept
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+constexpr inline bool isAsciiLower(char32_t c) noexcept
+{
+ return c >= 'a' && c <= 'z';
+}
+
+constexpr inline bool isAsciiLetterOrNumber(char32_t c) noexcept
+{
+ return isAsciiDigit(c) || isAsciiLower(c) || isAsciiUpper(c);
+}
+
+constexpr inline char toAsciiLower(char ch) noexcept
+{
+ return isAsciiUpper(ch) ? ch - 'A' + 'a' : ch;
+}
+
+constexpr inline char toAsciiUpper(char ch) noexcept
+{
+ return isAsciiLower(ch) ? ch - 'a' + 'A' : ch;
+}
+
+constexpr inline int caseCompareAscii(char lhs, char rhs) noexcept
+{
+ const char lhsLower = QtMiscUtils::toAsciiLower(lhs);
+ const char rhsLower = QtMiscUtils::toAsciiLower(rhs);
+ return int(uchar(lhsLower)) - int(uchar(rhsLower));
+}
+
+constexpr inline int isAsciiPrintable(char32_t ch) noexcept
+{
+ return ch >= ' ' && ch < 0x7f;
+}
+
+constexpr inline int qt_lencmp(qsizetype lhs, qsizetype rhs) noexcept
+{
+ return lhs == rhs ? 0 :
+ lhs > rhs ? 1 :
+ /* else */ -1 ;
}
-// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size.
-constexpr qsizetype MaxAllocSize = (std::numeric_limits<qsizetype>::max)();
+} // namespace QtMiscUtils
struct CalculateGrowingBlockSizeResult
{
diff --git a/src/corelib/tools/qtyperevision.cpp b/src/corelib/tools/qtyperevision.cpp
new file mode 100644
index 0000000000..6426236288
--- /dev/null
+++ b/src/corelib/tools/qtyperevision.cpp
@@ -0,0 +1,217 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qtyperevision.h>
+#include <QtCore/qhashfunctions.h>
+
+#ifndef QT_NO_DATASTREAM
+# include <QtCore/qdatastream.h>
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/qdebug.h>
+#endif
+
+#include <algorithm>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+QT_IMPL_METATYPE_EXTERN(QTypeRevision)
+
+/*!
+ \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.
+ \compares strong
+
+ 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, QTypeRevision::if_valid_segment_type<Integer> = true> static bool QTypeRevision::isValidSegment(Integer segment)
+
+ Returns true if the given number can be used as either major or minor
+ version in a QTypeRevision. The valid range for \a segment is \c {>= 0} and \c {< 255}.
+*/
+
+/*!
+ \fn QTypeRevision::QTypeRevision()
+
+ Produces an invalid revision.
+
+ \sa isValid()
+*/
+
+/*!
+ \fn template<typename Major, typename Minor, QTypeRevision::if_valid_segment_type<Major> = true, QTypeRevision::if_valid_segment_type<Minor> = true> 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, QTypeRevision::if_valid_segment_type<Major> = true> 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, QTypeRevision::if_valid_segment_type<Minor> = true> 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, QTypeRevision::if_valid_value_type<Integer> = true> 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, QTypeRevision::if_valid_value_type<Integer> = true> 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
+
+/*!
+ \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/qtyperevision.h b/src/corelib/tools/qtyperevision.h
new file mode 100644
index 0000000000..8f255a77e8
--- /dev/null
+++ b/src/corelib/tools/qtyperevision.h
@@ -0,0 +1,167 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2015 Keith Gardner <kreios4004@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTYPEREVISION_H
+#define QTYPEREVISION_H
+
+#include <QtCore/qassert.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qtypeinfo.h>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+class QDataStream;
+class QDebug;
+
+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:
+ friend constexpr bool
+ comparesEqual(const QTypeRevision &lhs, const QTypeRevision &rhs) noexcept
+ { return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>(); }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QTypeRevision &lhs, const QTypeRevision &rhs) noexcept
+ {
+ // For both major and minor the following rule applies:
+ // non-0 ver > unspecified ver > 0 ver
+ auto cmpUnspecified = [](quint8 leftVer, quint8 rightVer) {
+ Q_ASSERT(leftVer != rightVer
+ && (leftVer == QTypeRevision::SegmentUnknown
+ || rightVer == QTypeRevision::SegmentUnknown));
+ if (leftVer != QTypeRevision::SegmentUnknown)
+ return leftVer > 0 ? Qt::strong_ordering::greater : Qt::strong_ordering::less;
+ return rightVer > 0 ? Qt::strong_ordering::less : Qt::strong_ordering::greater;
+ };
+
+ if (lhs.hasMajorVersion() != rhs.hasMajorVersion()) {
+ return cmpUnspecified(lhs.majorVersion(), rhs.majorVersion());
+ } else {
+ const auto majorRes = Qt::compareThreeWay(lhs.majorVersion(), rhs.majorVersion());
+ if (is_eq(majorRes)) {
+ if (lhs.hasMinorVersion() != rhs.hasMinorVersion())
+ return cmpUnspecified(lhs.minorVersion(), rhs.minorVersion());
+ return Qt::compareThreeWay(lhs.minorVersion(), rhs.minorVersion());
+ }
+ return majorRes;
+ }
+ }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QTypeRevision)
+
+ enum { SegmentUnknown = 0xff };
+
+#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
+};
+
+static_assert(sizeof(QTypeRevision) == 2);
+Q_DECLARE_TYPEINFO(QTypeRevision, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QTypeRevision &revision);
+#endif
+
+QT_END_NAMESPACE
+
+QT_DECL_METATYPE_EXTERN(QTypeRevision, Q_CORE_EXPORT)
+
+#endif // QTYPEREVISION_H
+
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 2
+// make QVersionNumber available from <QTypeRevision>
+#include <QtCore/qversionnumber.h>
+#endif
diff --git a/src/corelib/tools/quniquehandle_p.h b/src/corelib/tools/quniquehandle_p.h
new file mode 100644
index 0000000000..7af1536c2e
--- /dev/null
+++ b/src/corelib/tools/quniquehandle_p.h
@@ -0,0 +1,225 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QUNIQUEHANDLE_P_H
+#define QUNIQUEHANDLE_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/qtconfigmacros.h>
+#include <QtCore/qassert.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal QUniqueHandle is a general purpose RAII wrapper intended
+ for interfacing with resource-allocating C-style APIs, for example
+ operating system APIs, database engine APIs, or any other scenario
+ where resources are allocated and released, and where pointer
+ semantics does not seem a perfect fit.
+
+ QUniqueHandle does not support copying, because it is intended to
+ maintain ownership of resources that can not be copied. This makes
+ it safer to use than naked handle types, since ownership is
+ maintained by design.
+
+ The underlying handle object is described using a client supplied
+ HandleTraits object that is implemented per resource type. The
+ traits struct must describe two properties of a handle:
+
+ 1) What value is considered invalid
+ 2) How to close a resource.
+
+ Example 1:
+
+ struct InvalidHandleTraits {
+ using Type = HANDLE;
+
+ static Type invalidValue() {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ static bool close(Type handle) {
+ return CloseHandle(handle) != 0;
+ }
+ }
+
+ using FileHandle = QUniqueHandle<InvalidHandleTraits>;
+
+ Usage:
+
+ // Takes ownership of returned handle.
+ FileHandle handle{ CreateFile(...) };
+
+ if (!handle.isValid()) {
+ qDebug() << GetLastError()
+ return;
+ }
+
+ ...
+
+ Example 2:
+
+ struct SqLiteTraits {
+ using Type = sqlite3*;
+
+ static Type invalidValue() {
+ return nullptr;
+ }
+
+ static bool close(Type handle) {
+ sqlite3_close(handle);
+ return true;
+ }
+ }
+
+ using DbHandle = QUniqueHandle<SqLiteTraits>;
+
+ Usage:
+
+ DbHandle h;
+
+ // Take ownership of returned handle.
+ int result = sqlite3_open(":memory:", &h);
+
+ ...
+
+ NOTE: The QUniqueHandle assumes that closing a resource is
+ guaranteed to succeed, and provides no support for handling failure
+ to close a resource. It is therefore only recommended for use cases
+ where failure to close a resource is either not an error, or an
+ unrecoverable error.
+*/
+
+// clang-format off
+
+template <typename HandleTraits>
+class QUniqueHandle
+{
+public:
+ using Type = typename HandleTraits::Type;
+
+ QUniqueHandle() = default;
+
+ explicit QUniqueHandle(const Type &handle) noexcept
+ : m_handle{ handle }
+ {}
+
+ QUniqueHandle(QUniqueHandle &&other) noexcept
+ : m_handle{ other.release() }
+ {}
+
+ ~QUniqueHandle() noexcept
+ {
+ close();
+ }
+
+ QUniqueHandle& operator=(QUniqueHandle &&rhs) noexcept
+ {
+ if (this != std::addressof(rhs))
+ reset(rhs.release());
+
+ return *this;
+ }
+
+ QUniqueHandle(const QUniqueHandle &) = delete;
+ QUniqueHandle &operator=(const QUniqueHandle &) = delete;
+
+
+ [[nodiscard]] bool isValid() const noexcept
+ {
+ return m_handle != HandleTraits::invalidValue();
+ }
+
+ [[nodiscard]] explicit operator bool() const noexcept
+ {
+ return isValid();
+ }
+
+ [[nodiscard]] Type get() const noexcept
+ {
+ return m_handle;
+ }
+
+ void reset(const Type& handle) noexcept
+ {
+ if (handle == m_handle)
+ return;
+
+ close();
+ m_handle = handle;
+ }
+
+ [[nodiscard]] Type release() noexcept
+ {
+ Type handle = m_handle;
+ m_handle = HandleTraits::invalidValue();
+ return handle;
+ }
+
+ [[nodiscard]] Type *operator&() noexcept // NOLINT(google-runtime-operator)
+ {
+ Q_ASSERT(!isValid());
+ return &m_handle;
+ }
+
+ void close() noexcept
+ {
+ if (!isValid())
+ return;
+
+ const bool success = HandleTraits::close(m_handle);
+ Q_ASSERT(success);
+
+ m_handle = HandleTraits::invalidValue();
+ }
+
+ [[nodiscard]] friend bool operator==(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() == rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator!=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() != rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator<(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() < rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator<=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() <= rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator>(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() > rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator>=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() >= rhs.get();
+ }
+
+private:
+ Type m_handle{ HandleTraits::invalidValue() };
+};
+
+// clang-format on
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 90be3b3299..afc345d3be 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -1,45 +1,14 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVARLENGTHARRAY_H
#define QVARLENGTHARRAY_H
+#if 0
+#pragma qt_class(QVarLengthArray)
+#pragma qt_sync_stop_processing
+#endif
+
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qglobal.h>
#include <QtCore/qalgorithms.h>
@@ -49,41 +18,320 @@
#include <algorithm>
#include <initializer_list>
#include <iterator>
+#include <QtCore/q20memory.h>
#include <new>
+
#include <string.h>
#include <stdlib.h>
QT_BEGIN_NAMESPACE
+template <size_t Size, size_t Align, qsizetype Prealloc>
+class QVLAStorage
+{
+ template <size_t> class print;
+protected:
+ ~QVLAStorage() = default;
+
+ alignas(Align) char array[Prealloc * (Align > Size ? Align : Size)];
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+ // ensure we maintain BC: std::aligned_storage_t was only specified by a
+ // minimum size, but for BC we need the substitution to be exact in size:
+ static_assert(std::is_same_v<print<sizeof(std::aligned_storage_t<Size, Align>[Prealloc])>,
+ print<sizeof(array)>>);
+ QT_WARNING_POP
+};
+
+class QVLABaseBase
+{
+protected:
+ ~QVLABaseBase() = default;
+
+ qsizetype a; // capacity
+ qsizetype s; // size
+ void *ptr; // data
+
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+
+ struct free_deleter {
+ void operator()(void *p) const noexcept { free(p); }
+ };
+ using malloced_ptr = std::unique_ptr<void, free_deleter>;
+
+public:
+ using size_type = qsizetype;
+
+ constexpr size_type capacity() const noexcept { return a; }
+ constexpr size_type size() const noexcept { return s; }
+ constexpr bool empty() const noexcept { return size() == 0; }
+};
+
+template<class T>
+class QVLABase : public QVLABaseBase
+{
+protected:
+ ~QVLABase() = default;
+
+public:
+ T *data() noexcept { return static_cast<T *>(ptr); }
+ const T *data() const noexcept { return static_cast<T *>(ptr); }
+
+ using iterator = T*;
+ using const_iterator = const T*;
+
+ iterator begin() noexcept { return data(); }
+ const_iterator begin() const noexcept { return data(); }
+ const_iterator cbegin() const noexcept { return begin(); }
+ iterator end() noexcept { return data() + size(); }
+ const_iterator end() const noexcept { return data() + size(); }
+ const_iterator cend() const noexcept { return end(); }
+
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
+ const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
+ const_reverse_iterator crend() const noexcept { return rend(); }
+
+ using value_type = T;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using difference_type = qptrdiff;
+
+ reference front()
+ {
+ verify();
+ return *begin();
+ }
+
+ const_reference front() const
+ {
+ verify();
+ return *begin();
+ }
+
+ reference back()
+ {
+ verify();
+ return *rbegin();
+ }
+
+ const_reference back() const
+ {
+ verify();
+ return *rbegin();
+ }
+
+ void pop_back()
+ {
+ verify();
+ if constexpr (QTypeInfo<T>::isComplex)
+ data()[size() - 1].~T();
+ --s;
+ }
+
+ template <typename AT = T>
+ qsizetype indexOf(const AT &t, qsizetype from = 0) const;
+ template <typename AT = T>
+ qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const;
+ template <typename AT = T>
+ bool contains(const AT &t) const;
+
+ reference operator[](qsizetype idx)
+ {
+ verify(idx);
+ return data()[idx];
+ }
+ const_reference operator[](qsizetype idx) const
+ {
+ verify(idx);
+ return data()[idx];
+ }
+
+ value_type value(qsizetype i) const;
+ value_type value(qsizetype i, const T& defaultValue) const;
+
+ void replace(qsizetype i, const T &t);
+ void remove(qsizetype i, qsizetype n = 1);
+ template <typename AT = T>
+ qsizetype removeAll(const AT &t);
+ template <typename AT = T>
+ bool removeOne(const AT &t);
+ template <typename Predicate>
+ qsizetype removeIf(Predicate pred);
+
+ void clear()
+ {
+ if constexpr (QTypeInfo<T>::isComplex)
+ std::destroy_n(data(), size());
+ s = 0;
+ }
+
+ iterator erase(const_iterator begin, const_iterator end);
+ iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
+
+ static constexpr qsizetype max_size() noexcept
+ {
+ // -1 to deal with the pointer one-past-the-end
+ return (QtPrivate::MaxAllocSize / sizeof(T)) - 1;
+ }
+
+ size_t hash(size_t seed) const noexcept(QtPrivate::QNothrowHashable_v<T>)
+ {
+ return qHashRange(begin(), end(), seed);
+ }
+protected:
+ void growBy(qsizetype prealloc, void *array, qsizetype increment)
+ { reallocate_impl(prealloc, array, size(), (std::max)(size() * 2, size() + increment)); }
+ template <typename...Args>
+ reference emplace_back_impl(qsizetype prealloc, void *array, Args&&...args)
+ {
+ if (size() == capacity()) // ie. size() != 0
+ growBy(prealloc, array, 1);
+ reference r = *q20::construct_at(end(), std::forward<Args>(args)...);
+ ++s;
+ return r;
+ }
+ template <typename...Args>
+ iterator emplace_impl(qsizetype prealloc, void *array, const_iterator pos, Args&&...arg);
+
+ iterator insert_impl(qsizetype prealloc, void *array, const_iterator pos, qsizetype n, const T &t);
+
+ template <typename S>
+ bool equal(const QVLABase<S> &other) const
+ {
+ return std::equal(begin(), end(), other.begin(), other.end());
+ }
+ template <typename S>
+ bool less_than(const QVLABase<S> &other) const
+ {
+ return std::lexicographical_compare(begin(), end(), other.begin(), other.end());
+ }
+
+ void append_impl(qsizetype prealloc, void *array, const T *buf, qsizetype n);
+ void reallocate_impl(qsizetype prealloc, void *array, qsizetype size, qsizetype alloc);
+ void resize_impl(qsizetype prealloc, void *array, qsizetype sz, const T &v)
+ {
+ if (QtPrivate::q_points_into_range(&v, begin(), end())) {
+ resize_impl(prealloc, array, sz, T(v));
+ return;
+ }
+ reallocate_impl(prealloc, array, sz, qMax(sz, capacity()));
+ while (size() < sz) {
+ q20::construct_at(data() + size(), v);
+ ++s;
+ }
+ }
+ void resize_impl(qsizetype prealloc, void *array, qsizetype sz)
+ {
+ reallocate_impl(prealloc, array, sz, qMax(sz, capacity()));
+ if constexpr (QTypeInfo<T>::isComplex) {
+ // call default constructor for new objects (which can throw)
+ while (size() < sz) {
+ q20::construct_at(data() + size());
+ ++s;
+ }
+ } else {
+ s = sz;
+ }
+ }
+
+ void assign_impl(qsizetype prealloc, void *array, qsizetype n, const T &t);
+ template <typename Iterator>
+ void assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last);
+
+ bool isValidIterator(const const_iterator &i) const
+ {
+ const std::less<const T *> less = {};
+ return !less(cend(), i) && !less(i, cbegin());
+ }
+};
// Prealloc = 256 by default, specified in qcontainerfwd.h
template<class T, qsizetype Prealloc>
class QVarLengthArray
+#if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || defined(QT_BOOTSTRAPPED)
+ : public QVLAStorage<sizeof(T), alignof(T), Prealloc>,
+ public QVLABase<T>
+#else
+ : public QVLABase<T>,
+ public QVLAStorage<sizeof(T), alignof(T), Prealloc>
+#endif
{
+ template <class S, qsizetype Prealloc2>
+ friend class QVarLengthArray;
+ using Base = QVLABase<T>;
+ using Storage = QVLAStorage<sizeof(T), alignof(T), Prealloc>;
+ static_assert(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0.");
static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+ using Base::verify;
+ template <typename U>
+ using if_copyable = std::enable_if_t<std::is_copy_constructible_v<U>, bool>;
+ template <typename InputIterator>
+ using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
public:
- QVarLengthArray() : QVarLengthArray(0) {}
+ static constexpr qsizetype PreallocatedSize = Prealloc;
+
+ using size_type = typename Base::size_type;
+ using value_type = typename Base::value_type;
+ using pointer = typename Base::pointer;
+ using const_pointer = typename Base::const_pointer;
+ using reference = typename Base::reference;
+ using const_reference = typename Base::const_reference;
+ using difference_type = typename Base::difference_type;
+
+ using iterator = typename Base::iterator;
+ using const_iterator = typename Base::const_iterator;
+ using reverse_iterator = typename Base::reverse_iterator;
+ using const_reverse_iterator = typename Base::const_reverse_iterator;
+
+ QVarLengthArray() noexcept
+ {
+ this->a = Prealloc;
+ this->s = 0;
+ this->ptr = this->array;
+ }
inline explicit QVarLengthArray(qsizetype size);
- inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
- : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
+#ifndef Q_QDOC
+ template <typename U = T, if_copyable<U> = true>
+#endif
+ explicit QVarLengthArray(qsizetype sz, const T &v)
+ : QVarLengthArray{}
+ {
+ resize(sz, v);
+ }
+
+ QVarLengthArray(const QVarLengthArray &other)
+ : QVarLengthArray{}
{
append(other.constData(), other.size());
}
QVarLengthArray(QVarLengthArray &&other)
noexcept(std::is_nothrow_move_constructible_v<T>)
- : a{other.a},
- s{other.s},
- ptr{other.ptr}
+ : Base(other)
{
const auto otherInlineStorage = reinterpret_cast<T*>(other.array);
- if (ptr == otherInlineStorage) {
+ if (data() == otherInlineStorage) {
// inline buffer - move into our inline buffer:
- ptr = reinterpret_cast<T*>(array);
- QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, s, ptr);
+ this->ptr = this->array;
+ QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, size(), data());
} else {
// heap buffer - we just stole the memory
}
@@ -98,7 +346,7 @@ public:
{
}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
inline QVarLengthArray(InputIterator first, InputIterator last)
: QVarLengthArray()
{
@@ -109,9 +357,9 @@ public:
inline ~QVarLengthArray()
{
if constexpr (QTypeInfo<T>::isComplex)
- std::destroy_n(ptr, s);
- if (ptr != reinterpret_cast<T *>(array))
- free(ptr);
+ std::destroy_n(data(), size());
+ if (data() != reinterpret_cast<T *>(this->array))
+ free(data());
}
inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other)
{
@@ -130,109 +378,119 @@ public:
// the moved-from state is the empty state, so we're good with the clear() here:
clear();
Q_ASSERT(capacity() >= Prealloc);
- const auto otherInlineStorage = reinterpret_cast<T *>(other.array);
+ const auto otherInlineStorage = other.array;
if (other.ptr != otherInlineStorage) {
// heap storage: steal the external buffer, reset other to otherInlineStorage
- a = std::exchange(other.a, Prealloc);
- ptr = std::exchange(other.ptr, otherInlineStorage);
+ this->a = std::exchange(other.a, Prealloc);
+ this->ptr = std::exchange(other.ptr, otherInlineStorage);
} else {
// inline storage: move into our storage (doesn't matter whether inline or external)
- QtPrivate::q_uninitialized_relocate_n(other.ptr, other.s, ptr);
+ QtPrivate::q_uninitialized_relocate_n(other.data(), other.size(), data());
}
- s = std::exchange(other.s, 0);
+ this->s = std::exchange(other.s, 0);
return *this;
}
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
{
- resize(qsizetype(list.size()));
- std::copy(list.begin(), list.end(),
- QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size()));
+ assign(list);
return *this;
}
inline void removeLast()
{
- Q_ASSERT(s > 0);
- if constexpr (QTypeInfo<T>::isComplex)
- ptr[s - 1].~T();
- --s;
+ Base::pop_back();
}
- inline qsizetype size() const { return s; }
- inline qsizetype count() const { return s; }
- inline qsizetype length() const { return s; }
+#ifdef Q_QDOC
+ inline qsizetype size() const { return this->s; }
+ static constexpr qsizetype max_size() noexcept { return QVLABase<T>::max_size(); }
+#endif
+ using Base::size;
+ inline qsizetype count() const { return size(); }
+ inline qsizetype length() const { return size(); }
inline T &first()
{
- Q_ASSERT(!isEmpty());
- return *begin();
+ return front();
}
inline const T &first() const
{
- Q_ASSERT(!isEmpty());
- return *begin();
+ return front();
}
T &last()
{
- Q_ASSERT(!isEmpty());
- return *(end() - 1);
+ return back();
}
const T &last() const
{
- Q_ASSERT(!isEmpty());
- return *(end() - 1);
+ return back();
}
- inline bool isEmpty() const { return (s == 0); }
- inline void resize(qsizetype size);
+ bool isEmpty() const { return empty(); }
+ void resize(qsizetype sz) { Base::resize_impl(Prealloc, this->array, sz); }
+#ifndef Q_QDOC
+ template <typename U = T, if_copyable<U> = true>
+#endif
+ void resize(qsizetype sz, const T &v)
+ { Base::resize_impl(Prealloc, this->array, sz, v); }
+ using Base::clear;
+#ifdef Q_QDOC
inline void clear() { resize(0); }
- inline void squeeze();
+#endif
+ void squeeze() { reallocate(size(), size()); }
- inline qsizetype capacity() const { return a; }
- inline void reserve(qsizetype size);
+ using Base::capacity;
+#ifdef Q_QDOC
+ qsizetype capacity() const { return this->a; }
+#endif
+ void reserve(qsizetype sz) { if (sz > capacity()) reallocate(size(), sz); }
+#ifdef Q_QDOC
template <typename AT = T>
inline qsizetype indexOf(const AT &t, qsizetype from = 0) const;
template <typename AT = T>
inline qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const;
template <typename AT = T>
inline bool contains(const AT &t) const;
+#endif
+ using Base::indexOf;
+ using Base::lastIndexOf;
+ using Base::contains;
+#ifdef Q_QDOC
inline T &operator[](qsizetype idx)
{
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
+ verify(idx);
+ return data()[idx];
}
inline const T &operator[](qsizetype idx) const
{
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
+ verify(idx);
+ return data()[idx];
}
+#endif
+ using Base::operator[];
inline const T &at(qsizetype idx) const { return operator[](idx); }
+#ifdef Q_QDOC
T value(qsizetype i) const;
T value(qsizetype i, const T &defaultValue) const;
+#endif
+ using Base::value;
inline void append(const T &t)
{
- if (s == a) { // i.e. s != 0
- T copy(t);
- reallocate(s, s << 1);
- const qsizetype idx = s++;
- new (ptr + idx) T(std::move(copy));
- } else {
- const qsizetype idx = s++;
- new (ptr + idx) T(t);
- }
+ if (size() == capacity())
+ emplace_back(T(t));
+ else
+ emplace_back(t);
}
void append(T &&t)
{
- if (s == a)
- reallocate(s, s << 1);
- const qsizetype idx = s++;
- new (ptr + idx) T(std::move(t));
+ emplace_back(std::move(t));
}
- void append(const T *buf, qsizetype size);
+ void append(const T *buf, qsizetype sz)
+ { Base::append_impl(Prealloc, this->array, buf, sz); }
inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
{ append(t); return *this; }
inline QVarLengthArray<T, Prealloc> &operator<<(T &&t)
@@ -242,71 +500,109 @@ public:
inline QVarLengthArray<T, Prealloc> &operator+=(T &&t)
{ append(std::move(t)); return *this; }
+#if QT_DEPRECATED_SINCE(6, 3)
+ QT_DEPRECATED_VERSION_X_6_3("This is slow. If you must, use insert(cbegin(), ~~~) instead.")
void prepend(T &&t);
+ QT_DEPRECATED_VERSION_X_6_3("This is slow. If you must, use insert(cbegin(), ~~~) instead.")
void prepend(const T &t);
+#endif
void insert(qsizetype i, T &&t);
void insert(qsizetype i, const T &t);
void insert(qsizetype i, qsizetype n, const T &t);
+
+ QVarLengthArray &assign(qsizetype n, const T &t)
+ { Base::assign_impl(Prealloc, this->array, n, t); return *this; }
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
+ QVarLengthArray &assign(InputIterator first, InputIterator last)
+ { Base::assign_impl(Prealloc, this->array, first, last); return *this; }
+ QVarLengthArray &assign(std::initializer_list<T> list)
+ { assign(list.begin(), list.end()); return *this; }
+
+#ifdef Q_QDOC
void replace(qsizetype i, const T &t);
- void remove(qsizetype i);
- void remove(qsizetype i, qsizetype n);
+ void remove(qsizetype i, qsizetype n = 1);
template <typename AT = T>
qsizetype removeAll(const AT &t);
template <typename AT = T>
bool removeOne(const AT &t);
template <typename Predicate>
qsizetype removeIf(Predicate pred);
+#endif
+ using Base::replace;
+ using Base::remove;
+ using Base::removeAll;
+ using Base::removeOne;
+ using Base::removeIf;
- inline T *data() { return ptr; }
- inline const T *data() const { return ptr; }
- inline const T *constData() const { return ptr; }
- typedef qsizetype 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;
-
- typedef T *iterator;
- typedef const T *const_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- inline iterator begin() { return ptr; }
- inline const_iterator begin() const { return ptr; }
- inline const_iterator cbegin() const { return ptr; }
- inline const_iterator constBegin() const { return ptr; }
- inline iterator end() { return ptr + s; }
- inline const_iterator end() const { return ptr + s; }
- inline const_iterator cend() const { return ptr + s; }
- inline const_iterator constEnd() const { return ptr + s; }
+#ifdef Q_QDOC
+ inline T *data() { return this->ptr; }
+ inline const T *data() const { return this->ptr; }
+#endif
+ using Base::data;
+ inline const T *constData() const { return data(); }
+#ifdef Q_QDOC
+ inline iterator begin() { return data(); }
+ inline const_iterator begin() const { return data(); }
+ inline const_iterator cbegin() const { return begin(); }
+ inline const_iterator constBegin() const { return begin(); }
+ inline iterator end() { return data() + size(); }
+ inline const_iterator end() const { return data() + size(); }
+ inline const_iterator cend() const { return end(); }
+#endif
+
+ using Base::begin;
+ using Base::cbegin;
+ auto constBegin() const -> const_iterator { return begin(); }
+ using Base::end;
+ using Base::cend;
+ inline const_iterator constEnd() const { return end(); }
+#ifdef Q_QDOC
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
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, qsizetype n, const T &x);
+#endif
+ using Base::rbegin;
+ using Base::crbegin;
+ using Base::rend;
+ using Base::crend;
+
+ iterator insert(const_iterator before, qsizetype n, const T &x)
+ { return Base::insert_impl(Prealloc, this->array, before, n, x); }
iterator insert(const_iterator before, T &&x) { return emplace(before, std::move(x)); }
inline iterator insert(const_iterator before, const T &x) { return insert(before, 1, x); }
+#ifdef Q_QDOC
iterator erase(const_iterator begin, const_iterator end);
inline iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
+#endif
+ using Base::erase;
// STL compatibility:
+#ifdef Q_QDOC
inline bool empty() const { return isEmpty(); }
+#endif
+ using Base::empty;
inline void push_back(const T &t) { append(t); }
void push_back(T &&t) { append(std::move(t)); }
+#ifdef Q_QDOC
inline void pop_back() { removeLast(); }
inline T &front() { return first(); }
inline const T &front() const { return first(); }
inline T &back() { return last(); }
inline const T &back() const { return last(); }
+#endif
+ using Base::pop_back;
+ using Base::front;
+ using Base::back;
void shrink_to_fit() { squeeze(); }
template <typename...Args>
- iterator emplace(const_iterator pos, Args &&...args);
+ iterator emplace(const_iterator pos, Args &&...args)
+ { return Base::emplace_impl(Prealloc, this->array, pos, std::forward<Args>(args)...); }
template <typename...Args>
- T &emplace_back(Args &&...args) { return *emplace(cend(), std::forward<Args>(args)...); }
+ T &emplace_back(Args &&...args)
+ { return Base::emplace_back_impl(Prealloc, this->array, std::forward<Args>(args)...); }
#ifdef Q_QDOC
@@ -326,12 +622,7 @@ public:
template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
QTypeTraits::compare_eq_result<U> operator==(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
{
- if (l.size() != r.size())
- return false;
- const T *rb = r.begin();
- const T *b = l.begin();
- const T *e = l.end();
- return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(rb, r.size()));
+ return l.equal(r);
}
template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
@@ -345,8 +636,7 @@ public:
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());
+ return lhs.less_than(rhs);
}
template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
@@ -372,18 +662,17 @@ public:
#endif
private:
- void reallocate(qsizetype size, qsizetype alloc);
+ template <typename U, qsizetype Prealloc2>
+ bool equal(const QVarLengthArray<U, Prealloc2> &other) const
+ { return Base::equal(other); }
+ template <typename U, qsizetype Prealloc2>
+ bool less_than(const QVarLengthArray<U, Prealloc2> &other) const
+ { return Base::less_than(other); }
- qsizetype a; // capacity
- qsizetype s; // size
- T *ptr; // data
- std::aligned_storage_t<sizeof(T), alignof(T)> array[Prealloc];
+ void reallocate(qsizetype sz, qsizetype alloc)
+ { Base::reallocate_impl(Prealloc, this->array, sz, alloc); }
- bool isValidIterator(const const_iterator &i) const
- {
- const std::less<const T *> less = {};
- return !less(cend(), i) && !less(i, cbegin());
- }
+ using Base::isValidIterator;
};
template <typename InputIterator,
@@ -393,59 +682,51 @@ QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray<ValueType>;
template <class T, qsizetype Prealloc>
Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype asize)
- : s(asize) {
- static_assert(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.");
- if (s > Prealloc) {
- ptr = reinterpret_cast<T *>(malloc(s * sizeof(T)));
- Q_CHECK_PTR(ptr);
- a = s;
- } else {
- ptr = reinterpret_cast<T *>(array);
- a = Prealloc;
- }
- if (QTypeInfo<T>::isComplex) {
- T *i = ptr + s;
- while (i != ptr)
- new (--i) T;
- }
-}
+ : QVarLengthArray()
+{
+ Q_ASSERT_X(asize >= 0, "QVarLengthArray::QVarLengthArray(qsizetype)",
+ "Size must be greater than or equal to 0.");
-template <class T, qsizetype Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(qsizetype asize)
-{ reallocate(asize, qMax(asize, a)); }
+ // historically, this ctor worked for non-copyable/non-movable T, so keep it working, why not?
+ // resize(asize) // this requires a movable or copyable T, can't use, need to do it by hand
-template <class T, qsizetype Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(qsizetype asize)
-{ if (asize > a) reallocate(s, asize); }
+ if (asize > Prealloc) {
+ this->ptr = malloc(asize * sizeof(T));
+ Q_CHECK_PTR(this->ptr);
+ this->a = asize;
+ }
+ if constexpr (QTypeInfo<T>::isComplex)
+ std::uninitialized_default_construct_n(data(), asize);
+ this->s = asize;
+}
-template <class T, qsizetype Prealloc>
+template <class T>
template <typename AT>
-Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::indexOf(const AT &t, qsizetype from) const
+Q_INLINE_TEMPLATE qsizetype QVLABase<T>::indexOf(const AT &t, qsizetype from) const
{
if (from < 0)
- from = qMax(from + s, qsizetype(0));
- if (from < s) {
- T *n = ptr + from - 1;
- T *e = ptr + s;
+ from = qMax(from + size(), qsizetype(0));
+ if (from < size()) {
+ const T *n = data() + from - 1;
+ const T *e = end();
while (++n != e)
if (*n == t)
- return n - ptr;
+ return n - data();
}
return -1;
}
-template <class T, qsizetype Prealloc>
+template <class T>
template <typename AT>
-Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const AT &t, qsizetype from) const
+Q_INLINE_TEMPLATE qsizetype QVLABase<T>::lastIndexOf(const AT &t, qsizetype from) const
{
if (from < 0)
- from += s;
- else if (from >= s)
- from = s - 1;
+ from += size();
+ else if (from >= size())
+ from = size() - 1;
if (from >= 0) {
- T *b = ptr;
- T *n = ptr + from + 1;
+ const T *b = begin();
+ const T *n = b + from + 1;
while (n != b) {
if (*--n == t)
return n - b;
@@ -454,12 +735,12 @@ Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const AT &
return -1;
}
-template <class T, qsizetype Prealloc>
+template <class T>
template <typename AT>
-Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const AT &t) const
+Q_INLINE_TEMPLATE bool QVLABase<T>::contains(const AT &t) const
{
- T *b = ptr;
- T *i = ptr + s;
+ const T *b = begin();
+ const T *i = end();
while (i != b) {
if (*--i == t)
return true;
@@ -467,72 +748,112 @@ Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const AT &t) const
return false;
}
-template <class T, qsizetype Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, qsizetype increment)
+template <class T>
+Q_OUTOFLINE_TEMPLATE void QVLABase<T>::append_impl(qsizetype prealloc, void *array, const T *abuf, qsizetype increment)
{
- Q_ASSERT(abuf);
+ Q_ASSERT(abuf || increment == 0);
if (increment <= 0)
return;
- const qsizetype asize = s + increment;
+ const qsizetype asize = size() + increment;
- if (asize >= a)
- reallocate(s, qMax(s * 2, asize));
+ if (asize >= capacity())
+ growBy(prealloc, array, increment);
if constexpr (QTypeInfo<T>::isComplex)
- std::uninitialized_copy_n(abuf, increment, ptr + s);
+ std::uninitialized_copy_n(abuf, increment, end());
else
- memcpy(static_cast<void *>(&ptr[s]), static_cast<const void *>(abuf), increment * sizeof(T));
+ memcpy(static_cast<void *>(end()), static_cast<const void *>(abuf), increment * sizeof(T));
- s = asize;
+ this->s = asize;
}
-template <class T, qsizetype Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::squeeze()
-{ reallocate(s, s); }
+template <class T>
+Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, qsizetype n, const T &t)
+{
+ Q_ASSERT(n >= 0);
+ if (n > capacity()) {
+ reallocate_impl(prealloc, array, 0, capacity()); // clear
+ resize_impl(prealloc, array, n, t);
+ } else {
+ auto mid = (std::min)(n, size());
+ std::fill(data(), data() + mid, t);
+ std::uninitialized_fill(data() + mid, data() + n, t);
+ s = n;
+ erase(data() + n, data() + size());
+ }
+}
-template <class T, qsizetype Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reallocate(qsizetype asize, qsizetype aalloc)
+template <class T>
+template <typename Iterator>
+Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *array, Iterator first, Iterator last)
+{
+ // This function only provides the basic exception guarantee.
+ constexpr bool IsFwdIt =
+ std::is_convertible_v<typename std::iterator_traits<Iterator>::iterator_category,
+ std::forward_iterator_tag>;
+ if constexpr (IsFwdIt) {
+ const qsizetype n = std::distance(first, last);
+ if (n > capacity())
+ reallocate_impl(prealloc, array, 0, n); // clear & reserve n
+ }
+
+ auto dst = begin();
+ const auto dend = end();
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else {
+ do {
+ emplace_back_impl(prealloc, array, *first);
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = *first; // overwrite existing element
+ ++dst;
+ ++first;
+ }
+ this->s = dst - begin();
+}
+
+template <class T>
+Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void *array, qsizetype asize, qsizetype aalloc)
{
Q_ASSERT(aalloc >= asize);
- Q_ASSERT(ptr);
- T *oldPtr = ptr;
- qsizetype osize = s;
+ Q_ASSERT(data());
+ T *oldPtr = data();
+ qsizetype osize = size();
const qsizetype copySize = qMin(asize, osize);
- Q_ASSUME(copySize >= 0);
- if (aalloc != a) {
- if (aalloc > Prealloc) {
- T *newPtr = reinterpret_cast<T *>(malloc(aalloc * sizeof(T)));
+ Q_ASSERT(copySize >= 0);
+
+ if (aalloc != capacity()) {
+ QVLABaseBase::malloced_ptr guard;
+ void *newPtr;
+ qsizetype newA;
+ if (aalloc > prealloc) {
+ newPtr = malloc(aalloc * sizeof(T));
+ guard.reset(newPtr);
Q_CHECK_PTR(newPtr); // could throw
// by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here
- ptr = newPtr;
- a = aalloc;
+ newA = aalloc;
} else {
- ptr = reinterpret_cast<T *>(array);
- a = Prealloc;
- }
- s = 0;
- if (!QTypeInfo<T>::isRelocatable) {
- QT_TRY {
- // move all the old elements
- while (s < copySize) {
- new (ptr+s) T(std::move(*(oldPtr+s)));
- (oldPtr+s)->~T();
- s++;
- }
- } QT_CATCH(...) {
- // clean up all the old objects and then free the old ptr
- qsizetype sClean = s;
- while (sClean < osize)
- (oldPtr+(sClean++))->~T();
- if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
- free(oldPtr);
- QT_RETHROW;
- }
- } else {
- memcpy(static_cast<void *>(ptr), static_cast<const void *>(oldPtr), copySize * sizeof(T));
+ newPtr = array;
+ newA = prealloc;
}
+ QtPrivate::q_uninitialized_relocate_n(oldPtr, copySize,
+ reinterpret_cast<T *>(newPtr));
+ // commit:
+ ptr = newPtr;
+ guard.release();
+ a = newA;
}
s = copySize;
@@ -542,155 +863,119 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reallocate(qsizetype asi
std::destroy(oldPtr + asize, oldPtr + osize);
}
- if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
+ if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != data())
free(oldPtr);
-
- if (QTypeInfo<T>::isComplex) {
- // call default constructor for new objects (which can throw)
- while (s < asize)
- new (ptr+(s++)) T;
- } else {
- s = asize;
- }
}
-template <class T, qsizetype Prealloc>
-Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(qsizetype i) const
+template <class T>
+Q_OUTOFLINE_TEMPLATE T QVLABase<T>::value(qsizetype i) const
{
if (size_t(i) >= size_t(size()))
return T();
- return at(i);
+ return operator[](i);
}
-template <class T, qsizetype Prealloc>
-Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(qsizetype i, const T &defaultValue) const
+template <class T>
+Q_OUTOFLINE_TEMPLATE T QVLABase<T>::value(qsizetype i, const T &defaultValue) const
{
- return (size_t(i) >= size_t(size())) ? defaultValue : at(i);
+ return (size_t(i) >= size_t(size())) ? defaultValue : operator[](i);
}
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");
+{ verify(i, 0);
insert(cbegin() + i, std::move(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");
+{ verify(i, 0);
insert(begin() + i, 1, 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");
+{ verify(i, 0);
insert(begin() + i, n, t); }
-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");
+template <class T>
+inline void QVLABase<T>::remove(qsizetype i, qsizetype n)
+{ verify(i, n);
erase(begin() + i, begin() + i + n); }
-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, qsizetype Prealloc>
+template <class T>
template <typename AT>
-inline qsizetype QVarLengthArray<T, Prealloc>::removeAll(const AT &t)
+inline qsizetype QVLABase<T>::removeAll(const AT &t)
{ return QtPrivate::sequential_erase_with_copy(*this, t); }
-template <class T, qsizetype Prealloc>
+template <class T>
template <typename AT>
-inline bool QVarLengthArray<T, Prealloc>::removeOne(const AT &t)
+inline bool QVLABase<T>::removeOne(const AT &t)
{ return QtPrivate::sequential_erase_one(*this, t); }
-template <class T, qsizetype Prealloc>
+template <class T>
template <typename Predicate>
-inline qsizetype QVarLengthArray<T, Prealloc>::removeIf(Predicate pred)
+inline qsizetype QVLABase<T>::removeIf(Predicate pred)
{ return QtPrivate::sequential_erase_if(*this, pred); }
+#if QT_DEPRECATED_SINCE(6, 3)
template <class T, qsizetype Prealloc>
inline void QVarLengthArray<T, Prealloc>::prepend(T &&t)
{ insert(cbegin(), std::move(t)); }
template <class T, qsizetype Prealloc>
inline void QVarLengthArray<T, Prealloc>::prepend(const T &t)
{ insert(begin(), 1, t); }
+#endif
-template <class T, qsizetype Prealloc>
-inline void QVarLengthArray<T, Prealloc>::replace(qsizetype i, const T &t)
+template <class T>
+inline void QVLABase<T>::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;
+ verify(i);
+ data()[i] = t;
}
-template <class T, qsizetype Prealloc>
+template <class T>
template <typename...Args>
-Q_OUTOFLINE_TEMPLATE auto QVarLengthArray<T, Prealloc>::emplace(const_iterator before, Args &&...args) -> iterator
+Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::emplace_impl(qsizetype prealloc, void *array, const_iterator before, Args &&...args) -> iterator
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
-
- qsizetype offset = qsizetype(before - ptr);
- reserve(s + 1);
- if (!QTypeInfo<T>::isRelocatable) {
- T *b = ptr + offset;
- T *i = ptr + s;
- T *j = i + 1;
- // 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 = T(std::forward<Args>(args)...);
- } else {
- new (b) T(std::forward<Args>(args)...);
- }
- } else {
- T *b = ptr + offset;
- memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (s - offset) * sizeof(T));
- new (b) T(std::forward<Args>(args)...);
- }
- s += 1;
- return ptr + offset;
+ Q_ASSERT(size() <= capacity());
+ Q_ASSERT(capacity() > 0);
+
+ const qsizetype offset = qsizetype(before - cbegin());
+ emplace_back_impl(prealloc, array, std::forward<Args>(args)...);
+ const auto b = begin() + offset;
+ const auto e = end();
+ QtPrivate::q_rotate(b, e - 1, e);
+ return b;
}
-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)
+template <class T>
+Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::insert_impl(qsizetype prealloc, void *array, const_iterator before, qsizetype n, const T &t) -> iterator
{
Q_ASSERT_X(isValidIterator(before), "QVarLengthArray::insert", "The specified const_iterator argument 'before' is invalid");
- qsizetype offset = qsizetype(before - ptr);
- if (n != 0) {
- const T copy(t); // `t` could alias an element in [begin(), end()[
- resize(s + n);
- if (!QTypeInfo<T>::isRelocatable) {
- T *b = ptr + offset;
- T *j = ptr + s;
- T *i = j - n;
- while (i != b)
- *--j = *--i;
- i = b + n;
- while (i != b)
- *--i = copy;
- } else {
- T *b = ptr + offset;
- T *i = b + n;
- memmove(static_cast<void *>(i), static_cast<const void *>(b), (s - offset - n) * sizeof(T));
- while (i != b)
- new (--i) T(copy);
- }
- }
- return ptr + offset;
+ const qsizetype offset = qsizetype(before - cbegin());
+ resize_impl(prealloc, array, size() + n, t);
+ const auto b = begin() + offset;
+ const auto e = end();
+ QtPrivate::q_rotate(b, e - n, e);
+ return b;
}
-template <class T, qsizetype Prealloc>
-Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator abegin, const_iterator aend)
+template <class T>
+Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::erase(const_iterator abegin, const_iterator aend) -> iterator
{
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");
- qsizetype f = qsizetype(abegin - ptr);
- qsizetype l = qsizetype(aend - ptr);
+ qsizetype f = qsizetype(abegin - cbegin());
+ qsizetype l = qsizetype(aend - cbegin());
qsizetype n = l - f;
+ if (n == 0) // avoid UB in std::move() below
+ return data() + f;
+
+ Q_ASSERT(n > 0); // aend must be reachable from abegin
+
if constexpr (QTypeInfo<T>::isComplex) {
- std::move(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f));
- std::destroy(ptr + s - n, ptr + s);
+ std::move(begin() + l, end(), QT_MAKE_CHECKED_ARRAY_ITERATOR(begin() + f, size() - f));
+ std::destroy(end() - n, end());
} else {
- memmove(static_cast<void *>(ptr + f), static_cast<const void *>(ptr + l), (s - l) * sizeof(T));
+ memmove(static_cast<void *>(data() + f), static_cast<const void *>(data() + l), (size() - l) * sizeof(T));
}
- s -= n;
- return ptr + f;
+ this->s -= n;
+ return data() + f;
}
#ifdef Q_QDOC
@@ -717,21 +1002,21 @@ bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T,
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)))
+ noexcept(QtPrivate::QNothrowHashable_v<T>)
{
- return qHashRange(key.cbegin(), key.cend(), seed);
+ return key.hash(seed);
}
template <typename T, qsizetype Prealloc, typename AT>
qsizetype erase(QVarLengthArray<T, Prealloc> &array, const AT &t)
{
- return QtPrivate::sequential_erase(array, t);
+ return array.removeAll(t);
}
template <typename T, qsizetype Prealloc, typename Predicate>
qsizetype erase_if(QVarLengthArray<T, Prealloc> &array, Predicate pred)
{
- return QtPrivate::sequential_erase_if(array, pred);
+ return array.removeIf(pred);
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 0ba939ab60..4467e0c65a 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QVarLengthArray
@@ -105,21 +81,34 @@
\l{default-constructed value}.
*/
+/*!
+ \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype size, const T &v)
+ \since 6.4
+
+ Constructs an array with an initial size of \a size elements filled with
+ copies of \a v.
+
+ \note This constructor is only available when \c T is copy-constructible.
+
+ \sa size(), squeeze()
+*/
+
/*! \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.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
-/*! \fn template<class T, qsizetype Prealloc> template<typename InputIterator> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
+/*! \fn template<class T, qsizetype Prealloc> template<typename InputIterator, QVarLengthArray<T, Prealloc>::if_input_iterator<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).
+ This constructor only participates in overload resolution if
+ \c InputIterator meets the requirements of an
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
The value type of \c InputIterator must be convertible to \c T.
*/
@@ -151,6 +140,15 @@
\sa isEmpty(), resize()
*/
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the array can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::first()
Returns a reference to the first item in the array. The array must
@@ -245,6 +243,19 @@
\sa size(), squeeze()
*/
+/*!
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::resize(qsizetype size, const T &v)
+ \since 6.4
+
+ Sets the size of the array to \a size. If \a size is greater than
+ the current size, copies of \a v are added to the end. If \a size is
+ less than the current size, elements are removed from the end.
+
+ \note This function is only available when \c T is copy-constructible.
+
+ \sa size(), squeeze()
+*/
+
/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::capacity() const
Returns the maximum number of elements that can be stored in the
@@ -419,9 +430,6 @@
\since 5.5
Assigns the values of \a list to this array, and returns a reference to this array.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
@@ -463,6 +471,15 @@
\a defaultValue.
*/
+/*
+ \var QVarLengthArray::PreallocatedSize
+ \since 6.8
+
+ The same value as the \c{Prealloc} template argument. Provided for easier
+ access compared to manually extracting the value from the template
+ argument.
+*/
+
/*!
\typedef QVarLengthArray::size_type
\since 4.7
@@ -545,6 +562,8 @@
\fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::prepend(T &&value)
\since 4.8
+ \deprecated [6.3] This is slow. If you must, use \c{insert(cbegin(), ~~~)} instead.
+
Inserts \a value at the beginning of the array.
@@ -569,16 +588,6 @@
\sa operator[](), remove()
*/
-/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::remove(qsizetype i)
-
- \overload
- \since 4.8
-
- Removes the element at index position \a i.
-
- \sa insert(), replace()
-*/
-
/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::remove(qsizetype i, qsizetype count)
\overload
@@ -999,3 +1008,40 @@
\sa erase()
*/
+
+/*! \fn template <class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>& QVarLengthArray<T, Prealloc>::assign(qsizetype n, const T &t)
+ \since 6.6
+
+ Replaces the contents of this container with \a n copies of \a t.
+
+ The size of this container will be equal to \a n. This function will only
+ allocate memory if \a n exceeds the capacity of the container.
+*/
+
+/*! \fn template <class T, qsizetype Prealloc> template <typename InputIterator, QVarLengthArray<T, Prealloc>::if_input_iterator<InputIterator>> QVarLengthArray<T, Prealloc>& QVarLengthArray<T, Prealloc>::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this container with a copy of the elements in the
+ iterator range [\a first, \a last).
+
+ The size of this container will be equal to the number of elements in the
+ range [\a first, \a last). This function will only allocate memory if the
+ number of elements in the range exceeds the capacity of the container.
+
+ This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of an
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
+ The behavior is undefined if either argument is an iterator into *this.
+*/
+
+/*! \fn template <class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>& QVarLengthArray<T, Prealloc>::assign(std::initializer_list<T> list)
+ \since 6.6
+
+ Replaces the contents of this container with a copy of the elements of \a list.
+
+ The size of this container will be equal to the number of elements in \a list.
+
+ This function only allocates memory if the number of elements in \a list
+ exceeds the capacity of the container.
+*/
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 8d880407dd..4fad2bce8f 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVECTOR_H
#define QVECTOR_H
@@ -43,6 +7,12 @@
#include <QtCore/qlist.h>
#include <QtCore/qcontainerfwd.h>
+#if 0
+#pragma qt_class(QVector)
+#pragma qt_class(QMutableVectorIterator)
+#pragma qt_class(QVectorIterator)
+#endif
+
QT_BEGIN_NAMESPACE
#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index da093a417d..4b8ace71cc 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qversionnumber.h>
#include <QtCore/qhash.h>
@@ -57,6 +21,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QVersionNumber)
+
/*!
\class QVersionNumber
\inmodule QtCore
@@ -105,18 +71,23 @@ QT_BEGIN_NAMESPACE
\fn QVersionNumber::QVersionNumber(QList<int> &&seg)
Move-constructs a version number from the list of numbers contained in \a seg.
-
- This constructor is only enabled if the compiler supports C++11 move semantics.
*/
/*!
\fn QVersionNumber::QVersionNumber(std::initializer_list<int> args)
- Construct a version number from the std::initializer_list specified by
+ Constructs a version number from the std::initializer_list specified by
\a args.
+*/
+
+/*!
+ \fn QVersionNumber::QVersionNumber(QSpan<const int> args)
+ \since 6.8
+
+ Constructs a version number from the span specified by \a args.
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
+ \note In Qt versions prior to 6.8, QVersionNumber could only be constructed
+ from QList, QVarLenthArray or std::initializer_list.
*/
/*!
@@ -168,7 +139,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QList<int>& QVersionNumber::segments() const
+ \fn QList<int> QVersionNumber::segments() const
Returns all of the numerical segments.
@@ -181,13 +152,13 @@ QList<int> QVersionNumber::segments() const
QList<int> result;
result.resize(segmentCount());
- for (int i = 0; i < segmentCount(); ++i)
+ for (qsizetype i = 0; i < segmentCount(); ++i)
result[i] = segmentAt(i);
return result;
}
/*!
- \fn int QVersionNumber::segmentAt(int index) const
+ \fn int QVersionNumber::segmentAt(qsizetype index) const
Returns the segment value at \a index. If the index does not exist,
returns 0.
@@ -196,7 +167,7 @@ QList<int> QVersionNumber::segments() const
*/
/*!
- \fn int QVersionNumber::segmentCount() const
+ \fn qsizetype QVersionNumber::segmentCount() const
Returns the number of integers stored in segments().
@@ -204,6 +175,55 @@ QList<int> QVersionNumber::segments() const
*/
/*!
+ \typedef QVersionNumber::const_iterator
+ \typedef QVersionNumber::const_reverse_iterator
+ \since 6.8
+
+ Typedefs for an opaque class that implements a (reverse) random-access
+ iterator over QVersionNumber segments.
+
+ \note QVersionNumber does not support modifying segments in-place, so
+ there is no mutable iterator.
+*/
+
+/*!
+ \typedef QVersionNumber::value_type
+ \typedef QVersionNumber::difference_type
+ \typedef QVersionNumber::size_type
+ \typedef QVersionNumber::reference
+ \typedef QVersionNumber::const_reference
+ \typedef QVersionNumber::pointer
+ \typedef QVersionNumber::const_pointer
+ \since 6.8
+
+ Provided for STL-compatibility.
+
+ \note QVersionNumber does not support modifying segments in-place, so
+ reference and const_reference, as well as pointer and const_pointer are
+ pairwise the same types.
+*/
+
+/*!
+ \fn QVersionNumber::begin() const
+ \fn QVersionNumber::end() const;
+ \fn QVersionNumber::rbegin() const
+ \fn QVersionNumber::rend() const;
+ \fn QVersionNumber::cbegin() const
+ \fn QVersionNumber::cend() const;
+ \fn QVersionNumber::crbegin() const
+ \fn QVersionNumber::crend() const;
+ \fn QVersionNumber::constBegin() const;
+ \fn QVersionNumber::constEnd() const;
+ \since 6.8
+
+ Returns a const_iterator or const_reverse_iterator, respectively, pointing
+ to the first or one past the last segment of this version number.
+
+ \note QVersionNumber does not support modifying segments in-place, so
+ there is no mutable iterator.
+*/
+
+/*!
\fn QVersionNumber QVersionNumber::normalized() const
Returns an equivalent version number but with all trailing zeros removed.
@@ -215,7 +235,7 @@ QList<int> QVersionNumber::segments() const
*/
QVersionNumber QVersionNumber::normalized() const
{
- int i;
+ qsizetype i;
for (i = m_segments.size(); i; --i)
if (m_segments.at(i - 1) != 0)
break;
@@ -239,7 +259,7 @@ bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const noexcept
{
if (segmentCount() > other.segmentCount())
return false;
- for (int i = 0; i < segmentCount(); ++i) {
+ for (qsizetype i = 0; i < segmentCount(); ++i) {
if (segmentAt(i) != other.segmentAt(i))
return false;
}
@@ -261,7 +281,7 @@ bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const noexcept
*/
int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept
{
- int commonlen;
+ qsizetype commonlen;
if (Q_LIKELY(!v1.m_segments.isUsingPointer() && !v2.m_segments.isUsingPointer())) {
// we can't use memcmp because it interprets the data as unsigned bytes
@@ -269,12 +289,12 @@ int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2)
const qint8 *ptr2 = v2.m_segments.inline_segments + InlineSegmentStartIdx;
commonlen = qMin(v1.m_segments.size(),
v2.m_segments.size());
- for (int i = 0; i < commonlen; ++i)
+ for (qsizetype i = 0; i < commonlen; ++i)
if (int x = ptr1[i] - ptr2[i])
return x;
} else {
commonlen = qMin(v1.segmentCount(), v2.segmentCount());
- for (int i = 0; i < commonlen; ++i) {
+ for (qsizetype i = 0; i < commonlen; ++i) {
if (v1.segmentAt(i) != v2.segmentAt(i))
return v1.segmentAt(i) - v2.segmentAt(i);
}
@@ -311,8 +331,8 @@ int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2)
QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
const QVersionNumber &v2)
{
- int commonlen = qMin(v1.segmentCount(), v2.segmentCount());
- int i;
+ qsizetype commonlen = qMin(v1.segmentCount(), v2.segmentCount());
+ qsizetype i;
for (i = 0; i < commonlen; ++i) {
if (v1.segmentAt(i) != v2.segmentAt(i))
break;
@@ -391,17 +411,19 @@ QString QVersionNumber::toString() const
QString version;
version.reserve(qMax(segmentCount() * 2 - 1, 0));
bool first = true;
- for (int i = 0; i < segmentCount(); ++i) {
+ for (qsizetype i = 0; i < segmentCount(); ++i) {
if (!first)
- version += QLatin1Char('.');
+ version += u'.';
version += QString::number(segmentAt(i));
first = false;
}
return version;
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
+ \fn QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex)
+ \since 6.4
+
Constructs a QVersionNumber from a specially formatted \a string of
non-negative decimal numbers delimited by a period (\c{.}).
@@ -409,74 +431,86 @@ QString QVersionNumber::toString() const
is considered to be the suffix string. The start index of that string will be
stored in \a suffixIndex if it is not null.
- \snippet qversionnumber/main.cpp 3
+ \snippet qversionnumber/main.cpp 3-latin1-1
+
+ \note In versions prior to Qt 6.4, this function was overloaded for QString,
+ QLatin1StringView and QStringView instead, and \a suffixIndex was an \c{int*}.
\sa isNull()
*/
-QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixIndex)
+
+static QVersionNumber from_string(QLatin1StringView string, qsizetype *suffixIndex)
{
- return fromString(QLatin1String(string.toLatin1()), suffixIndex);
-}
-#endif
+ // 32 should be more than enough, and, crucially, it means we're allocating
+ // not more (and often less) often when compared with direct QList usage
+ // for all possible segment counts (under the constraint that we don't want
+ // to keep more capacity around for the lifetime of the resulting
+ // QVersionNumber than required), esp. in the common case where the inline
+ // storage can be used.
+ QVarLengthArray<int, 32> seg;
-/*!
- \since 5.10
- \overload
+ const char *start = string.begin();
+ const char *lastGoodEnd = start;
+ const char *endOfString = string.end();
- Constructs a QVersionNumber from a specially formatted \a string of
- non-negative decimal numbers delimited by '.'.
+ do {
+ // parsing as unsigned so a minus sign is rejected
+ auto [value, used] = qstrntoull(start, endOfString - start, 10);
+ if (used <= 0 || value > qulonglong(std::numeric_limits<int>::max()))
+ break;
+ seg.append(int(value));
+ start += used + 1;
+ lastGoodEnd = start - 1;
+ } while (start < endOfString && *lastGoodEnd == '.');
- Once the numerical segments have been parsed, the remainder of the string
- is considered to be the suffix string. The start index of that string will be
- stored in \a suffixIndex if it is not null.
+ if (suffixIndex)
+ *suffixIndex = lastGoodEnd - string.begin();
- \snippet qversionnumber/main.cpp 3
+ return QVersionNumber(seg);
+}
- \sa isNull()
-*/
-QVersionNumber QVersionNumber::fromString(QStringView string, int *suffixIndex)
+static QVersionNumber from_string(q_no_char8_t::QUtf8StringView string, qsizetype *suffixIndex)
{
- return fromString(QLatin1String(string.toLatin1()), suffixIndex);
+ return from_string(QLatin1StringView(string.data(), string.size()), suffixIndex);
}
-/*!
- \since 5.10
- \overload
-
- Constructs a QVersionNumber from a specially formatted \a string of
- non-negative decimal numbers delimited by '.'.
-
- Once the numerical segments have been parsed, the remainder of the string
- is considered to be the suffix string. The start index of that string will be
- stored in \a suffixIndex if it is not null.
+// in qstring.cpp
+extern void qt_to_latin1(uchar *dst, const char16_t *uc, qsizetype len);
- \snippet qversionnumber/main.cpp 3-latin1-1
+static QVersionNumber from_string(QStringView string, qsizetype *suffixIndex)
+{
+ QVarLengthArray<char> copy;
+ copy.resize(string.size());
+ qt_to_latin1(reinterpret_cast<uchar*>(copy.data()), string.utf16(), string.size());
+ return from_string(QLatin1StringView(copy.data(), copy.size()), suffixIndex);
+}
- \sa isNull()
-*/
-QVersionNumber QVersionNumber::fromString(QLatin1String string, int *suffixIndex)
+QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex)
{
- QList<int> seg;
+ return string.visit([=] (auto string) { return from_string(string, suffixIndex); });
+}
- const char *start = string.begin();
- const char *end = start;
- const char *lastGoodEnd = start;
- const char *endOfString = string.end();
+void QVersionNumber::SegmentStorage::setListData(const QList<int> &seg)
+{
+ pointer_segments = new QList<int>(seg);
+}
- do {
- bool ok = false;
- const qulonglong value = qstrntoull(start, endOfString - start, &end, 10, &ok);
- if (!ok || value > qulonglong(std::numeric_limits<int>::max()))
- break;
- seg.append(int(value));
- start = end + 1;
- lastGoodEnd = end;
- } while (start < endOfString && (end < endOfString && *end == '.'));
+void QVersionNumber::SegmentStorage::setListData(QList<int> &&seg)
+{
+ pointer_segments = new QList<int>(std::move(seg));
+}
- if (suffixIndex)
- *suffixIndex = int(lastGoodEnd - string.begin());
+void QVersionNumber::SegmentStorage::setListData(const int *first, const int *last)
+{
+ pointer_segments = new QList<int>(first, last);
+}
- return QVersionNumber(std::move(seg));
+void QVersionNumber::SegmentStorage::resize(qsizetype len)
+{
+ if (isUsingPointer())
+ pointer_segments->resize(len);
+ else
+ setInlineSize(len);
}
void QVersionNumber::SegmentStorage::setVector(int len, int maj, int min, int mic)
@@ -529,13 +563,13 @@ QDataStream& operator>>(QDataStream &in, QVersionNumber &version)
QDebug operator<<(QDebug debug, const QVersionNumber &version)
{
QDebugStateSaver saver(debug);
- debug.noquote() << version.toString();
+ debug.nospace().noquote();
+ debug << "QVersionNumber(" << version.toString() << ")";
return debug;
}
#endif
/*!
- \fn size_t qHash(const QVersionNumber &key, size_t seed)
\relates QHash
\since 5.6
@@ -550,199 +584,4 @@ size_t qHash(const QVersionNumber &key, size_t seed)
return seed;
}
-/*!
- \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. The valid range for \a segment is \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 65f0952cd9..95217a6eff 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -1,53 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2015 Keith Gardner <kreios4004@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVERSIONNUMBER_H
#define QVERSIONNUMBER_H
+#include <QtCore/qcontainertools_impl.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qspan.h>
#include <QtCore/qstring.h>
#include <QtCore/qtypeinfo.h>
-#include <limits>
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 2
+#include <QtCore/qtyperevision.h>
+#endif // lean headers level 2
QT_BEGIN_NAMESPACE
@@ -96,13 +64,15 @@ class QVersionNumber
if (dataFitsInline(seg.data(), seg.size()))
setInlineData(seg.data(), seg.size());
else
- pointer_segments = new QList<int>(seg);
+ setListData(seg);
}
+ Q_CORE_EXPORT void setListData(const QList<int> &seg);
+
SegmentStorage(const SegmentStorage &other)
{
if (other.isUsingPointer())
- pointer_segments = new QList<int>(*other.pointer_segments);
+ setListData(*other.pointer_segments);
else
dummy = other.dummy;
}
@@ -112,7 +82,7 @@ class QVersionNumber
if (isUsingPointer() && other.isUsingPointer()) {
*pointer_segments = *other.pointer_segments;
} else if (other.isUsingPointer()) {
- pointer_segments = new QList<int>(*other.pointer_segments);
+ setListData(*other.pointer_segments);
} else {
if (isUsingPointer())
delete pointer_segments;
@@ -131,45 +101,50 @@ class QVersionNumber
void swap(SegmentStorage &other) noexcept
{
- qSwap(dummy, other.dummy);
+ std::swap(dummy, other.dummy);
}
explicit SegmentStorage(QList<int> &&seg)
{
- if (dataFitsInline(seg.data(), seg.size()))
- setInlineData(seg.data(), seg.size());
+ if (dataFitsInline(std::as_const(seg).data(), seg.size()))
+ setInlineData(std::as_const(seg).data(), seg.size());
else
- pointer_segments = new QList<int>(std::move(seg));
+ setListData(std::move(seg));
}
- SegmentStorage(std::initializer_list<int> args)
+
+ Q_CORE_EXPORT void setListData(QList<int> &&seg);
+
+ explicit SegmentStorage(QSpan<const int> args)
+ : SegmentStorage(args.begin(), args.end()) {}
+
+ explicit SegmentStorage(const int *first, const int *last)
{
- if (dataFitsInline(std::data(args), int(args.size()))) {
- setInlineData(std::data(args), int(args.size()));
+ if (dataFitsInline(first, last - first)) {
+ setInlineData(first, last - first);
} else {
- pointer_segments = new QList<int>(args);
+ setListData(first, last);
}
}
+ Q_CORE_EXPORT void setListData(const int *first, const int *last);
+
~SegmentStorage() { if (isUsingPointer()) delete pointer_segments; }
bool isUsingPointer() const noexcept
{ return (inline_segments[InlineSegmentMarker] & 1) == 0; }
- int size() const noexcept
+ qsizetype size() const noexcept
{ return isUsingPointer() ? pointer_segments->size() : (inline_segments[InlineSegmentMarker] >> 1); }
- void setInlineSize(int len)
- { inline_segments[InlineSegmentMarker] = qint8(1 + 2 * len); }
-
- void resize(int len)
+ void setInlineSize(qsizetype len)
{
- if (isUsingPointer())
- pointer_segments->resize(len);
- else
- setInlineSize(len);
+ Q_ASSERT(len <= InlineSegmentCount);
+ inline_segments[InlineSegmentMarker] = qint8(1 + 2 * len);
}
- int at(int index) const
+ Q_CORE_EXPORT void resize(qsizetype len);
+
+ int at(qsizetype index) const
{
return isUsingPointer() ?
pointer_segments->at(index) :
@@ -187,28 +162,29 @@ class QVersionNumber
}
private:
- static bool dataFitsInline(const int *data, int len)
+ static bool dataFitsInline(const int *data, qsizetype len)
{
if (len > InlineSegmentCount)
return false;
- for (int i = 0; i < len; ++i)
+ for (qsizetype i = 0; i < len; ++i)
if (data[i] != qint8(data[i]))
return false;
return true;
}
- void setInlineData(const int *data, int len)
+ void setInlineData(const int *data, qsizetype len)
{
+ Q_ASSERT(len <= InlineSegmentCount);
dummy = 1 + len * 2;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- for (int i = 0; i < len; ++i)
+ for (qsizetype i = 0; i < len; ++i)
dummy |= quintptr(data[i] & 0xFF) << (8 * (i + 1));
#elif Q_BYTE_ORDER == Q_BIG_ENDIAN
- for (int i = 0; i < len; ++i)
+ for (qsizetype i = 0; i < len; ++i)
dummy |= quintptr(data[i] & 0xFF) << (8 * (sizeof(void *) - i - 1));
#else
// the code above is equivalent to:
setInlineSize(len);
- for (int i = 0; i < len; ++i)
+ for (qsizetype i = 0; i < len; ++i)
inline_segments[InlineSegmentStartIdx + i] = data[i] & 0xFF;
#endif
}
@@ -216,17 +192,84 @@ class QVersionNumber
Q_CORE_EXPORT void setVector(int len, int maj, int min, int mic);
} m_segments;
+ class It
+ {
+ const QVersionNumber *v;
+ qsizetype i;
+
+ friend class QVersionNumber;
+ explicit constexpr It(const QVersionNumber *vn, qsizetype idx) noexcept : v(vn), i(idx) {}
+
+ friend constexpr bool comparesEqual(const It &lhs, const It &rhs)
+ { Q_ASSERT(lhs.v == rhs.v); return lhs.i == rhs.i; }
+ friend constexpr Qt::strong_ordering compareThreeWay(const It &lhs, const It &rhs)
+ { Q_ASSERT(lhs.v == rhs.v); return Qt::compareThreeWay(lhs.i, rhs.i); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(It)
+
+ public:
+ // Rule Of Zero applies
+ It() = default;
+
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = int;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using element_type = const int;
+#endif
+ using difference_type = qptrdiff; // difference to container requirements
+ using size_type = qsizetype; // difference to container requirements
+ using reference = value_type; // difference to container requirements
+ using pointer = QtPrivate::ArrowProxy<reference>;
+
+ reference operator*() const { return v->segmentAt(i); }
+ pointer operator->() const { return {**this}; }
+
+ It &operator++() { ++i; return *this; }
+ It operator++(int) { auto copy = *this; ++*this; return copy; }
+
+ It &operator--() { --i; return *this; }
+ It operator--(int) { auto copy = *this; --*this; return copy; }
+
+ It &operator+=(difference_type n) { i += n; return *this; }
+ friend It operator+(It it, difference_type n) { it += n; return it; }
+ friend It operator+(difference_type n, It it) { return it + n; }
+
+ It &operator-=(difference_type n) { i -= n; return *this; }
+ friend It operator-(It it, difference_type n) { it -= n; return it; }
+
+ friend difference_type operator-(It lhs, It rhs)
+ { Q_ASSERT(lhs.v == rhs.v); return lhs.i - rhs.i; }
+
+ reference operator[](difference_type n) const { return *(*this + n); }
+ };
+
public:
+ using const_iterator = It;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ using value_type = It::value_type;
+ using difference_type = It::difference_type;
+ using size_type = It::size_type;
+ using reference = It::reference;
+ using const_reference = reference;
+ using pointer = It::pointer;
+ using const_pointer = pointer;
+
inline QVersionNumber() noexcept
: m_segments()
{}
+ Q_WEAK_OVERLOAD
inline explicit QVersionNumber(const QList<int> &seg) : m_segments(seg) { }
// compiler-generated copy/move ctor/assignment operators and the destructor are ok
+ Q_WEAK_OVERLOAD
explicit QVersionNumber(QList<int> &&seg) : m_segments(std::move(seg)) { }
inline QVersionNumber(std::initializer_list<int> args)
+ : m_segments(QSpan{args})
+ {}
+
+ explicit QVersionNumber(QSpan<const int> args)
: m_segments(args)
{}
@@ -258,24 +301,59 @@ public:
[[nodiscard]] Q_CORE_EXPORT QList<int> segments() const;
- [[nodiscard]] inline int segmentAt(int index) const noexcept
+ [[nodiscard]] inline int segmentAt(qsizetype index) const noexcept
{ return (m_segments.size() > index) ? m_segments.at(index) : 0; }
- [[nodiscard]] inline int segmentCount() const noexcept
+ [[nodiscard]] inline qsizetype segmentCount() const noexcept
{ return m_segments.size(); }
+ [[nodiscard]] const_iterator begin() const noexcept { return const_iterator{this, 0}; }
+ [[nodiscard]] const_iterator end() const noexcept { return begin() + segmentCount(); }
+ [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator cend() const noexcept { return end(); }
+
+ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
+ [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
+ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ [[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); }
+
+ [[nodiscard]] const_iterator constBegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator constEnd() const noexcept { return end(); }
+
[[nodiscard]] Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const noexcept;
[[nodiscard]] Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept;
- [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
[[nodiscard]] Q_CORE_EXPORT QString toString() const;
-#if QT_STRINGVIEW_LEVEL < 2
- [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr);
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex = nullptr);
+
+#if QT_DEPRECATED_SINCE(6, 4) && QT_POINTER_SIZE != 4
+ Q_WEAK_OVERLOAD
+ QT_DEPRECATED_VERSION_X_6_4("Use the 'qsizetype *suffixIndex' overload.")
+ [[nodiscard]] static QVersionNumber fromString(QAnyStringView string, int *suffixIndex)
+ {
+ QT_WARNING_PUSH
+ // fromString() writes to *n unconditionally, but GCC can't know that
+ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
+ qsizetype n;
+ auto r = fromString(string, &n);
+ if (suffixIndex) {
+ Q_ASSERT(int(n) == n);
+ *suffixIndex = int(n);
+ }
+ return r;
+ QT_WARNING_POP
+ }
+#endif
+
+
+#if QT_CORE_REMOVED_SINCE(6, 4)
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(const QString &string, int *suffixIndex);
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(QLatin1StringView string, int *suffixIndex);
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(QStringView string, int *suffixIndex);
#endif
- [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex = nullptr);
- [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex = nullptr);
[[nodiscard]] friend bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
{ return compare(lhs, rhs) > 0; }
@@ -295,7 +373,6 @@ public:
[[nodiscard]] friend bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
{ return compare(lhs, rhs) != 0; }
-
private:
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
@@ -309,160 +386,8 @@ Q_DECLARE_TYPEINFO(QVersionNumber, Q_RELOCATABLE_TYPE);
Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version);
#endif
-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);
- }
-
- [[nodiscard]] friend constexpr bool operator==(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>();
- }
-
- [[nodiscard]] friend constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>();
- }
-
- [[nodiscard]] friend 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()))));
- }
-
- [[nodiscard]] friend constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs != rhs && !(lhs < rhs);
- }
-
- [[nodiscard]] friend constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs == rhs || lhs < rhs;
- }
-
- [[nodiscard]] friend constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs == rhs || !(lhs < rhs);
- }
-
-private:
- enum { SegmentUnknown = 0xff };
-
-#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
-};
-
-static_assert(sizeof(QTypeRevision) == 2);
-Q_DECLARE_TYPEINFO(QTypeRevision, Q_RELOCATABLE_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)
+QT_DECL_METATYPE_EXTERN(QVersionNumber, Q_CORE_EXPORT)
#endif // QVERSIONNUMBER_H