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.qdoc62
-rw-r--r--src/corelib/tools/qarraydata.cpp201
-rw-r--r--src/corelib/tools/qarraydata.h238
-rw-r--r--src/corelib/tools/qarraydataops.h1792
-rw-r--r--src/corelib/tools/qarraydatapointer.h487
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.h127
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.qdoc123
-rw-r--r--src/corelib/tools/qbitarray.cpp469
-rw-r--r--src/corelib/tools/qbitarray.h211
-rw-r--r--src/corelib/tools/qcache.h153
-rw-r--r--src/corelib/tools/qcache.qdoc42
-rw-r--r--src/corelib/tools/qcommandlineoption.cpp59
-rw-r--r--src/corelib/tools/qcommandlineoption.h46
-rw-r--r--src/corelib/tools/qcommandlineparser.cpp204
-rw-r--r--src/corelib/tools/qcommandlineparser.h40
-rw-r--r--src/corelib/tools/qcontainerfwd.h92
-rw-r--r--src/corelib/tools/qcontainertools_impl.h466
-rw-r--r--src/corelib/tools/qcontiguouscache.cpp68
-rw-r--r--src/corelib/tools/qcontiguouscache.h68
-rw-r--r--src/corelib/tools/qcryptographichash.cpp1595
-rw-r--r--src/corelib/tools/qcryptographichash.h64
-rw-r--r--src/corelib/tools/qduplicatetracker_p.h134
-rw-r--r--src/corelib/tools/qeasingcurve.cpp113
-rw-r--r--src/corelib/tools/qeasingcurve.h53
-rw-r--r--src/corelib/tools/qflatmap_p.h484
-rw-r--r--src/corelib/tools/qfreelist.cpp58
-rw-r--r--src/corelib/tools/qfreelist_p.h48
-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.cpp1618
-rw-r--r--src/corelib/tools/qhash.h1308
-rw-r--r--src/corelib/tools/qhashfunctions.h231
-rw-r--r--src/corelib/tools/qiterator.h189
-rw-r--r--src/corelib/tools/qiterator.qdoc376
-rw-r--r--src/corelib/tools/qline.cpp107
-rw-r--r--src/corelib/tools/qline.h89
-rw-r--r--src/corelib/tools/qlist.h903
-rw-r--r--src/corelib/tools/qlist.qdoc550
-rw-r--r--src/corelib/tools/qmakearray_p.h50
-rw-r--r--src/corelib/tools/qmap.h487
-rw-r--r--src/corelib/tools/qmap.qdoc315
-rw-r--r--src/corelib/tools/qmargins.cpp150
-rw-r--r--src/corelib/tools/qmargins.h183
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.cpp323
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.h69
-rw-r--r--src/corelib/tools/qminimalflatset_p.h156
-rw-r--r--src/corelib/tools/qmultimap.qdoc313
-rw-r--r--src/corelib/tools/qoffsetstringarray_p.h246
-rw-r--r--src/corelib/tools/qpair.h47
-rw-r--r--src/corelib/tools/qpair.qdoc46
-rw-r--r--src/corelib/tools/qpoint.cpp155
-rw-r--r--src/corelib/tools/qpoint.h364
-rw-r--r--src/corelib/tools/qqueue.cpp40
-rw-r--r--src/corelib/tools/qqueue.h40
-rw-r--r--src/corelib/tools/qrect.cpp138
-rw-r--r--src/corelib/tools/qrect.h185
-rw-r--r--src/corelib/tools/qrefcount.cpp40
-rw-r--r--src/corelib/tools/qrefcount.h40
-rw-r--r--src/corelib/tools/qringbuffer.cpp105
-rw-r--r--src/corelib/tools/qringbuffer_p.h109
-rw-r--r--src/corelib/tools/qscopedpointer.cpp93
-rw-r--r--src/corelib/tools/qscopedpointer.h163
-rw-r--r--src/corelib/tools/qscopedpointer_p.h148
-rw-r--r--src/corelib/tools/qscopedvaluerollback.cpp42
-rw-r--r--src/corelib/tools/qscopedvaluerollback.h63
-rw-r--r--src/corelib/tools/qscopeguard.h62
-rw-r--r--src/corelib/tools/qscopeguard.qdoc30
-rw-r--r--src/corelib/tools/qset.h105
-rw-r--r--src/corelib/tools/qset.qdoc373
-rw-r--r--src/corelib/tools/qshareddata.cpp137
-rw-r--r--src/corelib/tools/qshareddata.h375
-rw-r--r--src/corelib/tools/qshareddata_impl.h55
-rw-r--r--src/corelib/tools/qsharedpointer.cpp194
-rw-r--r--src/corelib/tools/qsharedpointer.h88
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h373
-rw-r--r--src/corelib/tools/qsize.cpp130
-rw-r--r--src/corelib/tools/qsize.h284
-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.h92
-rw-r--r--src/corelib/tools/qtaggedpointer.qdoc54
-rw-r--r--src/corelib/tools/qtimeline.cpp200
-rw-r--r--src/corelib/tools/qtimeline.h60
-rw-r--r--src/corelib/tools/qtools_p.h121
-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.h1141
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc220
-rw-r--r--src/corelib/tools/qvector.h46
-rw-r--r--src/corelib/tools/qversionnumber.cpp469
-rw-r--r--src/corelib/tools/qversionnumber.h446
-rw-r--r--src/corelib/tools/tools.pri117
97 files changed, 13769 insertions, 10413 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 f94a6856da..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
@@ -47,8 +24,7 @@
meet a certain set of requirements.
Different algorithms can have different requirements for the
- iterators they accept. For example, qFill() accepts two
- \l {forward iterators}. The iterator types required are specified
+ iterators they accept. The iterator types required are specified
for each algorithm. If an iterator of the wrong type is passed (for
example, if QList::ConstIterator is passed as an
\l {Output Iterators}{output iterator}), you will always get a
@@ -63,21 +39,7 @@
The generic algorithms can be used on other container classes
than those provided by Qt and STL. The syntax of STL-style
iterators is modeled after C++ pointers, so it's possible to use
- plain arrays as containers and plain pointers as iterators. A
- common idiom is to use qBinaryFind() together with two static
- arrays: one that contains a list of keys, and another that
- contains a list of associated values. For example, the following
- code will look up an HTML entity (e.g., \c &amp;) in the \c
- name_table array and return the corresponding Unicode value from
- the \c value_table if the entity is recognized:
-
- \snippet code/doc_src_qalgorithms.cpp 2
-
- This kind of code is for advanced users only; for most
- applications, a QMap- or QHash-based approach would work just as
- well:
-
- \snippet code/doc_src_qalgorithms.cpp 3
+ plain arrays as containers and plain pointers as iterators.
\section1 Types of Iterators
@@ -147,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 10
-*/
-
/*!
\fn template <typename ForwardIterator> void qDeleteAll(ForwardIterator begin, ForwardIterator end)
\relates <QtAlgorithms>
@@ -168,7 +118,7 @@
example, \c{QWidget *}).
Example:
- \snippet code/doc_src_qalgorithms.cpp 23
+ \snippet code/doc_src_qalgorithms.cpp 1
Notice that qDeleteAll() doesn't remove the items from the
container; it merely calls \c delete on them. In the example
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index ab4a0f8af6..6aebd4306a 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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) 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,79 +107,78 @@ 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, uint options)
-{
- // Calculate the byte size
// allocSize = objectSize * capacity + headerSize, but checked for overflow
// plus padded to grow in size
- if (options & (QArrayData::GrowsForward | QArrayData::GrowsBackwards)) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- return r.size;
+ if (option == QArrayData::Grow) {
+ return qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
} else {
- return qCalculateBlockSize(capacity, objectSize, headerSize);
+ return { qCalculateBlockSize(capacity, objectSize, headerSize), capacity };
}
}
-static QArrayData *allocateData(qsizetype allocSize, uint options)
+static QArrayData *allocateData(qsizetype allocSize)
{
QArrayData *header = static_cast<QArrayData *>(::malloc(size_t(allocSize)));
if (header) {
header->ref_.storeRelaxed(1);
- header->flags = options;
+ header->flags = {};
header->alloc = 0;
}
return header;
}
-void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
- qsizetype capacity, ArrayOptions options) noexcept
-{
- Q_ASSERT(dptr);
- // Alignment is a power of two
- Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
- && !(alignment & (alignment - 1)));
+namespace {
+struct AllocationResult {
+ void *data;
+ QArrayData *header;
+};
+}
+using QtPrivate::AlignedQArrayData;
- if (capacity == 0) {
- *dptr = nullptr;
- return nullptr;
- }
+static inline AllocationResult
+allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
+ QArrayData::AllocationOption option) noexcept
+{
+ if (capacity == 0)
+ return {};
- qsizetype headerSize = sizeof(QArrayData);
- const qsizetype headerAlignment = alignof(QArrayData);
+ qsizetype headerSize = sizeof(AlignedQArrayData);
+ const qsizetype headerAlignment = alignof(AlignedQArrayData);
if (alignment > headerAlignment) {
- // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
- // can properly align the data array. This assumes malloc is able to
- // provide appropriate alignment for the header -- as it should!
+ // 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, options);
- 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, options);
+ QArrayData *header = allocateData(allocSize);
void *data = nullptr;
if (header) {
// find where offset should point to so that data() is aligned to alignment bytes
@@ -223,31 +186,69 @@ 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, ArrayOptions options) noexcept
+ qsizetype objectSize, qsizetype capacity, AllocationOption option) noexcept
{
Q_ASSERT(!data || !data->isShared());
- qsizetype headerSize = sizeof(QArrayData);
- qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
- qptrdiff offset = dataPointer ? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data) : headerSize;
+ const qsizetype headerSize = sizeof(AlignedQArrayData);
+ auto r = calculateBlockSize(capacity, objectSize, headerSize, option);
+ qsizetype allocSize = r.size;
+ capacity = r.elementCount;
+ if (Q_UNLIKELY(allocSize < 0))
+ return {};
- allocSize = reserveExtraBytes(allocSize);
- if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot reallocate reliably
- return qMakePair(data, dataPointer);
+ const qptrdiff offset = dataPointer
+ ? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data)
+ : headerSize;
+ Q_ASSERT(offset > 0);
+ Q_ASSERT(offset <= allocSize); // equals when all free space is at the beginning
QArrayData *header = static_cast<QArrayData *>(::realloc(data, size_t(allocSize)));
if (header) {
- header->flags = options;
- header->alloc = uint(capacity);
+ header->alloc = capacity;
dataPointer = reinterpret_cast<char *>(header) + offset;
+ } 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 856a9521ad..da83fc1a21 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -1,75 +1,54 @@
-/****************************************************************************
-**
-** 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 Q_CORE_EXPORT QArrayData
+struct QArrayData
{
- enum ArrayOption {
- /// this option is used by the allocate() function
- DefaultAllocationFlags = 0,
- CapacityReserved = 0x1, //!< the capacity was reserved by the user, try to keep it
- GrowsForward = 0x2, //!< allocate with eyes towards growing through append()
- GrowsBackwards = 0x4 //!< allocate with eyes towards growing through prepend()
+ enum AllocationOption {
+ Grow,
+ KeepSize
+ };
+
+ enum GrowthPosition {
+ GrowsAtEnd,
+ GrowsAtBeginning
+ };
+
+ enum ArrayOption {
+ ArrayOptionDefault = 0,
+ CapacityReserved = 0x1 //!< the capacity was reserved by the user, try to keep it
};
Q_DECLARE_FLAGS(ArrayOptions, ArrayOption)
QBasicAtomicInt ref_;
- uint flags;
+ ArrayOptions flags;
qsizetype alloc;
- inline qsizetype allocatedCapacity() noexcept
+ qsizetype allocatedCapacity() noexcept
{
return alloc;
}
- inline qsizetype constAllocatedCapacity() const noexcept
+ qsizetype constAllocatedCapacity() const noexcept
{
return alloc;
}
@@ -95,7 +74,7 @@ struct Q_CORE_EXPORT 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;
}
@@ -107,127 +86,74 @@ struct Q_CORE_EXPORT QArrayData
return newSize;
}
- ArrayOptions detachFlags() const noexcept
- {
- ArrayOptions result = DefaultAllocationFlags;
- if (flags & CapacityReserved)
- result |= CapacityReserved;
- return result;
- }
-
- Q_REQUIRED_RESULT
-#if defined(Q_CC_GNU)
- __attribute__((__malloc__))
-#endif
- static void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
- qsizetype capacity, ArrayOptions options = DefaultAllocationFlags) noexcept;
- Q_REQUIRED_RESULT static QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
- qsizetype objectSize, qsizetype newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept;
- static void deallocate(QArrayData *data, qsizetype objectSize,
+ Q_DECL_MALLOCLIKE
+ static Q_CORE_EXPORT void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
+ qsizetype capacity, AllocationOption option = QArrayData::KeepSize) noexcept;
+ 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;
};
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
{
- class iterator {
- T *i = nullptr;
- public:
- typedef std::random_access_iterator_tag iterator_category;
- typedef qsizetype difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
-
- inline constexpr iterator() = default;
- inline iterator(T *n) : i(n) {}
- inline T &operator*() const { return *i; }
- inline T *operator->() const { return i; }
- inline T &operator[](qsizetype j) const { return *(i + j); }
- inline constexpr bool operator==(iterator o) const { return i == o.i; }
- inline constexpr bool operator!=(iterator o) const { return i != o.i; }
- inline constexpr bool operator<(iterator other) const { return i < other.i; }
- inline constexpr bool operator<=(iterator other) const { return i <= other.i; }
- inline constexpr bool operator>(iterator other) const { return i > other.i; }
- inline constexpr bool operator>=(iterator other) const { return i >= other.i; }
- inline constexpr bool operator==(pointer p) const { return i == p; }
- inline constexpr bool operator!=(pointer p) const { return i != p; }
- inline iterator &operator++() { ++i; return *this; }
- inline iterator operator++(int) { T *n = i; ++i; return n; }
- inline iterator &operator--() { i--; return *this; }
- inline iterator operator--(int) { T *n = i; i--; return n; }
- inline iterator &operator+=(qsizetype j) { i+=j; return *this; }
- inline iterator &operator-=(qsizetype j) { i-=j; return *this; }
- inline iterator operator+(qsizetype j) const { return iterator(i+j); }
- inline iterator operator-(qsizetype j) const { return iterator(i-j); }
- friend inline iterator operator+(qsizetype j, iterator k) { return k + j; }
- inline qsizetype operator-(iterator j) const { return i - j.i; }
- inline operator T*() const { return i; }
- };
-
- class const_iterator {
- const T *i = nullptr;
- public:
- typedef std::random_access_iterator_tag iterator_category;
- typedef qsizetype difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
-
- inline constexpr const_iterator() = default;
- inline const_iterator(const T *n) : i(n) {}
- inline constexpr const_iterator(iterator o): i(o) {}
- inline const T &operator*() const { return *i; }
- inline const T *operator->() const { return i; }
- inline const T &operator[](qsizetype j) const { return *(i + j); }
- inline constexpr bool operator==(const_iterator o) const { return i == o.i; }
- inline constexpr bool operator!=(const_iterator o) const { return i != o.i; }
- inline constexpr bool operator<(const_iterator other) const { return i < other.i; }
- inline constexpr bool operator<=(const_iterator other) const { return i <= other.i; }
- inline constexpr bool operator>(const_iterator other) const { return i > other.i; }
- inline constexpr bool operator>=(const_iterator other) const { return i >= other.i; }
- inline constexpr bool operator==(iterator o) const { return i == const_iterator(o).i; }
- inline constexpr bool operator!=(iterator o) const { return i != const_iterator(o).i; }
- inline constexpr bool operator==(pointer p) const { return i == p; }
- inline constexpr bool operator!=(pointer p) const { return i != p; }
- inline const_iterator &operator++() { ++i; return *this; }
- inline const_iterator operator++(int) { const T *n = i; ++i; return n; }
- inline const_iterator &operator--() { i--; return *this; }
- inline const_iterator operator--(int) { const T *n = i; i--; return n; }
- inline const_iterator &operator+=(qsizetype j) { i+=j; return *this; }
- inline const_iterator &operator-=(qsizetype j) { i-=j; return *this; }
- inline const_iterator operator+(qsizetype j) const { return const_iterator(i+j); }
- inline const_iterator operator-(qsizetype j) const { return const_iterator(i-j); }
- friend inline const_iterator operator+(qsizetype j, const_iterator k) { return k + j; }
- inline qsizetype operator-(const_iterator j) const { return i - j.i; }
- inline operator const T*() const { return i; }
- };
+ struct AlignmentDummy { QtPrivate::AlignedQArrayData header; T data; };
- class AlignmentDummy { QArrayData header; T data; };
-
- Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(qsizetype capacity,
- ArrayOptions options = DefaultAllocationFlags)
+ [[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, options);
-#if (defined(Q_CC_GNU) && Q_CC_GNU >= 407) || QT_HAS_BUILTIN(__builtin_assume_aligned)
+ 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 *>
- reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity,
- ArrayOptions options = DefaultAllocationFlags)
+ static std::pair<QTypedArrayData *, T *>
+ reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity, AllocationOption option)
{
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
- QPair<QArrayData *, void *> pair =
- QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, options);
- return qMakePair(static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second));
+ std::pair<QArrayData *, void *> pair =
+ QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, option);
+ return {static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second)};
}
static void deallocate(QArrayData *data) noexcept
@@ -244,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 {
@@ -284,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 1d7e307192..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>
@@ -58,211 +23,68 @@ template <class T> struct QArrayDataPointer;
namespace QtPrivate {
-/*!
- \internal
-
- This class provides basic building blocks to do reversible operations. This
- in turn allows to reason about exception safety under certain conditions.
-
- This class is not part of the Qt API. It exists for the convenience of other
- Qt classes. This class may change from version to version without notice,
- or even be removed.
-
- We mean it.
- */
-template<typename T>
-struct QArrayExceptionSafetyPrimitives
-{
- using parameter_type = typename QArrayDataPointer<T>::parameter_type;
- using iterator = typename QArrayDataPointer<T>::iterator;
-
- // Constructs a range of elements at the specified position. If an exception
- // is thrown during construction, already constructed elements are
- // destroyed. By design, only one function (create/copy/clone/move) and only
- // once is supposed to be called per class instance.
- struct Constructor
- {
- T *const where;
- size_t n = 0;
-
- template<typename It>
- using iterator_copy_value = decltype(*std::declval<It>());
- template<typename It>
- using iterator_move_value = decltype(std::move(*std::declval<It>()));
-
- Constructor(T *w) noexcept : where(w) {}
- qsizetype create(size_t size) noexcept(std::is_nothrow_default_constructible_v<T>)
- {
- n = 0;
- while (n != size) {
- new (where + n) T;
- ++n;
- }
- return qsizetype(std::exchange(n, 0));
- }
- template<typename ForwardIt>
- qsizetype copy(ForwardIt first, ForwardIt last)
- noexcept(std::is_nothrow_constructible_v<T, iterator_copy_value<ForwardIt>>)
- {
- n = 0;
- for (; first != last; ++first) {
- new (where + n) T(*first);
- ++n;
- }
- return qsizetype(std::exchange(n, 0));
- }
- qsizetype clone(size_t size, parameter_type t)
- noexcept(std::is_nothrow_constructible_v<T, parameter_type>)
- {
- n = 0;
- while (n != size) {
- new (where + n) T(t);
- ++n;
- }
- return qsizetype(std::exchange(n, 0));
- }
- template<typename ForwardIt>
- qsizetype move(ForwardIt first, ForwardIt last)
- noexcept(std::is_nothrow_constructible_v<T, iterator_move_value<ForwardIt>>)
- {
- n = 0;
- for (; first != last; ++first) {
- new (where + n) T(std::move(*first));
- ++n;
- }
- return qsizetype(std::exchange(n, 0));
- }
- ~Constructor() noexcept(std::is_nothrow_destructible_v<T>)
- {
- while (n)
- where[--n].~T();
- }
- };
-
- // Watches passed iterator. Unless commit() is called, all the elements that
- // the watched iterator passes through are deleted at the end of object
- // lifetime.
- //
- // Requirements: when not at starting position, the iterator is expected to
- // point to a valid object (to initialized memory)
- template<typename It = iterator>
- struct Destructor
- {
- It *iter;
- It end;
- It intermediate;
-
- Destructor(It &it) noexcept(std::is_nothrow_copy_constructible_v<It>)
- : iter(std::addressof(it)), end(it)
- { }
- void commit() noexcept
- {
- iter = std::addressof(end);
- }
- void freeze() noexcept(std::is_nothrow_copy_constructible_v<It>)
- {
- intermediate = *iter; iter = std::addressof(intermediate);
- }
- ~Destructor() noexcept(std::is_nothrow_destructible_v<T>)
- {
- // Step is either 1 or -1 and depends on the interposition of *iter
- // and end. Note that *iter is expected to point to a valid object
- // (see the logic below).
- for (const int step = *iter < end ? 1 : -1; *iter != end; std::advance(*iter, step))
- (*iter)->~T();
- }
- };
-
- // Moves the data range in memory by the specified amount. Unless commit()
- // is called, the data is moved back to the original place at the end of
- // object lifetime.
- struct Displacer
- {
- T *const begin;
- T *const end;
- qsizetype displace;
-
- static_assert(QTypeInfo<T>::isRelocatable, "Type must be relocatable");
-
- Displacer(T *start, T *finish, qsizetype diff) noexcept
- : begin(start), end(finish), displace(diff)
- {
- ::memmove(static_cast<void *>(begin + displace), static_cast<void *>(begin),
- (end - begin) * sizeof(T));
- }
- void commit() noexcept { displace = 0; }
- ~Displacer() noexcept
- {
- if (displace)
- ::memmove(static_cast<void *>(begin), static_cast<void *>(begin + displace),
- (end - begin) * sizeof(T));
- }
- };
-
- // Watches passed iterator. Moves the data range (defined as a start
- // iterator and a length) to the new starting position at the end of object
- // lifetime.
- struct Mover
- {
- T *&destination;
- const T *const source;
- size_t n;
- qsizetype &size;
-
- static_assert(QTypeInfo<T>::isRelocatable, "Type must be relocatable");
-
- Mover(T *&start, size_t length, qsizetype &sz) noexcept
- : destination(start), source(start), n(length), size(sz)
- { }
- ~Mover() noexcept
- {
- ::memmove(static_cast<void *>(destination), static_cast<const void *>(source),
- n * sizeof(T));
- size -= source > destination ? source - destination : destination - source;
- }
- };
-};
-
-// Tags for compile-time dispatch based on backwards vs forward growing policy
-struct GrowsForwardTag {};
-struct GrowsBackwardsTag {};
-template<typename> struct InverseTag;
-template<> struct InverseTag<GrowsForwardTag> { using tag = GrowsBackwardsTag; };
-template<> struct InverseTag<GrowsBackwardsTag> { using tag = GrowsForwardTag; };
-
-QT_WARNING_PUSH
-#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
-QT_WARNING_DISABLE_GCC("-Wstringop-overflow")
-#endif
-
template <class T>
struct QPodArrayOps
: public QArrayDataPointer<T>
{
+ static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
protected:
typedef QTypedArrayData<T> Data;
-
- template <typename ...Args>
- void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); }
+ using DataPointer = QArrayDataPointer<T>;
public:
typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
- void appendInitialize(size_t newSize)
+ using QArrayDataPointer<T>::QArrayDataPointer;
+
+ void appendInitialize(qsizetype newSize) noexcept
{
Q_ASSERT(this->isMutable());
Q_ASSERT(!this->isShared());
- Q_ASSERT(newSize > size_t(this->size));
- Q_ASSERT(newSize - this->size <= size_t(this->freeSpaceAtEnd()));
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
- ::memset(static_cast<void *>(this->end()), 0, (newSize - this->size) * sizeof(T));
- this->size = qsizetype(newSize);
+ T *where = this->end();
+ this->size = newSize;
+ const T *e = this->end();
+ while (where != e)
+ *where++ = T();
}
- void moveAppend(T *b, T *e)
- { insert(this->end(), b, e); }
+ void copyAppend(const T *b, const T *e) noexcept
+ {
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(b <= e);
+ Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
- void truncate(size_t newSize)
+ if (b == e)
+ return;
+
+ ::memcpy(static_cast<void *>(this->end()), static_cast<const void *>(b), (e - b) * sizeof(T));
+ this->size += (e - b);
+ }
+
+ void copyAppend(qsizetype n, parameter_type t) noexcept
+ {
+ Q_ASSERT(!this->isShared() || n == 0);
+ Q_ASSERT(this->freeSpaceAtEnd() >= n);
+ if (!n)
+ return;
+
+ T *where = this->end();
+ this->size += qsizetype(n);
+ while (n--)
+ *where++ = t;
+ }
+
+ void moveAppend(T *b, T *e) noexcept
+ {
+ copyAppend(b, e);
+ }
+
+ void truncate(size_t newSize) noexcept
{
Q_ASSERT(this->isMutable());
Q_ASSERT(!this->isShared());
@@ -271,7 +93,7 @@ public:
this->size = qsizetype(newSize);
}
- void destroyAll() // Call from destructors, ONLY!
+ void destroyAll() noexcept // Call from destructors, ONLY!
{
Q_ASSERT(this->d);
Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
@@ -280,154 +102,166 @@ public:
// exception safe; size not updated.
}
- void insert(T *where, const T *b, const T *e)
- { insert(GrowsForwardTag{}, where, b, e); }
-
- void insert(GrowsForwardTag, T *where, const T *b, const T *e)
+ T *createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
{
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
+ Q_ASSERT((pos == QArrayData::GrowsAtBeginning && n <= this->freeSpaceAtBegin()) ||
+ (pos == QArrayData::GrowsAtEnd && n <= this->freeSpaceAtEnd()));
- ::memmove(static_cast<void *>(where + (e - b)), static_cast<void *>(where),
- (static_cast<const T*>(this->end()) - where) * sizeof(T));
- ::memcpy(static_cast<void *>(where), static_cast<const void *>(b), (e - b) * sizeof(T));
- this->size += (e - b);
- }
-
- void insert(GrowsBackwardsTag, T *where, const T *b, const T *e)
- {
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT((e - b) <= this->freeSpaceAtBegin());
-
- auto oldBegin = this->begin();
- this->ptr -= (e - b);
- ::memmove(static_cast<void *>(this->begin()), static_cast<void *>(oldBegin),
- (where - static_cast<const T*>(oldBegin)) * sizeof(T));
- ::memcpy(static_cast<void *>(where - (e - b)), static_cast<const void *>(b),
- (e - b) * sizeof(T));
- this->size += (e - b);
+ T *insertionPoint = this->ptr + where;
+ if (pos == QArrayData::GrowsAtEnd) {
+ if (where < this->size)
+ ::memmove(static_cast<void *>(insertionPoint + n), static_cast<void *>(insertionPoint), (this->size - where) * sizeof(T));
+ } else {
+ Q_ASSERT(where == 0);
+ this->ptr -= n;
+ insertionPoint -= n;
+ }
+ this->size += n;
+ return insertionPoint;
}
- void insert(T *where, size_t n, parameter_type t)
- { insert(GrowsForwardTag{}, where, n, t); }
-
- void insert(GrowsForwardTag, T *where, size_t n, parameter_type t)
+ void insert(qsizetype i, const T *data, qsizetype n)
{
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(size_t(this->freeSpaceAtEnd()) >= n);
+ typename Data::GrowthPosition pos = Data::GrowsAtEnd;
+ if (this->size != 0 && i == 0)
+ pos = Data::GrowsAtBeginning;
- ::memmove(static_cast<void *>(where + n), static_cast<void *>(where),
- (static_cast<const T*>(this->end()) - where) * sizeof(T));
- this->size += qsizetype(n); // PODs can't throw on copy
- while (n--)
- *where++ = t;
- }
+ DataPointer oldData;
+ this->detachAndGrow(pos, n, &data, &oldData);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- void insert(GrowsBackwardsTag, T *where, size_t n, parameter_type t)
- {
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(size_t(this->freeSpaceAtBegin()) >= n);
-
- auto oldBegin = this->begin();
- this->ptr -= n;
- ::memmove(static_cast<void *>(this->begin()), static_cast<void *>(oldBegin),
- (where - static_cast<const T*>(oldBegin)) * sizeof(T));
- this->size += qsizetype(n); // PODs can't throw on copy
- where -= n;
- while (n--)
- *where++ = t;
+ T *where = createHole(pos, i, n);
+ ::memcpy(static_cast<void *>(where), static_cast<const void *>(data), n * sizeof(T));
}
-
- template <typename ...Args>
- void emplace(T *where, Args&&... args)
- { emplace(GrowsForwardTag{}, where, std::forward<Args>(args)...); }
-
- template <typename ...Args>
- void emplace(GrowsForwardTag, T *where, Args&&... args)
+ void insert(qsizetype i, qsizetype n, parameter_type t)
{
- Q_ASSERT(!this->isShared());
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(this->freeSpaceAtEnd() >= 1);
+ T copy(t);
- if (where == this->end()) {
- new (this->end()) T(std::forward<Args>(args)...);
- } else {
- // Preserve the value, because it might be a reference to some part of the moved chunk
- T t(std::forward<Args>(args)...);
+ typename Data::GrowthPosition pos = Data::GrowsAtEnd;
+ if (this->size != 0 && i == 0)
+ pos = Data::GrowsAtBeginning;
- ::memmove(static_cast<void *>(where + 1), static_cast<void *>(where),
- (static_cast<const T*>(this->end()) - where) * sizeof(T));
- *where = t;
- }
+ this->detachAndGrow(pos, n, nullptr, nullptr);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- ++this->size;
+ T *where = createHole(pos, i, n);
+ while (n--)
+ *where++ = copy;
}
- template <typename ...Args>
- void emplace(GrowsBackwardsTag, T *where, Args&&... args)
+ template<typename... Args>
+ void emplace(qsizetype i, Args &&... args)
{
- Q_ASSERT(!this->isShared());
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(this->freeSpaceAtBegin() >= 1);
-
- if (where == this->begin()) {
- new (this->begin() - 1) T(std::forward<Args>(args)...);
- --this->ptr;
- } else {
- // Preserve the value, because it might be a reference to some part of the moved chunk
- T t(std::forward<Args>(args)...);
-
- auto oldBegin = this->begin();
- --this->ptr;
- ::memmove(static_cast<void *>(this->begin()), static_cast<void *>(oldBegin),
- (where - oldBegin) * sizeof(T));
- *(where - 1) = t;
+ bool detach = this->needsDetach();
+ if (!detach) {
+ if (i == this->size && this->freeSpaceAtEnd()) {
+ new (this->end()) T(std::forward<Args>(args)...);
+ ++this->size;
+ return;
+ }
+ if (i == 0 && this->freeSpaceAtBegin()) {
+ new (this->begin() - 1) T(std::forward<Args>(args)...);
+ --this->ptr;
+ ++this->size;
+ return;
+ }
}
+ T tmp(std::forward<Args>(args)...);
+ typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
+ if (this->size != 0 && i == 0)
+ pos = QArrayData::GrowsAtBeginning;
- ++this->size;
- }
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
- void erase(T *b, T *e)
- { erase(GrowsForwardTag{}, b, e); }
+ T *where = createHole(pos, i, 1);
+ new (where) T(std::move(tmp));
+ }
- void erase(GrowsForwardTag, T *b, T *e)
+ void erase(T *b, qsizetype n)
{
+ T *e = b + n;
Q_ASSERT(this->isMutable());
Q_ASSERT(b < e);
Q_ASSERT(b >= this->begin() && b < this->end());
Q_ASSERT(e > this->begin() && e <= this->end());
- ::memmove(static_cast<void *>(b), static_cast<void *>(e),
- (static_cast<T *>(this->end()) - e) * sizeof(T));
- this->size -= (e - b);
+ // Comply with std::vector::erase(): erased elements and all after them
+ // are invalidated. However, erasing from the beginning effectively
+ // means that all iterators are invalidated. We can use this freedom to
+ // erase by moving towards the end.
+ if (b == this->begin() && e != this->end()) {
+ this->ptr = e;
+ } else if (e != this->end()) {
+ ::memmove(static_cast<void *>(b), static_cast<void *>(e),
+ (static_cast<T *>(this->end()) - e) * sizeof(T));
+ }
+ this->size -= n;
}
- void erase(GrowsBackwardsTag, T *b, T *e)
+ void eraseFirst() noexcept
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(b < e);
- Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e <= this->end());
+ Q_ASSERT(this->size);
+ ++this->ptr;
+ --this->size;
+ }
- const auto oldBegin = this->begin();
- this->ptr += (e - b);
- ::memmove(static_cast<void *>(this->begin()), static_cast<void *>(oldBegin),
- (b - static_cast<T *>(oldBegin)) * sizeof(T));
- this->size -= (e - b);
+ void eraseLast() noexcept
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->size);
+ --this->size;
}
- void assign(T *b, T *e, parameter_type t)
+ 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);
Q_ASSERT(b >= this->begin() && e <= this->end());
@@ -457,67 +291,90 @@ public:
}
}
- void reallocate(qsizetype alloc, typename Data::ArrayOptions options)
+ void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
{
- // when reallocating, take care of the situation when no growth is
- // happening - need to move the data in this case, unfortunately
- const bool grows = options & (Data::GrowsForward | Data::GrowsBackwards);
-
- // ### optimize me: there may be cases when moving is not obligatory
- if (const auto gap = this->freeSpaceAtBegin(); this->d && !grows && gap) {
- auto oldBegin = this->begin();
- this->ptr -= gap;
- ::memmove(static_cast<void *>(this->begin()), static_cast<void *>(oldBegin),
- this->size * sizeof(T));
- }
-
- auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, options);
+ auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
+ Q_CHECK_PTR(pair.second);
+ Q_ASSERT(pair.first != nullptr);
this->d = pair.first;
this->ptr = pair.second;
}
};
-QT_WARNING_POP
template <class T>
struct QGenericArrayOps
: public QArrayDataPointer<T>
{
+ static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
protected:
typedef QTypedArrayData<T> Data;
-
- template <typename ...Args>
- void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); }
+ using DataPointer = QArrayDataPointer<T>;
public:
typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
- void appendInitialize(size_t newSize)
+ void appendInitialize(qsizetype newSize)
{
Q_ASSERT(this->isMutable());
Q_ASSERT(!this->isShared());
- Q_ASSERT(newSize > size_t(this->size));
- Q_ASSERT(newSize - this->size <= size_t(this->freeSpaceAtEnd()));
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
T *const b = this->begin();
do {
new (b + this->size) T;
- } while (size_t(++this->size) != newSize);
+ } while (++this->size != newSize);
}
- void moveAppend(T *b, T *e)
+ void copyAppend(const T *b, const T *e)
{
Q_ASSERT(this->isMutable() || b == e);
Q_ASSERT(!this->isShared() || b == e);
Q_ASSERT(b <= e);
Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
- typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
+ if (b == e) // short-cut and handling the case b and e == nullptr
+ return;
+
+ T *data = this->begin();
+ while (b < e) {
+ new (data + this->size) T(*b);
+ ++b;
+ ++this->size;
+ }
+ }
+
+ void copyAppend(qsizetype n, parameter_type t)
+ {
+ Q_ASSERT(!this->isShared() || n == 0);
+ Q_ASSERT(this->freeSpaceAtEnd() >= n);
+ if (!n)
+ return;
+
+ T *data = this->begin();
+ while (n--) {
+ new (data + this->size) T(t);
+ ++this->size;
+ }
+ }
+
+ void moveAppend(T *b, T *e)
+ {
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(b <= e);
+ Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
- // Provides strong exception safety guarantee,
- // provided T::~T() nothrow
+ if (b == e)
+ return;
- CopyConstructor copier(this->end());
- this->size += copier.move(b, e);
+ T *data = this->begin();
+ while (b < e) {
+ new (data + this->size) T(std::move(*b));
+ ++b;
+ ++this->size;
+ }
}
void truncate(size_t newSize)
@@ -526,10 +383,8 @@ public:
Q_ASSERT(!this->isShared());
Q_ASSERT(newSize < size_t(this->size));
- const T *const b = this->begin();
- do {
- (b + --this->size)->~T();
- } while (size_t(this->size) != newSize);
+ std::destroy(this->begin() + newSize, this->end());
+ this->size = newSize;
}
void destroyAll() // Call from destructors, ONLY
@@ -540,304 +395,264 @@ public:
Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
- const T *const b = this->begin();
- const T *i = this->end();
-
- while (i != b)
- (--i)->~T();
+ std::destroy(this->begin(), this->end());
}
- void insert(T *where, const T *b, const T *e)
- { insert(GrowsForwardTag{}, where, b, e); }
-
- void insert(GrowsForwardTag, T *where, const T *b, const T *e)
+ struct Inserter
{
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
-
- typedef typename QArrayExceptionSafetyPrimitives<T>::template Destructor<T *> Destructor;
-
- // Array may be truncated at where in case of exceptions
-
- T *const end = this->end();
- const T *readIter = end;
- T *writeIter = end + (e - b);
+ QArrayDataPointer<T> *data;
+ T *begin;
+ qsizetype size;
- const T *const step1End = where + qMax(e - b, end - where);
-
- Destructor destroyer(writeIter);
-
- // Construct new elements in array
- while (writeIter != step1End) {
- --readIter;
- // If exception happens on construction, we should not call ~T()
- new (writeIter - 1) T(*readIter);
- --writeIter;
- }
+ qsizetype sourceCopyConstruct = 0, nSource = 0, move = 0, sourceCopyAssign = 0;
+ T *end = nullptr, *last = nullptr, *where = nullptr;
- while (writeIter != end) {
- --e;
- // If exception happens on construction, we should not call ~T()
- new (writeIter - 1) T(*e);
- --writeIter;
+ Inserter(QArrayDataPointer<T> *d) : data(d)
+ {
+ begin = d->ptr;
+ size = d->size;
}
-
- destroyer.commit();
- this->size += destroyer.end - end;
-
- // Copy assign over existing elements
- while (readIter != where) {
- --readIter;
- --writeIter;
- *writeIter = *readIter;
+ ~Inserter() {
+ data->ptr = begin;
+ data->size = size;
}
+ Q_DISABLE_COPY(Inserter)
- while (writeIter != where) {
- --e;
- --writeIter;
- *writeIter = *e;
+ void setup(qsizetype pos, qsizetype n)
+ {
+ end = begin + size;
+ last = end - 1;
+ where = begin + pos;
+ qsizetype dist = size - pos;
+ sourceCopyConstruct = 0;
+ nSource = n;
+ move = n - dist; // smaller 0
+ sourceCopyAssign = n;
+ if (n > dist) {
+ sourceCopyConstruct = n - dist;
+ move = 0;
+ sourceCopyAssign -= sourceCopyConstruct;
+ }
}
- }
- void insert(GrowsBackwardsTag, T *where, const T *b, const T *e)
- {
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT((e - b) <= this->freeSpaceAtBegin());
-
- typedef typename QArrayExceptionSafetyPrimitives<T>::template Destructor<T *> Destructor;
-
- T *const begin = this->begin();
- const T *readIter = begin;
- T *writeIter = begin - (e - b);
-
- const T *const step1End = where - qMax(e - b, where - begin);
-
- Destructor destroyer(writeIter);
+ void insert(qsizetype pos, const T *source, qsizetype n)
+ {
+ qsizetype oldSize = size;
+ Q_UNUSED(oldSize);
- // Construct new elements in array
- while (writeIter != step1End) {
- new (writeIter) T(*readIter);
- ++readIter;
- ++writeIter;
- }
+ setup(pos, n);
- while (writeIter != begin) {
- new (writeIter) T(*b);
- ++b;
- ++writeIter;
- }
+ // first create new elements at the end, by copying from elements
+ // to be inserted (if they extend past the current end of the array)
+ for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
+ new (end + i) T(source[nSource - sourceCopyConstruct + i]);
+ ++size;
+ }
+ Q_ASSERT(size <= oldSize + n);
- destroyer.commit();
- this->size += begin - destroyer.end;
- this->ptr -= begin - destroyer.end;
+ // now move construct new elements at the end from existing elements inside
+ // the array.
+ for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
+ new (end + i) T(std::move(*(end + i - nSource)));
+ ++size;
+ }
+ // array has the new size now!
+ Q_ASSERT(size == oldSize + n);
- // Copy assign over existing elements
- while (readIter != where) {
- *writeIter = *readIter;
- ++readIter;
- ++writeIter;
- }
+ // now move assign existing elements towards the end
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - nSource]);
- while (writeIter != where) {
- *writeIter = *b;
- ++b;
- ++writeIter;
+ // finally copy the remaining elements from source over
+ for (qsizetype i = 0; i != sourceCopyAssign; ++i)
+ where[i] = source[i];
}
- }
- void insert(T *where, size_t n, parameter_type t)
- { insert(GrowsForwardTag{}, where, n, t); }
-
- void insert(GrowsForwardTag, T *where, size_t n, parameter_type t)
- {
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(size_t(this->freeSpaceAtEnd()) >= n);
+ void insert(qsizetype pos, const T &t, qsizetype n)
+ {
+ const qsizetype oldSize = size;
+ Q_UNUSED(oldSize);
- typedef typename QArrayExceptionSafetyPrimitives<T>::template Destructor<T *> Destructor;
+ setup(pos, n);
- // Array may be truncated at where in case of exceptions
- T *const end = this->end();
- const T *readIter = end;
- T *writeIter = end + n;
+ // first create new elements at the end, by copying from elements
+ // to be inserted (if they extend past the current end of the array)
+ for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
+ new (end + i) T(t);
+ ++size;
+ }
+ Q_ASSERT(size <= oldSize + n);
- const T *const step1End = where + qMax<size_t>(n, end - where);
+ // now move construct new elements at the end from existing elements inside
+ // the array.
+ for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
+ new (end + i) T(std::move(*(end + i - nSource)));
+ ++size;
+ }
+ // array has the new size now!
+ Q_ASSERT(size == oldSize + n);
- Destructor destroyer(writeIter);
+ // now move assign existing elements towards the end
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - nSource]);
- // Construct new elements in array
- while (writeIter != step1End) {
- --readIter;
- // If exception happens on construction, we should not call ~T()
- new (writeIter - 1) T(*readIter);
- --writeIter;
+ // finally copy the remaining elements from source over
+ for (qsizetype i = 0; i != sourceCopyAssign; ++i)
+ where[i] = t;
}
- while (writeIter != end) {
- --n;
- // If exception happens on construction, we should not call ~T()
- new (writeIter - 1) T(t);
- --writeIter;
- }
+ void insertOne(qsizetype pos, T &&t)
+ {
+ setup(pos, 1);
- destroyer.commit();
- this->size += destroyer.end - end;
+ if (sourceCopyConstruct) {
+ Q_ASSERT(sourceCopyConstruct == 1);
+ new (end) T(std::move(t));
+ ++size;
+ } else {
+ // create a new element at the end by move constructing one existing element
+ // inside the array.
+ new (end) T(std::move(*(end - 1)));
+ ++size;
- // Copy assign over existing elements
- while (readIter != where) {
- --readIter;
- --writeIter;
- *writeIter = *readIter;
- }
+ // now move assign existing elements towards the end
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - 1]);
- while (writeIter != where) {
- --n;
- --writeIter;
- *writeIter = t;
+ // and move the new item into place
+ *where = std::move(t);
+ }
}
- }
+ };
- void insert(GrowsBackwardsTag, T *where, size_t n, parameter_type t)
+ void insert(qsizetype i, const T *data, qsizetype n)
{
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(size_t(this->freeSpaceAtBegin()) >= n);
-
- typedef typename QArrayExceptionSafetyPrimitives<T>::template Destructor<T *> Destructor;
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
- T *const begin = this->begin();
- const T *readIter = begin;
- T *writeIter = begin - n;
-
- const T *const step1End = where - qMax<size_t>(n, where - begin);
-
- Destructor destroyer(writeIter);
-
- // Construct new elements in array
- while (writeIter != step1End) {
- new (writeIter) T(*readIter);
- ++readIter;
- ++writeIter;
- }
+ DataPointer oldData;
+ this->detachAndGrow(pos, n, &data, &oldData);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- while (writeIter != begin) {
- new (writeIter) T(t);
- ++writeIter;
- }
-
- destroyer.commit();
- this->size += begin - destroyer.end;
- this->ptr -= begin - destroyer.end;
-
- // Copy assign over existing elements
- while (readIter != where) {
- *writeIter = *readIter;
- ++readIter;
- ++writeIter;
- }
-
- while (writeIter != where) {
- *writeIter = t;
- ++writeIter;
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n) {
+ --n;
+ new (this->begin() - 1) T(data[n]);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, data, n);
}
}
-
- template <typename iterator, typename ...Args>
- void emplace(iterator where, Args&&... args)
- { emplace(GrowsForwardTag{}, where, std::forward<Args>(args)...); }
-
- template <typename iterator, typename ...Args>
- void emplace(GrowsForwardTag, iterator where, Args&&... args)
+ void insert(qsizetype i, qsizetype n, parameter_type t)
{
- Q_ASSERT(!this->isShared());
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(this->freeSpaceAtEnd() >= 1);
+ T copy(t);
+
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
- createInPlace(this->end(), std::forward<Args>(args)...);
- ++this->size;
+ this->detachAndGrow(pos, n, nullptr, nullptr);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- std::rotate(where, this->end() - 1, this->end());
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n--) {
+ new (this->begin() - 1) T(copy);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, copy, n);
+ }
}
- template <typename iterator, typename ...Args>
- void emplace(GrowsBackwardsTag, iterator where, Args&&... args)
+ template<typename... Args>
+ void emplace(qsizetype i, Args &&... args)
{
- Q_ASSERT(!this->isShared());
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(this->freeSpaceAtBegin() >= 1);
+ bool detach = this->needsDetach();
+ if (!detach) {
+ if (i == this->size && this->freeSpaceAtEnd()) {
+ new (this->end()) T(std::forward<Args>(args)...);
+ ++this->size;
+ return;
+ }
+ if (i == 0 && this->freeSpaceAtBegin()) {
+ new (this->begin() - 1) T(std::forward<Args>(args)...);
+ --this->ptr;
+ ++this->size;
+ return;
+ }
+ }
+ T tmp(std::forward<Args>(args)...);
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
- createInPlace(this->begin() - 1, std::forward<Args>(args)...);
- --this->ptr;
- ++this->size;
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
- std::rotate(this->begin(), this->begin() + 1, where);
+ if (growsAtBegin) {
+ Q_ASSERT(this->freeSpaceAtBegin());
+ new (this->begin() - 1) T(std::move(tmp));
+ --this->ptr;
+ ++this->size;
+ } else {
+ Inserter(this).insertOne(i, std::move(tmp));
+ }
}
- void erase(T *b, T *e)
- { erase(GrowsForwardTag{}, b, e); }
-
- void erase(GrowsForwardTag, T *b, T *e)
+ void erase(T *b, qsizetype n)
{
+ T *e = b + n;
Q_ASSERT(this->isMutable());
Q_ASSERT(b < e);
Q_ASSERT(b >= this->begin() && b < this->end());
Q_ASSERT(e > this->begin() && e <= this->end());
- const T *const end = this->end();
-
- // move (by assignment) the elements from e to end
- // onto b to the new end
- while (e != end) {
- *b = *e;
- ++b;
- ++e;
+ // Comply with std::vector::erase(): erased elements and all after them
+ // are invalidated. However, erasing from the beginning effectively
+ // means that all iterators are invalidated. We can use this freedom to
+ // erase by moving towards the end.
+ if (b == this->begin() && e != this->end()) {
+ this->ptr = e;
+ } else {
+ const T *const end = this->end();
+
+ // move (by assignment) the elements from e to end
+ // onto b to the new end
+ while (e != end) {
+ *b = std::move(*e);
+ ++b;
+ ++e;
+ }
}
-
- // destroy the final elements at the end
- // here, b points to the new end and e to the actual end
- do {
- // Exceptions or not, dtor called once per instance
- --this->size;
- (--e)->~T();
- } while (e != b);
+ this->size -= n;
+ std::destroy(b, e);
}
- void erase(GrowsBackwardsTag, T *b, T *e)
+ void eraseFirst() noexcept
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(b < e);
- Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e <= this->end());
-
- const T *const begin = this->begin();
-
- // move (by assignment) the elements from begin to b
- // onto the new begin to e
- while (b != begin) {
- --b;
- --e;
- *e = *b;
- }
+ Q_ASSERT(this->size);
+ this->begin()->~T();
+ ++this->ptr;
+ --this->size;
+ }
- // destroy the final elements at the begin
- // here, e points to the new begin and b to the actual begin
- do {
- // Exceptions or not, dtor called once per instance
- ++this->ptr;
- --this->size;
- (b++)->~T();
- } while (b != e);
+ void eraseLast() noexcept
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->size);
+ (this->end() - 1)->~T();
+ --this->size;
}
+
void assign(T *b, T *e, parameter_type t)
{
Q_ASSERT(b <= e);
@@ -866,144 +681,195 @@ template <class T>
struct QMovableArrayOps
: QGenericArrayOps<T>
{
- // using QGenericArrayOps<T>::appendInitialize;
+ static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
+protected:
+ typedef QTypedArrayData<T> Data;
+ using DataPointer = QArrayDataPointer<T>;
+
+public:
// using QGenericArrayOps<T>::copyAppend;
// using QGenericArrayOps<T>::moveAppend;
// using QGenericArrayOps<T>::truncate;
// using QGenericArrayOps<T>::destroyAll;
typedef typename QGenericArrayOps<T>::parameter_type parameter_type;
- void insert(T *where, const T *b, const T *e)
- { insert(GrowsForwardTag{}, where, b, e); }
-
- void insert(GrowsForwardTag, T *where, const T *b, const T *e)
+ struct Inserter
{
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
+ QArrayDataPointer<T> *data;
+ T *displaceFrom;
+ T *displaceTo;
+ qsizetype nInserts = 0;
+ qsizetype bytes;
- typedef typename QArrayExceptionSafetyPrimitives<T>::Displacer ReversibleDisplace;
- typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
+ Inserter(QArrayDataPointer<T> *d) : data(d) { }
+ ~Inserter() {
+ if constexpr (!std::is_nothrow_copy_constructible_v<T>) {
+ if (displaceFrom != displaceTo) {
+ ::memmove(static_cast<void *>(displaceFrom), static_cast<void *>(displaceTo), bytes);
+ nInserts -= qAbs(displaceFrom - displaceTo);
+ }
+ }
+ data->size += nInserts;
+ }
+ Q_DISABLE_COPY(Inserter)
- // Provides strong exception safety guarantee,
- // provided T::~T() nothrow
+ T *displace(qsizetype pos, qsizetype n)
+ {
+ nInserts = n;
+ T *insertionPoint = data->ptr + pos;
+ displaceFrom = data->ptr + pos;
+ displaceTo = displaceFrom + n;
+ bytes = data->size - pos;
+ bytes *= sizeof(T);
+ ::memmove(static_cast<void *>(displaceTo), static_cast<void *>(displaceFrom), bytes);
+ return insertionPoint;
+ }
- ReversibleDisplace displace(where, this->end(), e - b);
- CopyConstructor copier(where);
- const auto copiedSize = copier.copy(b, e);
- displace.commit();
- this->size += copiedSize;
- }
+ void insert(qsizetype pos, const T *source, qsizetype n)
+ {
+ T *where = displace(pos, n);
- void insert(GrowsBackwardsTag, T *where, const T *b, const T *e)
- {
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT((e - b) <= this->freeSpaceAtBegin());
+ while (n--) {
+ new (where) T(*source);
+ ++where;
+ ++source;
+ ++displaceFrom;
+ }
+ }
- typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
- typedef typename QArrayExceptionSafetyPrimitives<T>::Displacer ReversibleDisplace;
+ void insert(qsizetype pos, const T &t, qsizetype n)
+ {
+ T *where = displace(pos, n);
+
+ while (n--) {
+ new (where) T(t);
+ ++where;
+ ++displaceFrom;
+ }
+ }
- // Provides strong exception safety guarantee,
- // provided T::~T() nothrow
+ void insertOne(qsizetype pos, T &&t)
+ {
+ T *where = displace(pos, 1);
+ new (where) T(std::move(t));
+ ++displaceFrom;
+ Q_ASSERT(displaceFrom == displaceTo);
+ }
- ReversibleDisplace displace(this->begin(), where, -(e - b));
- CopyConstructor copier(where - (e - b));
- const auto copiedSize = copier.copy(b, e);
- displace.commit();
- this->ptr -= copiedSize;
- this->size += copiedSize;
- }
+ };
- void insert(T *where, size_t n, parameter_type t)
- { insert(GrowsForwardTag{}, where, n, t); }
- void insert(GrowsForwardTag, T *where, size_t n, parameter_type t)
+ void insert(qsizetype i, const T *data, qsizetype n)
{
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(size_t(this->freeSpaceAtEnd()) >= n);
-
- typedef typename QArrayExceptionSafetyPrimitives<T>::Displacer ReversibleDisplace;
- typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
- // Provides strong exception safety guarantee,
- // provided T::~T() nothrow
+ DataPointer oldData;
+ this->detachAndGrow(pos, n, &data, &oldData);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- ReversibleDisplace displace(where, this->end(), qsizetype(n));
- CopyConstructor copier(where);
- const auto copiedSize = copier.clone(n, t);
- displace.commit();
- this->size += copiedSize;
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n) {
+ --n;
+ new (this->begin() - 1) T(data[n]);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, data, n);
+ }
}
- void insert(GrowsBackwardsTag, T *where, size_t n, parameter_type t)
+ void insert(qsizetype i, qsizetype n, parameter_type t)
{
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(size_t(this->freeSpaceAtBegin()) >= n);
-
- typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
- typedef typename QArrayExceptionSafetyPrimitives<T>::Displacer ReversibleDisplace;
-
- // Provides strong exception safety guarantee,
- // provided T::~T() nothrow
-
- ReversibleDisplace displace(this->begin(), where, -qsizetype(n));
- CopyConstructor copier(where - n);
- const auto copiedSize = copier.clone(n, t);
- displace.commit();
- this->ptr -= copiedSize;
- this->size += copiedSize;
- }
+ T copy(t);
- // use moving insert
- using QGenericArrayOps<T>::insert;
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
- void erase(T *b, T *e)
- { erase(GrowsForwardTag{}, b, e); }
+ this->detachAndGrow(pos, n, nullptr, nullptr);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
- void erase(GrowsForwardTag, T *b, T *e)
- {
- Q_ASSERT(this->isMutable());
- Q_ASSERT(b < e);
- Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e <= this->end());
-
- typedef typename QArrayExceptionSafetyPrimitives<T>::Mover Mover;
+ if (growsAtBegin) {
+ // copy construct items in reverse order at the begin
+ Q_ASSERT(this->freeSpaceAtBegin() >= n);
+ while (n--) {
+ new (this->begin() - 1) T(copy);
+ --this->ptr;
+ ++this->size;
+ }
+ } else {
+ Inserter(this).insert(i, copy, n);
+ }
+ }
- Mover mover(e, static_cast<const T *>(this->end()) - e, this->size);
+ template<typename... Args>
+ void emplace(qsizetype i, Args &&... args)
+ {
+ bool detach = this->needsDetach();
+ if (!detach) {
+ if (i == this->size && this->freeSpaceAtEnd()) {
+ new (this->end()) T(std::forward<Args>(args)...);
+ ++this->size;
+ return;
+ }
+ if (i == 0 && this->freeSpaceAtBegin()) {
+ new (this->begin() - 1) T(std::forward<Args>(args)...);
+ --this->ptr;
+ ++this->size;
+ return;
+ }
+ }
+ T tmp(std::forward<Args>(args)...);
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
- // destroy the elements we're erasing
- do {
- // Exceptions or not, dtor called once per instance
- (--e)->~T();
- } while (e != b);
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
+ if (growsAtBegin) {
+ Q_ASSERT(this->freeSpaceAtBegin());
+ new (this->begin() - 1) T(std::move(tmp));
+ --this->ptr;
+ ++this->size;
+ } else {
+ Inserter(this).insertOne(i, std::move(tmp));
+ }
}
- void erase(GrowsBackwardsTag, T *b, T *e)
+ void erase(T *b, qsizetype n)
{
+ T *e = b + n;
+
Q_ASSERT(this->isMutable());
Q_ASSERT(b < e);
Q_ASSERT(b >= this->begin() && b < this->end());
Q_ASSERT(e > this->begin() && e <= this->end());
- typedef typename QArrayExceptionSafetyPrimitives<T>::Mover Mover;
+ // Comply with std::vector::erase(): erased elements and all after them
+ // are invalidated. However, erasing from the beginning effectively
+ // means that all iterators are invalidated. We can use this freedom to
+ // erase by moving towards the end.
- Mover mover(this->ptr, b - static_cast<const T *>(this->begin()), this->size);
+ std::destroy(b, e);
+ if (b == this->begin() && e != this->end()) {
+ this->ptr = e;
+ } else if (e != this->end()) {
+ memmove(static_cast<void *>(b), static_cast<const void *>(e), (static_cast<const T *>(this->end()) - e)*sizeof(T));
+ }
+ this->size -= n;
+ }
- // destroy the elements we're erasing
- do {
- // Exceptions or not, dtor called once per instance
- ++this->ptr;
- (b++)->~T();
- } while (b != e);
+ void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
+ {
+ auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
+ Q_CHECK_PTR(pair.second);
+ Q_ASSERT(pair.first != nullptr);
+ this->d = pair.first;
+ this->ptr = pair.second;
}
};
@@ -1035,479 +901,83 @@ template <class T>
struct QCommonArrayOps : QArrayOpsSelector<T>::Type
{
using Base = typename QArrayOpsSelector<T>::Type;
+ using Data = QTypedArrayData<T>;
+ using DataPointer = QArrayDataPointer<T>;
using parameter_type = typename Base::parameter_type;
- using iterator = typename Base::iterator;
- using const_iterator = typename Base::const_iterator;
protected:
using Self = QCommonArrayOps<T>;
- // Tag dispatched helper functions
- inline void adjustPointer(GrowsBackwardsTag, size_t distance) noexcept
- {
- this->ptr -= distance;
- }
- inline void adjustPointer(GrowsForwardTag, size_t distance) noexcept
- {
- this->ptr += distance;
- }
- qsizetype freeSpace(GrowsBackwardsTag) const noexcept { return this->freeSpaceAtBegin(); }
- qsizetype freeSpace(GrowsForwardTag) const noexcept { return this->freeSpaceAtEnd(); }
-
- struct RelocatableMoveOps
- {
- // The necessary evil. Performs move "to the left" when grows backwards and
- // move "to the right" when grows forward
- template<typename GrowthTag>
- static void moveInGrowthDirection(GrowthTag tag, Self *this_, size_t futureGrowth)
- {
- Q_ASSERT(this_->isMutable());
- Q_ASSERT(!this_->isShared());
- Q_ASSERT(futureGrowth <= size_t(this_->freeSpace(tag)));
-
- const auto oldBegin = this_->begin();
- this_->adjustPointer(tag, futureGrowth);
-
- // Note: move all elements!
- ::memmove(static_cast<void *>(this_->begin()), static_cast<const void *>(oldBegin),
- this_->size * sizeof(T));
- }
- };
-
- struct GenericMoveOps
- {
- template <typename ...Args>
- static void createInPlace(T *where, Args&&... args)
- {
- new (where) T(std::forward<Args>(args)...);
- }
-
- template <typename ...Args>
- static void createInPlace(std::reverse_iterator<iterator> where, Args&&... args)
- {
- // Note: instead of std::addressof(*where)
- createInPlace(where.base() - 1, std::forward<Args>(args)...);
- }
-
- // Moves non-pod data range. Handles overlapping regions. By default, expect
- // this method to perform move to the _right_. When move to the _left_ is
- // needed, use reverse iterators.
- template<typename GrowthTag, typename It>
- static void moveNonPod(GrowthTag, Self *this_, It where, It begin, It end)
- {
- Q_ASSERT(begin <= end);
- Q_ASSERT(where > begin); // move to the right
-
- using Destructor = typename QArrayExceptionSafetyPrimitives<T>::template Destructor<It>;
-
- auto start = where + std::distance(begin, end);
- auto e = end;
-
- Destructor destroyer(start); // Keep track of added items
-
- auto [oldRangeEnd, overlapStart] = std::minmax(where, end);
-
- // step 1. move-initialize elements in uninitialized memory region
- while (start != overlapStart) {
- --e;
- createInPlace(start - 1, std::move_if_noexcept(*e));
- // change tracked iterator only after creation succeeded - avoid
- // destructing partially constructed objects if exception thrown
- --start;
- }
-
- // re-created the range. now there is an initialized memory region
- // somewhere in the allocated area. if something goes wrong, we must
- // clean it up, so "freeze" the position for now (cannot commit yet)
- destroyer.freeze();
-
- // step 2. move assign over existing elements in the overlapping
- // region (if there's an overlap)
- while (e != begin) {
- --start;
- --e;
- *start = std::move_if_noexcept(*e);
- }
-
- // step 3. destroy elements in the old range
- const qsizetype originalSize = this_->size;
- start = begin; // delete elements in reverse order to prevent any gaps
- while (start != oldRangeEnd) {
- // Exceptions or not, dtor called once per instance
- if constexpr (std::is_same_v<std::decay_t<GrowthTag>, GrowsForwardTag>)
- ++this_->ptr;
- --this_->size;
- (start++)->~T();
- }
-
- destroyer.commit();
- // restore old size as we consider data move to be done, the pointer
- // still has to be adjusted!
- this_->size = originalSize;
- }
-
- // Super inefficient function. The necessary evil. Performs move "to
- // the left" when grows backwards and move "to the right" when grows
- // forward
- template<typename GrowthTag>
- static void moveInGrowthDirection(GrowthTag tag, Self *this_, size_t futureGrowth)
- {
- Q_ASSERT(this_->isMutable());
- Q_ASSERT(!this_->isShared());
- Q_ASSERT(futureGrowth <= size_t(this_->freeSpace(tag)));
-
- if (futureGrowth == 0) // avoid doing anything if there's no need
- return;
-
- // Note: move all elements!
- if constexpr (std::is_same_v<std::decay_t<GrowthTag>, GrowsBackwardsTag>) {
- auto where = this_->begin() - futureGrowth;
- // here, magic happens. instead of having move to the right, we'll
- // have move to the left by using reverse iterators
- moveNonPod(tag, this_,
- std::make_reverse_iterator(where + this_->size), // rwhere
- std::make_reverse_iterator(this_->end()), // rbegin
- std::make_reverse_iterator(this_->begin())); // rend
- this_->ptr = where;
- } else {
- auto where = this_->begin() + futureGrowth;
- moveNonPod(tag, this_, where, this_->begin(), this_->end());
- this_->ptr = where;
- }
- }
- };
-
- // Moves all elements in a specific direction by moveSize if available
- // free space at one of the ends is smaller than required. Free space
- // becomes available at the beginning if grows backwards and at the end
- // if grows forward
- template<typename GrowthTag>
- qsizetype prepareFreeSpace(GrowthTag tag, size_t required, size_t moveSize)
- {
- Q_ASSERT(this->isMutable() || required == 0);
- Q_ASSERT(!this->isShared() || required == 0);
- Q_ASSERT(required <= this->constAllocatedCapacity() - this->size);
-
- using MoveOps = std::conditional_t<QTypeInfo<T>::isRelocatable,
- RelocatableMoveOps,
- GenericMoveOps>;
-
- // if free space at the end is not enough, we need to move the data,
- // move is performed in an inverse direction
- if (size_t(freeSpace(tag)) < required) {
- using MoveTag = typename InverseTag<std::decay_t<GrowthTag>>::tag;
- MoveOps::moveInGrowthDirection(MoveTag{}, this, moveSize);
-
- if constexpr (std::is_same_v<MoveTag, GrowsBackwardsTag>) {
- return -qsizetype(moveSize); // moving data to the left
- } else {
- return qsizetype(moveSize); // moving data to the right
- }
- }
- return 0;
- }
-
- // Helper wrapper that adjusts passed iterators along with moving the data
- // around. The adjustment is necessary when iterators point inside the
- // to-be-moved range
- template<typename GrowthTag, typename It>
- void prepareFreeSpace(GrowthTag tag, size_t required, size_t moveSize, It &b, It &e) {
- // Returns whether passed iterators are inside [this->begin(), this->end()]
- const auto iteratorsInRange = [&] (const It &first, const It &last) {
- using DecayedIt = std::decay_t<It>;
- using RemovedConstVolatileIt = std::remove_cv_t<It>;
- constexpr bool selfIterator =
- // if passed type is an iterator type:
- std::is_same_v<DecayedIt, iterator>
- || std::is_same_v<DecayedIt, const_iterator>
- // if passed type is a pointer type:
- || std::is_same_v<RemovedConstVolatileIt, T *>
- || std::is_same_v<RemovedConstVolatileIt, const T *>
- || std::is_same_v<RemovedConstVolatileIt, const volatile T *>;
- if constexpr (selfIterator) {
- return (first >= this->begin() && last <= this->end());
- } else {
- return false;
- }
- };
-
- const bool inRange = iteratorsInRange(b, e);
- const auto diff = prepareFreeSpace(tag, required, moveSize);
- if (inRange) {
- std::advance(b, diff);
- std::advance(e, diff);
- }
- }
-
- size_t moveSizeForAppend(size_t)
- {
- // Qt5 QList in append: make 100% free space at end if not enough space
- // Now:
- return this->freeSpaceAtBegin();
- }
-
- size_t moveSizeForPrepend(size_t required)
- {
- // Qt5 QList in prepend: make 33% of all space at front if not enough space
- // Now:
- qsizetype space = this->allocatedCapacity() / 3;
- space = qMax(space, qsizetype(required)); // in case required > 33% of all space
- return qMin(space, this->freeSpaceAtEnd());
- }
-
- // Helper functions that reduce usage boilerplate
- void prepareSpaceForAppend(size_t required)
- {
- prepareFreeSpace(GrowsForwardTag{}, required, moveSizeForAppend(required));
- }
- void prepareSpaceForPrepend(size_t required)
- {
- prepareFreeSpace(GrowsBackwardsTag{}, required, moveSizeForPrepend(required));
- }
- template<typename It>
- void prepareSpaceForAppend(It &b, It &e, size_t required)
- {
- prepareFreeSpace(GrowsForwardTag{}, required, moveSizeForAppend(required), b, e);
- }
- template<typename It>
- void prepareSpaceForPrepend(It &b, It &e, size_t required)
- {
- prepareFreeSpace(GrowsBackwardsTag{}, required, moveSizeForPrepend(required), b, e);
- }
-
- // Tells how much of the given size to insert at the beginning of the
- // container. This is insert-specific helper function
- qsizetype sizeToInsertAtBegin(const T *const where, qsizetype maxSize)
- {
- Q_ASSERT(size_t(maxSize) <= this->allocatedCapacity() - this->size);
- Q_ASSERT(where >= this->begin() && where <= this->end()); // in range
-
- const auto freeAtBegin = this->freeSpaceAtBegin();
- const auto freeAtEnd = this->freeSpaceAtEnd();
-
- // Idea: * if enough space on both sides, try to affect less elements
- // * if enough space on one of the sides, use only that side
- // * otherwise, split between front and back (worst case)
- if (freeAtBegin >= maxSize && freeAtEnd >= maxSize) {
- if (where - this->begin() < this->end() - where) {
- return maxSize;
- } else {
- return 0;
- }
- } else if (freeAtBegin >= maxSize) {
- return maxSize;
- } else if (freeAtEnd >= maxSize) {
- return 0;
- } else {
- return maxSize - freeAtEnd;
- }
- }
-
public:
- // Returns whether reallocation is desirable before adding more elements
- // into the container. This is a helper function that one can use to
- // theoretically improve average operations performance. Ignoring this
- // function does not affect the correctness of the array operations.
- bool shouldGrowBeforeInsert(const_iterator where, qsizetype n) const noexcept
- {
- if (this->d == nullptr)
- return true;
- if (this->d->flags & QArrayData::CapacityReserved)
- return false;
- if (!(this->d->flags & (QArrayData::GrowsForward | QArrayData::GrowsBackwards)))
- return false;
- Q_ASSERT(where >= this->begin() && where <= this->end()); // in range
-
- const qsizetype freeAtBegin = this->freeSpaceAtBegin();
- const qsizetype freeAtEnd = this->freeSpaceAtEnd();
- const qsizetype capacity = this->constAllocatedCapacity();
-
- if (this->size > 0 && where == this->begin()) { // prepend
- // Qt5 QList in prepend: not enough space at begin && 33% full
- // Now (below):
- return freeAtBegin < n && (this->size >= (capacity / 3));
- }
-
- if (where == this->end()) { // append
- // Qt5 QList in append: not enough space at end && less than 66% free space at front
- // Now (below):
- return freeAtEnd < n && !((freeAtBegin - n) >= (2 * capacity / 3));
- }
-
- // Qt5 QList in insert: no free space
- // Now: no free space OR not enough space on either of the sides (bad perf. case)
- return (freeAtBegin + freeAtEnd) < n || (freeAtBegin < n && freeAtEnd < n);
- }
-
// using Base::truncate;
// using Base::destroyAll;
// using Base::assign;
// using Base::compare;
- void appendInitialize(size_t newSize)
- {
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->isShared());
- Q_ASSERT(newSize > size_t(this->size));
- Q_ASSERT(newSize <= this->allocatedCapacity());
-
- // Since this is mostly an initialization function, do not follow append
- // logic of space arrangement. Instead, only prepare as much free space
- // as needed for this specific operation
- const size_t n = newSize - this->size;
- prepareFreeSpace(GrowsForwardTag{}, n,
- qMin(n, size_t(this->freeSpaceAtBegin()))); // ### perf. loss
-
- Base::appendInitialize(newSize);
- }
-
- void copyAppend(const T *b, const T *e)
- {
- Q_ASSERT(this->isMutable() || b == e);
- Q_ASSERT(!this->isShared() || b == e);
- Q_ASSERT(b <= e);
- Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
-
- prepareSpaceForAppend(b, e, e - b); // ### perf. loss
- Base::insert(GrowsForwardTag{}, this->end(), b, e);
- }
-
template<typename It>
- void copyAppend(It b, It e, QtPrivate::IfIsForwardIterator<It> = true,
- QtPrivate::IfIsNotSame<std::decay_t<It>, iterator> = true,
- QtPrivate::IfIsNotSame<std::decay_t<It>, const_iterator> = true)
+ void appendIteratorRange(It b, It e, QtPrivate::IfIsForwardIterator<It> = true)
{
Q_ASSERT(this->isMutable() || b == e);
Q_ASSERT(!this->isShared() || b == e);
const qsizetype distance = std::distance(b, e);
- Q_ASSERT(distance >= 0 && size_t(distance) <= this->allocatedCapacity() - this->size);
-
- prepareSpaceForAppend(b, e, distance); // ### perf. loss
-
- T *iter = this->end();
- for (; b != e; ++iter, ++b) {
- new (iter) T(*b);
- ++this->size;
- }
- }
-
- void moveAppend(T *b, T *e)
- {
- Q_ASSERT(this->isMutable() || b == e);
- Q_ASSERT(!this->isShared() || b == e);
- Q_ASSERT(b <= e);
- Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
-
- prepareSpaceForAppend(b, e, e - b); // ### perf. loss
- Base::moveAppend(b, e);
- }
-
- void copyAppend(size_t n, parameter_type t)
- {
- Q_ASSERT(!this->isShared() || n == 0);
- Q_ASSERT(this->allocatedCapacity() - size_t(this->size) >= n);
-
- // Preserve the value, because it might be a reference to some part of the moved chunk
- T tmp(t);
- prepareSpaceForAppend(n); // ### perf. loss
- Base::insert(GrowsForwardTag{}, this->end(), n, tmp);
- }
-
- void insert(T *where, const T *b, const T *e)
- {
- Q_ASSERT(this->isMutable() || (b == e && where == this->end()));
- Q_ASSERT(!this->isShared() || (b == e && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(b <= e);
- Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
- Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
-
- if (this->size > 0 && where == this->begin()) { // prepend case - special space arrangement
- prepareSpaceForPrepend(b, e, e - b); // ### perf. loss
- Base::insert(GrowsBackwardsTag{}, this->begin(), b, e);
- return;
- } else if (where == this->end()) { // append case - special space arrangement
- copyAppend(b, e);
- return;
+ Q_ASSERT(distance >= 0 && distance <= this->allocatedCapacity() - this->size);
+ Q_UNUSED(distance);
+
+#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
+ {
+ T *iter = this->end();
+ for (; b != e; ++iter, ++b) {
+ new (iter) T(*b);
+ ++this->size;
+ }
}
-
- // Insert elements based on the divided distance. Good case: only 1
- // insert happens (either to the front part or to the back part). Bad
- // case: both inserts happen, meaning that we touch all N elements in
- // the container (this should be handled "outside" by ensuring enough
- // free space by reallocating more frequently)
- const auto k = sizeToInsertAtBegin(where, e - b);
- Base::insert(GrowsBackwardsTag{}, where, b, b + k);
- Base::insert(GrowsForwardTag{}, where, b + k, e);
}
- void insert(T *where, size_t n, parameter_type t)
+ // slightly higher level API than copyAppend() that also preallocates space
+ void growAppend(const T *b, const T *e)
{
- Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(this->allocatedCapacity() - size_t(this->size) >= n);
-
- if (this->size > 0 && where == this->begin()) { // prepend case - special space arrangement
- // Preserve the value, because it might be a reference to some part of the moved chunk
- T tmp(t);
- prepareSpaceForPrepend(n); // ### perf. loss
- Base::insert(GrowsBackwardsTag{}, this->begin(), n, tmp);
- return;
- } else if (where == this->end()) { // append case - special space arrangement
- copyAppend(n, t);
+ if (b == e)
return;
- }
+ Q_ASSERT(b < e);
+ const qsizetype n = e - b;
+ DataPointer old;
- // Insert elements based on the divided distance. Good case: only 1
- // insert happens (either to the front part or to the back part). Bad
- // case: both inserts happen, meaning that we touch all N elements in
- // the container (this should be handled "outside" by ensuring enough
- // free space by reallocating more frequently)
- const auto beginSize = sizeToInsertAtBegin(where, qsizetype(n));
- Base::insert(GrowsBackwardsTag{}, where, beginSize, t);
- Base::insert(GrowsForwardTag{}, where, qsizetype(n) - beginSize, t);
+ // points into range:
+ if (QtPrivate::q_points_into_range(b, *this))
+ this->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
+ 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);
}
- template <typename iterator, typename ...Args>
- void emplace(iterator where, Args&&... args)
+ void appendUninitialized(qsizetype newSize)
{
+ Q_ASSERT(this->isMutable());
Q_ASSERT(!this->isShared());
- Q_ASSERT(where >= this->begin() && where <= this->end());
- Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
-
- // Qt5 QList in insert(1): try to move less data around
- // Now:
- const bool shouldInsertAtBegin = (where - this->begin()) < (this->end() - where)
- || this->freeSpaceAtEnd() <= 0;
- if (this->freeSpaceAtBegin() > 0 && shouldInsertAtBegin) {
- Base::emplace(GrowsBackwardsTag{}, where, std::forward<Args>(args)...);
- } else {
- Base::emplace(GrowsForwardTag{}, where, std::forward<Args>(args)...);
- }
- }
-
- template <typename ...Args>
- void emplaceBack(Args&&... args)
- {
- this->emplace(this->end(), std::forward<Args>(args)...);
- }
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
- void erase(T *b, T *e)
- {
- Q_ASSERT(this->isMutable());
- Q_ASSERT(b < e);
- Q_ASSERT(b >= this->begin() && b < this->end());
- Q_ASSERT(e > this->begin() && e <= this->end());
+ T *const b = this->begin();
+ do {
+ auto ptr = b + this->size;
- // Comply with std::vector::erase(): erased elements and all after them
- // are invalidated. However, erasing from the beginning effectively
- // means that all iterators are invalidated. We can use this freedom to
- // erase by moving towards the end.
- if (b == this->begin()) {
- Base::erase(GrowsBackwardsTag{}, b, e);
- } else {
- Base::erase(GrowsForwardTag{}, b, e);
- }
+ 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);
}
};
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index ad5acdb7fd..6657d40cf9 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QARRAYDATAPOINTER_H
#define QARRAYDATAPOINTER_H
@@ -43,6 +7,9 @@
#include <QtCore/qarraydataops.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/q20functional.h>
+#include <QtCore/q20memory.h>
+
QT_BEGIN_NAMESPACE
template <class T>
@@ -53,33 +20,46 @@ private:
typedef QArrayDataOps<T> DataOps;
public:
- typedef typename Data::iterator iterator;
- typedef typename Data::const_iterator const_iterator;
- enum { pass_parameter_by_value = std::is_fundamental<T>::value || std::is_pointer<T>::value };
+ enum {
+ pass_parameter_by_value =
+ std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_enum<T>::value
+ };
typedef typename std::conditional<pass_parameter_by_value, T, const T &>::type parameter_type;
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer() noexcept
: d(nullptr), ptr(nullptr), size(0)
{
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(const QArrayDataPointer &other) noexcept
: d(other.d), ptr(other.ptr), size(other.size)
{
ref();
}
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0) noexcept
: d(header), ptr(adata), size(n)
{
}
- explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
+ Q_NODISCARD_CTOR
+ explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
: d(adata.first), ptr(adata.second), size(n)
{
}
+ Q_NODISCARD_CTOR explicit
+ QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
+ QArrayData::AllocationOption option = QArrayData::KeepSize)
+ : QArrayDataPointer(Data::allocate(alloc, option), n)
+ {
+ }
+
+ Q_NODISCARD_CTOR
static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
{
Q_ASSERT(rawData || !length);
@@ -93,20 +73,15 @@ public:
return *this;
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(QArrayDataPointer &&other) noexcept
- : d(other.d), ptr(other.ptr), size(other.size)
+ : d(std::exchange(other.d, nullptr)),
+ ptr(std::exchange(other.ptr, nullptr)),
+ size(std::exchange(other.size, 0))
{
- other.d = nullptr;
- other.ptr = nullptr;
- other.size = 0;
}
- QArrayDataPointer &operator=(QArrayDataPointer &&other) noexcept
- {
- QArrayDataPointer moved(std::move(other));
- swap(moved);
- return *this;
- }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
DataOps &operator*() noexcept
{
@@ -132,7 +107,7 @@ public:
{
if (!deref()) {
(*this)->destroyAll();
- Data::deallocate(d);
+ free(d);
}
}
@@ -144,18 +119,18 @@ public:
T *data() noexcept { return ptr; }
const T *data() const noexcept { return ptr; }
- iterator begin(iterator = iterator()) noexcept { return data(); }
- iterator end(iterator = iterator()) noexcept { return data() + size; }
- const_iterator begin(const_iterator = const_iterator()) const noexcept { return data(); }
- const_iterator end(const_iterator = const_iterator()) const noexcept { return data() + size; }
- const_iterator constBegin(const_iterator = const_iterator()) const noexcept { return data(); }
- const_iterator constEnd(const_iterator = const_iterator()) const noexcept { return data() + size; }
+ T *begin() noexcept { return data(); }
+ T *end() noexcept { return data() + size; }
+ const T *begin() const noexcept { return data(); }
+ const T *end() const noexcept { return data() + size; }
+ const T *constBegin() const noexcept { return data(); }
+ const T *constEnd() const noexcept { return data() + size; }
void swap(QArrayDataPointer &other) noexcept
{
- qSwap(d, other.d);
- qSwap(ptr, other.ptr);
- qSwap(size, other.size);
+ qt_ptr_swap(d, other.d);
+ qt_ptr_swap(ptr, other.ptr);
+ std::swap(size, other.size);
}
void clear() noexcept(std::is_nothrow_destructible<T>::value)
@@ -164,33 +139,312 @@ public:
swap(tmp);
}
- bool detach()
+ void detach(QArrayDataPointer *old = nullptr)
+ {
+ if (needsDetach())
+ reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
+ }
+
+ /*! \internal
+
+ Reinterprets the data of this QArrayDataPointer to type X. It's the
+ caller's responsibility to ensure that the data contents are valid and
+ properly aligned, particularly if T and X are not trivial types (i.e,
+ don't do that). The current size is kept and the allocated capacity is
+ updated to account for the difference in the element type's size.
+
+ This is used in QString::fromLatin1 to perform in-place conversion of
+ QString to QByteArray.
+ */
+ template <typename X> QArrayDataPointer<X> reinterpreted() &&
+ {
+ if (sizeof(T) != sizeof(X)) {
+ Q_ASSERT(!d->isShared());
+ d->alloc = d->alloc * sizeof(T) / sizeof(X);
+ }
+ auto od = reinterpret_cast<QTypedArrayData<X> *>(std::exchange(d, nullptr));
+ auto optr = reinterpret_cast<X *>(std::exchange(ptr, nullptr));
+ return { od, optr, std::exchange(size, 0) };
+ }
+
+ /*! \internal
+
+ Detaches this (optionally) and grows to accommodate the free space for
+ \a n elements at the required side. The side is determined from \a pos.
+
+ \a data pointer can be provided when the caller knows that \a data
+ points into range [this->begin(), this->end()). In case it is, *data
+ would be updated so that it continues to point to the element it was
+ pointing to before the data move. if \a data does not point into range,
+ one can/should pass \c nullptr.
+
+ Similarly to \a data, \a old, pointer to a default-constructed QADP, can
+ be provided when the caller expects to e.g. copy the data from this to
+ itself:
+ \code
+ QList<T> list(5);
+ qsizetype pos = getArbitraryPos();
+ list.insert(pos, list.begin(), list.end());
+ \endcode
+
+ The default rule would be: \a data and \a old must either both be valid
+ pointers, or both equal to \c nullptr.
+ */
+ void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, const T **data,
+ QArrayDataPointer *old)
+ {
+ const bool detach = needsDetach();
+ bool readjusted = false;
+ if (!detach) {
+ if (!n || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
+ || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n))
+ return;
+ readjusted = tryReadjustFreeSpace(where, n, data);
+ Q_ASSERT(!readjusted
+ || (where == QArrayData::GrowsAtBeginning && freeSpaceAtBegin() >= n)
+ || (where == QArrayData::GrowsAtEnd && freeSpaceAtEnd() >= n));
+ }
+
+ if (!readjusted)
+ reallocateAndGrow(where, n, old);
+ }
+
+ /*! \internal
+
+ Reallocates to accommodate the free space for \a n elements at the
+ required side. The side is determined from \a pos. Might also shrink
+ when n < 0.
+ */
+ Q_NEVER_INLINE void reallocateAndGrow(QArrayData::GrowthPosition where, qsizetype n,
+ QArrayDataPointer *old = nullptr)
+ {
+ if constexpr (QTypeInfo<T>::isRelocatable && alignof(T) <= alignof(std::max_align_t)) {
+ if (where == QArrayData::GrowsAtEnd && !old && !needsDetach() && n > 0) {
+ (*this)->reallocate(constAllocatedCapacity() - freeSpaceAtEnd() + n, QArrayData::Grow); // fast path
+ return;
+ }
+ }
+
+ QArrayDataPointer dp(allocateGrow(*this, n, where));
+ if (n > 0)
+ Q_CHECK_PTR(dp.data());
+ if (where == QArrayData::GrowsAtBeginning) {
+ Q_ASSERT(dp.freeSpaceAtBegin() >= n);
+ } else {
+ Q_ASSERT(dp.freeSpaceAtEnd() >= n);
+ }
+ if (size) {
+ qsizetype toCopy = size;
+ if (n < 0)
+ toCopy += n;
+ if (needsDetach() || old)
+ dp->copyAppend(begin(), begin() + toCopy);
+ else
+ dp->moveAppend(begin(), begin() + toCopy);
+ Q_ASSERT(dp.size == toCopy);
+ }
+
+ swap(dp);
+ if (old)
+ old->swap(dp);
+ }
+
+ /*! \internal
+
+ Attempts to relocate [begin(), end()) to accommodate the free space for
+ \a n elements at the required side. The side is determined from \a pos.
+
+ Returns \c true if the internal data is moved. Returns \c false when
+ there is no point in moving the data or the move is impossible. If \c
+ false is returned, it is the responsibility of the caller to figure out
+ how to accommodate the free space for \a n elements at \a pos.
+
+ This function expects that certain preconditions are met, e.g. the
+ detach is not needed, n > 0 and so on. This is intentional to reduce the
+ number of if-statements when the caller knows that preconditions would
+ be satisfied.
+
+ \sa reallocateAndGrow
+ */
+ bool tryReadjustFreeSpace(QArrayData::GrowthPosition pos, qsizetype n, const T **data = nullptr)
+ {
+ Q_ASSERT(!this->needsDetach());
+ Q_ASSERT(n > 0);
+ Q_ASSERT((pos == QArrayData::GrowsAtEnd && this->freeSpaceAtEnd() < n)
+ || (pos == QArrayData::GrowsAtBeginning && this->freeSpaceAtBegin() < n));
+
+ const qsizetype capacity = this->constAllocatedCapacity();
+ const qsizetype freeAtBegin = this->freeSpaceAtBegin();
+ const qsizetype freeAtEnd = this->freeSpaceAtEnd();
+
+ qsizetype dataStartOffset = 0;
+ // algorithm:
+ // a. GrowsAtEnd: relocate if space at begin AND size < (capacity * 2) / 3
+ // [all goes to free space at end]:
+ // new free space at begin = 0
+ //
+ // b. GrowsAtBeginning: relocate if space at end AND size < capacity / 3
+ // [balance the free space]:
+ // new free space at begin = n + (total free space - n) / 2
+ if (pos == QArrayData::GrowsAtEnd && freeAtBegin >= n
+ && ((3 * this->size) < (2 * capacity))) {
+ // dataStartOffset = 0; - done in declaration
+ } else if (pos == QArrayData::GrowsAtBeginning && freeAtEnd >= n
+ && ((3 * this->size) < capacity)) {
+ // total free space == capacity - size
+ dataStartOffset = n + qMax(0, (capacity - this->size - n) / 2);
+ } else {
+ // nothing to do otherwise
+ return false;
+ }
+
+ relocate(dataStartOffset - freeAtBegin, data);
+
+ Q_ASSERT((pos == QArrayData::GrowsAtEnd && this->freeSpaceAtEnd() >= n)
+ || (pos == QArrayData::GrowsAtBeginning && this->freeSpaceAtBegin() >= n));
+ return true;
+ }
+
+ /*! \internal
+
+ Relocates [begin(), end()) by \a offset and updates \a data if it is not
+ \c nullptr and points into [begin(), end()).
+ */
+ void relocate(qsizetype offset, const T **data = nullptr)
+ {
+ T *res = this->ptr + offset;
+ QtPrivate::q_relocate_overlap_n(this->ptr, this->size, res);
+ // first update data pointer, then this->ptr
+ if (data && QtPrivate::q_points_into_range(*data, *this))
+ *data += offset;
+ this->ptr = res;
+ }
+
+ template <typename InputIterator, typename Projection = q20::identity>
+ void assign(InputIterator first, InputIterator last, Projection proj = {})
{
- if (needsDetach()) {
- QPair<Data *, T *> copy = clone(detachFlags());
- QArrayDataPointer old(d, ptr, size);
- d = copy.first;
- ptr = copy.second;
- return true;
+ // This function only provides the basic exception guarantee.
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag>;
+ constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
+
+ if constexpr (IsFwdIt) {
+ const qsizetype n = std::distance(first, last);
+ if (needsDetach() || n > constAllocatedCapacity()) {
+ QArrayDataPointer allocated(detachCapacity(n));
+ swap(allocated);
+ }
+ } else if (needsDetach()) {
+ QArrayDataPointer allocated(allocatedCapacity());
+ swap(allocated);
+ // We don't want to copy data that we know we'll overwrite
+ }
+
+ auto offset = freeSpaceAtBegin();
+ const auto capacityBegin = begin() - offset;
+ const auto prependBufferEnd = begin();
+
+ if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ // If construction can throw, and we have freeSpaceAtBegin(),
+ // it's easiest to just clear the container and start fresh.
+ // The alternative would be to keep track of two active, disjoint ranges.
+ if (offset) {
+ (*this)->truncate(0);
+ setBegin(capacityBegin);
+ offset = 0;
+ }
}
- return false;
+ auto dst = capacityBegin;
+ const auto dend = end();
+ if (offset) { // avoids dead stores
+ setBegin(capacityBegin); // undo prepend optimization
+
+ // By construction, the following loop is nothrow!
+ // (otherwise, we can't reach here)
+ // Assumes InputIterator operations don't throw.
+ // (but we can't statically assert that, as these operations
+ // have preconditons, so typically aren't noexcept)
+ while (true) {
+ if (dst == prependBufferEnd) { // ran out of prepend buffer space
+ size += offset;
+ // we now have a contiguous buffer, continue with the main loop:
+ break;
+ }
+ if (first == last) { // ran out of elements to assign
+ std::destroy(prependBufferEnd, dend);
+ size = dst - begin();
+ return;
+ }
+ // construct element in prepend buffer
+ q20::construct_at(dst, std::invoke(proj, *first));
+ ++dst;
+ ++first;
+ }
+ }
+
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt && IsIdentity) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else if constexpr (IsFwdIt && !IsIdentity
+ && std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ for (; first != last; ++dst, ++first) // uninitialized_copy with projection
+ q20::construct_at(dst, std::invoke(proj, *first));
+ break;
+ } else {
+ do {
+ (*this)->emplace(size, std::invoke(proj, *first));
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = std::invoke(proj, *first); // overwrite existing element
+ ++dst;
+ ++first;
+ }
+ size = dst - begin();
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
+ {
+ QArrayDataPointer result(n);
+ std::uninitialized_copy_n(begin() + pos, n, result.begin());
+ result.size = n;
+ return result;
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
+ {
+ if (needsDetach())
+ return sliced(pos, n);
+ T *newBeginning = begin() + pos;
+ std::destroy(begin(), newBeginning);
+ std::destroy(newBeginning + n, end());
+ setBegin(newBeginning);
+ size = n;
+ return std::move(*this);
}
// forwards from QArrayData
- size_t allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
- size_t constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
+ qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
+ qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
void ref() noexcept { if (d) d->ref(); }
bool deref() noexcept { return !d || d->deref(); }
bool isMutable() const noexcept { return d; }
bool isShared() const noexcept { return !d || d->isShared(); }
bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; }
bool needsDetach() const noexcept { return !d || d->needsDetach(); }
- size_t detachCapacity(size_t newSize) const noexcept { return d ? d->detachCapacity(newSize) : newSize; }
- const typename Data::ArrayOptions flags() const noexcept { return d ? typename Data::ArrayOption(d->flags) : Data::DefaultAllocationFlags; }
+ qsizetype detachCapacity(qsizetype newSize) const noexcept { return d ? d->detachCapacity(newSize) : newSize; }
+ const typename Data::ArrayOptions flags() const noexcept { return d ? d->flags : Data::ArrayOptionDefault; }
void setFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags |= f; }
- void clearFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags &= ~f; }
- typename Data::ArrayOptions detachFlags() const noexcept { return d ? d->detachFlags() : Data::DefaultAllocationFlags; }
+ void clearFlag(typename Data::ArrayOptions f) noexcept { if (d) d->flags &= ~f; }
Data *d_ptr() noexcept { return d; }
void setBegin(T *begin) noexcept { ptr = begin; }
@@ -209,75 +463,50 @@ public:
return d->constAllocatedCapacity() - freeSpaceAtBegin() - this->size;
}
- static QArrayDataPointer allocateGrow(const QArrayDataPointer &from,
- qsizetype newSize, QArrayData::ArrayOptions options)
+ // allocate and grow. Ensure that at the minimum requiredSpace is available at the requested end
+ static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
{
- return allocateGrow(from, from.detachCapacity(newSize), newSize, options);
- }
-
- static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype capacity,
- qsizetype newSize, QArrayData::ArrayOptions options)
- {
- auto [header, dataPtr] = Data::allocate(capacity, options);
+ // calculate new capacity. We keep the free capacity at the side that does not have to grow
+ // to avoid quadratic behavior with mixed append/prepend cases
+
+ // use qMax below, because constAllocatedCapacity() can be 0 when using fromRawData()
+ qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n;
+ // subtract the free space at the side we want to allocate. This ensures that the total size requested is
+ // the existing allocation at the other side + size + n.
+ minimalCapacity -= (position == QArrayData::GrowsAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin();
+ qsizetype capacity = from.detachCapacity(minimalCapacity);
+ const bool grows = capacity > from.constAllocatedCapacity();
+ auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize);
const bool valid = header != nullptr && dataPtr != nullptr;
- const bool grows = (options & (Data::GrowsForward | Data::GrowsBackwards));
- if (!valid || !grows)
+ if (!valid)
return QArrayDataPointer(header, dataPtr);
- // when growing, special rules apply to memory layout
-
- if (from.needsDetach()) {
- // When detaching: the free space reservation is biased towards
- // append as in Qt5 QList. If we're growing backwards, put the data
- // in the middle instead of at the end - assuming that prepend is
- // uncommon and even initial prepend will eventually be followed by
- // at least some appends.
- if (options & Data::GrowsBackwards)
- dataPtr += (header->alloc - newSize) / 2;
- } else {
- // When not detaching: fake ::realloc() policy - preserve existing
- // free space at beginning.
- dataPtr += from.freeSpaceAtBegin();
- }
+ // Idea: * when growing backwards, adjust pointer to prepare free space at the beginning
+ // * when growing forward, adjust by the previous data pointer offset
+ dataPtr += (position == QArrayData::GrowsAtBeginning)
+ ? n + qMax(0, (header->alloc - from.size - n) / 2)
+ : from.freeSpaceAtBegin();
+ header->flags = from.flags();
return QArrayDataPointer(header, dataPtr);
}
-private:
- Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const
+ friend bool operator==(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
{
- QPair<Data *, T *> pair = Data::allocate(detachCapacity(size), options);
- QArrayDataPointer copy(pair.first, pair.second, 0);
- if (size)
- copy->copyAppend(begin(), end());
-
- pair.first = copy.d;
- copy.d = nullptr;
- copy.ptr = nullptr;
- return pair;
+ return lhs.data() == rhs.data() && lhs.size == rhs.size;
+ }
+
+ friend bool operator!=(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
+ {
+ return lhs.data() != rhs.data() || lhs.size != rhs.size;
}
-protected:
Data *d;
T *ptr;
-
-public:
qsizetype size;
};
template <class T>
-inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) noexcept
-{
- return lhs.data() == rhs.data() && lhs.size == rhs.size;
-}
-
-template <class T>
-inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) noexcept
-{
- return lhs.data() != rhs.data() || lhs.size != rhs.size;
-}
-
-template <class T>
-inline void qSwap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
+inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
{
p1.swap(p2);
}
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 9bcd6a9306..e311fee51f 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2019 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// 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
@@ -110,6 +77,7 @@ QT_BEGIN_NAMESPACE
\sa QByteArray, QList
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
\fn QBitArray::QBitArray(QBitArray &&other)
@@ -118,6 +86,7 @@ QT_BEGIN_NAMESPACE
\since 5.2
*/
+#endif
/*! \fn QBitArray::QBitArray()
@@ -137,35 +106,52 @@ QT_BEGIN_NAMESPACE
* *d.constData() is the QByteArray's terminating NUL (0) byte.
*
* This allows for fast calculation of the bit array size:
- * inline int size() const { return (d.size() << 3) - *d.constData(); }
+ * 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(int size, bool value)
- : d(size <= 0 ? 0 : 1 + (size + 7)/8, Qt::Uninitialized)
+QBitArray::QBitArray(qsizetype size, bool value)
+ : 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 int QBitArray::size() const
+/*! \fn qsizetype QBitArray::size() const
Returns the number of bits stored in the bit array.
\sa resize()
*/
-/*! \fn int QBitArray::count() const
+/*! \fn qsizetype QBitArray::count() const
Same as size().
*/
@@ -175,9 +161,9 @@ QBitArray::QBitArray(int size, bool value)
1-bits stored in the bit array; otherwise the number
of 0-bits is returned.
*/
-int QBitArray::count(bool on) const
+qsizetype QBitArray::count(bool on) const
{
- int numBits = 0;
+ qsizetype numBits = 0;
const quint8 *bits = reinterpret_cast<const quint8 *>(d.data()) + 1;
// the loops below will try to read from *end
@@ -187,20 +173,20 @@ int QBitArray::count(bool on) const
while (bits + 7 <= end) {
quint64 v = qFromUnaligned<quint64>(bits);
bits += 8;
- numBits += int(qPopulationCount(v));
+ numBits += qsizetype(qPopulationCount(v));
}
if (bits + 3 <= end) {
quint32 v = qFromUnaligned<quint32>(bits);
bits += 4;
- numBits += int(qPopulationCount(v));
+ numBits += qsizetype(qPopulationCount(v));
}
if (bits + 1 < end) {
quint16 v = qFromUnaligned<quint16>(bits);
bits += 2;
- numBits += int(qPopulationCount(v));
+ numBits += qsizetype(qPopulationCount(v));
}
if (bits < end)
- numBits += int(qPopulationCount(bits[0]));
+ numBits += qsizetype(qPopulationCount(bits[0]));
return on ? numBits : size() - numBits;
}
@@ -217,19 +203,14 @@ int QBitArray::count(bool on) const
\sa size()
*/
-void QBitArray::resize(int size)
+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 {
- int 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);
}
}
@@ -256,7 +237,7 @@ void QBitArray::resize(int size)
\sa isEmpty()
*/
-/*! \fn bool QBitArray::fill(bool value, int size = -1)
+/*! \fn bool QBitArray::fill(bool value, qsizetype size = -1)
Sets every bit in the bit array to \a value, returning true if successful;
otherwise returns \c false. If \a size is different from -1 (the default),
@@ -285,15 +266,15 @@ void QBitArray::resize(int size)
\snippet code/src_corelib_tools_qbitarray.cpp 15
*/
-void QBitArray::fill(bool value, int begin, int end)
+void QBitArray::fill(bool value, qsizetype begin, qsizetype end)
{
while (begin < end && begin & 0x7)
setBit(begin++, value);
- int len = end - begin;
+ qsizetype len = end - begin;
if (len <= 0)
return;
- int s = len & ~0x7;
- uchar *c = reinterpret_cast<uchar*>(d.data());
+ qsizetype s = len & ~qsizetype(0x7);
+ uchar *c = reinterpret_cast<uchar *>(d.data());
memset(c + (begin >> 3) + 1, value ? 0xff : 0, s >> 3);
begin += s;
while (begin < end)
@@ -325,20 +306,15 @@ void QBitArray::fill(bool value, int begin, int 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;
}
@@ -391,7 +367,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa resize(), isEmpty()
*/
-/*! \fn void QBitArray::truncate(int pos)
+/*! \fn void QBitArray::truncate(qsizetype pos)
Truncates the bit array at index position \a pos.
@@ -400,7 +376,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa resize()
*/
-/*! \fn bool QBitArray::toggleBit(int i)
+/*! \fn bool QBitArray::toggleBit(qsizetype i)
Inverts the value of the bit at index position \a i, returning the
previous value of that bit as either true (if it was set) or false (if
@@ -415,7 +391,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa setBit(), clearBit()
*/
-/*! \fn bool QBitArray::testBit(int i) const
+/*! \fn bool QBitArray::testBit(qsizetype i) const
Returns \c true if the bit at index position \a i is 1; otherwise
returns \c false.
@@ -426,7 +402,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa setBit(), clearBit()
*/
-/*! \fn bool QBitArray::setBit(int i)
+/*! \fn bool QBitArray::setBit(qsizetype i)
Sets the bit at index position \a i to 1.
@@ -436,14 +412,14 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa clearBit(), toggleBit()
*/
-/*! \fn void QBitArray::setBit(int i, bool value)
+/*! \fn void QBitArray::setBit(qsizetype i, bool value)
\overload
Sets the bit at index position \a i to \a value.
*/
-/*! \fn void QBitArray::clearBit(int i)
+/*! \fn void QBitArray::clearBit(qsizetype i)
Sets the bit at index position \a i to 0.
@@ -453,7 +429,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa setBit(), toggleBit()
*/
-/*! \fn bool QBitArray::at(int i) const
+/*! \fn bool QBitArray::at(qsizetype i) const
Returns the value of the bit at index position \a i.
@@ -463,7 +439,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa operator[]()
*/
-/*! \fn QBitRef QBitArray::operator[](int i)
+/*! \fn QBitRef QBitArray::operator[](qsizetype i)
Returns the bit at index position \a i as a modifiable reference.
@@ -484,22 +460,13 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa at(), testBit(), setBit(), clearBit()
*/
-/*! \fn bool QBitArray::operator[](int i) const
-
- \overload
-*/
-
-/*! \fn QBitRef QBitArray::operator[](uint i)
-
- \overload
-*/
-
-/*! \fn bool QBitArray::operator[](uint i) const
+/*! \fn bool QBitArray::operator[](qsizetype i) const
\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.
@@ -511,7 +478,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.
@@ -523,6 +490,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
@@ -547,7 +515,129 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\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.
@@ -562,21 +652,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;
- int n = other.d.size() -1 ;
- int 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.
@@ -591,18 +680,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;
- int 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.
@@ -617,20 +708,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;
- int 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
@@ -638,24 +729,42 @@ QBitArray &QBitArray::operator^=(const QBitArray &other)
\sa operator&(), operator|(), operator^()
*/
-QBitArray QBitArray::operator~() const
+Q_NEVER_INLINE QBitArray QBitArray::inverted_inplace() &&
{
- int sz = size();
- QBitArray a(sz);
- const uchar *a1 = reinterpret_cast<const uchar *>(d.constData()) + 1;
- uchar *a2 = reinterpret_cast<uchar*>(a.d.data()) + 1;
- int 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.
@@ -672,13 +781,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.
@@ -695,13 +807,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.
@@ -718,8 +833,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;
}
@@ -735,7 +850,7 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
It is not for use in any other context.
*/
-/*! \fn QBitRef::QBitRef (QBitArray& a, int i)
+/*! \fn QBitRef::QBitRef (QBitArray& a, qsizetype i)
Constructs a reference to element \a i in the QBitArray \a a.
This is what QBitArray::operator[] constructs its return value
@@ -764,7 +879,6 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
Sets the value referenced by the QBitRef to \a v.
*/
-
/*****************************************************************************
QBitArray stream functions
*****************************************************************************/
@@ -780,10 +894,18 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
QDataStream &operator<<(QDataStream &out, const QBitArray &ba)
{
- quint32 len = ba.size();
- out << len;
+ const qsizetype len = ba.size();
+ if (out.version() < QDataStream::Qt_6_0) {
+ if (Q_UNLIKELY(len > qsizetype{(std::numeric_limits<qint32>::max)()})) {
+ out.setStatus(QDataStream::Status::SizeLimitExceeded);
+ return out;
+ }
+ out << quint32(len);
+ } else {
+ out << quint64(len);
+ }
if (len > 0)
- out.writeRawData(ba.d.constData() + 1, ba.d.size() - 1);
+ out.writeRawData(ba.d.data() + 1, ba.d.size() - 1);
return out;
}
@@ -798,19 +920,35 @@ QDataStream &operator<<(QDataStream &out, const QBitArray &ba)
QDataStream &operator>>(QDataStream &in, QBitArray &ba)
{
ba.clear();
- quint32 len;
- in >> len;
+ qsizetype len;
+ 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) {
ba.clear();
return in;
}
- const quint32 Step = 8 * 1024 * 1024;
- quint32 totalBytes = (len + 7) / 8;
- quint32 allocated = 0;
+ const qsizetype Step = 8 * 1024 * 1024;
+ const qsizetype totalBytes = storage_size(len);
+ qsizetype allocated = 0;
while (allocated < totalBytes) {
- int blockSize = qMin(Step, totalBytes - allocated);
+ qsizetype blockSize = qMin(Step, totalBytes - allocated);
ba.d.resize(allocated + blockSize + 1);
if (in.readRawData(ba.d.data() + 1 + allocated, blockSize) != blockSize) {
ba.clear();
@@ -820,14 +958,13 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
allocated += blockSize;
}
- int 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
@@ -837,7 +974,7 @@ QDebug operator<<(QDebug dbg, const QBitArray &array)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QBitArray(";
- for (int i = 0; i < array.size();) {
+ for (qsizetype i = 0; i < array.size();) {
if (array.testBit(i))
dbg << '1';
else
diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h
index 25c95bc2a5..4f99e693eb 100644
--- a/src/corelib/tools/qbitarray.h
+++ b/src/corelib/tools/qbitarray.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) 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
@@ -44,65 +8,122 @@
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(int size, bool val = false);
- QBitArray(const QBitArray &other) : d(other.d) {}
- inline QBitArray &operator=(const QBitArray &other) { d = other.d; return *this; }
+ explicit QBitArray(qsizetype size, bool val = false);
+ // 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)) {}
- inline QBitArray &operator=(QBitArray &&other) noexcept
- { qSwap(d, other.d); return *this; }
+ 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 int size() const { return (d.size() << 3) - *d.constData(); }
- inline int count() const { return (d.size() << 3) - *d.constData(); }
- int count(bool on) const;
+ 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(); }
inline bool isNull() const { return d.isNull(); }
- void resize(int size);
+ void resize(qsizetype size);
inline void detach() { d.detach(); }
inline bool isDetached() const { return d.isDetached(); }
inline void clear() { d.clear(); }
- bool testBit(int i) const;
- void setBit(int i);
- void setBit(int i, bool val);
- void clearBit(int i);
- bool toggleBit(int i);
-
- bool at(int i) const;
- QBitRef operator[](int i);
- bool operator[](int i) const;
- QBitRef operator[](uint i);
- bool operator[](uint i) const;
-
- QBitArray& operator&=(const QBitArray &);
- QBitArray& operator|=(const QBitArray &);
- QBitArray& operator^=(const QBitArray &);
- QBitArray operator~() 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; }
+ inline bool operator==(const QBitArray &other) const { return d == other.d; }
+ inline bool operator!=(const QBitArray &other) const { return d != other.d; }
- inline bool fill(bool val, int size = -1);
- void fill(bool val, int first, int last);
+ 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(int pos) { if (pos < size()) resize(pos); }
+ inline void truncate(qsizetype pos) { if (pos < size()) resize(pos); }
const char *bits() const { return isEmpty() ? nullptr : d.constData() + 1; }
static QBitArray fromBits(const char *data, qsizetype len);
@@ -112,58 +133,26 @@ 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, int 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(int i) const
-{ Q_ASSERT(uint(i) < uint(size()));
- return (*(reinterpret_cast<const uchar*>(d.constData())+1+(i>>3)) & (1 << (i & 7))) != 0; }
-
-inline void QBitArray::setBit(int i)
-{ Q_ASSERT(uint(i) < uint(size()));
- *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) |= uchar(1 << (i & 7)); }
-
-inline void QBitArray::clearBit(int i)
-{ Q_ASSERT(uint(i) < uint(size()));
- *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) &= ~uchar(1 << (i & 7)); }
-
-inline void QBitArray::setBit(int i, bool val)
-{ if (val) setBit(i); else clearBit(i); }
-
-inline bool QBitArray::toggleBit(int i)
-{ Q_ASSERT(uint(i) < uint(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[](int i) const { return testBit(i); }
-inline bool QBitArray::operator[](uint i) const { return testBit(i); }
-inline bool QBitArray::at(int i) const { return testBit(i); }
-
-class Q_CORE_EXPORT QBitRef
+class QT6_ONLY(Q_CORE_EXPORT) QBitRef
{
private:
- QBitArray& a;
- int i;
- inline QBitRef(QBitArray& array, int idx) : a(array), i(idx) {}
+ QBitArray &a;
+ qsizetype i;
+ inline QBitRef(QBitArray &array, qsizetype idx) : a(array), i(idx) { }
friend class QBitArray;
+
public:
inline operator bool() const { return a.testBit(i); }
inline bool operator!() const { return !a.testBit(i); }
- QBitRef& operator=(const QBitRef& val) { a.setBit(i, val); return *this; }
- QBitRef& operator=(bool val) { a.setBit(i, val); return *this; }
+ QBitRef &operator=(const QBitRef &val) { a.setBit(i, val); return *this; }
+ QBitRef &operator=(bool val) { a.setBit(i, val); return *this; }
};
-inline QBitRef QBitArray::operator[](int i)
+QBitRef QBitArray::operator[](qsizetype i)
{ Q_ASSERT(i >= 0); return QBitRef(*this, i); }
-inline QBitRef QBitArray::operator[](uint i)
-{ return QBitRef(*this, i); }
-
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &);
diff --git a/src/corelib/tools/qcache.h b/src/corelib/tools/qcache.h
index fbfa2ab997..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
@@ -48,11 +12,12 @@ QT_BEGIN_NAMESPACE
template <class Key, class T>
class QCache
{
- struct Value {
+ struct Value
+ {
T *t = nullptr;
- int cost = 0;
+ qsizetype cost = 0;
Value() noexcept = default;
- Value(T *tt, int c) noexcept
+ Value(T *tt, qsizetype c) noexcept
: t(tt), cost(c)
{}
Value(Value &&other) noexcept
@@ -63,24 +28,25 @@ 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; }
+
private:
Q_DISABLE_COPY(Value)
};
- struct Chain {
- Chain() noexcept
- : prev(this), next(this)
- {}
+ struct Chain
+ {
+ Chain() noexcept : prev(this), next(this) { }
Chain *prev;
Chain *next;
};
- struct Node : public Chain {
+ struct Node : public Chain
+ {
using KeyType = Key;
using ValueType = Value;
@@ -99,31 +65,14 @@ class QCache
value(std::move(t))
{
}
- static void createInPlace(Node *n, const Key &k, T *o, int cost)
+ static void createInPlace(Node *n, const Key &k, T *o, qsizetype cost)
{
new (n) Node{ Key(k), Value(o, cost) };
}
- void emplace(T *o, int cost)
+ void emplace(T *o, qsizetype cost)
{
value = Value(o, cost);
}
- static Node create(const Key &k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key> && std::is_nothrow_move_assignable_v<T>)
- {
- return Node(k, std::move(t));
- }
- void replace(const Value &t) noexcept(std::is_nothrow_assignable_v<T, 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),
@@ -143,8 +92,8 @@ class QCache
mutable Chain chain;
Data d;
- int mx = 0;
- int total = 0;
+ qsizetype mx = 0;
+ qsizetype total = 0;
void unlink(Node *n) noexcept(std::is_nothrow_destructible_v<Node>)
{
@@ -153,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;
@@ -175,13 +126,11 @@ class QCache
return n->value.t;
}
- void trim(int m) noexcept(std::is_nothrow_destructible_v<Node>)
+ 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);
}
}
@@ -189,31 +138,38 @@ class QCache
Q_DISABLE_COPY(QCache)
public:
- inline explicit QCache(int maxCost = 100) noexcept
+ inline explicit QCache(qsizetype maxCost = 100) noexcept
: mx(maxCost)
- {}
- inline ~QCache() { clear(); }
+ {
+ }
+ inline ~QCache()
+ {
+ static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
- inline int maxCost() const noexcept { return mx; }
- void setMaxCost(int m) noexcept(std::is_nothrow_destructible_v<Node>)
+ clear();
+ }
+
+ inline qsizetype maxCost() const noexcept { return mx; }
+ void setMaxCost(qsizetype m) noexcept(std::is_nothrow_destructible_v<Node>)
{
mx = m;
trim(mx);
}
- inline int totalCost() const noexcept { return total; }
+ inline qsizetype totalCost() const noexcept { return total; }
- inline qsizetype size() const noexcept { return d.size; }
- inline qsizetype count() const noexcept { return d.size; }
+ inline qsizetype size() const noexcept { return qsizetype(d.size); }
+ inline qsizetype count() const noexcept { return qsizetype(d.size); }
inline bool isEmpty() const noexcept { return !d.size; }
inline QList<Key> keys() const
{
QList<Key> k;
- if (d.size) {
- k.reserve(typename QList<Key>::size_type(d.size));
+ if (size()) {
+ k.reserve(size());
for (auto it = d.begin(); it != d.end(); ++it)
k << it.node()->key;
}
- Q_ASSERT(k.size() == qsizetype(d.size));
+ Q_ASSERT(k.size() == size());
return k;
}
@@ -225,11 +181,10 @@ public:
chain.prev = &chain;
}
- bool insert(const Key &key, T *object, int cost = 1)
+ bool insert(const Key &key, T *object, qsizetype cost = 1)
{
- remove(key);
-
if (cost > mx) {
+ remove(key);
delete object;
return false;
}
@@ -237,16 +192,18 @@ public:
auto result = d.findOrInsert(key);
Node *n = result.it.node();
if (result.initialized) {
- cost -= n->value.cost;
+ auto prevCost = n->value.cost;
result.it.node()->emplace(object, cost);
+ cost -= prevCost;
+ relink(key);
} else {
Node::createInPlace(n, key, object, cost);
+ n->prev = &chain;
+ n->next = chain.next;
+ chain.next->prev = n;
+ chain.next = n;
}
total += cost;
- n->prev = &chain;
- n->next = chain.next;
- chain.next->prev = n;
- chain.next = n;
return true;
}
T *object(const Key &key) const noexcept
@@ -259,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;
@@ -275,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 ffc21318f4..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
@@ -80,7 +56,7 @@
\sa QPixmapCache, QHash, QMap
*/
-/*! \fn template <class Key, class T> QCache<Key, T>::QCache(int maxCost = 100)
+/*! \fn template <class Key, class T> QCache<Key, T>::QCache(qsizetype maxCost = 100)
Constructs a cache whose contents will never have a total cost
greater than \a maxCost.
@@ -91,14 +67,14 @@
Destroys the cache. Deletes all the objects in the cache.
*/
-/*! \fn template <class Key, class T> int QCache<Key, T>::maxCost() const
+/*! \fn template <class Key, class T> qsizetype QCache<Key, T>::maxCost() const
Returns the maximum allowed total cost of the cache.
\sa setMaxCost(), totalCost()
*/
-/*! \fn template <class Key, class T> void QCache<Key, T>::setMaxCost(int cost)
+/*! \fn template <class Key, class T> void QCache<Key, T>::setMaxCost(qsizetype cost)
Sets the maximum allowed total cost of the cache to \a cost. If
the current total cost is greater than \a cost, some objects are
@@ -107,7 +83,7 @@
\sa maxCost(), totalCost()
*/
-/*! \fn template <class Key, class T> int QCache<Key, T>::totalCost() const
+/*! \fn template <class Key, class T> qsizetype QCache<Key, T>::totalCost() const
Returns the total cost of the objects in the cache.
@@ -120,14 +96,14 @@
\sa setMaxCost()
*/
-/*! \fn template <class Key, class T> int QCache<Key, T>::size() const
+/*! \fn template <class Key, class T> qsizetype QCache<Key, T>::size() const
Returns the number of objects in the cache.
\sa isEmpty()
*/
-/*! \fn template <class Key, class T> int QCache<Key, T>::count() const
+/*! \fn template <class Key, class T> qsizetype QCache<Key, T>::count() const
Same as size().
*/
@@ -153,7 +129,7 @@
*/
-/*! \fn template <class Key, class T> bool QCache<Key, T>::insert(const Key &key, T *object, int cost = 1)
+/*! \fn template <class Key, class T> bool QCache<Key, T>::insert(const Key &key, T *object, qsizetype cost = 1)
Inserts \a object into the cache with key \a key and
associated cost \a cost. Any object with the same key already in
diff --git a/src/corelib/tools/qcommandlineoption.cpp b/src/corelib/tools/qcommandlineoption.cpp
index 60ae7ed0da..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;
@@ -286,8 +248,7 @@ QStringList QCommandLineOptionPrivate::removeInvalidNames(QStringList nameList)
if (Q_UNLIKELY(nameList.isEmpty()))
qWarning("QCommandLineOption: Options must have at least one name");
else
- nameList.erase(std::remove_if(nameList.begin(), nameList.end(), IsInvalidName()),
- nameList.end());
+ nameList.removeIf(IsInvalidName());
return nameList;
}
diff --git a/src/corelib/tools/qcommandlineoption.h b/src/corelib/tools/qcommandlineoption.h
index 6de9a31aea..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
@@ -72,10 +36,10 @@ public:
~QCommandLineOption();
QCommandLineOption &operator=(const QCommandLineOption &other);
- QCommandLineOption &operator=(QCommandLineOption &&other) noexcept { swap(other); return *this; }
+ 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 1b93fb84cf..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;
@@ -126,7 +93,7 @@ public:
//! True if parse() needs to be called
bool needsParsing;
};
-Q_DECLARE_TYPEINFO(QCommandLineParserPrivate::PositionalArgumentDefinition, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QCommandLineParserPrivate::PositionalArgumentDefinition, Q_RELOCATABLE_TYPE);
QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
{
@@ -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;
@@ -1125,44 +1105,46 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
const QLatin1Char nl('\n');
QString text;
QString usage;
- usage += QCoreApplication::instance()->arguments().constFirst(); // executable name
+ // executable name
+ usage += qApp ? QStringView(QCoreApplication::arguments().constFirst())
+ : QStringView(u"<executable_name>");
QList<QCommandLineOption> options = commandLineOptionList;
- if (includeQtOptions)
- QCoreApplication::instance()->d_func()->addQtOptions(&options);
+ 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;
+ text += description + nl;
text += nl;
if (!options.isEmpty())
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 575cd1def9..d5590553fa 100644
--- a/src/corelib/tools/qcontainerfwd.h
+++ b/src/corelib/tools/qcontainerfwd.h
@@ -1,76 +1,64 @@
-/****************************************************************************
-**
-** 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 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/qglobal.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 <tuple>
-#include <variant>
+#include <cstddef> // std::size_t
+#include <utility>
+#include <limits>
QT_BEGIN_NAMESPACE
-template <class Key, class T> class QCache;
-template <class Key, class T> class QHash;
-template <class Key, class T> class QMap;
-template <class Key, class T> class QMultiHash;
-template <class Key, class T> class QMultiMap;
+template <typename Key, typename T> class QCache;
+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>;
-template <class T> class QQueue;
-template <class T> class QSet;
-template <class T> class QStack;
-template<class T, qsizetype Prealloc = 256> class QVarLengthArray;
-template <class T> class QList;
+#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;
+constexpr qsizetype QVarLengthArrayDefaultPrealloc = 256;
+template <typename T, qsizetype Prealloc = QVarLengthArrayDefaultPrealloc> class QVarLengthArray;
+template <typename T> class QList;
+class QString;
+#ifndef Q_QDOC
template<typename T> using QVector = QList<T>;
-#ifndef Q_CLANG_QDOC
using QStringList = QList<QString>;
+class QByteArray;
using QByteArrayList = QList<QByteArray>;
#else
+template<typename T> class QVector;
class QStringList;
class QByteArrayList;
#endif
class QMetaType;
class QVariant;
+using QVariantList = QList<QVariant>;
+using QVariantMap = QMap<QString, QVariant>;
+using QVariantHash = QHash<QString, QVariant>;
+using QVariantPair = std::pair<QVariant, QVariant>;
+
+namespace QtPrivate
+{
+[[maybe_unused]]
+constexpr qsizetype MaxAllocSize = (std::numeric_limits<qsizetype>::max)();
+}
+
QT_END_NAMESPACE
#endif // QCONTAINERFWD_H
diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h
index caac5a07e8..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,31 +14,252 @@
#include <QtCore/qglobal.h>
#include <QtCore/qtypeinfo.h>
+#include <QtCore/qxptype_traits.h>
+
#include <cstring>
#include <iterator>
#include <memory>
+#include <algorithm>
QT_BEGIN_NAMESPACE
namespace QtPrivate
{
+/*!
+ \internal
+
+ Returns whether \a p is within a range [b, e). In simplest form equivalent to:
+ b <= p < e.
+*/
+template<typename T, typename Cmp = std::less<>>
+static constexpr bool q_points_into_range(const T *p, const T *b, const T *e,
+ Cmp less = {}) noexcept
+{
+ 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)
+{
+ // requires: [first, n) is a valid range
+ // requires: d_first + n is reachable from d_first
+ // requires: iterator is at least a random access iterator
+ // requires: value_type(iterator) has a non-throwing destructor
+
+ Q_ASSERT(n);
+ Q_ASSERT(d_first < first); // only allow moves to the "left"
+ using T = typename std::iterator_traits<iterator>::value_type;
+
+ // Watches passed iterator. Unless commit() is called, all the elements that
+ // the watched iterator passes through are deleted at the end of object
+ // lifetime. freeze() could be used to stop watching the passed iterator and
+ // remain at current place.
+ //
+ // requires: the iterator is expected to always point to an invalid object
+ // (to uninitialized memory)
+ struct Destructor
+ {
+ iterator *iter;
+ iterator end;
+ iterator intermediate;
+
+ Destructor(iterator &it) noexcept : iter(std::addressof(it)), end(it) { }
+ void commit() noexcept { iter = std::addressof(end); }
+ void freeze() noexcept
+ {
+ intermediate = *iter;
+ iter = std::addressof(intermediate);
+ }
+ ~Destructor() noexcept
+ {
+ for (const int step = *iter < end ? 1 : -1; *iter != end;) {
+ std::advance(*iter, step);
+ (*iter)->~T();
+ }
+ }
+ } destroyer(d_first);
+
+ const iterator d_last = d_first + n;
+ // Note: use pair and explicitly copy iterators from it to prevent
+ // accidental reference semantics instead of copy. equivalent to:
+ //
+ // auto [overlapBegin, overlapEnd] = std::minmax(d_last, first);
+ auto pair = std::minmax(d_last, first);
+
+ // overlap area between [d_first, d_first + n) and [first, first + n) or an
+ // uninitialized memory area between the two ranges
+ iterator overlapBegin = pair.first;
+ iterator overlapEnd = pair.second;
+
+ // move construct elements in uninitialized region
+ while (d_first != overlapBegin) {
+ // account for std::reverse_iterator, cannot use new(d_first) directly
+ new (std::addressof(*d_first)) T(std::move_if_noexcept(*first));
+ ++d_first;
+ ++first;
+ }
+
+ // cannot commit but have to stop - there might be an overlap region
+ // which we don't want to delete (because it's part of existing data)
+ destroyer.freeze();
+
+ // move assign elements in overlap region
+ while (d_first != d_last) {
+ *d_first = std::move_if_noexcept(*first);
+ ++d_first;
+ ++first;
+ }
+
+ Q_ASSERT(d_first == destroyer.end + n);
+ destroyer.commit(); // can commit here as ~T() below does not throw
+
+ while (first != overlapEnd)
+ (--first)->~T();
+}
+
+/*!
+ \internal
+
+ Relocates a range [first, n) to [d_first, n) taking care of potential memory
+ overlaps. This is a generic equivalent of memmove.
+
+ If an exception is thrown during the relocation, all the relocated elements
+ are destroyed and [first, n) may contain valid but unspecified values,
+ including moved-from values (basic exception safety).
+*/
+template<typename T, typename N>
+void q_relocate_overlap_n(T *first, N n, T *d_first)
+{
+ static_assert(std::is_nothrow_destructible_v<T>,
+ "This algorithm requires that T has a non-throwing destructor");
+
+ if (n == N(0) || first == d_first || first == nullptr || d_first == nullptr)
+ return;
+
+ if constexpr (QTypeInfo<T>::isRelocatable) {
+ std::memmove(static_cast<void *>(d_first), static_cast<const void *>(first), n * sizeof(T));
+ } else { // generic version has to be used
+ if (d_first < first) {
+ q_relocate_overlap_n_left_move(first, n, d_first);
+ } else { // first < d_first
+ auto rfirst = std::make_reverse_iterator(first + n);
+ auto rd_first = std::make_reverse_iterator(d_first + n);
+ q_relocate_overlap_n_left_move(rfirst, n, rd_first);
+ }
+ }
+}
+
+template <typename T>
+struct ArrowProxy
+{
+ T t;
+ T *operator->() noexcept { return &t; }
+};
template <typename Iterator>
using IfIsInputIterator = typename std::enable_if<
@@ -106,51 +291,178 @@ void reserveIfForwardIterator(Container *c, ForwardIterator f, ForwardIterator l
c->reserve(static_cast<typename Container::size_type>(std::distance(f, l)));
}
-// for detecting expression validity
-template <typename ... T>
-using void_t = void;
-
-template <typename Iterator, typename = void_t<>>
-struct AssociativeIteratorHasKeyAndValue : std::false_type
-{
-};
-
template <typename Iterator>
-struct AssociativeIteratorHasKeyAndValue<
- Iterator,
- void_t<decltype(std::declval<Iterator &>().key()),
- decltype(std::declval<Iterator &>().value())>
- >
- : std::true_type
-{
-};
-
-template <typename Iterator, typename = void_t<>, typename = void_t<>>
-struct AssociativeIteratorHasFirstAndSecond : std::false_type
-{
-};
+using KeyAndValueTest = decltype(
+ std::declval<Iterator &>().key(),
+ std::declval<Iterator &>().value()
+);
template <typename Iterator>
-struct AssociativeIteratorHasFirstAndSecond<
- Iterator,
- 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 =
typename std::enable_if<!std::is_same<T, U>::value, bool>::type;
+
+template<typename T, typename U>
+using IfIsNotConvertible = typename std::enable_if<!std::is_convertible<T, U>::value, bool>::type;
+
+template <typename Container, typename Predicate>
+auto sequential_erase_if(Container &c, Predicate &pred)
+{
+ // 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_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();
+
+ 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 &>;
+ return sequential_erase(c, CopyProxy(t));
+}
+
+template <typename Container, typename T>
+auto sequential_erase_one(Container &c, const T &t)
+{
+ const auto cend = c.cend();
+ const auto it = std::find(c.cbegin(), cend, t);
+ if (it == cend)
+ return false;
+ c.erase(it);
+ return true;
+}
+
+template <typename T, typename Predicate>
+qsizetype qset_erase_if(QSet<T> &set, Predicate &pred)
+{
+ qsizetype result = 0;
+ auto it = set.begin();
+ const auto e = set.end();
+ while (it != e) {
+ if (pred(*it)) {
+ ++result;
+ it = set.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ return result;
+}
+
+
+// Prerequisite: F is invocable on ArgTypes
+template <typename R, typename F, typename ... ArgTypes>
+struct is_invoke_result_explicitly_convertible : std::is_constructible<R, std::invoke_result_t<F, ArgTypes...>>
+{};
+
+// is_invocable_r checks for implicit conversions, but we need to check
+// for explicit conversions in remove_if. So, roll our own trait.
+template <typename R, typename F, typename ... ArgTypes>
+constexpr bool is_invocable_explicit_r_v = std::conjunction_v<
+ std::is_invocable<F, ArgTypes...>,
+ is_invoke_result_explicitly_convertible<R, F, ArgTypes...>
+>;
+
+template <typename Container, typename Predicate>
+auto associative_erase_if(Container &c, Predicate &pred)
+{
+ // we support predicates callable with either Container::iterator
+ // or with std::pair<const Key &, Value &>
+ using Iterator = typename Container::iterator;
+ using Key = typename Container::key_type;
+ using Value = typename Container::mapped_type;
+ using KeyValuePair = std::pair<const Key &, Value &>;
+
+ typename Container::size_type result = 0;
+
+ auto it = c.begin();
+ const auto e = c.end();
+ while (it != e) {
+ if constexpr (is_invocable_explicit_r_v<bool, Predicate &, Iterator &>) {
+ if (pred(it)) {
+ it = c.erase(it);
+ ++result;
+ } else {
+ ++it;
+ }
+ } else if constexpr (is_invocable_explicit_r_v<bool, Predicate &, KeyValuePair &&>) {
+ KeyValuePair p(it.key(), it.value());
+ if (pred(std::move(p))) {
+ it = c.erase(it);
+ ++result;
+ } else {
+ ++it;
+ }
+ } else {
+ static_assert(sizeof(Container) == 0, "Predicate has an incompatible signature");
+ }
+ }
+
+ return result;
+}
+
} // namespace QtPrivate
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp
index cc3510ef88..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
@@ -119,7 +85,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
See the \l{Contiguous Cache Example}{Contiguous Cache} example.
*/
-/*! \fn template<typename T> QContiguousCache<T>::QContiguousCache(int capacity)
+/*! \fn template<typename T> QContiguousCache<T>::QContiguousCache(qsizetype capacity)
Constructs a cache with the given \a capacity.
@@ -224,7 +190,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa operator==()
*/
-/*! \fn template<typename T> int QContiguousCache<T>::capacity() const
+/*! \fn template<typename T> qsizetype QContiguousCache<T>::capacity() const
Returns the number of items the cache can store before it is full.
When a cache contains a number of items equal to its capacity, adding new
@@ -233,12 +199,12 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa setCapacity(), size()
*/
-/*! \fn template<typename T> int QContiguousCache<T>::count() const
+/*! \fn template<typename T> qsizetype QContiguousCache<T>::count() const
Same as size().
*/
-/*! \fn template<typename T> int QContiguousCache<T>::size() const
+/*! \fn template<typename T> qsizetype QContiguousCache<T>::size() const
Returns the number of items contained within the cache.
@@ -260,7 +226,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa size(), capacity()
*/
-/*! \fn template<typename T> int QContiguousCache<T>::available() const
+/*! \fn template<typename T> qsizetype QContiguousCache<T>::available() const
Returns the number of items that can be added to the cache before it becomes full.
@@ -272,7 +238,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
Removes all items from the cache. The capacity is unchanged.
*/
-/*! \fn template<typename T> void QContiguousCache<T>::setCapacity(int size)
+/*! \fn template<typename T> void QContiguousCache<T>::setCapacity(qsizetype size)
Sets the capacity of the cache to the given \a size. A cache can hold a
number of items equal to its capacity. When inserting, appending or prepending
@@ -285,7 +251,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa capacity(), isFull()
*/
-/*! \fn template<typename T> const T &QContiguousCache<T>::at(int i) const
+/*! \fn template<typename T> const T &QContiguousCache<T>::at(qsizetype i) const
Returns the item at index position \a i in the cache. \a i must
be a valid index position in the cache (i.e, firstIndex() <= \a i <= lastIndex()).
@@ -299,7 +265,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa firstIndex(), lastIndex(), insert(), operator[]()
*/
-/*! \fn template<typename T> T &QContiguousCache<T>::operator[](int i)
+/*! \fn template<typename T> T &QContiguousCache<T>::operator[](qsizetype i)
Returns the item at index position \a i as a modifiable reference. If
the cache does not contain an item at the given index position \a i
@@ -314,7 +280,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa insert(), at()
*/
-/*! \fn template<typename T> const T &QContiguousCache<T>::operator[](int i) const
+/*! \fn template<typename T> const T &QContiguousCache<T>::operator[](qsizetype i) const
\overload
@@ -337,7 +303,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa append(), insert(), isFull()
*/
-/*! \fn template<typename T> void QContiguousCache<T>::insert(int i, const T &value)
+/*! \fn template<typename T> void QContiguousCache<T>::insert(qsizetype i, const T &value)
Inserts the \a value at the index position \a i. If the cache already contains
an item at \a i then that value is replaced. If \a i is either one more than
@@ -357,14 +323,14 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa prepend(), append(), isFull(), firstIndex(), lastIndex()
*/
-/*! \fn template<typename T> bool QContiguousCache<T>::containsIndex(int i) const
+/*! \fn template<typename T> bool QContiguousCache<T>::containsIndex(qsizetype i) const
Returns \c true if the cache's index range includes the given index \a i.
\sa firstIndex(), lastIndex()
*/
-/*! \fn template<typename T> int QContiguousCache<T>::firstIndex() const
+/*! \fn template<typename T> qsizetype QContiguousCache<T>::firstIndex() const
Returns the first valid index in the cache. The index will be invalid if the
cache is empty.
@@ -372,7 +338,7 @@ void QContiguousCacheData::freeData(QContiguousCacheData *data)
\sa capacity(), size(), lastIndex()
*/
-/*! \fn template<typename T> int QContiguousCache<T>::lastIndex() const
+/*! \fn template<typename T> qsizetype QContiguousCache<T>::lastIndex() const
Returns the last valid index in the cache. The index will be invalid if the cache is empty.
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 79f5e3fdb6..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
@@ -73,6 +43,8 @@ struct QContiguousCacheTypedData : public QContiguousCacheData
template<typename T>
class QContiguousCache {
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
typedef QContiguousCacheTypedData<T> Data;
Data *d;
public:
@@ -94,10 +66,10 @@ public:
inline bool isDetached() const { return d->ref.loadRelaxed() == 1; }
QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
- inline QContiguousCache<T> &operator=(QContiguousCache<T> &&other) noexcept
- { qSwap(d, other.d); return *this; }
- inline void swap(QContiguousCache<T> &other) noexcept { qSwap(d, other.d); }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QContiguousCache)
+ void swap(QContiguousCache &other) noexcept { qt_ptr_swap(d, other.d); }
+#ifndef Q_QDOC
template <typename U = T>
QTypeTraits::compare_eq_result<U> operator==(const QContiguousCache<T> &other) const
{
@@ -116,6 +88,10 @@ public:
template <typename U = T>
QTypeTraits::compare_eq_result<U> operator!=(const QContiguousCache<T> &other) const
{ return !(*this == other); }
+#else
+ bool operator==(const QContiguousCache &other) const;
+ bool operator!=(const QContiguousCache &other) const;
+#endif // Q_QDOC
inline qsizetype capacity() const {return d->alloc; }
inline qsizetype count() const { return d->count; }
@@ -210,13 +186,13 @@ void QContiguousCache<T>::setCapacity(qsizetype asize)
x->alloc = asize;
x->count = qMin(d->count, asize);
x->offset = d->offset + d->count - x->count;
- if(asize)
+ if (asize)
x->start = x->offset % x->alloc;
else
x->start = 0;
qsizetype oldcount = x->count;
- if(oldcount)
+ if (oldcount)
{
T *dest = x->array + (x->start + x->count-1) % x->alloc;
T *src = d->array + (d->start + d->count-1) % d->alloc;
@@ -357,8 +333,7 @@ void QContiguousCache<T>::prepend(T &&value)
if (d->count != d->alloc)
d->count++;
else
- if (d->count == d->alloc)
- (d->array + d->start)->~T();
+ (d->array + d->start)->~T();
new (d->array + d->start) T(std::move(value));
}
@@ -378,7 +353,6 @@ void QContiguousCache<T>::prepend(const T &value)
if (d->count != d->alloc)
d->count++;
else
- if (d->count == d->alloc)
(d->array + d->start)->~T();
new (d->array + d->start) T(value);
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index d5a6c4e5a0..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,55 +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
-/*
- These #defines replace the typedefs needed by the RFC6234 code. Normally
- the typedefs would come from from stdint.h, but since this header is not
- available on all platforms (MSVC 2008, for example), we #define them to the
- Qt equivalents.
-*/
-
-#ifdef uint64_t
-#undef uint64_t
-#endif
-
-#define uint64_t QT_PREPEND_NAMESPACE(quint64)
-
-#ifdef uint32_t
-#undef uint32_t
-#endif
-
-#define uint32_t QT_PREPEND_NAMESPACE(quint32)
-
-#ifdef uint8_t
-#undef uint8_t
-#endif
-
-#define uint8_t QT_PREPEND_NAMESPACE(quint8)
-
-#ifdef int_least16_t
-#undef int_least16_t
-#endif
-
-#define int_least16_t QT_PREPEND_NAMESPACE(qint16)
-
-// Header from rfc6234 with 1 modification:
-// sha1.h - commented out '#include <stdint.h>' on line 74
-#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'
@@ -149,21 +94,19 @@ static int SHA384_512AddLength(SHA512Context *context, unsigned int length);
// sha384-512.c - appended 'M' to the SHA224_256AddLength macro on line 304
#include "../../3rdparty/rfc6234/sha384-512.c"
-#undef uint64_t
-#undef uint32_t
-#undef uint68_t
-#undef int_least16_t
-
static inline int SHA224_256AddLength(SHA256Context *context, unsigned int length)
{
- QT_PREPEND_NAMESPACE(quint32) addTemp;
+ uint32_t addTemp;
return SHA224_256AddLengthM(context, length);
}
static inline int SHA384_512AddLength(SHA512Context *context, unsigned int length)
{
- QT_PREPEND_NAMESPACE(quint64) addTemp;
+ 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>
@@ -173,39 +116,279 @@ 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
+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 : \
+ return Size \
+ /*end*/
+ CASE(Sha1, 20);
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ CASE(Md4, 16);
+ CASE(Md5, 16);
+ CASE(Sha224, SHA224HashSize);
+ CASE(Sha256, SHA256HashSize);
+ CASE(Sha384, SHA384HashSize);
+ CASE(Sha512, SHA512HashSize);
+ CASE(Blake2s_128, 128 / 8);
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2s_160:
+ return 160 / 8;
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::Keccak_224:
+ case QCryptographicHash::Blake2s_224:
+ return 224 / 8;
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::Keccak_256:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2s_256:
+ return 256 / 8;
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::Keccak_384:
+ case QCryptographicHash::Blake2b_384:
+ return 384 / 8;
+ case QCryptographicHash::RealSha3_512:
+ case QCryptographicHash::Keccak_512:
+ case QCryptographicHash::Blake2b_512:
+ 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:
- QCryptographicHash::Algorithm method;
- union {
+ explicit QCryptographicHashPrivate(QCryptographicHash::Algorithm method) noexcept
+ : state(method), method(method)
+ {
+ }
+ ~QCryptographicHashPrivate()
+ {
+ 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;
+
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
- QByteArray 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
@@ -229,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;
@@ -241,7 +424,7 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
break;
}
- sha3Final(&copy, reinterpret_cast<BitSequence *>(result.data()));
+ sha3Final(&copy, result.data());
}
#endif
@@ -298,19 +481,30 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
\omitvalue RealSha3_256
\omitvalue RealSha3_384
\omitvalue RealSha3_512
+ \omitvalue NumAlgorithms
*/
/*!
Constructs an object that can be used to create a cryptographic hash from data using \a method.
*/
QCryptographicHash::QCryptographicHash(Algorithm method)
- : d(new QCryptographicHashPrivate)
+ : d(new QCryptographicHashPrivate{method})
{
- d->method = method;
- reset();
}
/*!
+ \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()
@@ -319,14 +513,129 @@ 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()
+void QCryptographicHash::reset() noexcept
{
- switch (d->method) {
- case Sha1:
- new (&d->sha1Context) Sha1State;
- sha1InitState(&d->sha1Context);
+ d->reset();
+}
+
+/*!
+ 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;
break;
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
default:
@@ -334,82 +643,241 @@ void QCryptographicHash::reset()
Q_UNREACHABLE();
break;
#else
- case Md4:
- new (&d->md4Context) md4_context;
- md4_init(&d->md4Context);
- break;
- case Md5:
- new (&d->md5Context) MD5Context;
- MD5Init(&d->md5Context);
- break;
- case Sha224:
- new (&d->sha224Context) SHA224Context;
- SHA224Reset(&d->sha224Context);
- break;
- case Sha256:
- new (&d->sha256Context) SHA256Context;
- SHA256Reset(&d->sha256Context);
- break;
- case Sha384:
- new (&d->sha384Context) SHA384Context;
- SHA384Reset(&d->sha384Context);
- break;
- case Sha512:
- new (&d->sha512Context) SHA512Context;
- SHA512Reset(&d->sha512Context);
- break;
- case RealSha3_224:
- case Keccak_224:
- case RealSha3_256:
- case Keccak_256:
- case RealSha3_384:
- case Keccak_384:
- case RealSha3_512:
- case Keccak_512:
- new (&d->sha3Context) SHA3Context;
- sha3Init(&d->sha3Context, hashLength(d->method) * 8);
- break;
- case Blake2b_160:
- case Blake2b_256:
- case Blake2b_384:
- case Blake2b_512:
- new (&d->blake2bContext) blake2b_state;
- blake2b_init(&d->blake2bContext, hashLength(d->method));
- break;
- case Blake2s_128:
- case Blake2s_160:
- case Blake2s_224:
- case Blake2s_256:
- new (&d->blake2sContext) blake2s_state;
- blake2s_init(&d->blake2sContext, hashLength(d->method));
+ case QCryptographicHash::Md4:
+ new (&md4Context) md4_context;
+ break;
+ case QCryptographicHash::Md5:
+ new (&md5Context) MD5Context;
+ break;
+ case QCryptographicHash::Sha224:
+ new (&sha224Context) SHA224Context;
+ break;
+ case QCryptographicHash::Sha256:
+ new (&sha256Context) SHA256Context;
+ break;
+ case QCryptographicHash::Sha384:
+ new (&sha384Context) SHA384Context;
+ break;
+ case QCryptographicHash::Sha512:
+ new (&sha512Context) 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:
+ new (&sha3Context) SHA3Context;
+ break;
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ new (&blake2bContext) blake2b_state;
+ break;
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+ new (&blake2sContext) blake2s_state;
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);
}
- d->result.clear();
+ // 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
hash.
+
+ \obsolete
+ Use the QByteArrayView overload instead.
*/
void QCryptographicHash::addData(const char *data, qsizetype length)
{
Q_ASSERT(length >= 0);
+ addData(QByteArrayView{data, length});
+}
+#endif
+
+/*!
+ Adds the characters in \a bytes to the cryptographic hash.
+
+ \note In Qt versions prior to 6.3, this function took QByteArray,
+ not QByteArrayView.
+*/
+void QCryptographicHash::addData(QByteArrayView bytes) noexcept
+{
+ d->addData(bytes);
+}
+
+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();
#if QT_POINTER_SIZE == 8
// feed the data UINT_MAX bytes at a time, as some of the methods below
// take a uint (of course, feeding more than 4G of data into the hashing
// functions will be pretty slow anyway)
- qsizetype remaining = length;
- while (remaining) {
+ for (auto remaining = length; remaining; remaining -= length, data += length) {
length = qMin(qsizetype(std::numeric_limits<uint>::max()), remaining);
- remaining -= length;
#else
{
#endif
- switch (d->method) {
- case Sha1:
- sha1Update(&d->sha1Context, (const unsigned char *)data, length);
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ sha1Update(&sha1Context, (const unsigned char *)data, length);
break;
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
default:
@@ -417,72 +885,65 @@ void QCryptographicHash::addData(const char *data, qsizetype length)
Q_UNREACHABLE();
break;
#else
- case Md4:
- md4_update(&d->md4Context, (const unsigned char *)data, length);
- break;
- case Md5:
- MD5Update(&d->md5Context, (const unsigned char *)data, length);
- break;
- case Sha224:
- SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Md4:
+ md4_update(&md4Context, (const unsigned char *)data, length);
break;
- case Sha256:
- SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Md5:
+ MD5Update(&md5Context, (const unsigned char *)data, length);
break;
- case Sha384:
- SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Sha224:
+ SHA224Input(&sha224Context, reinterpret_cast<const unsigned char *>(data), length);
break;
- case Sha512:
- SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Sha256:
+ SHA256Input(&sha256Context, reinterpret_cast<const unsigned char *>(data), length);
break;
- case RealSha3_224:
- case Keccak_224:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ case QCryptographicHash::Sha384:
+ SHA384Input(&sha384Context, reinterpret_cast<const unsigned char *>(data), length);
break;
- case RealSha3_256:
- case Keccak_256:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ case QCryptographicHash::Sha512:
+ SHA512Input(&sha512Context, reinterpret_cast<const unsigned char *>(data), length);
break;
- case RealSha3_384:
- case Keccak_384:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ 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:
+ sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
break;
- case RealSha3_512:
- case Keccak_512:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
break;
- case Blake2b_160:
- case Blake2b_256:
- case Blake2b_384:
- case Blake2b_512:
- blake2b_update(&d->blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
- break;
- case Blake2s_128:
- case Blake2s_160:
- case Blake2s_224:
- case Blake2s_256:
- blake2s_update(&d->blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+ blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
break;
#endif
+ case QCryptographicHash::NumAlgorithms:
+ Q_UNREACHABLE();
}
}
- d->result.clear();
-}
-
-/*!
- \overload addData()
-*/
-void QCryptographicHash::addData(const QByteArray &data)
-{
- addData(data.constData(), data.length());
}
+#endif // !USING_OPENSSL30
/*!
Reads the data from the open QIODevice \a device until it ends
and hashes it. Returns \c true if reading was successful.
\since 5.0
*/
-bool QCryptographicHash::addData(QIODevice* device)
+bool QCryptographicHash::addData(QIODevice *device)
+{
+ return d->addData(device);
+}
+
+bool QCryptographicHashPrivate::addData(QIODevice *device)
{
if (!device->isReadable())
return false;
@@ -491,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)
- addData(buffer,length);
+ while ((length = device->read(buffer, sizeof(buffer))) > 0)
+ addData({buffer, qsizetype(length)}); // length always <= 1024
return device->atEnd();
}
@@ -503,19 +964,105 @@ bool QCryptographicHash::addData(QIODevice* device)
/*!
Returns the final hash value.
- \sa QByteArray::toHex()
+ \sa resultView(), QByteArray::toHex()
*/
QByteArray QCryptographicHash::result() const
{
- if (!d->result.isEmpty())
- return d->result;
+ return resultView().toByteArray();
+}
+
+/*!
+ \since 6.3
+
+ Returns the final hash value.
+
+ Note that the returned view remains valid only as long as the QCryptographicHash object is
+ not modified by other means.
+
+ \sa result()
+*/
+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
- switch (d->method) {
- case Sha1: {
- Sha1State copy = d->sha1Context;
- d->result.resize(20);
+void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method,
+ HashResult &result) noexcept
+{
+ switch (method) {
+ case QCryptographicHash::Sha1: {
+ Sha1State copy = sha1Context;
+ result.resizeForOverwrite(20);
sha1FinalizeState(&copy);
- sha1ToHash(&copy, (unsigned char *)d->result.data());
+ sha1ToHash(&copy, result.data());
break;
}
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
@@ -524,107 +1071,95 @@ QByteArray QCryptographicHash::result() const
Q_UNREACHABLE();
break;
#else
- case Md4: {
- md4_context copy = d->md4Context;
- d->result.resize(MD4_RESULTLEN);
- md4_final(&copy, (unsigned char *)d->result.data());
+ case QCryptographicHash::Md4: {
+ md4_context copy = md4Context;
+ result.resizeForOverwrite(MD4_RESULTLEN);
+ md4_final(&copy, result.data());
break;
}
- case Md5: {
- MD5Context copy = d->md5Context;
- d->result.resize(16);
- MD5Final(&copy, (unsigned char *)d->result.data());
+ case QCryptographicHash::Md5: {
+ MD5Context copy = md5Context;
+ result.resizeForOverwrite(16);
+ MD5Final(&copy, result.data());
break;
}
- case Sha224: {
- SHA224Context copy = d->sha224Context;
- d->result.resize(SHA224HashSize);
- SHA224Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
+ case QCryptographicHash::Sha224: {
+ SHA224Context copy = sha224Context;
+ result.resizeForOverwrite(SHA224HashSize);
+ SHA224Result(&copy, result.data());
break;
}
- case Sha256:{
- SHA256Context copy = d->sha256Context;
- d->result.resize(SHA256HashSize);
- SHA256Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
+ case QCryptographicHash::Sha256: {
+ SHA256Context copy = sha256Context;
+ result.resizeForOverwrite(SHA256HashSize);
+ SHA256Result(&copy, result.data());
break;
}
- case Sha384:{
- SHA384Context copy = d->sha384Context;
- d->result.resize(SHA384HashSize);
- SHA384Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
+ case QCryptographicHash::Sha384: {
+ SHA384Context copy = sha384Context;
+ result.resizeForOverwrite(SHA384HashSize);
+ SHA384Result(&copy, result.data());
break;
}
- case Sha512:{
- SHA512Context copy = d->sha512Context;
- d->result.resize(SHA512HashSize);
- SHA512Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
+ case QCryptographicHash::Sha512: {
+ SHA512Context copy = sha512Context;
+ result.resizeForOverwrite(SHA512HashSize);
+ SHA512Result(&copy, result.data());
break;
}
- case RealSha3_224: {
- d->sha3Finish(224, QCryptographicHashPrivate::Sha3Variant::Sha3);
- break;
- }
- case RealSha3_256: {
- d->sha3Finish(256, QCryptographicHashPrivate::Sha3Variant::Sha3);
- break;
- }
- case RealSha3_384: {
- d->sha3Finish(384, QCryptographicHashPrivate::Sha3Variant::Sha3);
- break;
- }
- case RealSha3_512: {
- d->sha3Finish(512, QCryptographicHashPrivate::Sha3Variant::Sha3);
- break;
- }
- case Keccak_224: {
- d->sha3Finish(224, QCryptographicHashPrivate::Sha3Variant::Keccak);
- break;
- }
- case Keccak_256: {
- d->sha3Finish(256, QCryptographicHashPrivate::Sha3Variant::Keccak);
- break;
- }
- case Keccak_384: {
- d->sha3Finish(384, QCryptographicHashPrivate::Sha3Variant::Keccak);
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::RealSha3_512: {
+ sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Sha3);
break;
}
- case Keccak_512: {
- d->sha3Finish(512, QCryptographicHashPrivate::Sha3Variant::Keccak);
+ case QCryptographicHash::Keccak_224:
+ case QCryptographicHash::Keccak_256:
+ case QCryptographicHash::Keccak_384:
+ case QCryptographicHash::Keccak_512: {
+ sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
break;
}
- case Blake2b_160:
- case Blake2b_256:
- case Blake2b_384:
- case Blake2b_512: {
- const auto length = hashLength(d->method);
- blake2b_state copy = d->blake2bContext;
- d->result.resize(length);
- blake2b_final(&copy, reinterpret_cast<uint8_t *>(d->result.data()), length);
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512: {
+ const auto length = hashLengthInternal(method);
+ blake2b_state copy = blake2bContext;
+ result.resizeForOverwrite(length);
+ blake2b_final(&copy, result.data(), length);
break;
}
- case Blake2s_128:
- case Blake2s_160:
- case Blake2s_224:
- case Blake2s_256: {
- const auto length = hashLength(d->method);
- blake2s_state copy = d->blake2sContext;
- d->result.resize(length);
- blake2s_final(&copy, reinterpret_cast<uint8_t *>(d->result.data()), length);
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256: {
+ const auto length = hashLengthInternal(method);
+ blake2s_state copy = blake2sContext;
+ result.resizeForOverwrite(length);
+ blake2s_final(&copy, result.data(), length);
break;
}
#endif
+ case QCryptographicHash::NumAlgorithms:
+ Q_UNREACHABLE();
}
- return d->result;
}
+#endif // !USING_OPENSSL30
/*!
Returns the hash of \a data using \a method.
+
+ \note In Qt versions prior to 6.3, this function took QByteArray,
+ not QByteArrayView.
*/
-QByteArray QCryptographicHash::hash(const QByteArray &data, Algorithm method)
+QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method)
{
- QCryptographicHash hash(method);
+ QCryptographicHashPrivate hash(method);
hash.addData(data);
- return hash.result();
+ hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash'
+ return hash.resultView().toByteArray();
}
/*!
@@ -634,49 +1169,483 @@ QByteArray QCryptographicHash::hash(const QByteArray &data, Algorithm method)
*/
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:
- return 20;
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
case QCryptographicHash::Md4:
- return 16;
case QCryptographicHash::Md5:
- return 16;
case QCryptographicHash::Sha224:
- return SHA224HashSize;
case QCryptographicHash::Sha256:
- return SHA256HashSize;
case QCryptographicHash::Sha384:
- return SHA384HashSize;
case QCryptographicHash::Sha512:
- return SHA512HashSize;
- case QCryptographicHash::Blake2s_128:
- return 128 / 8;
- case QCryptographicHash::Blake2b_160:
- case QCryptographicHash::Blake2s_160:
- return 160 / 8;
case QCryptographicHash::RealSha3_224:
case QCryptographicHash::Keccak_224:
- case QCryptographicHash::Blake2s_224:
- return 224 / 8;
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:
- return 256 / 8;
+#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:
- case QCryptographicHash::Blake2b_384:
- return 384 / 8;
+ 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 512 / 8;
+ 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 bef0c4dbe1..294453adce 100644
--- a/src/corelib/tools/qcryptographichash.h
+++ b/src/corelib/tools/qcryptographichash.h
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** 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
@@ -95,22 +60,39 @@ 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();
- void reset();
+ 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_CORE_REMOVED_SINCE(6, 3)
void addData(const QByteArray &data);
- bool addData(QIODevice* device);
+#endif
+ void addData(QByteArrayView data) noexcept;
+ bool addData(QIODevice *device);
QByteArray result() const;
+ QByteArrayView resultView() const noexcept;
+#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 baf21bfd12..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,11 +14,12 @@
// We mean it.
//
-#include <qglobal.h>
+#include <private/qglobal_p.h>
-#if QT_HAS_INCLUDE(<memory_resource>) && __cplusplus > 201402L
+#ifdef __cpp_lib_memory_resource
# include <unordered_set>
# include <memory_resource>
+# include <qhash.h> // for the hashing helpers
#else
# include <qset.h>
#endif
@@ -64,40 +29,70 @@ QT_BEGIN_NAMESPACE
template <typename T, size_t Prealloc = 32>
class QDuplicateTracker {
#ifdef __cpp_lib_memory_resource
- char buffer[Prealloc * sizeof(T)];
+ template <typename HT>
+ struct QHasher {
+ size_t storedSeed = QHashSeed::globalSeed();
+ size_t operator()(const HT &t) const {
+ return QHashPrivate::calculateHash(t, storedSeed);
+ }
+ };
+
+ struct node_guesstimate { void *next; size_t hash; T value; };
+ static constexpr size_t bufferSize(size_t N) {
+ return N * sizeof(void*) // bucket list
+ + N * sizeof(node_guesstimate); // nodes
+ }
+
+ char buffer[bufferSize(Prealloc)];
std::pmr::monotonic_buffer_resource res{buffer, sizeof buffer};
- std::pmr::unordered_set<T> set{&res};
+ std::pmr::unordered_set<T, QHasher<T>> set{Prealloc, &res};
#else
- QSet<T> set;
- int setSize = 0;
+ class Set : public QSet<T> {
+ qsizetype setSize = 0;
+ public:
+ explicit Set(qsizetype n) : QSet<T>{}
+ { this->reserve(n); }
+
+ auto insert(const T &e) {
+ auto it = QSet<T>::insert(e);
+ const auto n = this->size();
+ 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, std::exchange(setSize, n) != n};
+ }
+ };
+ Set set{Prealloc};
#endif
Q_DISABLE_COPY_MOVE(QDuplicateTracker);
public:
+ static constexpr inline bool uses_pmr =
+ #ifdef __cpp_lib_memory_resource
+ true
+ #else
+ false
+ #endif
+ ;
QDuplicateTracker() = default;
- void reserve(int n) { set.reserve(n); }
- Q_REQUIRED_RESULT bool hasSeen(const T &s)
- {
- bool inserted;
+ explicit QDuplicateTracker(qsizetype n)
#ifdef __cpp_lib_memory_resource
- inserted = set.insert(s).second;
+ : set{size_t(n), &res}
#else
- set.insert(s);
- const int n = set.size();
- inserted = qExchange(setSize, n) != n;
+ : set{n}
#endif
- return !inserted;
+ {}
+ Q_DECL_DEPRECATED_X("Pass the capacity to reserve() to the ctor instead.")
+ void reserve(qsizetype n) { set.reserve(n); }
+ [[nodiscard]] bool hasSeen(const T &s)
+ {
+ return !set.insert(s).second;
}
- Q_REQUIRED_RESULT bool hasSeen(T &&s)
+ [[nodiscard]] bool hasSeen(T &&s)
{
- bool inserted;
-#ifdef __cpp_lib_memory_resource
- inserted = set.insert(std::move(s)).second;
-#else
- set.insert(std::move(s));
- const int n = set.size();
- inserted = qExchange(setSize, n) != n;
-#endif
- return !inserted;
+ return !set.insert(std::move(s)).second;
}
template <typename C>
@@ -110,8 +105,17 @@ public:
template <typename C>
void appendTo(C &c) &&
{
- for (auto &e : set)
- c.push_back(std::move(e));
+ if constexpr (uses_pmr) {
+ while (!set.empty())
+ c.push_back(std::move(set.extract(set.begin()).value()));
+ } else {
+ return appendTo(c); // lvalue version
+ }
+ }
+
+ void clear()
+ {
+ set.clear();
}
};
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index 389efcb8f9..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
/*
@@ -320,7 +284,8 @@ static bool isConfigFunction(QEasingCurve::Type type)
type == QEasingCurve::TCBSpline;
}
-struct TCBPoint {
+struct TCBPoint
+{
QPointF _point;
qreal _t;
qreal _c;
@@ -482,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();
@@ -501,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();
@@ -570,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;
@@ -605,8 +570,8 @@ struct BezierEase : public QEasingCurveFunction
const qreal s = 1 - t;
- const qreal s_squared = s*s;
- const qreal t_squared = t*t;
+ const qreal s_squared = s * s;
+ const qreal t_squared = t * t;
const qreal s_cubic = s_squared * s;
const qreal t_cubic = t_squared * t;
@@ -623,8 +588,8 @@ struct BezierEase : public QEasingCurveFunction
const qreal s = 1 - t;
- const qreal s_squared = s*s;
- const qreal t_squared = t*t;
+ const qreal s_squared = s * s;
+ const qreal t_squared = t * t;
const qreal s_cubic = s_squared * s;
const qreal t_cubic = t_squared * t;
@@ -639,7 +604,7 @@ struct BezierEase : public QEasingCurveFunction
const qreal p2 = singleCubicBezier.p2x;
const qreal p3 = singleCubicBezier.p3x;
- const qreal t_squared = t*t;
+ const qreal t_squared = t * t;
return -3*p0 + 3*p1 + 6*p0*t - 12*p1*t + 6*p2*t + 3*p3*t_squared - 3*p0*t_squared + 9*p1*t_squared - 9*p2*t_squared;
}
@@ -739,7 +704,7 @@ struct BezierEase : public QEasingCurveFunction
qreal cos = b * x - a * x_squared;
if (cos < 0)
- return 0.225 * (cos * 1 *-cos - cos) + cos;
+ return 0.225 * (cos * 1 * -cos - cos) + cos;
return 0.225 * (cos * cos - cos) + cos;
}
@@ -794,15 +759,15 @@ struct BezierEase : public QEasingCurveFunction
if (D >= 0) {
const qreal D_sqrt = qSqrt(D);
- qreal u = _cbrt( -q * 0.5 + D_sqrt);
- qreal v = _cbrt( -q * 0.5 - D_sqrt);
+ qreal u = _cbrt(-q * 0.5 + D_sqrt);
+ qreal v = _cbrt(-q * 0.5 - D_sqrt);
qreal z1 = u + v;
qreal t1 = z1 - a_by3;
if (inRange(t1))
return t1;
- qreal z2 = -1 *u;
+ qreal z2 = -1 * u;
qreal t2 = z2 - a_by3;
return t2;
}
@@ -825,7 +790,7 @@ struct BezierEase : public QEasingCurveFunction
cosacos(g, s1, s2, s3);
- qreal z1 = -1* f * s2;
+ qreal z1 = -1 * f * s2;
qreal t1 = z1 - a_by3;
if (inRange(t1))
return t1;
@@ -904,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");
@@ -940,7 +905,7 @@ struct ElasticEase : public QEasingCurveFunction
{
qreal p = (_p < 0) ? qreal(0.3) : _p;
qreal a = (_a < 0) ? qreal(1.0) : _a;
- switch(_t) {
+ switch (_t) {
case QEasingCurve::InElastic:
return easeInElastic(t, a, p);
case QEasingCurve::OutElastic:
@@ -973,7 +938,7 @@ struct BounceEase : public QEasingCurveFunction
qreal value(qreal t) override
{
qreal a = (_a < 0) ? qreal(1.0) : _a;
- switch(_t) {
+ switch (_t) {
case QEasingCurve::InBounce:
return easeInBounce(t, a);
case QEasingCurve::OutBounce:
@@ -1011,7 +976,7 @@ struct BackEase : public QEasingCurveFunction
if (!(t < 1))
return 1;
qreal o = (_o < 0) ? qreal(1.70158) : _o;
- switch(_t) {
+ switch (_t) {
case QEasingCurve::InBack:
return easeInBack(t, o);
case QEasingCurve::OutBack:
@@ -1028,7 +993,7 @@ struct BackEase : public QEasingCurveFunction
static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
{
- switch(curve) {
+ switch (curve) {
case QEasingCurve::Linear:
return &easeNone;
case QEasingCurve::InQuad:
@@ -1103,7 +1068,7 @@ static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
{
- switch(type) {
+ switch (type) {
case QEasingCurve::InElastic:
case QEasingCurve::OutElastic:
case QEasingCurve::InOutElastic:
@@ -1197,14 +1162,14 @@ bool QEasingCurve::operator==(const QEasingCurve &other) const
&& d_ptr->type == other.d_ptr->type;
if (res) {
if (d_ptr->config && other.d_ptr->config) {
- // catch the config content
+ // catch the config content
res = d_ptr->config->operator==(*(other.d_ptr->config));
} else if (d_ptr->config || other.d_ptr->config) {
- // one one has a config object, which could contain default values
- res = qFuzzyCompare(amplitude(), other.amplitude()) &&
- qFuzzyCompare(period(), other.period()) &&
- qFuzzyCompare(overshoot(), other.overshoot());
+ // one one has a config object, which could contain default values
+ res = qFuzzyCompare(amplitude(), other.amplitude())
+ && qFuzzyCompare(period(), other.period())
+ && qFuzzyCompare(overshoot(), other.overshoot());
}
}
return res;
@@ -1275,7 +1240,7 @@ void QEasingCurve::setPeriod(qreal period)
*/
qreal QEasingCurve::overshoot() const
{
- return d_ptr->config ? d_ptr->config->_o : qreal(1.70158) ;
+ return d_ptr->config ? d_ptr->config->_o : qreal(1.70158);
}
/*!
@@ -1309,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));
@@ -1356,7 +1321,7 @@ QList<QPointF> static inline tcbToBezier(const TCBPoints &tcbPoints)
/*!
Adds a segment of a TCB bezier spline to define a custom easing curve.
It is only applicable if type() is QEasingCurve::TCBSpline.
- The spline has to start explitly at (0.0, 0.0) and has to end at (1.0, 1.0) to
+ The spline has to start explicitly at (0.0, 0.0) and has to end at (1.0, 1.0) to
be a valid easing curve.
The tension \a t changes the length of the tangent vector.
The continuity \a c changes the sharpness in change between the tangents.
@@ -1372,7 +1337,7 @@ void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qre
if (!d_ptr->config)
d_ptr->config = curveToFunctionObject(d_ptr->type);
- d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c ,b));
+ d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c, b));
if (nextPoint == QPointF(1.0, 1.0)) {
d_ptr->config->_bezierCurves = tcbToBezier(d_ptr->config->_tcbPoints);
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index e6ee7b56d5..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
@@ -49,7 +13,6 @@ QT_REQUIRE_CONFIG(easingcurve);
QT_BEGIN_NAMESPACE
-
class QEasingCurvePrivate;
class QPointF;
class Q_CORE_EXPORT QEasingCurve
@@ -80,10 +43,9 @@ public:
QEasingCurve &operator=(const QEasingCurve &other)
{ if ( this != &other ) { QEasingCurve copy(other); swap(copy); } return *this; }
QEasingCurve(QEasingCurve &&other) noexcept : d_ptr(other.d_ptr) { other.d_ptr = nullptr; }
- QEasingCurve &operator=(QEasingCurve &&other) noexcept
- { qSwap(d_ptr, other.d_ptr); return *this; }
+ 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
@@ -98,7 +60,7 @@ public:
qreal overshoot() const;
void setOvershoot(qreal overshoot);
- void addCubicBezierSegment(const QPointF & c1, const QPointF & c2, const QPointF & endPoint);
+ void addCubicBezierSegment(const QPointF &c1, const QPointF &c2, const QPointF &endPoint);
void addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qreal b);
QList<QPointF> toCubicSpline() const;
@@ -109,13 +71,14 @@ public:
EasingFunction customType() const;
qreal valueForProgress(qreal progress) const;
+
private:
QEasingCurvePrivate *d_ptr;
#ifndef QT_NO_DEBUG_STREAM
friend Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
#endif
#ifndef QT_NO_DATASTREAM
- friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QEasingCurve&);
+ friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QEasingCurve &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QEasingCurve &);
#endif
};
@@ -126,7 +89,7 @@ Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
#endif
#ifndef QT_NO_DATASTREAM
-Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QEasingCurve&);
+Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QEasingCurve &);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QEasingCurve &);
#endif
diff --git a/src/corelib/tools/qflatmap_p.h b/src/corelib/tools/qflatmap_p.h
index bf0efb2543..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,27 +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>
{
- 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)
- {
- }
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
- U *operator->()
- {
- return &ref;
- }
- };
+ template<class U>
+ using mock_pointer = qflatmap::detail::QFlatMapMockPointer<U>;
public:
using key_type = Key;
@@ -159,12 +144,12 @@ public:
{
}
- reference operator*()
+ reference operator*() const
{
return { c->keys[i], c->values[i] };
}
- pointer operator->()
+ pointer operator->() const
{
return { operator*() };
}
@@ -189,7 +174,7 @@ public:
{
iterator r = *this;
- i++;
+ ++*this;
return r;
}
@@ -202,7 +187,7 @@ public:
iterator operator--(int)
{
iterator r = *this;
- i--;
+ --*this;
return r;
}
@@ -240,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] };
@@ -267,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
@@ -296,12 +281,12 @@ public:
{
}
- reference operator*()
+ reference operator*() const
{
return { c->keys[i], c->values[i] };
}
- pointer operator->()
+ pointer operator->() const
{
return { operator*() };
}
@@ -326,7 +311,7 @@ public:
{
const_iterator r = *this;
- i++;
+ ++*this;
return r;
}
@@ -339,7 +324,7 @@ public:
const_iterator operator--(int)
{
const_iterator r = *this;
- i--;
+ --*this;
return r;
}
@@ -377,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] };
@@ -404,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:
@@ -417,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<
@@ -430,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}
{
@@ -437,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();
}
@@ -468,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())
{
}
@@ -513,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}
@@ -553,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)
@@ -614,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)
@@ -631,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
@@ -682,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)
{
@@ -756,6 +764,7 @@ public:
{
insertOrderedUniqueRange(first, last);
}
+#endif
iterator begin() { return { &c, 0 }; }
const_iterator begin() const { return { &c, 0 }; }
@@ -782,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 };
}
@@ -804,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
@@ -825,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)
{
@@ -872,7 +998,7 @@ private:
class IndexedKeyComparator
{
public:
- IndexedKeyComparator(const full_map_t *am)
+ IndexedKeyComparator(const QFlatMap *am)
: m(am)
{
}
@@ -883,7 +1009,7 @@ private:
}
private:
- const full_map_t *m;
+ const QFlatMap *m;
};
template <class InputIt>
@@ -904,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()));
@@ -951,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 dd584413fc..db15fac5d6 100644
--- a/src/corelib/tools/qfreelist.cpp
+++ b/src/corelib/tools/qfreelist.cpp
@@ -1,64 +1,30 @@
-/****************************************************************************
-**
-** 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,
Offset2 = 0x00080000,
Offset3 = 0x00800000,
- Size0 = Offset1 - Offset0,
- Size1 = Offset2 - Offset1,
- Size2 = Offset3 - Offset2,
+ Size0 = Offset1 - Offset0,
+ Size1 = Offset2 - Offset1,
+ 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 c49473802a..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
@@ -56,7 +20,6 @@
QT_BEGIN_NAMESPACE
-
/*! \internal
Element in a QFreeList. ConstReferenceType and ReferenceType are used as
@@ -161,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
@@ -208,9 +170,7 @@ public:
template <typename T, typename ConstantsType>
constexpr inline QFreeList<T, ConstantsType>::QFreeList()
:
-#if defined(Q_COMPILER_CONSTEXPR)
_v{}, // uniform initialization required
-#endif
_next(ConstantsType::InitialNextValue)
{ }
@@ -251,7 +211,7 @@ inline int QFreeList<T, ConstantsType>::next()
v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]);
if (!_v[block].testAndSetRelease(nullptr, v)) {
// race with another thread lost
- delete [] v;
+ delete[] v;
v = _v[block].loadAcquire();
Q_ASSERT(v != nullptr);
}
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 7c58be0f84..12e90daecf 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 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
@@ -60,27 +24,161 @@
#include <qdatetime.h>
#include <qbasicatomic.h>
#include <qendian.h>
+#include <private/qrandom_p.h>
#include <private/qsimd_p.h>
#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.
@@ -138,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;
@@ -187,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 { \
@@ -220,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;
@@ -229,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;
@@ -249,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;
@@ -289,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.
@@ -300,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 { \
@@ -325,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;
@@ -334,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;
@@ -354,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;
@@ -385,33 +508,109 @@ 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);
+}
-#if QT_COMPILER_SUPPORTS_HERE(AES) && QT_COMPILER_SUPPORTS_HERE(SSE4_2) && \
- !(defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__))
-# define AESHASH
+enum ZeroExtension {
+ None = 0,
+ ByteToWord = 1,
+};
-QT_FUNCTION_TARGET(AES)
-static size_t aeshash(const uchar *p, size_t len, size_t seed) noexcept
+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
{
- __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(seed);
- key = _mm_insert_epi32(mseed, replicated_len, 1);
- key = _mm_unpacklo_epi64(key, key);
+ 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
+#elif __has_feature(address_sanitizer) || __has_feature(thread_sanitizer) // Clang
+# define QHASH_AES_SANITIZER_BUILD
+#endif
+
+// When built with a sanitizer, aeshash() is rightfully reported to have a
+// heap-buffer-overflow issue. However, we consider it to be safe in this
+// specific case and overcome the problem by correctly discarding the
+// out-of-range bits. To allow building the code with sanitizer,
+// QHASH_AES_SANITIZER_BUILD is used to disable aeshash() usage.
+#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
+
+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
@@ -419,19 +618,376 @@ 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
+
+Q_ALWAYS_INLINE AESHashSeed::AESHashSeed(size_t seed, size_t seed2)
+{
+ __m128i mseed = mm_cvtsz_si128(seed);
+ mseed2 = mm_set1_epz(seed2);
+
+ // 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);
+
+ // 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
+{
+ {
+ // unlike the Go code, we don't have more per-process seed
+ __m128i state1 = _mm_aesenc_si128(state0, mseed2);
+ return state1;
+ }
+}
+
+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);
+ }
+
+ return mm_cvtsi128_sz(state0);
+}
+
+// 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) {
+ // 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 ((quintptr(src) & (CachelineSize / 2)) == 0) {
+ // lower half of the cacheline:
+ __m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(maskarray + 15 - len));
+ data = loadu128<ZX>(src);
+ data = _mm_and_si128(data, mask);
+ } else {
+ // upper half of the cacheline:
+ __m128i control = _mm_loadu_si128(reinterpret_cast<const __m128i *>(shufflecontrol + 15 - len));
+ data = loadu128<ZX>(advance<ZX>(srcend, -1));
+ data = _mm_shuffle_epi8(data, control);
+ }
+
+ hash16bytes(state0, data);
+ }
+ return mm_cvtsi128_sz(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);
+}
- __m128i state0 = key;
+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 // 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, size_t seed2) noexcept
+{
+ uint8x16_t key;
+# if QT_POINTER_SIZE == 8
+ uint64x2_t vseed = vcombine_u64(vcreate_u64(seed), vcreate_u64(seed2));
+ key = vreinterpretq_u8_u64(vseed);
+# else
+
+ uint32x2_t vseed = vmov_n_u32(seed);
+ vseed = vset_lane_u32(seed2, vseed, 1);
+ key = vreinterpretq_u8_u32(vcombine_u32(vseed, vseed));
+# endif
+
+ // Compared to x86 AES, ARM splits each round into two instructions
+ // and includes the pre-xor instead of the post-xor.
+ const auto hash16bytes = [](uint8x16_t &state0, uint8x16_t data) {
+ auto state1 = state0;
+ state0 = vaeseq_u8(state0, data);
+ state0 = vaesmcq_u8(state0);
+ auto state2 = state0;
+ state0 = vaeseq_u8(state0, state1);
+ state0 = vaesmcq_u8(state0);
+ auto state3 = state0;
+ state0 = vaeseq_u8(state0, state2);
+ state0 = vaesmcq_u8(state0);
+ state0 = veorq_u8(state0, state3);
+ };
+
+ uint8x16_t state0 = key;
+
+ if (len < 8)
+ goto lt8;
if (len < 16)
goto lt16;
if (len < 32)
@@ -440,77 +996,92 @@ static size_t aeshash(const uchar *p, size_t len, size_t seed) noexcept
// rounds of 32 bytes
{
// Make state1 = ~state0:
- __m128i one = _mm_cmpeq_epi64(key, key);
- __m128i state1 = _mm_xor_si128(state0, one);
+ uint8x16_t state1 = veorq_u8(state0, vdupq_n_u8(255));
// 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;
+ const auto *e = p + len - 31;
+ while (p < e) {
+ uint8x16_t data0 = vld1q_u8(p);
+ uint8x16_t data1 = vld1q_u8(p + 16);
+ auto oldstate0 = state0;
+ auto oldstate1 = state1;
+ state0 = vaeseq_u8(state0, data0);
+ state1 = vaeseq_u8(state1, data1);
+ state0 = vaesmcq_u8(state0);
+ state1 = vaesmcq_u8(state1);
+ auto laststate0 = state0;
+ auto laststate1 = state1;
+ state0 = vaeseq_u8(state0, oldstate0);
+ state1 = vaeseq_u8(state1, oldstate1);
+ state0 = vaesmcq_u8(state0);
+ state1 = vaesmcq_u8(state1);
+ state0 = veorq_u8(state0, laststate0);
+ state1 = veorq_u8(state1, laststate1);
+ p += 32;
}
- state0 = _mm_xor_si128(state0, state1);
+ state0 = veorq_u8(state0, state1);
}
len &= 0x1f;
// do we still have 16 or more bytes?
if (len & 0x10) {
lt32:
- __m128i data = _mm_loadu_si128(src);
+ uint8x16_t data = vld1q_u8(p);
hash16bytes(state0, data);
- ++src;
+ p += 16;
}
len &= 0xf;
+ if (len & 0x08) {
lt16:
+ uint8x8_t data8 = vld1_u8(p);
+ uint8x16_t data = vcombine_u8(data8, vdup_n_u8(0));
+ hash16bytes(state0, data);
+ p += 8;
+ }
+ len &= 0x7;
+
+lt8:
if (len) {
// load the last chunk of data
- // We're going to load 16 bytes and mask zero the part we don't care
+ // We're going to load 8 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
- __m128i data;
+ uint8x8_t data8;
- if (Q_LIKELY(quintptr(src + 1) & 0xff0)) {
+ if (Q_LIKELY(quintptr(p + 8) & 0xff8)) {
// same page, we definitely can't fault:
- // load all 16 bytes and mask off the bytes past the end of the source
+ // load all 8 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,
- };
- __m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(maskarray + 15 - len));
- data = _mm_loadu_si128(src);
- data = _mm_and_si128(data, mask);
+ -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0,
+ };
+ uint8x8_t mask = vld1_u8(reinterpret_cast<const quint8 *>(maskarray) + 7 - len);
+ data8 = vld1_u8(p);
+ data8 = vand_u8(data8, 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
+ // load 8 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
+ 1, 2, 3, 4, 5, 6, 7,
+ -1, -1, -1, -1, -1, -1, -1,
};
- __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 = _mm_shuffle_epi8(data, control);
+ uint8x8_t control = vld1_u8(reinterpret_cast<const quint8 *>(shufflecontrol) + 7 - len);
+ data8 = vld1_u8(p - 8 + len);
+ data8 = vtbl1_u8(data8, control);
}
-
+ uint8x16_t data = vcombine_u8(data8, vdup_n_u8(0));
hash16bytes(state0, data);
}
// extract state0
# if QT_POINTER_SIZE == 8
- return _mm_cvtsi128_si64(state0);
+ return vgetq_lane_u64(vreinterpretq_u64_u8(state0), 0);
# else
- return _mm_cvtsi128_si32(state0);
+ return vgetq_lane_u32(vreinterpretq_u32_u8(state0), 0);
# endif
}
#endif
@@ -522,22 +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 (seed && qCpuHasFeature(AES))
+ 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);
-}
-size_t qHash(const QByteArray &key, size_t seed) noexcept
-{
- return qHashBits(key.constData(), size_t(key.size()), seed);
+ return qHashBits_fallback<>(data, size, seed, seed2);
}
-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);
}
@@ -547,92 +1121,157 @@ 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
{
- int m = bitArray.d.size() - 1;
+ qsizetype m = bitArray.d.size() - 1;
size_t result = qHashBits(reinterpret_cast<const uchar *>(bitArray.d.constData()), size_t(qMax(0, m)), seed);
// deal with the last 0 to 7 bits manually, because we can't trust that
// the padding is initialized to 0 in bitArray.d
- int n = bitArray.size();
+ qsizetype n = bitArray.size();
if (n & 0x7)
result = ((result << 4) + bitArray.d.at(m)) & ((1 << n) - 1);
return result;
}
+#endif
-size_t qHash(QLatin1String key, size_t seed) noexcept
+size_t qHash(QLatin1StringView key, size_t seed) noexcept
{
- return qHashBits(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
+#ifdef 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
+
+ auto data = reinterpret_cast<const uchar *>(key.data());
+ size_t size = key.size();
+
+ // 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);
+
+#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);
}
/*!
- \internal
+ \class QHashSeed
+ \inmodule QtCore
+ \since 6.2
+
+ The QHashSeed class is used to convey the QHash seed. This is used
+ internally by QHash and provides three static member functions to allow
+ users to obtain the hash and to reset it.
+
+ QHash and the qHash() functions implement what is called as "salted hash".
+ The intent is that different applications and different instances of the
+ same application will produce different hashing values for the same input,
+ thus causing the ordering of elements in QHash to be unpredictable by
+ external observers. This improves the applications' resilience against
+ attacks that attempt to force hashing tables into degenerate mode.
+
+ Most applications will not need to deal directly with the hash seed, as
+ QHash will do so when needed. However, applications may wish to use this
+ for their own purposes in the same way as QHash does: as an
+ application-global random value (but see \l QRandomGenerator too). Note
+ that the global hash seed may change during the application's lifetime, if
+ the resetRandomGlobalSeed() function is called. Users of the global hash
+ need to store the value they are using and not rely on getting it again.
+
+ This class also implements functionality to set the hash seed to a
+ deterministic value, which the qHash() functions will take to mean that
+ they should use a fixed hashing function on their data too. This
+ functionality is only meant to be used in debugging applications. This
+ behavior can also be controlled by setting the \c QT_HASH_SEED environment
+ variable to the value zero (any other value is ignored).
+
+ \sa QHash, QRandomGenerator
*/
-static uint qt_create_qhash_seed()
-{
- uint seed = 0;
-#ifndef QT_BOOTSTRAPPED
- QByteArray envSeed = qgetenv("QT_HASH_SEED");
- if (!envSeed.isNull()) {
- uint seed = envSeed.toUInt();
- if (seed) {
- // can't use qWarning here (reentrancy)
- fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0, cannot guarantee that the "
- "hashing functions will produce a stable value.");
- }
- return seed;
- }
+/*!
+ \fn QHashSeed::QHashSeed(size_t data)
- seed = QRandomGenerator::system()->generate();
-#endif // QT_BOOTSTRAPPED
+ Constructs a new QHashSeed object using \a data as the seed.
+ */
+
+/*!
+ \fn QHashSeed::operator size_t() const
+
+ Converts the returned hash seed into a \c size_t.
+ */
+
+/*!
+ \threadsafe
- return seed;
+ Returns the current global QHash seed. The value returned by this function
+ will be zero if setDeterministicGlobalSeed() has been called or if the
+ \c{QT_HASH_SEED} environment variable is set to zero.
+ */
+QHashSeed QHashSeed::globalSeed() noexcept
+{
+ return qt_qhash_seed.currentSeed(0);
}
-/*
- The QHash seed itself.
-*/
-static QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
+/*!
+ \threadsafe
+
+ Forces the Qt hash seed to a deterministic value (zero) and asks the
+ qHash() functions to use a pre-determined hashing function. This mode is
+ only useful for debugging and should not be used in production code.
+
+ Regular operation can be restored by calling resetRandomGlobalSeed().
+ */
+void QHashSeed::setDeterministicGlobalSeed()
+{
+ qt_qhash_seed.clearSeed();
+}
/*!
- \internal
+ \threadsafe
- Seed == -1 means it that it was not initialized yet.
+ Reseeds the Qt hashing seed to a new, random value. Calling this function
+ is not necessary, but long-running applications may want to do so after a
+ long period of time in which information about its hash may have been
+ exposed to potential attackers.
- We let qt_create_qhash_seed return any unsigned integer,
- but convert it to signed in order to initialize the seed.
+ If the environment variable \c QT_HASH_SEED is set to zero, calling this
+ function will result in a no-op.
- We don't actually care about the fact that different calls to
- qt_create_qhash_seed() might return different values,
- as long as in the end everyone uses the very same value.
-*/
-static void qt_initialize_qhash_seed()
+ Qt never calls this function during the execution of the application, but
+ unless the \c QT_HASH_SEED variable is set to 0, the hash seed returned by
+ globalSeed() will be a random value as if this function had been called.
+ */
+void QHashSeed::resetRandomGlobalSeed()
{
- if (qt_qhash_seed.loadRelaxed() == -1) {
- int x(qt_create_qhash_seed() & INT_MAX);
- qt_qhash_seed.testAndSetRelaxed(-1, x);
- }
+ qt_qhash_seed.resetSeed();
}
+#if QT_DEPRECATED_SINCE(6,6)
/*! \relates QHash
\since 5.6
+ \deprecated [6.6] Use QHashSeed::globalSeed() instead.
Returns the current global QHash seed.
The seed is set in any newly created QHash. See \l{qHash} about how this seed
is being used by QHash.
- \sa qSetGlobalQHashSeed
+ \sa QHashSeed, QHashSeed::globalSeed()
*/
int qGlobalQHashSeed()
{
- qt_initialize_qhash_seed();
- return qt_qhash_seed.loadRelaxed();
+ return int(QHashSeed::globalSeed() & INT_MAX);
}
/*! \relates QHash
\since 5.6
+ \deprecated [6.6] Use QHashSeed instead.
Sets the global QHash seed to \a newSeed.
@@ -652,24 +1291,21 @@ int qGlobalQHashSeed()
If the environment variable \c QT_HASH_SEED is set, calling this function will
result in a no-op.
- \sa qGlobalQHashSeed
+ \sa QHashSeed::globalSeed(), QHashSeed
*/
void qSetGlobalQHashSeed(int newSeed)
{
- if (qEnvironmentVariableIsSet("QT_HASH_SEED"))
- return;
- if (newSeed == -1) {
- int x(qt_create_qhash_seed() & INT_MAX);
- qt_qhash_seed.storeRelaxed(x);
+ if (Q_LIKELY(newSeed == 0 || newSeed == -1)) {
+ if (newSeed == 0)
+ QHashSeed::setDeterministicGlobalSeed();
+ else
+ QHashSeed::resetRandomGlobalSeed();
} else {
- if (newSeed) {
- // can't use qWarning here (reentrancy)
- fprintf(stderr, "qSetGlobalQHashSeed: forced seed value is not 0, cannot guarantee that the "
- "hashing functions will produce a stable value.");
- }
- qt_qhash_seed.storeRelaxed(newSeed & INT_MAX);
+ // can't use qWarning here (reentrancy)
+ fprintf(stderr, "qSetGlobalQHashSeed: forced seed value is not 0; ignoring call\n");
}
}
+#endif // QT_DEPRECATED_SINCE(6,6)
/*!
\internal
@@ -702,16 +1338,6 @@ uint qt_hash(QStringView key, uint chained) noexcept
}
/*!
- \fn template <typename T1, typename T2> size_t qHash(const QPair<T1, T2> &key, size_t seed = 0)
- \since 5.0
- \relates QHash
-
- Returns the hash value for the \a key, using \a seed to seed the calculation.
-
- Types \c T1 and \c T2 must be supported by qHash().
-*/
-
-/*!
\fn template <typename T1, typename T2> size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
\since 5.7
\relates QHash
@@ -719,11 +1345,6 @@ uint qt_hash(QStringView key, uint chained) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
Types \c T1 and \c T2 must be supported by qHash().
-
- \note The return type of this function is \e{not} the same as that of
- \snippet code/src_corelib_tools_qhash.cpp 29
- The two functions use different hashing algorithms; due to binary compatibility
- constraints, we cannot change the QPair algorithm to match the std::pair one before Qt 6.
*/
/*!
@@ -941,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
@@ -969,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
@@ -994,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
@@ -1012,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
@@ -1056,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
@@ -1070,13 +1709,28 @@ 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
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
+/*! \fn template<typename T> bool qHashEquals(const T &a, const T &b)
+ \relates QHash
+ \since 6.0
+ \internal
+
+ This method is being used by QHash to compare two keys. Returns true if the
+ keys \a a and \a b are considered equal for hashing purposes.
+
+ The default implementation returns the result of (a == b). It can be reimplemented
+ for a certain type if the equality operator is not suitable for hashing purposes.
+ This is for example the case if the equality operator uses qFuzzyCompare to compare
+ floating point values.
+*/
+
+
/*!
\class QHash
\inmodule QtCore
@@ -1183,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
@@ -1197,31 +1851,54 @@ size_t qHash(long double key, size_t seed) noexcept
instead, store a QWidget *.
\target qHash
- \section2 The qHash() hashing function
+ \section2 The hashing function
A QHash's key type has additional requirements other than being an
assignable data type: it must provide operator==(), and there must also be
- a qHash() function in the type's namespace that returns a hash value for an
- argument of the key's type.
+ a hashing function that returns a hash value for an argument of the
+ key's type.
- The qHash() function computes a numeric value based on a key. It
+ The hashing function computes a numeric value based on a key. It
can use any algorithm imaginable, as long as it always returns
the same value if given the same argument. In other words, if
- \c{e1 == e2}, then \c{qHash(e1) == qHash(e2)} must hold as well.
- However, to obtain good performance, the qHash() function should
+ \c{e1 == e2}, then \c{hash(e1) == hash(e2)} must hold as well.
+ However, to obtain good performance, the hashing function should
attempt to return different hash values for different keys to the
largest extent possible.
- For a key type \c{K}, the qHash function must have one of these signatures:
+ A hashing function for a key type \c{K} may be provided in two
+ different ways.
+
+ The first way is by having an overload of \c{qHash()} in \c{K}'s
+ namespace. The \c{qHash()} function must have one of these signatures:
\snippet code/src_corelib_tools_qhash.cpp 32
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
+ suitable function call operator for it:
+
+ \snippet code/src_corelib_tools_qhash.cpp 33
+
+ The seed argument has the same meaning as for \c{qHash()},
+ and may be left out.
+
+ This second way allows to reuse the same hash function between
+ QHash and the C++ Standard Library unordered associative containers.
+ If both a \c{qHash()} overload and a \c{std::hash} specializations
+ are provided for a type, then the \c{qHash()} overload is preferred.
Here's a partial list of the C++ and Qt types that can serve as keys in a
QHash: any integer type (char, unsigned long, etc.), any pointer type,
@@ -1231,9 +1908,11 @@ size_t qHash(long double key, size_t seed) noexcept
the documentation of each class.
If you want to use other types as the key, make sure that you provide
- operator==() and a qHash() implementation. The convenience qHashMulti()
- function can be used to implement qHash() for a custom type, where
- one usually wants to produce a hash value from multiple fields:
+ operator==() and a hash implementation.
+
+ The convenience qHashMulti() function can be used to implement
+ qHash() for a custom type, where one usually wants to produce a
+ hash value from multiple fields:
Example:
\snippet code/src_corelib_tools_qhash.cpp 13
@@ -1268,7 +1947,7 @@ size_t qHash(long double key, size_t seed) noexcept
where you temporarily need deterministic behavior, for example for debugging or
regression testing. To disable the randomization, define the environment
variable \c QT_HASH_SEED to have the value 0. Alternatively, you can call
- the qSetGlobalQHashSeed() function with the value 0.
+ the QHashSeed::setDeterministicGlobalSeed() function.
\sa QHashIterator, QMutableHashIterator, QMap, QSet
*/
@@ -1301,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.
*/
@@ -1378,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.
@@ -1393,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.
@@ -1422,7 +2101,7 @@ size_t qHash(long double key, size_t seed) noexcept
*/
-/*! \fn template <class Key, class T> void QHash<Key, T>::reserve(int size)
+/*! \fn template <class Key, class T> void QHash<Key, T>::reserve(qsizetype size)
Ensures that the QHash's internal hash table has space to store at
least \a size items without having to grow the hash table.
@@ -1504,6 +2183,21 @@ size_t qHash(long double key, size_t seed) noexcept
\sa clear(), take()
*/
+/*! \fn template <class Key, class T> template <typename Predicate> qsizetype QHash<Key, T>::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the hash.
+
+ The function supports predicates which take either an argument of
+ type \c{QHash<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ Returns the number of elements removed, if any.
+
+ \sa clear(), take()
+*/
+
/*! \fn template <class Key, class T> T QHash<Key, T>::take(const Key &key)
Removes the item with the \a key from the hash and returns
@@ -1522,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)
@@ -1544,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()
*/
@@ -1595,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
@@ -1625,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
@@ -1639,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()
*/
@@ -1647,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()
*/
@@ -1656,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()
*/
@@ -1664,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
@@ -1677,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()
*/
@@ -1686,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()
*/
@@ -1695,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()
*/
@@ -1704,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()
*/
@@ -1713,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()
*/
@@ -1722,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()
*/
@@ -1731,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()
*/
@@ -1740,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()
*/
@@ -1749,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
@@ -1766,11 +2522,9 @@ size_t qHash(long double key, size_t seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 15
- \sa remove(), take(), find()
-*/
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::erase(iterator pos)
- \overload
+ \sa remove(), take(), find()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::find(const Key &key)
@@ -1789,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
@@ -1806,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()
*/
@@ -1815,17 +2575,23 @@ 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
*/
/*!
- \fn template <typename T> template <typename ...Args> QHash<Key, T>::iterator QHash<Key, T>::emplace(const Key &key, Args&&... args)
- \fn template <typename T> template <typename ...Args> QHash<Key, T>::iterator QHash<Key, T>::emplace(Key &&key, Args&&... args)
+ \fn template <class Key, class T> template <typename ...Args> QHash<Key, T>::iterator QHash<Key, T>::emplace(const Key &key, Args&&... args)
+ \fn template <class Key, class T> template <typename ...Args> QHash<Key, T>::iterator QHash<Key, T>::emplace(Key &&key, Args&&... args)
Inserts a new element into the container. This new element
is constructed in-place using \a args as the arguments for its
construction.
Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
@@ -1836,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
@@ -1848,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
@@ -1955,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,
@@ -1981,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.
@@ -2016,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.
@@ -2028,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()
@@ -2124,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
@@ -2140,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
@@ -2162,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()
@@ -2240,8 +2979,6 @@ size_t qHash(long double key, size_t seed) noexcept
item.
Calling this function on QHash::end() leads to undefined results.
-
- \sa operator--()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator++(int)
@@ -2325,7 +3062,6 @@ size_t qHash(long double key, size_t seed) noexcept
Calling this function on QHash::keyEnd() leads to undefined results.
- \sa operator--()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::key_iterator QHash<Key, T>::key_iterator::operator++(int)
@@ -2402,11 +3138,10 @@ size_t qHash(long double key, size_t seed) noexcept
hashes. A multi-valued hash is a hash that allows multiple values
with the same key.
- Because QMultiHash inherits QHash, all of QHash's functionality also
- applies to QMultiHash. For example, you can use isEmpty() to test
+ QMultiHash mostly mirrors QHash's API. For example, you can use isEmpty() to test
whether the hash is empty, and you can traverse a QMultiHash using
QHash's iterator classes (for example, QHashIterator). But opposed to
- QHash, it provides an insert() function will allow the insertion of
+ QHash, it provides an insert() function that allows the insertion of
multiple items with the same key. The replace() function corresponds to
QHash::insert(). It also provides convenient operator+() and
operator+=().
@@ -2457,17 +3192,12 @@ 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)
Constructs a copy of \a other (which can be a QHash or a
QMultiHash).
-
- \sa operator=()
*/
/*! \fn template <class Key, class T> template <class InputIterator> QMultiHash<Key, T>::QMultiHash(InputIterator begin, InputIterator end)
@@ -2475,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.
*/
@@ -2491,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()
*/
@@ -2503,12 +3237,16 @@ 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()
*/
/*!
- \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplace(const Key &key, Args&&... args)
- \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplace(Key &&key, Args&&... args)
+ \fn template <class Key, class T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplace(const Key &key, Args&&... args)
+ \fn template <class Key, class T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplace(Key &&key, Args&&... args)
Inserts a new element into the container. This new element
is constructed in-place using \a args as the arguments for its
@@ -2521,12 +3259,14 @@ 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
*/
/*!
- \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplaceReplace(const Key &key, Args&&... args)
- \fn template <typename T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplaceReplace(Key &&key, Args&&... args)
+ \fn template <class Key, class T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplaceReplace(const Key &key, Args&&... args)
+ \fn template <class Key, class T> template <typename ...Args> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::emplaceReplace(Key &&key, Args&&... args)
Inserts a new element into the container. This new element
is constructed in-place using \a args as the arguments for its
@@ -2537,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
*/
@@ -2550,6 +3292,16 @@ size_t qHash(long double key, size_t seed) noexcept
\sa insert()
*/
+
+/*! \fn template <class Key, class T> QMultiHash &QMultiHash<Key, T>::unite(const QHash<Key, T> &other)
+ \since 6.0
+
+ Inserts all the items in the \a other hash into this hash
+ and returns a reference to this hash.
+
+ \sa insert()
+*/
+
/*! \fn template <class Key, class T> QList<Key> QMultiHash<Key, T>::uniqueKeys() const
\since 5.13
@@ -2559,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
@@ -2593,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()
*/
@@ -2624,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
@@ -2633,6 +3397,30 @@ size_t qHash(long double key, size_t seed) noexcept
\sa remove()
*/
+/*!
+ \fn template <class Key, class T> void QMultiHash<Key, T>::clear()
+ \since 4.3
+
+ Removes all items from the hash and frees up all memory used by it.
+
+ \sa remove()
+*/
+
+/*! \fn template <class Key, class T> template <typename Predicate> qsizetype QMultiHash<Key, T>::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the multi hash.
+
+ The function supports predicates which take either an argument of
+ type \c{QMultiHash<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ Returns the number of elements removed, if any.
+
+ \sa clear(), take()
+*/
+
/*! \fn template <class Key, class T> T QMultiHash<Key, T>::take(const Key &key)
Removes the item with the \a key from the hash and returns
@@ -2680,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
@@ -2692,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.
@@ -2709,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
*/
/*!
@@ -2726,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()
@@ -2733,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
@@ -2747,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()
*/
@@ -2755,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()
*/
@@ -2764,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()
*/
@@ -2772,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()
*/
@@ -2785,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()
*/
@@ -2794,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()
*/
@@ -2803,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()
*/
@@ -2812,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()
*/
@@ -2821,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()
*/
@@ -2830,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()
*/
@@ -2839,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()
*/
@@ -2848,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()
*/
@@ -2857,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,
@@ -2891,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.
@@ -2926,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.
@@ -2938,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()
@@ -3034,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
@@ -3050,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
@@ -3063,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, QMultiHashIterator
+ \sa QMultiHash::iterator, QMultiHash::key_iterator, QMultiHash::const_key_value_iterator
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator()
@@ -3157,8 +3967,6 @@ size_t qHash(long double key, size_t seed) noexcept
item.
Calling this function on QMultiHash::end() leads to undefined results.
-
- \sa operator--()
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::const_iterator::operator++(int)
@@ -3241,8 +4049,6 @@ size_t qHash(long double key, size_t seed) noexcept
item.
Calling this function on QMultiHash::keyEnd() leads to undefined results.
-
- \sa operator--()
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::key_iterator::operator++(int)
@@ -3324,4 +4130,64 @@ size_t qHash(long double key, size_t seed) noexcept
Type \c T must be supported by qHash().
*/
+/*! \fn template <typename Key, typename T, typename Predicate> qsizetype erase_if(QHash<Key, T> &hash, Predicate pred)
+ \relates QHash
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the hash \a hash.
+
+ The function supports predicates which take either an argument of
+ type \c{QHash<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ Returns the number of elements removed, if any.
+*/
+
+/*! \fn template <typename Key, typename T, typename Predicate> qsizetype erase_if(QMultiHash<Key, T> &hash, Predicate pred)
+ \relates QMultiHash
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the multi hash \a hash.
+
+ The function supports predicates which take either an argument of
+ type \c{QMultiHash<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ 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 2b1b155efb..e7cd4123fb 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -1,53 +1,21 @@
-/****************************************************************************
-**
-** 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.
+// 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>
+#include <functional> // for std::hash
+
+class tst_QHash; // for befriending
QT_BEGIN_NAMESPACE
@@ -58,25 +26,44 @@ struct QHashDummyValue
namespace QHashPrivate {
-// QHash uses a power of two growth policy.
-namespace GrowthPolicy
-{
-inline constexpr size_t maxNumBuckets() noexcept
-{
- return size_t(1) << (8*sizeof(size_t) - 1);
-}
-inline constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
-{
- if (requestedCapacity <= 8)
- return 16;
- if (requestedCapacity >= maxNumBuckets())
- return maxNumBuckets();
- return qNextPowerOfTwo(QIntegerForSize<sizeof(size_t)>::Unsigned(2*requestedCapacity - 1));
-}
-inline constexpr size_t bucketForHash(size_t nBuckets, size_t hash) noexcept
+template <typename T, typename = void>
+constexpr inline bool HasQHashOverload = false;
+
+template <typename T>
+constexpr inline bool HasQHashOverload<T, std::enable_if_t<
+ std::is_convertible_v<decltype(qHash(std::declval<const T &>(), std::declval<size_t>())), size_t>
+>> = true;
+
+template <typename T, typename = void>
+constexpr inline bool HasStdHashSpecializationWithSeed = false;
+
+template <typename T>
+constexpr inline bool HasStdHashSpecializationWithSeed<T, std::enable_if_t<
+ std::is_convertible_v<decltype(std::hash<T>()(std::declval<const T &>(), std::declval<size_t>())), size_t>
+>> = true;
+
+template <typename T, typename = void>
+constexpr inline bool HasStdHashSpecializationWithoutSeed = false;
+
+template <typename T>
+constexpr inline bool HasStdHashSpecializationWithoutSeed<T, std::enable_if_t<
+ std::is_convertible_v<decltype(std::hash<T>()(std::declval<const T &>())), size_t>
+>> = true;
+
+template <typename T>
+size_t calculateHash(const T &t, size_t seed = 0)
{
- return hash & (nBuckets - 1);
-}
+ if constexpr (HasQHashOverload<T>) {
+ return qHash(t, seed);
+ } else if constexpr (HasStdHashSpecializationWithSeed<T>) {
+ return std::hash<T>()(t, seed);
+ } else if constexpr (HasStdHashSpecializationWithoutSeed<T>) {
+ Q_UNUSED(seed);
+ return std::hash<T>()(t);
+ } else {
+ static_assert(sizeof(T) == 0, "The key type must have a qHash overload or a std::hash specialization");
+ return 0;
+ }
}
template <typename Key, typename T>
@@ -185,9 +172,8 @@ struct MultiNode
MultiNode(MultiNode &&other)
: key(other.key),
- value(other.value)
+ value(std::exchange(other.value, nullptr))
{
- other.value = nullptr;
}
MultiNode(const MultiNode &other)
@@ -217,16 +203,13 @@ struct MultiNode
void insertMulti(Args &&... args)
{
Chain *e = new Chain{ T(std::forward<Args>(args)...), nullptr };
- e->next = value;
- value = e;
+ e->next = std::exchange(value, e);
}
template<typename ...Args>
void emplaceValue(Args &&... args)
{
value->value = T(std::forward<Args>(args)...);
}
-
- // compiler generated move operators are fine
};
template<typename Node>
@@ -235,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.
@@ -245,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
@@ -259,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()
{
@@ -282,18 +267,18 @@ 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();
}
}
- delete [] entries;
+ delete[] entries;
entries = nullptr;
}
}
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;
@@ -304,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;
@@ -320,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();
}
@@ -350,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);
@@ -369,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>()) {
@@ -384,36 +369,77 @@ 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
if constexpr (isRelocatable<Node>()) {
if (allocated)
- memcpy(newEntries, entries, allocated*sizeof(Entry));
+ memcpy(newEntries, entries, allocated * sizeof(Entry));
} else {
for (size_t i = 0; i < allocated; ++i) {
new (&newEntries[i].node()) Node(std::move(entries[i].node()));
entries[i].node().~Node();
}
}
- for (size_t i = allocated; i < allocated + increment; ++i) {
+ for (size_t i = allocated; i < alloc; ++i) {
newEntries[i].nextFree() = uchar(i + 1);
}
- delete [] entries;
+ delete[] entries;
entries = newEntries;
allocated = uchar(alloc);
}
};
+// QHash uses a power of two growth policy.
+namespace GrowthPolicy {
+inline constexpr size_t bucketsForCapacity(size_t requestedCapacity) noexcept
+{
+ 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
+{
+ return hash & (nBuckets - 1);
+}
+} // namespace GrowthPolicy
+
template <typename Node>
struct iterator;
@@ -429,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];
- seed = qGlobalQHashSeed();
+ 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);
@@ -475,10 +606,9 @@ struct Data
return dd;
}
-
void clear()
{
- delete [] spans;
+ delete[] spans;
spans = nullptr;
size = 0;
numBuckets = 0;
@@ -510,25 +640,24 @@ 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();
}
- delete [] oldSpans;
+ delete[] oldSpans;
}
size_t nextBucket(size_t bucket) const noexcept
@@ -548,104 +677,94 @@ 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 = qHash(key, seed);
- size_t bucket = GrowthPolicy::bucketForHash(numBuckets, hash);
+ size_t hash = QHashPrivate::calculateHash(key, seed);
+ 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);
- if (n.key == key)
- return iterator{ this, bucket };
+ Node &n = bucket.nodeAtOffset(offset);
+ if (qHashEquals(n.key, key))
+ 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)
+ auto bucket = findBucket(key);
+ if (bucket.isUnused())
return nullptr;
- iterator it = find(key);
- if (it.isUnused())
- return nullptr;
- return it.node();
+ return bucket.node();
}
- struct InsertionResult {
+ struct InsertionResult
+ {
iterator it;
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 = qHash(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 (!spans[span].hasNode(index))
- ++it;
- return it;
}
~Data()
@@ -661,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
@@ -696,12 +815,14 @@ struct iterator {
} // namespace QHashPrivate
-template <class Key, class T>
+template <typename Key, typename T>
class QHash
{
using Node = QHashPrivate::Node<Key, T>;
using Data = QHashPrivate::Data<Node>;
friend class QSet<Key>;
+ friend class QMultiHash<Key, T>;
+ friend tst_QHash;
Data *d = nullptr;
@@ -729,6 +850,9 @@ public:
}
~QHash()
{
+ static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
if (d && !d->ref.deref())
delete d;
}
@@ -750,15 +874,7 @@ public:
: d(std::exchange(other.d, nullptr))
{
}
- QHash &operator=(QHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
- {
- if (d != other.d) {
- if (d && !d->ref.deref())
- delete d;
- d = std::exchange(other.d, nullptr);
- }
- return *this;
- }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHash)
#ifdef Q_QDOC
template <typename InputIterator>
QHash(InputIterator f, InputIterator l);
@@ -781,10 +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); }
- template <typename U = T>
- QTypeTraits::compare_eq_result<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;
@@ -799,9 +916,13 @@ public:
// all values must be the same as size is the same
return true;
}
- template <typename U = T>
- QTypeTraits::compare_eq_result<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_QDOC
inline qsizetype size() const noexcept { return d ? qsizetype(d->size) : 0; }
inline bool isEmpty() const noexcept { return !d || d->size == 0; }
@@ -809,12 +930,19 @@ 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
d = Data::detached(d, size_t(size));
}
- inline void squeeze() { reserve(0); }
+ inline void squeeze()
+ {
+ if (capacity())
+ reserve(0);
+ }
inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
@@ -829,23 +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();
@@ -853,6 +1003,7 @@ public:
return value;
}
+public:
bool contains(const Key &key) const noexcept
{
if (!d)
@@ -864,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();
@@ -875,27 +1027,57 @@ public:
}
}
- return defaultKey;
+ return defaultFn();
}
- T value(const Key &key, const T &defaultValue = T()) const noexcept
+
+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; });
+ }
+
+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);
@@ -1043,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)
{
@@ -1050,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
+ {
+ return equal_range_impl(*this, key);
+ }
+private:
+ template <typename Hash, typename K> static auto equal_range_impl(Hash &self, const K &key)
{
- auto first = find(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
{
@@ -1129,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)...);
@@ -1139,24 +1360,74 @@ 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 <class Key, class T>
+template <typename Key, typename T>
class QMultiHash
{
using Node = QHashPrivate::MultiNode<Key, T>;
using Data = QHashPrivate::Data<Node>;
using Chain = QHashPrivate::MultiNodeChain<T>;
- Data *d = nullptr;
+ Data *d = nullptr;
qsizetype m_size = 0;
public:
@@ -1203,6 +1474,9 @@ public:
}
~QMultiHash()
{
+ static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
if (d && !d->ref.deref())
delete d;
}
@@ -1220,10 +1494,10 @@ public:
}
return *this;
}
- QMultiHash(QMultiHash &&other) noexcept : d(other.d), m_size(other.m_size)
+ QMultiHash(QMultiHash &&other) noexcept
+ : d(std::exchange(other.d, nullptr)),
+ m_size(std::exchange(other.m_size, 0))
{
- other.d = nullptr;
- other.m_size = 0;
}
QMultiHash &operator=(QMultiHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
{
@@ -1232,26 +1506,43 @@ public:
return *this;
}
- QMultiHash(const QHash<Key, T> &other)
+ explicit QMultiHash(const QHash<Key, T> &other)
: QMultiHash(other.begin(), other.end())
{}
- void swap(QMultiHash &other) noexcept { qSwap(d, other.d); qSwap(m_size, other.m_size); }
- bool operator==(const QMultiHash &other) const noexcept
+ explicit QMultiHash(QHash<Key, T> &&other)
+ {
+ unite(std::move(other));
+ }
+
+ 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;
- if (!d || ! other.d)
+ if (m_size != other.m_size)
return false;
- if (m_size != other.m_size || d->size != other.d->size)
+ if (m_size == 0)
+ return true;
+ // equal size, and both non-zero size => d pointers allocated for both
+ Q_ASSERT(d);
+ Q_ASSERT(other.d);
+ 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;
@@ -1265,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; }
@@ -1274,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
@@ -1295,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());
@@ -1308,13 +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;
@@ -1332,6 +1654,7 @@ public:
return t;
}
+public:
bool contains(const Key &key) const noexcept
{
if (!d)
@@ -1339,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();
@@ -1351,9 +1675,20 @@ public:
}
}
- return defaultKey;
+ return defaultValue();
+ }
+public:
+ Key key(const T &value) const noexcept
+ {
+ return keyImpl(value, [] { return Key(); });
}
- T value(const Key &key, const T &defaultValue = T()) const noexcept
+ Key key(const T &value, const Key &defaultKey) const noexcept
+ {
+ return keyImpl(value, [&] { return defaultKey; });
+ }
+
+private:
+ template <typename K, typename Fn> T valueImpl(const K &key, Fn &&defaultValue) const noexcept
{
if (d) {
Node *n = d->findNode(key);
@@ -1362,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);
@@ -1399,15 +1752,21 @@ public:
QList<Key> res;
const_iterator i = begin();
while (i != end()) {
- if (i.value()->contains(value))
+ if (i.value() == value)
res.append(i.key());
++i;
}
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);
@@ -1422,6 +1781,7 @@ public:
return values;
}
+public:
class const_iterator;
class iterator
@@ -1571,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)
{
@@ -1601,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;
@@ -1609,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;
@@ -1623,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);
+ return end();
+ return iterator(it.toIterator(d));
}
- const_iterator find(const Key &key) const noexcept
- {
- return constFind(key);
- }
- 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);
@@ -1660,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(); }
@@ -1693,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)
@@ -1712,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);
@@ -1720,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 false;
+ 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;
@@ -1748,9 +2145,17 @@ public:
return n;
}
+public:
qsizetype count(const Key &key) const noexcept
{
- auto it = d->find(key);
+ return countImpl(key);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key) const noexcept
+ {
+ if (!d)
+ return 0;
+ auto it = d->findBucket(key);
if (it.isUnused())
return 0;
qsizetype n = 0;
@@ -1763,9 +2168,17 @@ public:
return n;
}
+public:
qsizetype count(const Key &key, const T &value) const noexcept
{
- auto it = d->find(key);
+ 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->findBucket(key);
if (it.isUnused())
return 0;
qsizetype n = 0;
@@ -1779,17 +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());
@@ -1801,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()) {
@@ -1816,24 +2243,59 @@ public:
return *this;
}
- QPair<iterator, iterator> equal_range(const Key &key)
+ QMultiHash &unite(const QHash<Key, T> &other)
+ {
+ for (auto cit = other.cbegin(); cit != other.cend(); ++cit)
+ insert(cit.key(), *cit);
+ return *this;
+ }
+
+ QMultiHash &unite(QHash<Key, T> &&other)
+ {
+ if (!other.isDetached()) {
+ unite(other);
+ return *this;
+ }
+ auto it = other.d->begin();
+ for (const auto end = other.d->end(); it != end; ++it)
+ emplace(std::move(it.node()->key), std::move(it.node()->takeValue()));
+ other.clear();
+ return *this;
+ }
+
+ 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
{
- auto it = d->find(key);
- if (it.isUnused())
- return qMakePair(end(), end());
+ 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 {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) {
@@ -1845,162 +2307,164 @@ private:
delete d;
d = dd;
}
-};
-#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
-template<class Key, class T>
-class QHashIterator
-{
- typedef typename QHash<Key, T>::const_iterator const_iterator;
- typedef const_iterator Item;
- QHash<Key, T> c;
- const_iterator i, n;
- inline bool item_exists() const noexcept { return n != c.constEnd(); }
+ 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:
- inline QHashIterator(const QHash<Key, T> &container) noexcept
- : c(container), i(c.constBegin()), n(c.constEnd())
- { }
- inline QHashIterator &operator=(const QHash<Key, T> &container) noexcept
- {
- c = container;
- i = c.constBegin();
- n = c.constEnd();
- return *this;
+#ifdef __cpp_concepts
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
}
- inline void toFront() noexcept
+ T take(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
{
- i = c.constBegin();
- n = c.constEnd();
+ return takeImpl(key);
}
- inline void toBack() noexcept
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
- i = c.constEnd();
- n = c.constEnd();
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
}
- inline bool hasNext() const noexcept { return i != c.constEnd(); }
- inline Item next() noexcept
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
- n = i++;
- return n;
+ return valueImpl(key, [] { return T(); });
}
- inline Item peekNext() const noexcept { return i; }
- inline const T &value() const noexcept
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &defaultValue) const noexcept
{
- Q_ASSERT(item_exists());
- return *n;
+ return valueImpl(key, [&] { return defaultValue; });
}
- inline const Key &key() const noexcept
+ T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
{
- Q_ASSERT(item_exists());
- return n.key();
+ return operatorIndexImpl(key);
}
- inline bool findNext(const T &t) noexcept
+ const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
- while ((n = i) != c.constEnd())
- if (*i++ == t)
- return true;
- return false;
+ return value(key);
}
-};
-
-template<class Key, class T>
-class QMutableHashIterator
-{
- typedef typename QHash<Key, T>::iterator iterator;
- typedef typename QHash<Key, T>::const_iterator const_iterator;
- typedef iterator Item;
- QHash<Key, T> *c;
- iterator i, n;
- inline bool item_exists() const noexcept { return const_iterator(n) != c->constEnd(); }
-
-public:
- inline QMutableHashIterator(QHash<Key, T> &container)
- : c(&container)
+ QList<T> values(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
{
- i = c->begin();
- n = c->end();
+ return valuesImpl(key);
}
- inline QMutableHashIterator &operator=(QHash<Key, T> &container)
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
{
- c = &container;
- i = c->begin();
- n = c->end();
- return *this;
+ return findImpl(key);
}
- inline void toFront()
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
- i = c->begin();
- n = c->end();
+ return constFindImpl(key);
}
- inline void toBack() noexcept
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
- i = c->end();
- n = c->end();
+ return constFindImpl(key);
}
- inline bool hasNext() const noexcept { return const_iterator(i) != c->constEnd(); }
- inline Item next() noexcept
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
{
- n = i++;
- return n;
+ return containsImpl(key, value);
}
- inline Item peekNext() const noexcept { return i; }
- inline void remove()
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
{
- if (const_iterator(n) != c->constEnd()) {
- i = c->erase(n);
- n = c->end();
- }
+ return removeImpl(key, value);
}
- inline void setValue(const T &t)
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
{
- if (const_iterator(n) != c->constEnd())
- *n = t;
+ return countImpl(key);
}
- inline T &value() noexcept
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
{
- Q_ASSERT(item_exists());
- return *n;
+ return countImpl(key, value);
}
- inline const T &value() const noexcept
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
{
- Q_ASSERT(item_exists());
- return *n;
+ return findImpl(key, value);
}
- inline const Key &key() const noexcept
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
{
- Q_ASSERT(item_exists());
- return n.key();
+ return constFindImpl(key, value);
}
- inline bool findNext(const T &t) noexcept
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
{
- while (const_iterator(n = i) != c->constEnd())
- if (*i++ == t)
- return true;
- return false;
+ 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
};
-#endif // !QT_NO_JAVA_STYLE_ITERATORS
+
+Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
+Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
+Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
+Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(MultiHash)
template <class Key, class T>
size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
- QtPrivate::QHashCombineCommutative hash;
+ size_t hash = 0;
for (auto it = key.begin(), end = key.end(); it != end; ++it) {
- const Key &k = it.key();
- const T &v = it.value();
- seed = hash(seed, std::pair<const Key&, const T&>(k, v));
+ QtPrivate::QHashCombine combine;
+ size_t h = combine(seed, it.key());
+ // use + to keep the result independent of the ordering of the keys
+ hash += combine(h, it.value());
}
- return seed;
+ return hash;
}
template <class Key, class T>
inline size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
- const QHash<Key, T> &key2 = key;
- return qHash(key2, seed);
+ size_t hash = 0;
+ for (auto it = key.begin(), end = key.end(); it != end; ++it) {
+ QtPrivate::QHashCombine combine;
+ size_t h = combine(seed, it.key());
+ // use + to keep the result independent of the ordering of the keys
+ hash += combine(h, it.value());
+ }
+ return hash;
+}
+
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QHash<Key, T> &hash, Predicate pred)
+{
+ return QtPrivate::associative_erase_if(hash, pred);
+}
+
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QMultiHash<Key, T> &hash, Predicate pred)
+{
+ return QtPrivate::associative_erase_if(hash, pred);
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index 94c6e13b1c..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,12 +30,40 @@
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")
Q_CORE_EXPORT int qGlobalQHashSeed();
+QT_DEPRECATED_VERSION_X_6_6("Use QHashSeed instead")
Q_CORE_EXPORT void qSetGlobalQHashSeed(int newSeed);
+#endif
+
+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;
+ 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 {
@@ -90,10 +88,15 @@ Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
}
}
+template <typename T1, typename T2> static constexpr bool noexceptPairHash();
}
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHashBits(const void *p, size_t size, size_t seed = 0) noexcept;
+// implementation below qHashMulti
+template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
+ noexcept(QHashPrivate::noexceptPairHash<T1, T2>());
+
// C++ builtin types
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char key, size_t seed = 0) noexcept
{ return QHashPrivate::hash(size_t(key), seed); }
@@ -119,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
@@ -129,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
@@ -150,29 +183,92 @@ 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;
-template<typename T> inline size_t qHash(const T &t, size_t seed)
- noexcept(noexcept(qHash(t)))
+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); }
+
+// ### 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)
+{
+ 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 {
+struct QHashCombine
+{
typedef size_t result_type;
template <typename T>
constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
@@ -180,7 +276,8 @@ struct QHashCombine {
{ return seed ^ (qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2)) ; }
};
-struct QHashCombineCommutative {
+struct QHashCombineCommutative
+{
// QHashCombine is a good hash combiner, but is not commutative,
// ie. it depends on the order of the input elements. That is
// usually what we want: {0,1,3} should hash differently than
@@ -210,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>
@@ -254,8 +354,16 @@ inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, siz
return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative());
}
-template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
- noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
+namespace QHashPrivate {
+template <typename T1, typename T2> static constexpr bool noexceptPairHash()
+{
+ size_t seed = 0;
+ return noexcept(qHash(std::declval<T1>(), seed)) && noexcept(qHash(std::declval<T2>(), seed));
+}
+} // QHashPrivate
+
+template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed)
+ noexcept(QHashPrivate::noexceptPairHash<T1, T2>())
{
return qHashMulti(seed, key.first, key.second);
}
@@ -268,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))); \
} \
}; \
} \
@@ -290,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 c315b77c85..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,16 +163,78 @@ 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; } \
};
+#define Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(C) \
+\
+template <class Key, class T> \
+class Q##C##Iterator \
+{ \
+ typedef typename Q##C<Key,T>::const_iterator const_iterator; \
+ Q##C<Key,T> c; \
+ const_iterator i, n; \
+ inline bool item_exists() const { return n != c.constEnd(); } \
+public: \
+ typedef const_iterator Item; \
+ inline Q##C##Iterator(const Q##C<Key,T> &container) \
+ : c(container), i(c.constBegin()), n(c.constEnd()) {} \
+ inline Q##C##Iterator &operator=(const Q##C<Key,T> &container) \
+ { c = container; i = c.constBegin(); n = c.constEnd(); return *this; } \
+ inline void toFront() { i = c.constBegin(); n = c.constEnd(); } \
+ inline void toBack() { i = c.constEnd(); n = c.constEnd(); } \
+ inline bool hasNext() const { return i != c.constEnd(); } \
+ inline Item next() { n = i++; return n; } \
+ inline Item peekNext() const { return i; } \
+ 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; } \
+};
+
+#define Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(C) \
+\
+template <class Key, class T> \
+class QMutable##C##Iterator \
+{ \
+ typedef typename Q##C<Key,T>::iterator iterator; \
+ typedef typename Q##C<Key,T>::const_iterator const_iterator; \
+ Q##C<Key,T> *c; \
+ iterator i, n; \
+ inline bool item_exists() const { return const_iterator(n) != c->constEnd(); } \
+public: \
+ typedef iterator Item; \
+ inline QMutable##C##Iterator(Q##C<Key,T> &container) \
+ : c(&container) \
+ { i = c->begin(); n = c->end(); } \
+ inline QMutable##C##Iterator &operator=(Q##C<Key,T> &container) \
+ { c = &container; i = c->begin(); n = c->end(); return *this; } \
+ inline void toFront() { i = c->begin(); n = c->end(); } \
+ inline void toBack() { i = c->end(); n = c->end(); } \
+ inline bool hasNext() const { return const_iterator(i) != c->constEnd(); } \
+ inline Item next() { n = i++; return n; } \
+ inline Item peekNext() const { return i; } \
+ inline void remove() \
+ { if (const_iterator(n) != c->constEnd()) { i = c->erase(n); n = c->end(); } } \
+ inline void setValue(const T &t) { if (const_iterator(n) != c->constEnd()) *n = t; } \
+ inline T &value() { Q_ASSERT(item_exists()); return *n; } \
+ 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 (const_iterator(n = i) != c->constEnd()) if (*i++ == t) return true; return false; } \
+};
+
+
#else // QT_NO_JAVA_STYLE_ITERATORS
#define Q_DECLARE_SEQUENTIAL_ITERATOR(C)
#define Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(C)
#define Q_DECLARE_ASSOCIATIVE_ITERATOR(C)
#define Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(C)
+#define Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(C)
+#define Q_DECLARE_MUTABLE_ASSOCIATIVE_FORWARD_ITERATOR(C)
#endif // QT_NO_JAVA_STYLE_ITERATORS
template<typename Key, typename T, class Iterator>
@@ -205,29 +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; }
@@ -243,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 2c07dcf423..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
@@ -89,8 +65,7 @@
\sa operator*()
*/
-/*! \fn template<typename Key, typename T, class Iterator> bool operator==(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs)
- \relates QKeyValueIterator
+/*! \fn template<typename Key, typename T, class Iterator> bool QKeyValueIterator<Key, T, Iterator>::operator==(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs)
Returns \c true if \a rhs points to the same item as \a lhs otherwise returns
\c false.
@@ -98,8 +73,7 @@
\sa operator!=()
*/
-/*! \fn template<typename Key, typename T, class Iterator> bool operator!=(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs) const
- \relates QKeyValueIterator
+/*! \fn template<typename Key, typename T, class Iterator> bool QKeyValueIterator<Key, T, Iterator>::operator!=(QKeyValueIterator<Key, T, Iterator> lhs, QKeyValueIterator<Key, T, Iterator> rhs)
Returns \c true if \a rhs points to a different item than \a lhs otherwise
returns \c false.
@@ -110,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
@@ -123,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
@@ -132,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
@@ -145,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
@@ -163,9 +137,8 @@
\brief The QListIterator class provides a Java-style const iterator for QList and QQueue.
QList has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
An alternative to using iterators is to use index positions. Most
QList member functions take an index as their first parameter,
@@ -214,10 +187,9 @@
\inmodule QtCore
\brief The QSetIterator class provides a Java-style const iterator for QSet.
- QSet supports both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ QSet has both \l{Java-style iterators} and \l{STL-style
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QSetIterator\<T\> allows you to iterate over a QSet\<T\>. If you
want to modify the set as you iterate over it, use
@@ -241,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
@@ -263,9 +231,8 @@
\brief The QMutableListIterator class provides a Java-style non-const iterator for QList, QQueue and QStack.
QList has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
An alternative to using iterators is to use index positions. Most
QList member functions take an index as their first parameter,
@@ -330,9 +297,8 @@
\brief The QMutableSetIterator class provides a Java-style non-const iterator for QSet.
QSet has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QMutableSetIterator\<T\> allows you to iterate over a QSet\<T\>
and remove items from the set as you iterate. If you don't want
@@ -357,10 +323,6 @@
\image javaiterators1.png
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 18
-
If you want to remove items as you iterate over the set, use
remove().
@@ -423,40 +385,92 @@
*/
/*! \fn template <class T> void QListIterator<T>::toBack()
- \fn template <class T> void QSetIterator<T>::toBack()
\fn template <class T> void QMutableListIterator<T>::toBack()
- \fn template <class T> void QMutableSetIterator<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
+ item).
+
+ \sa toFront()
+*/
+
/*! \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
- \fn template <class T> bool QMutableSetIterator<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,
+ i.e. the iterator is \e not at the back of the container;
+ otherwise returns \c false.
+
+ \sa next()
+*/
+
/*! \fn template <class T> const T &QListIterator<T>::next()
- \fn template <class T> const T &QSetIterator<T>::next()
- \fn template <class T> const T &QMutableSetIterator<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.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext()
+*/
+
+/*! \fn template <class T> const T &QMutableSetIterator<T>::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.
+
+ \sa hasNext(), peekNext()
+*/
+
/*! \fn template <class T> T &QMutableListIterator<T>::next()
Returns a reference to the next item, and advances the iterator
@@ -469,40 +483,45 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekNext() const
- \fn template <class T> const T &QSetIterator<T>::peekNext() const
- \fn template <class T> const T &QMutableSetIterator<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> T &QMutableListIterator<T>::peekNext() const
+/*!
+ \fn template <class T> const T &QSetIterator<T>::peekNext() const
+ \include qiterator.qdoc peekNext
+ \sa hasNext(), next()
+*/
- Returns a reference to the next item, without moving the iterator.
+/*!
+ \fn template <class T> const T &QMutableSetIterator<T>::peekNext() const
+
+ 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.
- \sa hasNext(), next(), peekPrevious()
+ \sa hasNext(), next()
*/
-/*!
- \fn template <class T> bool QMutableSetIterator<T>::hasPrevious() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
+/*! \fn template <class T> T &QMutableListIterator<T>::peekNext() const
- Returns \c true if there is at least one item behind the iterator,
- i.e. the iterator is \e not at the front of the container;
- otherwise returns \c false.
+ Returns a reference to the next item, without moving the iterator.
- \sa hasNext(), previous()
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+
+ \sa hasNext(), next(), peekPrevious()
*/
/*! \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,
@@ -512,21 +531,7 @@
\sa hasNext(), previous()
*/
-/*!
- \fn template <class T> const T &QMutableSetIterator<T>::previous()
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns the previous item and moves the iterator back by one
- position.
-
- Calling this function on an iterator located at the front of the
- container leads to undefined results.
-
- \sa hasPrevious(), peekPrevious(), next()
-*/
-
/*! \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.
@@ -548,20 +553,7 @@
\sa hasPrevious(), peekPrevious(), next()
*/
-/*!
- \fn template <class T> const T &QMutableSetIterator<T>::peekPrevious() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns the previous item without moving the iterator.
-
- Calling this function on an iterator located at the front of the
- container leads to undefined results.
-
- \sa hasPrevious(), previous(), peekNext()
-*/
-
/*! \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.
@@ -583,7 +575,6 @@
/*!
\fn template <class T> bool QMutableSetIterator<T>::findNext(const T &value)
- \obsolete Deprecated in order to align with std::unordered_set functionality.
Searches for \a value starting from the current iterator position
forward. Returns \c true if \a value is found; otherwise returns \c false.
@@ -591,28 +582,29 @@
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.
-
- \sa findPrevious()
*/
/*! \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)
- \fn template <class T> bool QMutableSetIterator<T>::findPrevious(const T &value)
Searches for \a value starting from the current iterator position
backward. Returns \c true if \a value is found; otherwise returns
@@ -639,7 +631,7 @@
/*! \fn template <class T> void QMutableSetIterator<T>::remove()
Removes the last item that was jumped over using one of the
- traversal functions (next(), previous(), findNext(), findPrevious()).
+ traversal functions (next(), findNext()).
Example:
\snippet code/doc_src_qiterator.cpp 22
@@ -662,7 +654,6 @@
*/
/*! \fn template <class T> const T &QMutableListIterator<T>::value() const
- \fn template <class T> const T &QMutableSetIterator<T>::value() const
Returns the value of the last item that was jumped over using one
of the traversal functions (next(), previous(), findNext(),
@@ -673,6 +664,12 @@
equivalent to peekNext().
*/
+/*! \fn template <class T> const T &QMutableSetIterator<T>::value() const
+
+ Returns the value of the last item that was jumped over using
+ next() or findNext().
+*/
+
/*!
\fn template <class T> T &QMutableListIterator<T>::value()
\overload
@@ -696,9 +693,8 @@
\brief The QMapIterator class provides a Java-style const iterator for QMap.
QMap has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QMapIterator\<Key, T\> allows you to iterate over a QMap.
If you want to modify the map as you iterate over
@@ -747,9 +743,8 @@
\brief The QMultiMapIterator class provides a Java-style const iterator for QMultiMap.
QMultiMap has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QMultiMapIterator\<Key, T\> allows you to iterate over a QMultiMap.
If you want to modify the map as you iterate over
@@ -789,7 +784,7 @@
continue iterating over the original map, ignoring the modified
copy.
- \sa QMutableMultiMapIterator, QMultiMapIterator::const_iterator
+ \sa QMutableMultiMapIterator
*/
/*!
@@ -799,9 +794,8 @@
\brief The QHashIterator class provides a Java-style const iterator for QHash and QMultiHash.
QHash has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QHashIterator\<Key, T\> allows you to iterate over a QHash (or a
QMultiHash). If you want to modify the hash as you iterate over
@@ -847,9 +841,8 @@
\brief The QMutableMapIterator class provides a Java-style non-const iterator for QMap.
QMap has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QMutableMapIterator\<Key, T\> allows you to iterate over a QMap
and modify the map. If you don't want to modify
@@ -912,9 +905,8 @@
\brief The QMutableMultiMapIterator class provides a Java-style non-const iterator for QMultiMap.
QMultiMap has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ be preferred.
QMutableMultiMapIterator\<Key, T\> allows you to iterate over a QMultiMap
and modify the map. If you don't want to modify
@@ -977,14 +969,12 @@
\brief The QMutableHashIterator class provides a Java-style non-const iterator for QHash and QMultiHash.
QHash has both \l{Java-style iterators} and \l{STL-style
- iterators}. The Java-style iterators are more high-level and
- easier to use than the STL-style iterators; on the other hand,
- they are slightly less efficient.
+ iterators}. STL-style iterators are more efficient and should
+ 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
@@ -1139,7 +1129,7 @@
Calling this function on an iterator located at the back of the
container leads to undefined results.
- \sa hasNext(), peekNext(), previous()
+ \sa hasNext(), {QMapIterator::}{peekNext()}, previous()
*/
/*! \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::next()
@@ -1185,7 +1175,7 @@
*/
/*! \fn template <class Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::peekNext() const
- \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekNext()
+ \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekNext() const
Returns the next item without moving the iterator.
@@ -1199,7 +1189,7 @@
*/
/*! \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekNext() const
- \fn template <class Key, class T> QMutableMultiMapIterator<Key, T>::Item QMutableMultiMapIterator<Key, T>::peekNext()
+ \fn template <class Key, class T> QMutableMultiMapIterator<Key, T>::Item QMutableMultiMapIterator<Key, T>::peekNext() const
Returns a reference to the next item without moving the iterator.
@@ -1252,28 +1242,6 @@
\sa hasNext(), previous()
*/
-/*!
- \fn template <class Key, class T> bool QHashIterator<Key, T>::hasPrevious() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns \c true if there is at least one item behind the iterator,
- i.e. the iterator is \e not at the front of the container;
- otherwise returns \c false.
-
- \sa hasNext(), previous()
-*/
-
-/*!
- \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::hasPrevious() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns \c true if there is at least one item behind the iterator,
- i.e. the iterator is \e not at the front of the container;
- otherwise returns \c false.
-
- \sa hasNext(), previous()
-*/
-
/*! \fn template <class Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::previous()
\fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::previous()
\fn template <class Key, class T> QMultiMapIterator<Key, T>::Item QMultiMapIterator<Key, T>::previous()
@@ -1291,38 +1259,6 @@
\sa hasPrevious(), peekPrevious(), next()
*/
-/*!
- \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::previous()
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns the previous item and moves the iterator back by one
- position.
-
- Call key() on the return value to obtain the item's key, and
- value() to obtain the value.
-
- Calling this function on an iterator located at the front of the
- container leads to undefined results.
-
- \sa hasPrevious(), peekPrevious(), next()
-*/
-
-/*!
- \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::previous()
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns the previous item and moves the iterator back by one
- position.
-
- Call key() on the return value to obtain the item's key, and
- value() to obtain the value.
-
- Calling this function on an iterator located at the front of the
- container leads to undefined results.
-
- \sa hasPrevious(), peekPrevious(), next()
-*/
-
/*! \fn template <class Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::peekPrevious() const
\fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekPrevious() const
\fn template <class Key, class T> QMultiMapIterator<Key, T>::Item QMultiMapIterator<Key, T>::peekPrevious() const
@@ -1336,37 +1272,7 @@
Calling this function on an iterator located at the front of the
container leads to undefined results.
- \sa hasPrevious(), previous(), peekNext()
-*/
-
-/*!
- \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::peekPrevious() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns the previous item without moving the iterator.
-
- Call key() on the return value to obtain the item's key, and
- value() to obtain the value.
-
- Calling this function on an iterator located at the front of the
- container leads to undefined results.
-
- \sa hasPrevious(), previous(), peekNext()
-*/
-
-/*!
- \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::peekPrevious() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Returns the previous item without moving the iterator.
-
- Call key() on the return value to obtain the item's key, and
- value() to obtain the value.
-
- Calling this function on an iterator located at the front of the
- container leads to undefined results.
-
- \sa hasPrevious(), previous(), peekNext()
+ \sa hasPrevious(), previous(), {QMapIterator::}{peekNext()}
*/
/*! \fn template <class Key, class T> const T &QMapIterator<Key, T>::value() const
@@ -1495,36 +1401,6 @@
\sa findNext()
*/
-/*!
- \fn template <class Key, class T> bool QHashIterator<Key, T>::findPrevious(const T &value)
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Searches for \a value starting from the current iterator position
- backward. Returns \c true if a (key, value) pair with value \a value
- is found; otherwise returns \c false.
-
- After the call, if \a value was found, the iterator is positioned
- just before the matching item; otherwise, the iterator is
- positioned at the front of the container.
-
- \sa findNext()
-*/
-
-/*!
- \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::findPrevious(const T &value)
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- Searches for \a value starting from the current iterator position
- backward. Returns \c true if a (key, value) pair with value \a value
- is found; otherwise returns \c false.
-
- After the call, if \a value was found, the iterator is positioned
- just before the matching item; otherwise, the iterator is
- positioned at the front of the container.
-
- \sa findNext()
-*/
-
/*! \fn template <class Key, class T> void QMutableMapIterator<Key, T>::remove()
\fn template <class Key, class T> void QMutableMultiMapIterator<Key, T>::remove()
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index d284883dcc..9216b8875b 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** 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"
+
#include "qdebug.h"
#include "qdatastream.h"
+#include "qmath.h"
#include <private/qnumeric_p.h>
QT_BEGIN_NAMESPACE
@@ -98,7 +64,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn bool QLine::isNull() const
- Returns \c true if the line is not set up with valid start and end point;
+ Returns \c true if the line does not have distinct start and end points;
otherwise returns \c false.
*/
@@ -261,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
@@ -320,7 +295,7 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
A QLineF describes a finite length line (or line segment) on a
two-dimensional surface. QLineF defines the start and end points
of the line using floating point accuracy for coordinates. Use
- the toLine() function to retrieve an integer based copy of this
+ the toLine() function to retrieve an integer-based copy of this
line.
\table
@@ -364,7 +339,7 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
\typealias QLineF::IntersectType
- \obsolete Use QLineF::IntersectionType instead.
+ \deprecated Use QLineF::IntersectionType instead.
*/
/*!
@@ -421,14 +396,20 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
Construct a QLineF object from the given integer-based \a line.
- \sa toLine()
+ \sa toLine(), QLine::toLineF()
*/
/*!
\fn bool QLineF::isNull() const
- Returns \c true if the line is not set up with valid start and end point;
- otherwise returns \c false.
+ Returns \c true if the line does not have distinct start and end points;
+ otherwise returns \c false. The start and end points are considered distinct
+ if qFuzzyCompare() can distinguish them in at least one coordinate.
+
+ \note Due to the use of fuzzy comparison, isNull() may return \c true for
+ lines whose length() is not zero.
+
+ \sa qFuzzyCompare(), length()
*/
/*!
@@ -450,12 +431,12 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
\fn QLine QLineF::toLine() const
- Returns an integer based copy of this line.
+ Returns an integer-based copy of this 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
@@ -508,13 +489,11 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
\fn void QLineF::setLength(qreal length)
- Sets the length of the line to the given \a length. QLineF will
- move the end point - p2() - of the line to give the line its new length.
-
- If the line is a null line, the length will remain zero regardless
- of the length specified.
+ Sets the length of the line to the given finite \a length. QLineF will move
+ the end point - p2() - of the line to give the line its new length, unless
+ length() was previously zero, in which case no scaling is attempted.
- \sa length(), isNull()
+ \sa length(), unitVector()
*/
/*!
@@ -549,9 +528,8 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
\fn qreal QLineF::pointAt(qreal t) const
- Returns the point at the parameterized position specified by \a
- t. The function returns the line's start point if t = 0, and its end
- point if t = 1.
+ Returns the point at the position specified by finite parameter \a t. The
+ function returns the line's start point if t = 0, and its end point if t = 1.
\sa dx(), dy()
*/
@@ -559,13 +537,11 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
Returns the length of the line.
- \sa setLength()
+ \sa setLength(), isNull()
*/
qreal QLineF::length() const
{
- qreal x = pt2.x() - pt1.x();
- qreal y = pt2.y() - pt1.y();
- return qSqrt(x*x + y*y);
+ return qHypot(dx(), dy());
}
/*!
@@ -636,17 +612,18 @@ QLineF QLineF::fromPolar(qreal length, qreal angle)
/*!
Returns the unit vector for this line, i.e a line starting at the
- same point as \e this line with a length of 1.0.
+ same point as \e this line with a length of 1.0, provided the line
+ is non-null.
- \sa normalVector()
+ \sa normalVector(), setLength()
*/
QLineF QLineF::unitVector() const
{
- qreal x = pt2.x() - pt1.x();
- qreal y = pt2.y() - pt1.y();
+ const qreal x = dx();
+ const qreal y = dy();
- qreal len = qSqrt(x*x + y*y);
- QLineF f(p1(), QPointF(pt1.x() + x/len, pt1.y() + y/len));
+ const qreal len = qHypot(x, y);
+ QLineF f(p1(), QPointF(pt1.x() + x / len, pt1.y() + y / len));
#ifndef QT_NO_DEBUG
if (qAbs(f.length() - 1) >= 0.001)
diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h
index c3fb2fd5f5..e23ffbe9d5 100644
--- a/src/corelib/tools/qline.h
+++ b/src/corelib/tools/qline.h
@@ -1,51 +1,14 @@
-/****************************************************************************
-**
-** 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
-#include <QtCore/qmath.h>
-
#include <QtCore/qpoint.h>
QT_BEGIN_NAMESPACE
+class QLineF;
/*******************************************************************************
* class QLine
@@ -75,23 +38,25 @@ public:
inline void translate(const QPoint &p);
inline void translate(int dx, int dy);
- Q_REQUIRED_RESULT constexpr inline QLine translated(const QPoint &p) const;
- Q_REQUIRED_RESULT constexpr inline QLine translated(int dx, int dy) const;
+ [[nodiscard]] constexpr inline QLine translated(const QPoint &p) const;
+ [[nodiscard]] constexpr inline QLine translated(int dx, int dy) const;
- Q_REQUIRED_RESULT constexpr inline QPoint center() const;
+ [[nodiscard]] constexpr inline QPoint center() const;
inline void setP1(const QPoint &p1);
inline void setP2(const QPoint &p2);
inline void setPoints(const QPoint &p1, const QPoint &p2);
inline void setLine(int x1, int y1, int x2, int y2);
- constexpr inline bool operator==(const QLine &d) const;
- constexpr inline bool operator!=(const QLine &d) const { return !(*this == d); }
+ 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_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QLine, Q_PRIMITIVE_TYPE);
/*******************************************************************************
* class QLine inline members
@@ -196,7 +161,7 @@ inline void QLine::setLine(int aX1, int aY1, int aX2, int aY2)
pt2 = QPoint(aX2, aY2);
}
-constexpr inline bool QLine::operator==(const QLine &d) const
+constexpr inline bool QLine::operator==(const QLine &d) const noexcept
{
return pt1 == d.pt1 && pt2 == d.pt2;
}
@@ -225,7 +190,7 @@ public:
constexpr inline QLineF(qreal x1, qreal y1, qreal x2, qreal y2);
constexpr inline QLineF(const QLine &line) : pt1(line.p1()), pt2(line.p2()) { }
- Q_REQUIRED_RESULT static QLineF fromPolar(qreal length, qreal angle);
+ [[nodiscard]] static QLineF fromPolar(qreal length, qreal angle);
constexpr bool isNull() const;
@@ -249,8 +214,8 @@ public:
qreal angleTo(const QLineF &l) const;
- Q_REQUIRED_RESULT QLineF unitVector() const;
- Q_REQUIRED_RESULT constexpr inline QLineF normalVector() const;
+ [[nodiscard]] QLineF unitVector() const;
+ [[nodiscard]] constexpr inline QLineF normalVector() const;
IntersectionType intersects(const QLineF &l, QPointF *intersectionPoint = nullptr) const;
@@ -258,10 +223,10 @@ public:
inline void translate(const QPointF &p);
inline void translate(qreal dx, qreal dy);
- Q_REQUIRED_RESULT constexpr inline QLineF translated(const QPointF &p) const;
- Q_REQUIRED_RESULT constexpr inline QLineF translated(qreal dx, qreal dy) const;
+ [[nodiscard]] constexpr inline QLineF translated(const QPointF &p) const;
+ [[nodiscard]] constexpr inline QLineF translated(qreal dx, qreal dy) const;
- Q_REQUIRED_RESULT constexpr inline QPointF center() const;
+ [[nodiscard]] constexpr inline QPointF center() const;
inline void setP1(const QPointF &p1);
inline void setP2(const QPointF &p2);
@@ -276,7 +241,7 @@ public:
private:
QPointF pt1, pt2;
};
-Q_DECLARE_TYPEINFO(QLineF, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QLineF, Q_PRIMITIVE_TYPE);
/*******************************************************************************
* class QLineF inline members
@@ -372,15 +337,15 @@ constexpr inline QPointF QLineF::center() const
return QPointF(0.5 * pt1.x() + 0.5 * pt2.x(), 0.5 * pt1.y() + 0.5 * pt2.y());
}
-QT_WARNING_DISABLE_FLOAT_COMPARE
-
inline void QLineF::setLength(qreal len)
{
- const qreal oldlength = qSqrt(dx() * dx() + dy() * dy());
- if (!oldlength)
- return;
- const qreal factor = len / oldlength;
- pt2 = QPointF(pt1.x() + dx() * factor, pt1.y() + dy() * factor);
+ Q_ASSERT(qIsFinite(len));
+ const qreal oldLength = length();
+ Q_ASSERT(qIsFinite(oldLength));
+ // Scale len by dx() / length() and dy() / length(), two O(1) quantities,
+ // rather than scaling dx() and dy() by len / length(), which might overflow.
+ if (oldLength > 0)
+ pt2 = QPointF(pt1.x() + len * (dx() / oldLength), pt1.y() + len * (dy() / oldLength));
}
constexpr inline QPointF QLineF::pointAt(qreal t) const
@@ -388,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 3f621e71fb..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
@@ -45,12 +9,16 @@
#include <QtCore/qnamespace.h>
#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 {
@@ -58,62 +26,245 @@ namespace QtPrivate {
template <typename V, typename U> qsizetype lastIndexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
}
-template <typename T> struct QListSpecialMethods
+template <typename T> struct QListSpecialMethodsBase
{
protected:
- ~QListSpecialMethods() = default;
+ ~QListSpecialMethodsBase() = default;
+
+ using Self = QList<T>;
+ Self *self() { return static_cast<Self *>(this); }
+ const Self *self() const { return static_cast<const Self *>(this); }
+
public:
- qsizetype indexOf(const T &t, qsizetype from = 0) const noexcept;
- qsizetype lastIndexOf(const T &t, qsizetype from = -1) const noexcept;
+ template <typename AT = T>
+ qsizetype indexOf(const AT &t, qsizetype from = 0) const noexcept;
+ template <typename AT = T>
+ qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const noexcept;
- bool contains(const T &t) const noexcept
+ template <typename AT = T>
+ bool contains(const AT &t) const noexcept
{
- return indexOf(t) != -1;
+ return self()->indexOf(t) != -1;
}
};
+template <typename T> struct QListSpecialMethods : QListSpecialMethodsBase<T>
+{
+protected:
+ ~QListSpecialMethods() = default;
+public:
+ using QListSpecialMethodsBase<T>::indexOf;
+ using QListSpecialMethodsBase<T>::lastIndexOf;
+ using QListSpecialMethodsBase<T>::contains;
+};
template <> struct QListSpecialMethods<QByteArray>;
template <> struct QListSpecialMethods<QString>;
+#if !defined(QT_STRICT_QLIST_ITERATORS) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) && !defined(Q_OS_WIN)
+#define QT_STRICT_QLIST_ITERATORS
+#endif
+
+#ifdef Q_QDOC // define QVector for QDoc
+template<typename T> class QVector : public QList<T> {};
+#endif
+
template <typename T>
class QList
#ifndef Q_QDOC
: public QListSpecialMethods<T>
#endif
{
- typedef QTypedArrayData<T> Data;
- typedef QArrayDataOps<T> DataOps;
- typedef QArrayDataPointer<T> DataPointer;
+ using Data = QTypedArrayData<T>;
+ using DataOps = QArrayDataOps<T>;
+ 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:
- typedef T Type;
- typedef T value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef value_type &reference;
- typedef const value_type &const_reference;
- typedef qsizetype size_type;
- typedef qptrdiff difference_type;
- typedef typename Data::iterator iterator;
- typedef typename Data::const_iterator const_iterator;
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- typedef typename DataPointer::parameter_type parameter_type;
+ using Type = T;
+ using value_type = T;
+ using pointer = T *;
+ using const_pointer = const T *;
+ using reference = T &;
+ using const_reference = const T &;
+ using size_type = qsizetype;
+ using difference_type = qptrdiff;
+#ifndef Q_QDOC
+ using parameter_type = typename DataPointer::parameter_type;
using rvalue_ref = typename std::conditional<DataPointer::pass_parameter_by_value, DisableRValueRefs, T &&>::type;
+#else // simplified aliases for QDoc
+ using parameter_type = const T &;
+ using rvalue_ref = T &&;
+#endif
+
+ class const_iterator;
+ class iterator {
+ friend class QList<T>;
+ friend class const_iterator;
+ T *i = nullptr;
+#ifdef QT_STRICT_QLIST_ITERATORS
+ inline constexpr explicit iterator(T *n) : i(n) {}
+#endif
+
+ public:
+ using difference_type = qsizetype;
+ using value_type = T;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using iterator_concept = std::contiguous_iterator_tag;
+ using element_type = value_type;
+#endif
+ using iterator_category = std::random_access_iterator_tag;
+ using pointer = T *;
+ using reference = T &;
+
+ inline constexpr iterator() = default;
+#ifndef QT_STRICT_QLIST_ITERATORS
+ inline constexpr explicit iterator(T *n) : i(n) {}
+#endif
+ inline T &operator*() const { return *i; }
+ inline T *operator->() const { return i; }
+ inline T &operator[](qsizetype j) const { return *(i + j); }
+ inline constexpr bool operator==(iterator o) const { return i == o.i; }
+ inline constexpr bool operator!=(iterator o) const { return i != o.i; }
+ inline constexpr bool operator<(iterator other) const { return i < other.i; }
+ inline constexpr bool operator<=(iterator other) const { return i <= other.i; }
+ inline constexpr bool operator>(iterator other) const { return i > other.i; }
+ inline constexpr bool operator>=(iterator other) const { return i >= other.i; }
+ inline constexpr bool operator==(const_iterator o) const { return i == o.i; }
+ inline constexpr bool operator!=(const_iterator o) const { return i != o.i; }
+ inline constexpr bool operator<(const_iterator other) const { return i < other.i; }
+ inline constexpr bool operator<=(const_iterator other) const { return i <= other.i; }
+ inline constexpr bool operator>(const_iterator other) const { return i > other.i; }
+ inline constexpr bool operator>=(const_iterator other) const { return i >= other.i; }
+ inline constexpr bool operator==(pointer p) const { return i == p; }
+ inline constexpr bool operator!=(pointer p) const { return i != p; }
+ inline iterator &operator++() { ++i; return *this; }
+ inline iterator operator++(int) { auto copy = *this; ++*this; return copy; }
+ inline iterator &operator--() { --i; return *this; }
+ inline iterator operator--(int) { auto copy = *this; --*this; return copy; }
+ inline qsizetype operator-(iterator j) const { return i - j.i; }
+#if QT_DEPRECATED_SINCE(6, 3) && !defined(QT_STRICT_QLIST_ITERATORS)
+ QT_DEPRECATED_VERSION_X_6_3("Use operator* or operator-> rather than relying on "
+ "the implicit conversion between a QList/QVector::iterator "
+ "and a raw pointer")
+ inline operator T*() const { return i; }
+
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, iterator>
+ &operator+=(Int j) { i+=j; return *this; }
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, iterator>
+ &operator-=(Int j) { i-=j; return *this; }
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, iterator>
+ operator+(Int j) const { return iterator(i+j); }
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, iterator>
+ operator-(Int j) const { return iterator(i-j); }
+ template <typename Int> friend std::enable_if_t<std::is_integral_v<Int>, iterator>
+ operator+(Int j, iterator k) { return k + j; }
+#else
+ inline iterator &operator+=(qsizetype j) { i += j; return *this; }
+ inline iterator &operator-=(qsizetype j) { i -= j; return *this; }
+ inline iterator operator+(qsizetype j) const { return iterator(i + j); }
+ inline iterator operator-(qsizetype j) const { return iterator(i - j); }
+ friend inline iterator operator+(qsizetype j, iterator k) { return k + j; }
+#endif
+ };
+
+ class const_iterator {
+ friend class QList<T>;
+ friend class iterator;
+ const T *i = nullptr;
+#ifdef QT_STRICT_QLIST_ITERATORS
+ inline constexpr explicit const_iterator(const T *n) : i(n) {}
+#endif
+
+ public:
+ using difference_type = qsizetype;
+ using value_type = T;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using iterator_concept = std::contiguous_iterator_tag;
+ using element_type = const value_type;
+#endif
+ using iterator_category = std::random_access_iterator_tag;
+ using pointer = const T *;
+ using reference = const T &;
+
+ inline constexpr const_iterator() = default;
+#ifndef QT_STRICT_QLIST_ITERATORS
+ inline constexpr explicit const_iterator(const T *n) : i(n) {}
+#endif
+ inline constexpr const_iterator(iterator o): i(o.i) {}
+ inline const T &operator*() const { return *i; }
+ inline const T *operator->() const { return i; }
+ inline const T &operator[](qsizetype j) const { return *(i + j); }
+ inline constexpr bool operator==(const_iterator o) const { return i == o.i; }
+ inline constexpr bool operator!=(const_iterator o) const { return i != o.i; }
+ inline constexpr bool operator<(const_iterator other) const { return i < other.i; }
+ inline constexpr bool operator<=(const_iterator other) const { return i <= other.i; }
+ inline constexpr bool operator>(const_iterator other) const { return i > other.i; }
+ inline constexpr bool operator>=(const_iterator other) const { return i >= other.i; }
+ inline constexpr bool operator==(iterator o) const { return i == o.i; }
+ inline constexpr bool operator!=(iterator o) const { return i != o.i; }
+ inline constexpr bool operator<(iterator other) const { return i < other.i; }
+ inline constexpr bool operator<=(iterator other) const { return i <= other.i; }
+ inline constexpr bool operator>(iterator other) const { return i > other.i; }
+ inline constexpr bool operator>=(iterator other) const { return i >= other.i; }
+ inline constexpr bool operator==(pointer p) const { return i == p; }
+ inline constexpr bool operator!=(pointer p) const { return i != p; }
+ inline const_iterator &operator++() { ++i; return *this; }
+ inline const_iterator operator++(int) { auto copy = *this; ++*this; return copy; }
+ inline const_iterator &operator--() { --i; return *this; }
+ inline const_iterator operator--(int) { auto copy = *this; --*this; return copy; }
+ inline qsizetype operator-(const_iterator j) const { return i - j.i; }
+#if QT_DEPRECATED_SINCE(6, 3) && !defined(QT_STRICT_QLIST_ITERATORS)
+ QT_DEPRECATED_VERSION_X_6_3("Use operator* or operator-> rather than relying on "
+ "the implicit conversion between a QList/QVector::const_iterator "
+ "and a raw pointer")
+ inline operator const T*() const { return i; }
+
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, const_iterator>
+ &operator+=(Int j) { i+=j; return *this; }
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, const_iterator>
+ &operator-=(Int j) { i-=j; return *this; }
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, const_iterator>
+ operator+(Int j) const { return const_iterator(i+j); }
+ template <typename Int> std::enable_if_t<std::is_integral_v<Int>, const_iterator>
+ operator-(Int j) const { return const_iterator(i-j); }
+ template <typename Int> friend std::enable_if_t<std::is_integral_v<Int>, const_iterator>
+ operator+(Int j, const_iterator k) { return k + j; }
+#else
+ inline const_iterator &operator+=(qsizetype j) { i += j; return *this; }
+ inline const_iterator &operator-=(qsizetype j) { i -= j; return *this; }
+ inline const_iterator operator+(qsizetype j) const { return const_iterator(i + j); }
+ inline const_iterator operator-(qsizetype j) const { return const_iterator(i - j); }
+ friend inline const_iterator operator+(qsizetype j, const_iterator k) { return k + j; }
+#endif
+ };
+ using Iterator = iterator;
+ using ConstIterator = const_iterator;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
- void resize_internal(qsizetype i, Qt::Initialization);
+ void resize_internal(qsizetype i);
bool isValidIterator(const_iterator i) const
{
const std::less<const T*> less = {};
- return !less(d->end(), i) && !less(i, d->begin());
+ 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
@@ -124,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, const T &t)
- : d(Data::allocate(size))
+ QList(qsizetype size, parameter_type t)
+ : 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());
@@ -145,25 +296,28 @@ 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;
- }
- template <typename InputIterator, QtPrivate::IfIsForwardIterator<InputIterator> = true>
- QList(InputIterator i1, InputIterator i2)
- {
- const auto distance = std::distance(i1, i2);
- if (distance) {
- d = DataPointer(Data::allocate(distance));
- d->copyAppend(i1, i2);
- }
+ return assign(args);
}
- template <typename InputIterator, QtPrivate::IfIsNotForwardIterator<InputIterator> = true>
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
QList(InputIterator i1, InputIterator i2)
{
- std::copy(i1, i2, std::back_inserter(*this));
+ 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(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> ||
+ std::is_same_v<std::decay_t<InputIterator>, const_iterator>) {
+ d->copyAppend(i1.i, i2.i);
+ } else {
+ d->appendIteratorRange(i1, i2);
+ }
+ }
+ }
}
// This constructor is here for compatibility with QStringList in Qt 5, that has a QStringList(const QString &) constructor
@@ -171,14 +325,74 @@ 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_QDOC
+ template <typename U = T>
+ QTypeTraits::compare_eq_result_container<QList, U> operator==(const QList &other) const
+ {
+ if (size() != other.size())
+ return false;
+ if (begin() == other.begin())
+ return true;
+
+ // do element-by-element comparison
+ return d->compare(data(), other.data(), size());
+ }
+ template <typename U = T>
+ QTypeTraits::compare_eq_result_container<QList, U> operator!=(const QList &other) const
+ {
+ return !(*this == other);
+ }
+
+ template <typename U = T>
+ QTypeTraits::compare_lt_result_container<QList, U> operator<(const QList &other) const
+ noexcept(noexcept(std::lexicographical_compare<typename QList<U>::const_iterator,
+ typename QList::const_iterator>(
+ std::declval<QList<U>>().begin(), std::declval<QList<U>>().end(),
+ other.begin(), other.end())))
+ {
+ return std::lexicographical_compare(begin(), end(),
+ other.begin(), other.end());
+ }
- template <typename U>
- friend QTypeTraits::compare_eq_result<U> operator==(const QList<U> &l, const QList<U> &r);
- template <typename U>
- friend QTypeTraits::compare_eq_result<U> operator!=(const QList<U> &l, const QList<U> &r);
+ template <typename U = T>
+ QTypeTraits::compare_lt_result_container<QList, U> operator>(const QList &other) const
+ noexcept(noexcept(other < std::declval<QList<U>>()))
+ {
+ return other < *this;
+ }
+
+ template <typename U = T>
+ QTypeTraits::compare_lt_result_container<QList, U> operator<=(const QList &other) const
+ noexcept(noexcept(other < std::declval<QList<U>>()))
+ {
+ return !(other < *this);
+ }
+
+ template <typename U = T>
+ QTypeTraits::compare_lt_result_container<QList, U> operator>=(const QList &other) const
+ noexcept(noexcept(std::declval<QList<U>>() < other))
+ {
+ return !(*this < other);
+ }
+#else
+ bool operator==(const QList &other) const;
+ bool operator!=(const QList &other) const;
+ bool operator<(const QList &other) const;
+ bool operator>(const QList &other) const;
+ bool operator<=(const QList &other) const;
+ bool operator>=(const QList &other) const;
+#endif // Q_QDOC
qsizetype size() const noexcept { return d->size; }
qsizetype count() const noexcept { return size(); }
@@ -188,16 +402,22 @@ public:
void resize(qsizetype size)
{
- resize_internal(size, Qt::Uninitialized);
+ resize_internal(size);
if (size > this->size())
d->appendInitialize(size);
}
void resize(qsizetype size, parameter_type c)
{
- resize_internal(size, Qt::Uninitialized);
+ resize_internal(size);
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);
@@ -216,7 +436,7 @@ public:
return;
if (d->needsDetach()) {
// must allocate memory
- DataPointer detached(Data::allocate(d.allocatedCapacity(), d->detachFlags()));
+ DataPointer detached(d.allocatedCapacity());
d.swap(detached);
} else {
d->truncate(0);
@@ -231,24 +451,42 @@ 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); }
- void append(const_reference t)
- { append(const_iterator(std::addressof(t)), const_iterator(std::addressof(t)) + 1); }
+ void append(parameter_type t) { emplaceBack(t); }
void append(const_iterator i1, const_iterator i2);
- void append(rvalue_ref t) { emplaceBack(std::move(t)); }
- void append(const QList<T> &l) { append(l.constBegin(), l.constEnd()); }
+ void append(rvalue_ref t)
+ {
+ if constexpr (DataPointer::pass_parameter_by_value) {
+ Q_UNUSED(t);
+ } else {
+ emplaceBack(std::move(t));
+ }
+ }
+ void append(const QList<T> &l)
+ {
+ append(l.constBegin(), l.constEnd());
+ }
void append(QList<T> &&l);
- void prepend(rvalue_ref t);
- void prepend(const T &t);
+ void prepend(rvalue_ref t) {
+ if constexpr (DataPointer::pass_parameter_by_value) {
+ Q_UNUSED(t);
+ } else {
+ emplaceFront(std::move(t));
+ }
+ }
+ void prepend(parameter_type t) { emplaceFront(t); }
+
+ template<typename... Args>
+ inline reference emplaceBack(Args &&... args);
template <typename ...Args>
- reference emplaceBack(Args&&... args) { return *emplace(count(), std::forward<Args>(args)...); }
+ inline reference emplaceFront(Args&&... args);
iterator insert(qsizetype i, parameter_type t)
- { return insert(i, 1, t); }
+ { return emplace(i, t); }
iterator insert(qsizetype i, qsizetype n, parameter_type t);
iterator insert(const_iterator before, parameter_type t)
{
@@ -265,7 +503,28 @@ public:
Q_ASSERT_X(isValidIterator(before), "QList::insert", "The specified iterator argument 'before' is invalid");
return insert(std::distance(constBegin(), before), std::move(t));
}
- iterator insert(qsizetype i, rvalue_ref t) { return emplace(i, std::move(t)); }
+ iterator insert(qsizetype i, rvalue_ref t) {
+ if constexpr (DataPointer::pass_parameter_by_value) {
+ Q_UNUSED(i);
+ Q_UNUSED(t);
+ return end();
+ } else {
+ return emplace(i, std::move(t));
+ }
+ }
+
+ 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)
@@ -281,24 +540,31 @@ public:
iterator insert( const_iterator pos, InputIt first, InputIt last );
iterator insert( const_iterator pos, std::initializer_list<T> ilist );
#endif
- void replace(qsizetype i, const T &t)
+ void replace(qsizetype i, parameter_type t)
{
Q_ASSERT_X(i >= 0 && i < d->size, "QList<T>::replace", "index out of range");
- const T copy(t);
- data()[i] = copy;
+ DataPointer oldData;
+ d.detach(&oldData);
+ d.data()[i] = t;
}
void replace(qsizetype i, rvalue_ref t)
{
- Q_ASSERT_X(i >= 0 && i < d->size, "QList<T>::replace", "index out of range");
- const T copy(std::move(t));
- data()[i] = std::move(copy);
+ if constexpr (DataPointer::pass_parameter_by_value) {
+ Q_UNUSED(i);
+ Q_UNUSED(t);
+ } else {
+ Q_ASSERT_X(i >= 0 && i < d->size, "QList<T>::replace", "index out of range");
+ DataPointer oldData;
+ d.detach(&oldData);
+ d.data()[i] = std::move(t);
+ }
}
void remove(qsizetype i, qsizetype n = 1);
- void removeFirst() { Q_ASSERT(!isEmpty()); remove(0); }
- void removeLast() { Q_ASSERT(!isEmpty()); remove(size() - 1); }
- value_type takeFirst() { Q_ASSERT(!isEmpty()); value_type v = std::move(first()); remove(0); return v; }
- value_type takeLast() { Q_ASSERT(!isEmpty()); value_type v = std::move(last()); remove(size() - 1); return v; }
+ void removeFirst() noexcept;
+ void removeLast() noexcept;
+ value_type takeFirst() { Q_ASSERT(!isEmpty()); value_type v = std::move(first()); d->eraseFirst(); return v; }
+ value_type takeLast() { Q_ASSERT(!isEmpty()); value_type v = std::move(last()); d->eraseLast(); return v; }
QList<T> &fill(parameter_type t, qsizetype size = -1);
@@ -307,39 +573,39 @@ public:
using QListSpecialMethods<T>::indexOf;
using QListSpecialMethods<T>::lastIndexOf;
#else
- qsizetype indexOf(const T &t, qsizetype from = 0) const noexcept;
- qsizetype lastIndexOf(const T &t, qsizetype from = -1) const noexcept;
- bool contains(const T &t) const noexcept;
+ template <typename AT>
+ qsizetype indexOf(const AT &t, qsizetype from = 0) const noexcept;
+ template <typename AT>
+ qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const noexcept;
+ template <typename AT>
+ bool contains(const AT &t) const noexcept;
#endif
- qsizetype count(const T &t) const noexcept
+ 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));
}
- // QList compatibility
void removeAt(qsizetype i) { remove(i); }
- qsizetype removeAll(const T &t)
- {
- const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
- if (cit == ce)
- return 0;
- qsizetype index = cit - this->cbegin();
- // next operation detaches, so ce, cit, t may become invalidated:
- const T tCopy = t;
- const iterator e = end(), it = std::remove(begin() + index, e, tCopy);
- const qsizetype result = std::distance(it, e);
- erase(it, e);
- return result;
- }
- bool removeOne(const T &t)
- {
- const qsizetype i = indexOf(t);
- if (i < 0)
- return false;
- remove(i);
- return true;
+ template <typename AT = T>
+ qsizetype removeAll(const AT &t)
+ {
+ return QtPrivate::sequential_erase_with_copy(*this, t);
+ }
+
+ template <typename AT = T>
+ bool removeOne(const AT &t)
+ {
+ return QtPrivate::sequential_erase_one(*this, t);
+ }
+
+ template <typename Predicate>
+ qsizetype removeIf(Predicate pred)
+ {
+ return QtPrivate::sequential_erase_if(*this, pred);
}
+
T takeAt(qsizetype i) { T t = std::move((*this)[i]); remove(i); return t; }
void move(qsizetype from, qsizetype to)
{
@@ -356,15 +622,15 @@ public:
}
// STL-style
- iterator begin() { detach(); return d->begin(); }
- iterator end() { detach(); return d->end(); }
-
- const_iterator begin() const noexcept { return d->constBegin(); }
- const_iterator end() const noexcept { return d->constEnd(); }
- const_iterator cbegin() const noexcept { return d->constBegin(); }
- const_iterator cend() const noexcept { return d->constEnd(); }
- const_iterator constBegin() const noexcept { return d->constBegin(); }
- const_iterator constEnd() const noexcept { return d->constEnd(); }
+ iterator begin() { detach(); return iterator(d->begin()); }
+ iterator end() { detach(); return iterator(d->end()); }
+
+ const_iterator begin() const noexcept { return const_iterator(d->constBegin()); }
+ const_iterator end() const noexcept { return const_iterator(d->constEnd()); }
+ const_iterator cbegin() const noexcept { return const_iterator(d->constBegin()); }
+ const_iterator cend() const noexcept { return const_iterator(d->constEnd()); }
+ const_iterator constBegin() const noexcept { return const_iterator(d->constBegin()); }
+ const_iterator constEnd() const noexcept { return const_iterator(d->constEnd()); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
@@ -377,40 +643,26 @@ public:
// more Qt
inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T &constFirst() const { Q_ASSERT(!isEmpty()); return *begin(); }
+ inline const T &first() const noexcept { Q_ASSERT(!isEmpty()); return *begin(); }
+ inline const T &constFirst() const noexcept { Q_ASSERT(!isEmpty()); return *begin(); }
inline T& last() { Q_ASSERT(!isEmpty()); return *(end()-1); }
- inline const T &last() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
- inline const T &constLast() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
- inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
- inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
+ inline const T &last() const noexcept { Q_ASSERT(!isEmpty()); return *(end()-1); }
+ inline const T &constLast() const noexcept { Q_ASSERT(!isEmpty()); return *(end()-1); }
+ inline bool startsWith(parameter_type t) const { return !isEmpty() && first() == t; }
+ inline bool endsWith(parameter_type t) const { return !isEmpty() && last() == t; }
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, const T &defaultValue) const;
+ T value(qsizetype i, parameter_type defaultValue) const;
void swapItemsAt(qsizetype i, qsizetype j) {
Q_ASSERT_X(i >= 0 && i < size() && j >= 0 && j < size(),
@@ -420,34 +672,42 @@ public:
}
// STL compatibility
- inline void push_back(const T &t) { append(t); }
+ inline void push_back(parameter_type t) { append(t); }
void push_back(rvalue_ref t) { append(std::move(t)); }
void push_front(rvalue_ref t) { prepend(std::move(t)); }
- inline void push_front(const T &t) { prepend(t); }
- void pop_back() { removeLast(); }
- void pop_front() { removeFirst(); }
+ inline void push_front(parameter_type t) { prepend(t); }
+ void pop_back() noexcept { removeLast(); }
+ void pop_front() noexcept { removeFirst(); }
template <typename ...Args>
reference emplace_back(Args&&... args) { return emplaceBack(std::forward<Args>(args)...); }
- inline bool empty() const
+ inline bool empty() const noexcept
{ return d->size == 0; }
inline reference front() { return first(); }
- inline const_reference front() const { return first(); }
+ inline const_reference front() const noexcept { return first(); }
inline reference back() { return last(); }
- inline const_reference back() const { 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.cbegin(), l.cend()); return *this; }
+ 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; }
- inline QList<T> &operator+=(const T &t)
+ 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<< (const T &t)
+ inline QList<T> &operator<< (parameter_type t)
{ append(t); return *this; }
inline QList<T> &operator<<(const QList<T> &l)
{ *this += l; return *this; }
@@ -459,43 +719,34 @@ public:
{ append(std::move(t)); return *this; }
// Consider deprecating in 6.4 or later
- static QList<T> fromList(const QList<T> &list) { return list; }
- QList<T> toList() const { return *this; }
+ static QList<T> fromList(const QList<T> &list) noexcept { return list; }
+ QList<T> toList() const noexcept { return *this; }
- static inline QList<T> fromVector(const QList<T> &vector) { return vector; }
- inline QList<T> toVector() const { return *this; }
+ static inline QList<T> fromVector(const QList<T> &vector) noexcept { return vector; }
+ inline QList<T> toVector() const noexcept { return *this; }
template<qsizetype N>
- static QList<T> fromReadOnlyData(const T (&t)[N])
+ static QList<T> fromReadOnlyData(const T (&t)[N]) noexcept
{
return QList<T>({ nullptr, const_cast<T *>(t), N });
}
};
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
template <typename InputIterator,
typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
QtPrivate::IfIsInputIterator<InputIterator> = true>
QList(InputIterator, InputIterator) -> QList<ValueType>;
-#endif
template <typename T>
-inline void QList<T>::resize_internal(qsizetype newSize, Qt::Initialization)
+inline void QList<T>::resize_internal(qsizetype newSize)
{
Q_ASSERT(newSize >= 0);
if (d->needsDetach() || newSize > capacity() - d.freeSpaceAtBegin()) {
- // must allocate memory
- DataPointer detached(Data::allocate(d->detachCapacity(newSize),
- d->detachFlags()));
- if (size() && newSize) {
- detached->copyAppend(constBegin(), constBegin() + qMin(newSize, size()));
- }
- d.swap(detached);
- }
-
- if (newSize < size())
+ d.detachAndGrow(QArrayData::GrowsAtEnd, newSize - d.size, nullptr, nullptr);
+ } else if (newSize < size()) {
d->truncate(newSize);
+ }
}
template <typename T>
@@ -512,23 +763,31 @@ void QList<T>::reserve(qsizetype asize)
}
}
- DataPointer detached(Data::allocate(qMax(asize, size()),
- d->detachFlags() | Data::CapacityReserved));
- detached->copyAppend(constBegin(), constEnd());
+ DataPointer detached(qMax(asize, size()));
+ detached->copyAppend(d->begin(), d->end());
+ if (detached.d_ptr())
+ detached->setFlag(Data::CapacityReserved);
d.swap(detached);
}
template <typename T>
inline void QList<T>::squeeze()
{
- if (d->needsDetach() || size() != capacity()) {
+ if (!d.isMutable())
+ return;
+ if (d->needsDetach() || size() < capacity()) {
// must allocate memory
- DataPointer detached(Data::allocate(size(), d->detachFlags() & ~Data::CapacityReserved));
+ DataPointer detached(size());
if (size()) {
- detached->copyAppend(constBegin(), constEnd());
+ if (d.needsDetach())
+ detached->copyAppend(d.data(), d.data() + d.size);
+ else
+ detached->moveAppend(d.data(), d.data() + d.size);
}
d.swap(detached);
}
+ // We're detached so this is fine
+ d->clearFlag(Data::CapacityReserved);
}
template <typename T>
@@ -540,33 +799,29 @@ inline void QList<T>::remove(qsizetype i, qsizetype n)
if (n == 0)
return;
- const size_t newSize = size() - n;
- if (d->needsDetach() ||
- ((d->flags() & Data::CapacityReserved) == 0
- && newSize < d->allocatedCapacity()/2)) {
- // allocate memory
- DataPointer detached(Data::allocate(d->detachCapacity(newSize), d->detachFlags()));
- const_iterator where = constBegin() + i;
- if (newSize) {
- detached->copyAppend(constBegin(), where);
- detached->copyAppend(where + n, constEnd());
- }
- d.swap(detached);
- } else {
- // we're detached and we can just move data around
- d->erase(d->begin() + i, d->begin() + i + n);
- }
+ d.detach();
+ d->erase(d->begin() + i, n);
}
template <typename T>
-inline void QList<T>::prepend(const T &t)
-{ insert(0, 1, t); }
+inline void QList<T>::removeFirst() noexcept
+{
+ Q_ASSERT(!isEmpty());
+ d.detach();
+ d->eraseFirst();
+}
+
template <typename T>
-void QList<T>::prepend(rvalue_ref t)
-{ insert(0, std::move(t)); }
+inline void QList<T>::removeLast() noexcept
+{
+ Q_ASSERT(!isEmpty());
+ d.detach();
+ d->eraseLast();
+}
+
template<typename T>
-inline T QList<T>::value(qsizetype i, const T &defaultValue) const
+inline T QList<T>::value(qsizetype i, parameter_type defaultValue) const
{
return size_t(i) < size_t(d->size) ? at(i) : defaultValue;
}
@@ -574,48 +829,30 @@ inline T QList<T>::value(qsizetype i, const T &defaultValue) const
template <typename T>
inline void QList<T>::append(const_iterator i1, const_iterator i2)
{
- if (i1 == i2)
- return;
- const size_t distance = std::distance(i1, i2);
- const size_t newSize = size() + distance;
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), qsizetype(distance));
- if (d->needsDetach() || newSize > d->allocatedCapacity() || shouldGrow) {
- DataPointer detached(DataPointer::allocateGrow(d, newSize,
- d->detachFlags() | Data::GrowsForward));
- detached->copyAppend(constBegin(), constEnd());
- detached->copyAppend(i1, i2);
- d.swap(detached);
- } else {
- // we're detached and we can just move data around
- d->copyAppend(i1, i2);
- }
+ d->growAppend(i1.i, i2.i);
}
template <typename T>
inline void QList<T>::append(QList<T> &&other)
{
+ Q_ASSERT(&other != this);
if (other.isEmpty())
return;
if (other.d->needsDetach() || !std::is_nothrow_move_constructible_v<T>)
return append(other);
- const size_t newSize = size() + other.size();
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.end(), other.size());
- if (d->needsDetach() || newSize > d->allocatedCapacity() || shouldGrow) {
- DataPointer detached(DataPointer::allocateGrow(d, newSize,
- d->detachFlags() | Data::GrowsForward));
-
- if (!d->needsDetach())
- detached->moveAppend(begin(), end());
- else
- detached->copyAppend(cbegin(), cend());
- detached->moveAppend(other.begin(), other.end());
+ // due to precondition &other != this, we can unconditionally modify 'this'
+ d.detachAndGrow(QArrayData::GrowsAtEnd, other.size(), nullptr, nullptr);
+ Q_ASSERT(d.freeSpaceAtEnd() >= other.size());
+ d->moveAppend(other.d->begin(), other.d->end());
+}
- d.swap(detached);
- } else {
- // we're detached and we can just move data around
- d->moveAppend(other.begin(), other.end());
- }
+template<typename T>
+template<typename... Args>
+inline typename QList<T>::reference QList<T>::emplaceFront(Args &&... args)
+{
+ d->emplace(0, std::forward<Args>(args)...);
+ return *d.begin();
}
@@ -624,33 +861,10 @@ inline typename QList<T>::iterator
QList<T>::insert(qsizetype i, qsizetype n, parameter_type t)
{
Q_ASSERT_X(size_t(i) <= size_t(d->size), "QList<T>::insert", "index out of range");
-
- // we don't have a quick exit for n == 0
- // it's not worth wasting CPU cycles for that
-
- const size_t newSize = size() + n;
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + i, n);
- if (d->needsDetach() || newSize > d->allocatedCapacity() || shouldGrow) {
- typename Data::ArrayOptions flags = d->detachFlags() | Data::GrowsForward;
- if (d.size != 0 && i <= d.size / 4)
- flags |= Data::GrowsBackwards;
-
- DataPointer detached(DataPointer::allocateGrow(d, newSize, flags));
- const_iterator where = constBegin() + i;
- detached->copyAppend(constBegin(), where);
- detached->copyAppend(n, t);
- detached->copyAppend(where, constEnd());
- d.swap(detached);
- } else {
- // we're detached and we can just move data around
- if (i == size()) {
- d->copyAppend(n, t);
- } else {
- T copy(t);
- d->insert(d.begin() + i, n, copy);
- }
- }
- return d.begin() + i;
+ Q_ASSERT_X(n >= 0, "QList::insert", "invalid count");
+ if (Q_LIKELY(n))
+ d->insert(i, n, t);
+ return begin() + i;
}
template <typename T>
@@ -658,31 +872,17 @@ template <typename ...Args>
typename QList<T>::iterator
QList<T>::emplace(qsizetype i, Args&&... args)
{
- Q_ASSERT_X(i >= 0 && i <= d->size, "QList<T>::insert", "index out of range");
-
- const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + i, 1);
- const size_t newSize = size() + 1;
- if (d->needsDetach() || newSize > d->allocatedCapacity() || shouldGrow) {
- typename Data::ArrayOptions flags = d->detachFlags() | Data::GrowsForward;
- if (d.size != 0 && i <= d.size / 4)
- flags |= Data::GrowsBackwards;
-
- DataPointer detached(DataPointer::allocateGrow(d, newSize, flags));
- const_iterator where = constBegin() + i;
- // Create an element here to handle cases when a user moves the element
- // from a container to the same container. This is a critical step for
- // COW types (e.g. Qt types) since copyAppend() done before emplace()
- // would shallow-copy the passed element and ruin the move
- T tmp(std::forward<Args>(args)...);
-
- detached->copyAppend(constBegin(), where);
- detached->emplace(detached.end(), std::move(tmp));
- detached->copyAppend(where, constEnd());
- d.swap(detached);
- } else {
- d->emplace(d.begin() + i, std::forward<Args>(args)...);
- }
- return d.begin() + i;
+ Q_ASSERT_X(i >= 0 && i <= d->size, "QList<T>::insert", "index out of range");
+ d->emplace(i, std::forward<Args>(args)...);
+ return begin() + i;
+}
+
+template<typename T>
+template<typename... Args>
+inline typename QList<T>::reference QList<T>::emplaceBack(Args &&... args)
+{
+ d->emplace(d->size, std::forward<Args>(args)...);
+ return *(end() - 1);
}
template <typename T>
@@ -692,11 +892,11 @@ typename QList<T>::iterator QList<T>::erase(const_iterator abegin, const_iterato
Q_ASSERT_X(isValidIterator(aend), "QList::erase", "The specified iterator argument 'aend' is invalid");
Q_ASSERT(aend >= abegin);
- qsizetype i = std::distance(d.constBegin(), abegin);
+ qsizetype i = std::distance(constBegin(), abegin);
qsizetype n = std::distance(abegin, aend);
remove(i, n);
- return d.begin() + i;
+ return begin() + i;
}
template <typename T>
@@ -706,16 +906,18 @@ 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),
- d->detachFlags()));
+ DataPointer detached(d->detachCapacity(newSize));
detached->copyAppend(newSize, t);
d.swap(detached);
} else {
// we're detached
const T copy(t);
d->assign(d.begin(), d.begin() + qMin(size(), newSize), t);
- if (newSize > size())
+ if (newSize > size()) {
d->copyAppend(newSize - size(), copy);
+ } else if (newSize < size()) {
+ d->truncate(newSize);
+ }
}
return *this;
}
@@ -756,15 +958,17 @@ qsizetype lastIndexOf(const QList<T> &vector, const U &u, qsizetype from) noexce
}
template <typename T>
-qsizetype QListSpecialMethods<T>::indexOf(const T &t, qsizetype from) const noexcept
+template <typename AT>
+qsizetype QListSpecialMethodsBase<T>::indexOf(const AT &t, qsizetype from) const noexcept
{
- return QtPrivate::indexOf(*static_cast<const QList<T> *>(this), t, from);
+ return QtPrivate::indexOf(*self(), t, from);
}
template <typename T>
-qsizetype QListSpecialMethods<T>::lastIndexOf(const T &t, qsizetype from) const noexcept
+template <typename AT>
+qsizetype QListSpecialMethodsBase<T>::lastIndexOf(const AT &t, qsizetype from) const noexcept
{
- return QtPrivate::lastIndexOf(*static_cast<const QList<T> *>(this), t, from);
+ return QtPrivate::lastIndexOf(*self(), t, from);
}
template <typename T>
@@ -784,8 +988,8 @@ inline QList<T> QList<T>::mid(qsizetype pos, qsizetype len) const
}
// Allocate memory
- DataPointer copied(Data::allocate(l));
- copied->copyAppend(constBegin() + p, constBegin() + p + l);
+ DataPointer copied(l);
+ copied->copyAppend(data() + p, data() + p + l);
return copied;
}
@@ -799,58 +1003,19 @@ size_t qHash(const QList<T> &key, size_t seed = 0)
return qHashRange(key.cbegin(), key.cend(), seed);
}
-template <typename U>
-QTypeTraits::compare_eq_result<U> operator==(const QList<U> &l, const QList<U> &r)
-{
- if (l.size() != r.size())
- return false;
- if (l.begin() == r.begin())
- return true;
-
- // do element-by-element comparison
- return l.d->compare(l.begin(), r.begin(), l.size());
-}
-
-template <typename U>
-QTypeTraits::compare_eq_result<U> operator!=(const QList<U> &l, const QList<U> &r)
-{
- return !(l == r);
-}
-
-template <typename T>
-auto operator<(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end())))
- -> decltype(std::declval<T>() < std::declval<T>())
-{
- return std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end());
-}
-
-template <typename T>
-auto operator>(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(lhs < rhs))
- -> decltype(lhs < rhs)
+template <typename T, typename AT>
+qsizetype erase(QList<T> &list, const AT &t)
{
- return rhs < lhs;
+ return QtPrivate::sequential_erase(list, t);
}
-template <typename T>
-auto operator<=(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(lhs < rhs))
- -> decltype(lhs < rhs)
-{
- return !(lhs > rhs);
-}
-
-template <typename T>
-auto operator>=(const QList<T> &lhs, const QList<T> &rhs)
- noexcept(noexcept(lhs < rhs))
- -> decltype(lhs < rhs)
+template <typename T, typename Predicate>
+qsizetype erase_if(QList<T> &list, Predicate pred)
{
- return !(lhs < rhs);
+ return QtPrivate::sequential_erase_if(list, pred);
}
+// ### Qt 7 char32_t
QList<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); }
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
index c25a7fe4cb..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
@@ -136,14 +112,14 @@
to reduce the number of reallocations by preallocating up to twice
as much memory as the actual data needs.
- If you know in advance approximately how many items the QList
- will contain, you can call reserve(), asking QList to
- preallocate a certain amount of memory. You can also call
- capacity() to find out how much memory QList actually
- allocated.
+ If you're building a QList gradually and know in advance
+ approximately how many elements it will contain, you can call reserve(),
+ asking QList to preallocate a certain amount of memory.
+ You can also call capacity() to find out how much memory the
+ QList actually has allocated.
- Note that using non-const operators and functions can cause
- QList to do a deep copy of the data. This is due to \l{implicit sharing}.
+ Note that using non-const operators and functions can cause QList
+ to do a deep copy of the data, due to \l{implicit sharing}.
QList's value type must be an \l{assignable data type}. This
covers most data types that are commonly used, but the compiler
@@ -153,20 +129,12 @@
support \c operator==(). These requirements are documented on a
per-function basis.
- Like the other container classes, QList provides \l{Java-style
- iterators} (QListIterator and QMutableListIterator) and
- \l{STL-style iterators} (QList::const_iterator and
- QList::iterator). In practice, these are rarely used, because
- you can use indexes into the QList.
+ 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
speed.
- QList does \e not support inserting, prepending, appending or replacing
- with references to its own values. Doing so will cause your application to
- abort with an error message.
-
\section2 More Information on Using Qt Containers
For a detailed discussion comparing Qt containers with each other and
@@ -174,16 +142,16 @@
\section1 Maximum size and out-of-memory conditions
- The maximum size of QList depends on the architecture. You should be able to
- use more than 2 GB of memory and you can typically expect 2^63 bytes
- limitation in size on 64-bit systems. The actual value also depends on the
- overhead required for managing the data block, which is no more than 32
- bytes, and extra reserved space, which is 2 bytes. The number of elements
- that can be stored in a QList is this possible size divided by the size of a
- stored element.
+ The maximum size of QList depends on the architecture. Most 64-bit
+ systems can allocate more than 2 GB of memory, with a typical limit
+ of 2^63 bytes. The actual value also depends on the overhead required for
+ managing the data block. As a result, you can expect the maximum size
+ of 2 GB minus overhead on 32-bit platforms, and 2^63 bytes minus overhead
+ on 64-bit platforms. The number of elements that can be stored in a
+ QList is this maximum size divided by the size of a stored element.
- In case memory allocation fails, QList will use the \l Q_CHECK_PTR macro,
- which will throw a \c std::bad_alloc exception if the application is being
+ When memory allocation fails, QList uses the \l Q_CHECK_PTR macro,
+ which throws a \c std::bad_alloc exception if the application is being
compiled with exception support. If exceptions are disabled, then running
out of memory is undefined behavior.
@@ -279,7 +247,32 @@
\sa resize()
*/
-/*! \fn template <typename T> QList<T>::QList(qsizetype size, const T &value)
+/*! \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.
Each element is initialized with \a value.
@@ -304,16 +297,17 @@
\since 4.8
Constructs a list from the std::initializer_list given by \a args.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
-/*! \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.
*/
@@ -338,13 +332,9 @@
/*!
\fn template <typename T> QList<T> &QList<T>::operator=(std::initializer_list<T> args)
+ \since 5.14
Assigns the collection of values in \a args to this QList instance.
-
- This operator is only enabled if the compiler supports C++11 initializer
- lists.
-
- \since 5.14
*/
/*! \fn template <typename T> void QList<T>::swap(QList<T> &other)
@@ -391,49 +381,45 @@
\sa operator==()
*/
-/*! \fn template <typename T> bool operator<(const QList<T> &lhs, const QList<T> &rhs)
+/*! \fn template <typename T> bool QList<T>::operator<(const QList<T> &other) const
\since 5.6
- \relates QList
- Returns \c true if list \a lhs is
+ Returns \c true if this list is
\l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically less than} \a rhs; otherwise returns \c false.
+ {lexically less than} \a other; otherwise returns \c false.
This function requires the value type to have an implementation
of \c operator<().
*/
-/*! \fn template <typename T> bool operator<=(const QList<T> &lhs, const QList<T> &rhs)
+/*! \fn template <typename T> bool QList<T>::operator<=(const QList<T> &other) const
\since 5.6
- \relates QList
- Returns \c true if list \a lhs is
+ Returns \c true if this list is
\l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically less than or equal to} \a rhs; otherwise returns \c false.
+ {lexically less than or equal to} \a other; otherwise returns \c false.
This function requires the value type to have an implementation
of \c operator<().
*/
-/*! \fn template <typename T> bool operator>(const QList<T> &lhs, const QList<T> &rhs)
+/*! \fn template <typename T> bool QList<T>::operator>(const QList<T> &other) const
\since 5.6
- \relates QList
- Returns \c true if list \a lhs is
+ Returns \c true if this list is
\l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically greater than} \a rhs; otherwise returns \c false.
+ {lexically greater than} \a other; otherwise returns \c false.
This function requires the value type to have an implementation
of \c operator<().
*/
-/*! \fn template <typename T> bool operator>=(const QList<T> &lhs, const QList<T> &rhs)
+/*! \fn template <typename T> bool QList<T>::operator>=(const QList<T> &other) const
\since 5.6
- \relates QList
- Returns \c true if list \a lhs is
+ Returns \c true if this list is
\l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically greater than or equal to} \a rhs; otherwise returns \c false.
+ {lexically greater than or equal to} \a other; otherwise returns \c false.
This function requires the value type to have an implementation
of \c operator<().
@@ -465,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
@@ -490,36 +493,35 @@
\note a statically allocated list will report a capacity of 0,
even if it's not empty.
- \note The free space position in the allocated memory block is undefined. In
- other words, one should not assume that the free memory is always located
- after the initialized elements.
+ \warning The free space position in the allocated memory block is undefined.
+ In other words, you should not assume that the free memory is always located
+ at the end of the list. You can call reserve() to ensure that there is
+ enough space at the end.
\sa reserve(), squeeze()
*/
/*! \fn template <typename T> void QList<T>::reserve(qsizetype size)
- Attempts to allocate memory for at least \a size elements. If you
- know in advance how large the list will be, you should call this
- function to prevent reallocations and memory fragmentation.
+ Attempts to allocate memory for at least \a size elements.
- If \a size is an underestimate, the worst that will happen is that
- the QList will be a bit slower. If \a size is an overestimate, you
- may have used more memory than the normal QList growth strategy
- would have allocated—or you may have used less.
+ If you know in advance how large the list will be, you should call this
+ function to prevent reallocations and memory fragmentation. If you resize
+ the list often, you are also likely to get better performance.
- An alternative to reserve() is calling resize(). Whether or not that is
- faster than reserve() depends on the element type, because resize()
- default-constructs all elements, and requires assignment to existing
- entries rather than calling append(), which copy- or move-constructs.
- For simple types, like \c int or \c double, resize() is typically faster,
- but for anything more complex, you should prefer reserve().
+ If in doubt about how much space shall be needed, it is usually better to
+ use an upper bound as \a size, or a high estimate of the most likely size,
+ if a strict upper bound would be much bigger than this. If \a size is an
+ underestimate, the list will grow as needed once the reserved size is
+ exceeded, which may lead to a larger allocation than your best overestimate
+ would have and will slow the operation that triggers it.
- \warning If the size passed to resize() was underestimated, you run out
- of allocated space and into undefined behavior. This problem does not
- exist with reserve(), because it treats the size as just a hint.
+ \warning reserve() reserves memory but does not change the size of the
+ list. Accessing data beyond the current end of the list is
+ undefined behavior. If you need to access memory beyond the current end of
+ the list, use resize().
- \sa squeeze(), capacity()
+ \sa squeeze(), capacity(), resize()
*/
/*! \fn template <typename T> void QList<T>::squeeze()
@@ -593,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.
- \sa squeeze()
+ \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 resize(), squeeze()
*/
/*! \fn template <typename T> const T &QList<T>::at(qsizetype i) const
@@ -637,7 +636,7 @@
*/
/*!
- \fn template <typename T> void QList<T>::append(const T &value)
+ \fn template <typename T> void QList<T>::append(parameter_type value)
Inserts \a value at the end of the list.
@@ -655,7 +654,7 @@
*/
/*!
- \fn template <typename T> void QList<T>::append(T &&value)
+ \fn template <typename T> void QList<T>::append(rvalue_ref value)
\since 5.6
\overload
@@ -686,8 +685,8 @@
*/
/*!
- \fn template <typename T> void QList<T>::prepend(const T &value)
- \fn template <typename T> void QList<T>::prepend(T &&value)
+ \fn template <typename T> void QList<T>::prepend(parameter_type value)
+ \fn template <typename T> void QList<T>::prepend(rvalue_ref value)
Inserts \a value at the beginning of the list.
@@ -696,11 +695,12 @@
This is the same as list.insert(0, \a value).
- For large lists, this operation can be slow (\l{linear time}),
- because it requires moving all the items in the list by one
- position further in memory. If you want a container class that
- provides a fast prepend operation, use std::list
- instead.
+ Normally this operation is relatively fast (amortized \l{constant time}).
+ QList is able to allocate extra memory at the beginning of the list data
+ and grow in that direction without reallocating or moving the data on each
+ operation. However if you want a container class with a guarantee of
+ \l{constant time} prepend, use std::list instead,
+ but prefer QList otherwise.
\sa append(), insert()
*/
@@ -727,8 +727,8 @@
\sa emplace
*/
-/*! \fn template <typename T> void QList<T>::insert(qsizetype i, const T &value)
- \fn template <typename T> void QList<T>::insert(qsizetype i, T &&value)
+/*! \fn template <typename T> void QList<T>::insert(qsizetype i, parameter_type value)
+ \fn template <typename T> void QList<T>::insert(qsizetype i, rvalue_ref value)
Inserts \a value at index position \a i in the list. If \a i is
0, the value is prepended to the list. If \a i is size(), the
@@ -746,7 +746,7 @@
\sa append(), prepend(), remove()
*/
-/*! \fn template <typename T> void QList<T>::insert(qsizetype i, qsizetype count, const T &value)
+/*! \fn template <typename T> void QList<T>::insert(qsizetype i, qsizetype count, parameter_type value)
\overload
@@ -757,9 +757,8 @@
\snippet code/src_corelib_tools_qlist.cpp 10
*/
-/*!
- \fn template <typename T> QList<T>::iterator QList<T>::insert(iterator before, const T &value)
- \fn template <typename T> QList<T>::iterator QList<T>::insert(iterator before, T &&value)
+/*! \fn template <typename T> QList<T>::iterator QList<T>::insert(const_iterator before, parameter_type value)
+ \fn template <typename T> QList<T>::iterator QList<T>::insert(const_iterator before, rvalue_ref value)
\overload
@@ -767,7 +766,7 @@
\a before. Returns an iterator pointing at the inserted item.
*/
-/*! \fn template <typename T> QList<T>::iterator QList<T>::insert(iterator before, qsizetype count, const T &value)
+/*! \fn template <typename T> QList<T>::iterator QList<T>::insert(const_iterator before, qsizetype count, parameter_type value)
Inserts \a count copies of \a value in front of the item pointed to
by the iterator \a before. Returns an iterator pointing at the
@@ -786,7 +785,7 @@
Example:
\snippet code/src_corelib_tools_qlist.cpp emplace
- \note It is garanteed that the element will be created in place
+ \note It is guaranteed that the element will be created in place
at the beginning, but after that it might be copied or
moved to the right position.
@@ -794,7 +793,8 @@
*/
-/*! \fn template <typename T> void QList<T>::replace(qsizetype i, const T &value)
+/*! \fn template <typename T> void QList<T>::replace(qsizetype i, parameter_type value)
+ \fn template <typename T> void QList<T>::replace(qsizetype i, rvalue_ref value)
Replaces the item at index position \a i with \a value.
@@ -808,15 +808,15 @@
Removes \a n elements from the list, starting at index position \a i.
- If too many elements are removed from the list, the list may shrink the
- capacity to reduce the allocated memory size. To make sure this does not
- happen, use reserve() to give a hint to the list that the capacity should be
- preserved.
+//! [shrinking-erase]
+ Element removal will preserve the list's capacity and not reduce the amount of
+ allocated memory. To shed extra capacity and free as much memory as possible,
+ call squeeze().
+//! [shrinking-erase]
//! [iterator-invalidation-erase]
- \note When QList is not \l{implicitly shared} and the capacity is reserved
- with a call to reserve(), this function only invalidates iterators at or
- after the specified position.
+ \note When QList is not \l{implicitly shared}, this function only
+ invalidates iterators at or after the specified position.
//! [iterator-invalidation-erase]
\sa insert(), replace(), fill()
@@ -831,31 +831,41 @@
remove(i);
\endcode
+ \include qlist.qdoc shrinking-erase
\include qlist.qdoc iterator-invalidation-erase
- \sa remove(), QList::removeAt()
+ \sa remove()
*/
-/*! \fn template <typename T> qsizetype QList<T>::removeAll(const T &t)
+/*! \fn template <typename T> template <typename AT = T> qsizetype QList<T>::removeAll(const AT &t)
\since 5.4
Removes all elements that compare equal to \a t from the
list. Returns the number of elements removed, if any.
- Provided for compatibility with QList.
+ \include qlist.qdoc shrinking-erase
- \sa removeOne(), QList::removeAll()
+ \sa removeOne()
*/
-/*! \fn template <typename T> bool QList<T>::removeOne(const T &t)
+/*! \fn template <typename T> template <typename AT = T> bool QList<T>::removeOne(const AT &t)
\since 5.4
Removes the first element that compares equal to \a t from the
list. Returns whether an element was, in fact, removed.
- Provided for compatibility with QList.
+ \include qlist.qdoc shrinking-erase
- \sa removeAll(), QList::removeOne()
+ \sa removeAll()
+*/
+
+/*! \fn template <typename T> template <typename Predicate> qsizetype QList<T>::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the list. Returns the number of elements removed, if any.
+
+ \sa removeAll()
*/
/*! \fn template <typename T> qsizetype QList<T>::length() const
@@ -863,9 +873,7 @@
Same as size() and count().
- Provided for compatibility with QList.
-
- \sa size(), count(), QList::length()
+ \sa size(), count()
*/
/*! \fn template <typename T> T QList<T>::takeAt(qsizetype i)
@@ -880,19 +888,15 @@
return t;
\endcode
- Provided for compatibility with QList.
+ \include qlist.qdoc iterator-invalidation-erase
- \sa takeFirst(), takeLast(), QList::takeAt()
+ \sa takeFirst(), takeLast()
*/
/*! \fn template <typename T> void QList<T>::move(qsizetype from, qsizetype to)
\since 5.6
Moves the item at index position \a from to index position \a to.
-
- Provided for compatibility with QList.
-
- \sa QList::move()
*/
/*! \fn template <typename T> void QList<T>::removeFirst()
@@ -902,6 +906,8 @@
the list can be empty, call isEmpty() before calling this
function.
+ \include qlist.qdoc shrinking-erase
+
\sa remove(), takeFirst(), isEmpty()
*/
@@ -912,6 +918,8 @@
empty. If the list can be empty, call isEmpty() before calling
this function.
+ \include qlist.qdoc shrinking-erase
+
\sa remove(), takeLast(), removeFirst(), isEmpty()
*/
@@ -939,7 +947,7 @@
*/
/*!
- \fn template <typename T> template <typename ...Args> QList<T>::iterator QList<T>::emplace(QList<T>::iterator before, Args&&... args)
+ \fn template <typename T> template <typename ...Args> QList<T>::iterator QList<T>::emplace(const_iterator before, Args&&... args)
\overload
@@ -950,11 +958,10 @@
Returns an iterator to the new element.
*/
-/*! \fn template <typename T> QList<T> &QList<T>::fill(const T &value, qsizetype size = -1)
+/*! \fn template <typename T> QList<T> &QList<T>::fill(parameter_type value, qsizetype size = -1)
Assigns \a value to all items in the list. If \a size is
- different from -1 (the default), the list is resized to size \a
- size beforehand.
+ different from -1 (the default), the list is resized to \a size beforehand.
Example:
\snippet code/src_corelib_tools_qlist.cpp 11
@@ -962,7 +969,7 @@
\sa resize()
*/
-/*! \fn template <typename T> qsizetype QList<T>::indexOf(const T &value, qsizetype from = 0) const
+/*! \fn template <typename T> template <typename AT = T> qsizetype QList<T>::indexOf(const AT &value, qsizetype from = 0) const
Returns the index position of the first occurrence of \a value in
the list, searching forward from index position \a from.
@@ -977,7 +984,7 @@
\sa lastIndexOf(), contains()
*/
-/*! \fn template <typename T> qsizetype QList<T>::lastIndexOf(const T &value, qsizetype from = -1) const
+/*! \fn template <typename T> template <typename AT = T> qsizetype QList<T>::lastIndexOf(const AT &value, qsizetype from = -1) const
Returns the index position of the last occurrence of the value \a
value in the list, searching backward from index position \a
@@ -993,7 +1000,7 @@
\sa indexOf()
*/
-/*! \fn template <typename T> bool QList<T>::contains(const T &value) const
+/*! \fn template <typename T> template <typename AT = T> bool QList<T>::contains(const AT &value) const
Returns \c true if the list contains an occurrence of \a value;
otherwise returns \c false.
@@ -1004,7 +1011,7 @@
\sa indexOf(), count()
*/
-/*! \fn template <typename T> bool QList<T>::startsWith(const T &value) const
+/*! \fn template <typename T> bool QList<T>::startsWith(parameter_type value) const
\since 4.5
Returns \c true if this list is not empty and its first
@@ -1013,7 +1020,7 @@
\sa isEmpty(), first()
*/
-/*! \fn template <typename T> bool QList<T>::endsWith(const T &value) const
+/*! \fn template <typename T> bool QList<T>::endsWith(parameter_type value) const
\since 4.5
Returns \c true if this list is not empty and its last
@@ -1023,7 +1030,7 @@
*/
-/*! \fn template <typename T> qsizetype QList<T>::count(const T &value) const
+/*! \fn template <typename T> template <typename AT = T> qsizetype QList<T>::count(const AT &value) const
Returns the number of occurrences of \a value in the list.
@@ -1061,8 +1068,8 @@
/*! \fn template <typename T> QList<T>::const_iterator QList<T>::cbegin() const
\since 5.0
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
+ first item in the list.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1071,8 +1078,8 @@
/*! \fn template <typename T> QList<T>::const_iterator QList<T>::constBegin() const
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
+ first item in the list.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1081,8 +1088,8 @@
/*! \fn template <typename T> QList<T>::iterator QList<T>::end()
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
- after the last item in the list.
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing just after
+ the last item in the list.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1097,8 +1104,8 @@
/*! \fn template <typename T> QList<T>::const_iterator QList<T>::cend() const
\since 5.0
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
+ after the last item in the list.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1107,8 +1114,8 @@
/*! \fn template <typename T> QList<T>::const_iterator QList<T>::constEnd() const
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
+ after the last item in the list.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1118,8 +1125,8 @@
/*! \fn template <typename T> QList<T>::reverse_iterator QList<T>::rbegin()
\since 5.6
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to
+ the first item in the list, in reverse order.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1134,8 +1141,8 @@
/*! \fn template <typename T> QList<T>::const_reverse_iterator QList<T>::crbegin() const
\since 5.6
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing
+ to the first item in the list, in reverse order.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1145,8 +1152,8 @@
/*! \fn template <typename T> QList<T>::reverse_iterator QList<T>::rend()
\since 5.6
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last item in the list, in reverse order.
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing just
+ after the last item in the list, in reverse order.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1161,8 +1168,8 @@
/*! \fn template <typename T> QList<T>::const_reverse_iterator QList<T>::crend() const
\since 5.6
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last item in the list, in reverse order.
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing
+ just after the last item in the list, in reverse order.
\include qlist.qdoc iterator-invalidation-func-desc
@@ -1175,6 +1182,7 @@
list, and returns an iterator to the next item in the list
(which may be end()).
+ \include qlist.qdoc shrinking-erase
\include qlist.qdoc iterator-invalidation-erase
\sa insert(), remove()
@@ -1188,6 +1196,7 @@
end. Returns an iterator to the same item that \a end referred to
before the call.
+ \include qlist.qdoc shrinking-erase
\include qlist.qdoc iterator-invalidation-erase
*/
@@ -1246,27 +1255,27 @@
\sa at(), operator[]()
*/
-/*! \fn template <typename T> T QList<T>::value(qsizetype i, const T &defaultValue) const
+/*! \fn template <typename T> T QList<T>::value(qsizetype i, parameter_type defaultValue) const
\overload
If the index \a i is out of bounds, the function returns \a defaultValue.
*/
-/*! \fn template <typename T> void QList<T>::push_back(const T &value)
+/*! \fn template <typename T> void QList<T>::push_back(parameter_type value)
This function is provided for STL compatibility. It is equivalent
to append(\a value).
*/
-/*! \fn template <typename T> void QList<T>::push_back(T &&value)
+/*! \fn template <typename T> void QList<T>::push_back(rvalue_ref value)
\since 5.6
\overload
*/
/*!
- \fn template <typename T> void QList<T>::push_front(const T &value)
- \fn template <typename T> void QList<T>::push_front(T &&value)
+ \fn template <typename T> void QList<T>::push_front(parameter_type value)
+ \fn template <typename T> void QList<T>::push_front(rvalue_ref value)
This function is provided for STL compatibility. It is equivalent
to prepend(\a value).
@@ -1320,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
@@ -1336,7 +1354,7 @@
\sa operator+(), append()
*/
-/*! \fn template <typename T> void QList<T>::operator+=(const T &value)
+/*! \fn template <typename T> void QList<T>::operator+=(parameter_type value)
\overload
@@ -1345,7 +1363,7 @@
\sa append(), operator<<()
*/
-/*! \fn template <typename T> void QList<T>::operator+=(T &&value)
+/*! \fn template <typename T> void QList<T>::operator+=(rvalue_ref value)
\since 5.11
\overload
@@ -1353,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.
@@ -1361,22 +1383,14 @@
\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<<(const T &value)
+/*! \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.
\sa append(), operator+=()
*/
-/*! \fn template <typename T> QList<T> &QList<T>::operator<<(T &&value)
+/*! \fn template <typename T> QList<T> &QList<T>::operator<<(rvalue_ref value)
\since 5.11
\overload
@@ -1396,14 +1410,12 @@
\overload
*/
-/*! \typedef QList::iterator
-
- The QList::iterator typedef provides an STL-style non-const
- iterator for QList and QStack.
+/*! \class QList::iterator
+ \inmodule QtCore
+ \brief Provides an STL-style non-const iterator for QList and QStack.
QList provides both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style non-const iterator is simply a typedef
- for "T *" (pointer to T).
+ iterators}.
//! [iterator-invalidation-class-desc]
\warning Iterators on implicitly shared containers do not work
@@ -1419,14 +1431,12 @@
\sa QList::begin(), QList::end(), QList::const_iterator, QMutableListIterator
*/
-/*! \typedef QList::const_iterator
-
- The QList::const_iterator typedef provides an STL-style const
- iterator for QList and QStack.
+/*! \class QList::const_iterator
+ \inmodule QtCore
+ \brief Provides an STL-style const iterator for QList and QStack.
QList provides both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style const iterator is simply a typedef for
- "const T *" (pointer to const T).
+ iterators}.
\include qlist.qdoc iterator-invalidation-class-desc
@@ -1439,8 +1449,6 @@
The QList::reverse_iterator typedef provides an STL-style non-const
reverse iterator for QList.
- It is simply a typedef for \c{std::reverse_iterator<T*>}.
-
\include qlist.qdoc iterator-invalidation-class-desc
\sa QList::rbegin(), QList::rend(), QList::const_reverse_iterator, QList::iterator
@@ -1452,8 +1460,6 @@
The QList::const_reverse_iterator typedef provides an STL-style const
reverse iterator for QList.
- It is simply a typedef for \c{std::reverse_iterator<const T*>}.
-
\include qlist.qdoc iterator-invalidation-class-desc
\sa QList::rbegin(), QList::rend(), QList::reverse_iterator, QList::const_iterator
@@ -1471,42 +1477,50 @@
/*! \typedef QList::const_pointer
- Typedef for const T *. Provided for STL compatibility.
+ Provided for STL compatibility.
*/
/*! \typedef QList::const_reference
- Typedef for T &. Provided for STL compatibility.
+ Provided for STL compatibility.
*/
/*! \typedef QList::difference_type
- Typedef for ptrdiff_t. Provided for STL compatibility.
+ Provided for STL compatibility.
*/
/*! \typedef QList::pointer
- Typedef for T *. Provided for STL compatibility.
+ Provided for STL compatibility.
*/
/*! \typedef QList::reference
- Typedef for T &. Provided for STL compatibility.
+ Provided for STL compatibility.
*/
/*! \typedef QList::size_type
- Typedef for int. Provided for STL compatibility.
+ Provided for STL compatibility.
*/
/*! \typedef QList::value_type
- Typedef for T. Provided for STL compatibility.
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::parameter_type
+
+*/
+
+/*! \typedef QList::rvalue_ref
+
*/
/*! \fn template <typename T> QList<T> QList<T>::toList() const
\fn template <typename T> QList<T> QList<T>::toVector() const
- \obsolete
+ \deprecated
A no-op in Qt 6. Provided for backwards compatibility with
Qt 5, where QList and QVector where two different types.
@@ -1516,7 +1530,7 @@
/*! \fn template <typename T> QList<T> QList<T>::fromList(const QList<T> &list)
\fn template <typename T> QList<T> QList<T>::fromVector(const QList<T> &list)
- \obsolete
+ \deprecated
A no-op in Qt 6. Provided for backwards compatibility with
Qt 5, where QList and QVector were two different types.
@@ -1524,48 +1538,92 @@
Returns this list.
*/
-/*! \fn template <typename T> QList<T> QList<T>::fromStdVector(const std::vector<T> &vector)
+/*! \fn template <typename T> QDataStream &operator<<(QDataStream &out, const QList<T> &list)
+ \relates QList
- Returns a QList object with the data contained in \a vector. The
- order of the elements in the QList is the same as in \a vector.
+ Writes the list \a list to stream \a out.
- Example:
+ This function requires the value type to implement \c operator<<().
- \snippet code/src_corelib_tools_qlist.cpp 16
+ \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+*/
- \include containers-range-constructor.qdocinc
+/*! \fn template <typename T> QDataStream &operator>>(QDataStream &in, QList<T> &list)
+ \relates QList
- \sa toStdVector(), QList::fromStdList()
-*/
+ Reads a list from stream \a in into \a list.
-/*! \fn template <typename T> std::vector<T> QList<T>::toStdVector() const
+ This function requires the value type to implement \c operator>>().
- Returns a std::vector object with the data contained in this QList.
- Example:
+ \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+*/
+
+/*! \fn template <typename T, typename AT> qsizetype erase(QList<T> &list, const AT &t)
+ \relates QList
+ \since 6.1
- \snippet code/src_corelib_tools_qlist.cpp 17
+ Removes all elements that compare equal to \a t from the
+ list \a list. Returns the number of elements removed, if any.
- \include containers-range-constructor.qdocinc
+ \note Unlike QList::removeAll, \a t is not allowed to be a
+ reference to an element inside \a list. If you cannot be sure that
+ this is not the case, take a copy of \a t and call this function
+ with the copy.
- \sa fromStdVector(), QList::toStdList()
+ \sa QList::removeAll(), erase_if
*/
-/*! \fn template <typename T> QDataStream &operator<<(QDataStream &out, const QList<T> &list)
+/*! \fn template <typename T, typename Predicate> qsizetype erase_if(QList<T> &list, Predicate pred)
\relates QList
+ \since 6.1
- Writes the list \a list to stream \a out.
+ Removes all elements for which the predicate \a pred returns true
+ from the list \a list. Returns the number of elements removed, if
+ any.
- This function requires the value type to implement \c operator<<().
+ \sa erase
+*/
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+/*! \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> QDataStream &operator>>(QDataStream &in, QList<T> &list)
- \relates QList
+/*! \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
- Reads a list from stream \a in into \a list.
+ Replaces the contents of this list with a copy of the elements in the
+ iterator range [\a first, \a last).
- This function requires the value type to implement \c operator>>().
+ The size of this list will be equal to the number of elements in the
+ range [\a first, \a last).
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+ 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 71441c2c27..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>
@@ -61,17 +25,17 @@ QT_BEGIN_NAMESPACE
namespace QtPrivate {
template<typename T>
-constexpr T&& Forward(typename std::remove_reference<T>::type& t) noexcept
+constexpr T &&Forward(typename std::remove_reference<T>::type &t) noexcept
{
- return static_cast<T&&>(t);
+ return static_cast<T &&>(t);
}
template<typename T>
-constexpr T&& Forward(typename std::remove_reference<T>::type&& t) noexcept
+constexpr T &&Forward(typename std::remove_reference<T>::type &&t) noexcept
{
static_assert(!std::is_lvalue_reference<T>::value,
"template argument substituting T is an lvalue reference type");
- return static_cast<T&&>(t);
+ return static_cast<T &&>(t);
}
template <typename ManualType, typename ...>
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index d09fa361a0..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) 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) 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>
@@ -68,6 +33,9 @@ public:
using iterator = typename Map::iterator;
using const_iterator = typename Map::const_iterator;
+ static_assert(std::is_nothrow_destructible_v<Key>, "Types with throwing destructors are not supported in Qt containers.");
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
Map m;
QMapData() = default;
@@ -217,7 +185,8 @@ public:
template <class Key, class T>
class QMap
{
- using MapData = QMapData<std::map<Key, T>>;
+ using Map = std::map<Key, T>;
+ using MapData = QMapData<Map>;
QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
friend class QMultiMap<Key, T>;
@@ -234,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)
@@ -272,13 +241,28 @@ public:
return {};
}
- // CHANGE: non-member equality comparison
- template <typename AKey, typename AT>
- friend QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs);
- template <typename AKey, typename AT>
- friend QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs);
+#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)
+ {
+ if (lhs.d == rhs.d)
+ return true;
+ if (!lhs.d)
+ return rhs == lhs;
+ Q_ASSERT(lhs.d);
+ return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
+ }
+ template <typename AKey = Key, typename AT = T> friend
+ QTypeTraits::compare_eq_result_container<QMap, AKey, AT> operator!=(const QMap &lhs, const QMap &rhs)
+ {
+ return !(lhs == rhs);
+ }
// TODO: add the other comparison operators; std::map has them.
+#else
+ friend bool operator==(const QMap &lhs, const QMap &rhs);
+ friend bool operator!=(const QMap &lhs, const QMap &rhs);
+#endif // Q_QDOC
size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
@@ -329,11 +313,18 @@ public:
return result;
}
+ template <typename Predicate>
+ size_type removeIf(Predicate pred)
+ {
+ return QtPrivate::associative_erase_if(*this, pred);
+ }
+
T take(const Key &key)
{
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();
@@ -375,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())
@@ -436,14 +428,14 @@ public:
friend class QMap<Key, T>;
friend class const_iterator;
- typename MapData::Map::iterator i;
- explicit iterator(typename MapData::Map::iterator it) : i(it) {}
+ typename Map::iterator i;
+ explicit iterator(typename Map::iterator it) : i(it) {}
public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = qptrdiff;
+ using value_type = T;
+ using pointer = T *;
+ using reference = T &;
iterator() = default;
@@ -476,23 +468,47 @@ public:
--i;
return r;
}
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
+ //! [qmap-op-it-plus-step]
+ friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
+ //! [qmap-op-it-minus-step]
+ friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
+ iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
+ iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
+ //! [qmap-op-step-plus-it]
+ friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
+ //! [qmap-op-step-minus-it]
+ friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
+#endif
};
class const_iterator
{
friend class QMap<Key, T>;
- typename MapData::Map::const_iterator i;
- explicit const_iterator(typename MapData::Map::const_iterator it) : i(it) {}
+ typename Map::const_iterator i;
+ explicit const_iterator(typename Map::const_iterator it) : i(it) {}
public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = qptrdiff;
+ using value_type = T;
+ using pointer = const T *;
+ using reference = const T &;
const_iterator() = default;
- /* implicit */ const_iterator(const iterator &o) { i = o.i; }
+ Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
const Key &key() const { return i->first; }
const T &value() const { return i->second; }
@@ -523,6 +539,30 @@ public:
--i;
return r;
}
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
+ //! [qmap-op-it-plus-step-const]
+ friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
+ //! [qmap-op-it-minus-step-const]
+ friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMap iterators are not random access")
+ const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMap iterators are not random access")
+ const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMap iterators are not random access")
+ //! [qmap-op-step-plus-it-const]
+ friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMap iterators are not random access")
+ //! [qmap-op-step-minus-it-const]
+ friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
+#endif
};
class key_iterator
@@ -571,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)
{
@@ -596,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));
}
@@ -614,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));
}
@@ -627,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));
}
@@ -640,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);
@@ -648,10 +696,16 @@ public:
iterator insert(const_iterator pos, const Key &key, const T &value)
{
// TODO: improve. In case of assignment, why copying first?
- auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
- detach();
- auto detachedPos = std::next(d->m.cbegin(), posDistance);
- return iterator(d->m.insert_or_assign(detachedPos, key, value));
+ 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();
+ dpos = std::next(d->m.cbegin(), posDistance);
+ } else {
+ dpos = pos.i;
+ }
+ return iterator(d->m.insert_or_assign(dpos, key, value));
}
void insert(const QMap<Key, T> &map)
@@ -709,40 +763,55 @@ 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)
Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
-template <typename AKey, typename AT>
-QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs)
-{
- if (lhs.d == rhs.d)
- return true;
- if (!lhs.d)
- return rhs == lhs;
- Q_ASSERT(lhs.d);
- return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
-}
-
-template <typename AKey, typename AT>
-QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap<AKey, AT> &lhs, const QMap<AKey, AT> &rhs)
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
{
- return !(lhs == rhs);
+ return QtPrivate::associative_erase_if(map, pred);
}
@@ -753,7 +822,8 @@ QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMap<AKey, AT> &lhs, c
template <class Key, class T>
class QMultiMap
{
- using MapData = QMapData<std::multimap<Key, T>>;
+ using Map = std::multimap<Key, T>;
+ using MapData = QMapData<Map>;
QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
public:
@@ -774,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)
@@ -842,13 +912,28 @@ public:
return {};
}
- // CHANGE: non-member equality comparison
- template <typename AKey, typename AT>
- friend QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs);
- template <typename AKey, typename AT>
- friend QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs);
+#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)
+ {
+ if (lhs.d == rhs.d)
+ return true;
+ if (!lhs.d)
+ return rhs == lhs;
+ Q_ASSERT(lhs.d);
+ return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
+ }
+ template <typename AKey = Key, typename AT = T> friend
+ QTypeTraits::compare_eq_result_container<QMultiMap, AKey, AT> operator!=(const QMultiMap &lhs, const QMultiMap &rhs)
+ {
+ return !(lhs == rhs);
+ }
// TODO: add the other comparison operators; std::multimap has them.
+#else
+ friend bool operator==(const QMultiMap &lhs, const QMultiMap &rhs);
+ friend bool operator!=(const QMultiMap &lhs, const QMultiMap &rhs);
+#endif // Q_QDOC
size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
@@ -904,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 througout the iteration below
+ // 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();
@@ -931,11 +1016,19 @@ public:
return result;
}
+ template <typename Predicate>
+ size_type removeIf(Predicate pred)
+ {
+ return QtPrivate::associative_erase_if(*this, pred);
+ }
+
T take(const Key &key)
{
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();
@@ -1060,14 +1153,14 @@ public:
friend class QMultiMap<Key, T>;
friend class const_iterator;
- typename MapData::Map::iterator i;
- explicit iterator(typename MapData::Map::iterator it) : i(it) {}
+ typename Map::iterator i;
+ explicit iterator(typename Map::iterator it) : i(it) {}
public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = qptrdiff;
+ using value_type = T;
+ using pointer = T *;
+ using reference = T &;
iterator() = default;
@@ -1100,23 +1193,47 @@ public:
--i;
return r;
}
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
+ //! [qmultimap-op-it-plus-step]
+ friend iterator operator+(iterator it, difference_type j) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
+ //! [qmultimap-op-it-minus-step]
+ friend iterator operator-(iterator it, difference_type j) { return std::prev(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
+ iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
+ iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
+ //! [qmultimap-op-step-plus-it]
+ friend iterator operator+(difference_type j, iterator it) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
+ //! [qmultimap-op-step-minus-it]
+ friend iterator operator-(difference_type j, iterator it) { return std::prev(it, j); }
+#endif
};
class const_iterator
{
friend class QMultiMap<Key, T>;
- typename MapData::Map::const_iterator i;
- explicit const_iterator(typename MapData::Map::const_iterator it) : i(it) {}
+ typename Map::const_iterator i;
+ explicit const_iterator(typename Map::const_iterator it) : i(it) {}
public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = qptrdiff;
+ using value_type = T;
+ using pointer = const T *;
+ using reference = const T &;
const_iterator() = default;
- /* implicit */ const_iterator(const iterator &o) { i = o.i; }
+ Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
const Key &key() const { return i->first; }
const T &value() const { return i->second; }
@@ -1147,6 +1264,30 @@ public:
--i;
return r;
}
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
+ //! [qmultimap-op-it-plus-step-const]
+ friend const_iterator operator+(const_iterator it, difference_type j) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
+ //! [qmultimap-op-it-minus-step-const]
+ friend const_iterator operator-(const_iterator it, difference_type j) { return std::prev(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next or std::advance; QMultiMap iterators are not random access")
+ const_iterator &operator+=(difference_type j) { std::advance(*this, j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev or std::advance; QMultiMap iterators are not random access")
+ const_iterator &operator-=(difference_type j) { std::advance(*this, -j); return *this; }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::next; QMultiMap iterators are not random access")
+ //! [qmultimap-op-step-plus-it-const]
+ friend const_iterator operator+(difference_type j, const_iterator it) { return std::next(it, j); }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use std::prev; QMultiMap iterators are not random access")
+ //! [qmultimap-op-step-minus-it-const]
+ friend const_iterator operator-(difference_type j, const_iterator it) { return std::prev(it, j); }
+#endif
};
class key_iterator
@@ -1195,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)
{
@@ -1225,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));
}
@@ -1243,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);
@@ -1275,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));
}
@@ -1288,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));
}
@@ -1301,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.
@@ -1310,64 +1461,47 @@ public:
iterator insert(const_iterator pos, const Key &key, const T &value)
{
- auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
- detach();
- auto detachedPos = std::next(d->m.cbegin(), posDistance);
- return iterator(d->m.insert(detachedPos, {key, 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;
+ detach();
+ dpos = std::next(d->m.cbegin(), posDistance);
+ } else {
+ dpos = pos.i;
+ }
+ return iterator(d->m.insert(dpos, {key, value}));
}
- // CHANGE: provide insertMulti for compatibility
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
iterator insertMulti(const Key &key, const T &value)
{
return insert(key, value);
}
-
+ QT_DEPRECATED_VERSION_X_6_0("Use insert() instead")
iterator insertMulti(const_iterator pos, const Key &key, const T &value)
{
return insert(pos, key, value);
}
+ QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
void insert(const QMultiMap<Key, T> &map)
{
- if (map.isEmpty())
- return;
-
- detach();
-
- auto copy = map.d->m;
-#ifdef __cpp_lib_node_extract
- copy.merge(std::move(d->m));
-#else
- copy.insert(std::make_move_iterator(d->m.begin()),
- std::make_move_iterator(d->m.end()));
-#endif
- d->m = std::move(copy);
+ unite(map);
}
+ QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
void insert(QMultiMap<Key, T> &&map)
{
- if (!map.d || map.d->m.empty())
- return;
-
- if (map.d.isShared()) {
- // fall back to a regular copy
- insert(map);
- return;
- }
-
- detach();
-
-#ifdef __cpp_lib_node_extract
- map.d->m.merge(std::move(d->m));
-#else
- map.d->m.insert(std::make_move_iterator(d->m.begin()),
- std::make_move_iterator(d->m.end()));
-#endif
- *this = std::move(map);
+ unite(std::move(map));
}
+#endif
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();
@@ -1385,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 {};
@@ -1402,7 +1537,42 @@ public:
QMultiMap &unite(const QMultiMap &other)
{
- insert(other);
+ if (other.isEmpty())
+ return *this;
+
+ detach();
+
+ auto copy = other.d->m;
+#ifdef __cpp_lib_node_extract
+ copy.merge(std::move(d->m));
+#else
+ copy.insert(std::make_move_iterator(d->m.begin()),
+ std::make_move_iterator(d->m.end()));
+#endif
+ d->m = std::move(copy);
+ return *this;
+ }
+
+ QMultiMap &unite(QMultiMap<Key, T> &&other)
+ {
+ if (!other.d || other.d->m.empty())
+ return *this;
+
+ if (other.d.isShared()) {
+ // fall back to a regular copy
+ unite(other);
+ return *this;
+ }
+
+ detach();
+
+#ifdef __cpp_lib_node_extract
+ other.d->m.merge(std::move(d->m));
+#else
+ other.d->m.insert(std::make_move_iterator(d->m.begin()),
+ std::make_move_iterator(d->m.end()));
+#endif
+ *this = std::move(other);
return *this;
}
};
@@ -1410,23 +1580,6 @@ public:
Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
-template <typename AKey, typename AT>
-QTypeTraits::compare_eq_result<AKey, AT> operator==(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs)
-{
- if (lhs.d == rhs.d)
- return true;
- if (!lhs.d)
- return rhs == lhs;
- Q_ASSERT(lhs.d);
- return rhs.d ? (lhs.d->m == rhs.d->m) : lhs.d->m.empty();
-}
-
-template <typename AKey, typename AT>
-QTypeTraits::compare_eq_result<AKey, AT> operator!=(const QMultiMap<AKey, AT> &lhs, const QMultiMap<AKey, AT> &rhs)
-{
- return !(lhs == rhs);
-}
-
template <typename Key, typename T>
QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
{
@@ -1441,6 +1594,12 @@ QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rh
return lhs.unite(rhs);
}
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
+{
+ return QtPrivate::associative_erase_if(map, pred);
+}
+
QT_END_NAMESPACE
#endif // QMAP_H
diff --git a/src/corelib/tools/qmap.qdoc b/src/corelib/tools/qmap.qdoc
index 1857a05a13..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
@@ -49,8 +13,7 @@
\reentrant
QMap\<Key, T\> is one of Qt's generic \l{container classes}. It
- stores (key, value) pairs and provides fast lookup of the
- value associated with a key.
+ stores (key, value) pairs and provides fast lookup by key.
QMap and QHash provide very similar functionality. The
differences are:
@@ -124,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
@@ -244,13 +197,21 @@
\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> bool operator==(const QMap<Key, T> &lhs, const QMap<Key, T> &rhs) const
- \relates 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
false.
@@ -264,8 +225,7 @@
\sa operator!=()
*/
-/*! \fn template <class Key, class T> bool operator!=(const QMap<Key, T> &lhs, const QMap<Key, T> &rhs) const
- \relates QMap
+/*! \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 not equal to \a rhs; otherwise returns
false.
@@ -336,15 +296,28 @@
\sa clear(), take()
*/
+/*! \fn template <class Key, class T> template <typename Predicate> size_type QMap<Key, T>::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the map.
+
+ The function supports predicates which take either an argument of
+ type \c{QMap<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ Returns the number of elements removed, if any.
+
+ \sa clear(), take()
+*/
+
/*! \fn template <class Key, class T> T QMap<Key, T>::take(const Key &key)
Removes the item with the key \a key from the map and returns
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.
@@ -394,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()
*/
@@ -419,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
@@ -437,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
@@ -651,12 +620,33 @@
\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
from the map, and returns an iterator to the next item in the
map.
+ \note The iterator \a pos \e must be valid and dereferenceable.
+
\sa remove()
*/
@@ -667,6 +657,8 @@
[\a first, \a last) from the map.
Returns an iterator to the item in the map following the last removed element.
+ \note The range \c {[first, last)} \e must be a valid range in \c {*this}.
+
\sa remove()
*/
@@ -738,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)
@@ -764,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)
@@ -774,21 +766,27 @@
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.
+/*! \fn template <class Key, class T> void QMap<Key, T>::insert(QMap<Key, T> &&map)
+ \since 5.15
+
+ Moves all the items from \a map into this map.
+
+ If a key is common to both maps, its value will be replaced with
+ the value stored in \a map.
- \sa QMultiMap::insert()
+ If \a map is shared, then the items will be copied instead.
*/
/*! \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
@@ -820,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
*/
@@ -837,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
@@ -862,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
@@ -897,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
@@ -943,7 +919,7 @@
There is no direct way of changing an item's key through an
iterator, although it can be done by calling QMap::erase()
- followed by QMap::insert() or QMap::insertMulti().
+ followed by QMap::insert().
\sa value()
*/
@@ -977,28 +953,28 @@
*/
/*!
- \fn template <class Key, class T> bool QMap<Key, T>::iterator::operator==(const iterator &other) const
- \fn template <class Key, class T> bool QMap<Key, T>::iterator::operator==(const const_iterator &other) const
+ \fn template <class Key, class T> bool QMap<Key, T>::iterator::operator==(const iterator &lhs, const iterator &rhs)
+ \fn template <class Key, class T> bool QMap<Key, T>::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to the same item as the \a rhs iterator;
+ otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn template <class Key, class T> bool QMap<Key, T>::iterator::operator!=(const iterator &other) const
- \fn template <class Key, class T> bool QMap<Key, T>::iterator::operator!=(const const_iterator &other) const
+ \fn template <class Key, class T> bool QMap<Key, T>::iterator::operator!=(const iterator &lhs, const iterator &rhs)
+ \fn template <class Key, class T> bool QMap<Key, T>::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different item than the \a rhs iterator;
+ otherwise returns \c false.
\sa operator==()
*/
/*! \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.
@@ -1011,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
@@ -1031,21 +1007,32 @@
\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.
*/
+/*! //! friends
+ \fn [qmap-op-it-plus-step] template <class Key, class T> typename QMap<Key, T>::iterator QMap<Key, T>::iterator::operator+(QMap<Key, T>::iterator, difference_type n)
+ \fn [qmap-op-step-plus-it] template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator+(difference_type n, QMap<Key, T>::iterator)
+ \fn [qmap-op-it-minus-step] template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator-(QMap<Key, T>::iterator, difference_type n)
+ \fn [qmap-op-step-minus-it] template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator-(difference_type n, QMap<Key, T>::iterator)
+
+ //! members
+ \fn template <class Key, class T> typename QMap<Key, T>::iterator QMap<Key, T>::iterator::operator+=(QMap<Key, T>::iterator::difference_type n)
+ \fn template <class Key, class T> typename QMap<Key, T>::iterator QMap<Key, T>::iterator::operator-=(QMap<Key, T>::iterator::difference_type n)
+
+ \deprecated [6.2] Use \c{std::next}, \c{std::prev} or \c{std::advance} instead.
+
+ Moves an iterator by \e{n} positions. These operations can be
+ expensive for large values of \e{n}; QMap iterators are not
+ random access.
+*/
+
/*! \class QMap::const_iterator
\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
@@ -1056,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.
@@ -1075,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
@@ -1150,25 +1145,9 @@
\sa value()
*/
-/*! \fn template <class Key, class T> bool QMap<Key, T>::const_iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*! \fn template <class Key, class T> bool QMap<Key, T>::const_iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
/*! \fn template <class Key, class T> 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.
@@ -1181,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
@@ -1201,11 +1180,28 @@
\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.
*/
+/*! //! friends
+ \fn [qmap-op-it-plus-step-const] template <class Key, class T> QMap<Key, T>::const_iterator::operator+(QMap<Key, T>::const_iterator, difference_type n)
+ \fn [qmap-op-step-plus-it-const] template <class Key, class T> QMap<Key, T>::operator+(difference_type n, QMap<Key, T>::const_iterator)
+ \fn [qmap-op-it-minus-step-const] template <class Key, class T> QMap<Key, T>::operator-(QMap<Key, T>::const_iterator, difference_type n)
+ \fn [qmap-op-step-minus-it-const] template <class Key, class T> QMap<Key, T>::operator-(difference_type n, QMap<Key, T>::const_iterator)
+
+ //! members
+ \fn template <class Key, class T> typename QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator+=(QMap<Key, T>::const_iterator::difference_type n)
+ \fn template <class Key, class T> typename QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator-=(QMap<Key, T>::const_iterator::difference_type n)
+
+ \deprecated [6.2] Use \c{std::next}, \c{std::prev} or \c{std::advance} instead.
+
+ Moves an iterator by \e{n} positions. These operations can be
+ expensive for large values of \e{n}. QMap iterators are not
+ random access.
+*/
+
/*! \class QMap::key_iterator
\inmodule QtCore
\since 5.6
@@ -1292,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.
@@ -1305,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
@@ -1325,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.
*/
@@ -1379,3 +1375,26 @@
\sa{Serializing Qt Data Types}{Format of the QDataStream operators}
*/
+
+/*! \fn template <typename Key, typename T, typename Predicate> qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
+ \relates QMap
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the map \a map.
+
+ The function supports predicates which take either an argument of
+ type \c{QMap<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ 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 a238032f65..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"
@@ -52,7 +16,7 @@ QT_BEGIN_NAMESPACE
\brief The QMargins class defines the four margins of a rectangle.
- QMargin defines a set of four margins; left, top, right and bottom,
+ QMargin defines a set of four margins; left, top, right, and bottom,
that describe the size of the borders surrounding a rectangle.
The isNull() function returns \c true only if all margins are set to zero.
@@ -76,7 +40,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QMargins::QMargins(int left, int top, int right, int bottom)
- Constructs margins with the given \a left, \a top, \a right, \a bottom
+ Constructs margins with the given \a left, \a top, \a right, and \a bottom
\sa setLeft(), setRight(), setTop(), setBottom()
*/
@@ -143,15 +107,13 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool operator==(const QMargins &m1, const QMargins &m2)
- \relates QMargins
+ \fn bool QMargins::operator==(const QMargins &m1, const QMargins &m2)
Returns \c true if \a m1 and \a m2 are equal; otherwise returns \c false.
*/
/*!
- \fn bool operator!=(const QMargins &m1, const QMargins &m2)
- \relates QMargins
+ \fn bool QMargins::operator!=(const QMargins &m1, const QMargins &m2)
Returns \c true if \a m1 and \a m2 are different; otherwise returns \c false.
*/
@@ -408,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
*****************************************************************************/
@@ -469,10 +440,10 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\brief The QMarginsF class defines the four margins of a rectangle.
- QMarginsF defines a set of four margins; left, top, right and bottom,
- that describe the size of the borders surrounding a rectangle.
+ QMarginsF defines a set of four margins; left, top, right, and bottom,
+ that describe the finite size of the borders surrounding a rectangle.
- The isNull() function returns \c true only if all margins are set to zero.
+ The isNull() function returns \c true only if all margins are very close to zero.
QMarginsF objects can be streamed as well as compared.
*/
@@ -493,7 +464,8 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
/*!
\fn QMarginsF::QMarginsF(qreal left, qreal top, qreal right, qreal bottom)
- Constructs margins with the given \a left, \a top, \a right, \a bottom
+ Constructs margins with the given \a left, \a top, \a right, and \a bottom.
+ All parameters must be finite.
\sa setLeft(), setRight(), setTop(), setBottom()
*/
@@ -501,14 +473,18 @@ 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()
*/
/*!
\fn bool QMarginsF::isNull() const
- Returns \c true if all margins are 0; otherwise returns
+ Returns \c true if all margins are very close to 0; otherwise returns
false.
+
+ \sa {<QtNumeric>::}{qFuzzyIsNull()}
*/
@@ -542,41 +518,51 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
/*!
- \fn void QMarginsF::setLeft(qreal left)
+ \fn void QMarginsF::setLeft(qreal aleft)
- Sets the left margin to \a left.
+ Sets the left margin to \a aleft (which must be finite).
*/
/*!
- \fn void QMarginsF::setTop(qreal Top)
+ \fn void QMarginsF::setTop(qreal atop)
- Sets the Top margin to \a Top.
+ Sets the top margin to \a atop (which must be finite).
*/
/*!
- \fn void QMarginsF::setRight(qreal right)
+ \fn void QMarginsF::setRight(qreal aright)
- Sets the right margin to \a right.
+ Sets the right margin to \a aright (which must be finite).
*/
/*!
- \fn void QMarginsF::setBottom(qreal bottom)
+ \fn void QMarginsF::setBottom(qreal abottom)
- Sets the bottom margin to \a bottom.
+ Sets the bottom margin to \a abottom (which must be finite).
*/
/*!
- \fn bool operator==(const QMarginsF &lhs, const QMarginsF &rhs)
- \relates QMarginsF
+ \fn bool QMarginsF::operator==(const QMarginsF &lhs, const QMarginsF &rhs)
+
+ Returns \c true if \a lhs and \a rhs are approximately equal; otherwise
+ returns false.
- Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false.
+ \warning This function does not check for strict equality; instead,
+ it uses a fuzzy comparison to compare the margins.
+
+ \sa qFuzzyCompare
*/
/*!
- \fn bool operator!=(const QMarginsF &lhs, const QMarginsF &rhs)
- \relates QMarginsF
+ \fn bool QMarginsF::operator!=(const QMarginsF &lhs, const QMarginsF &rhs)
+
+ Returns \c true if \a lhs and \a rhs are sufficiently different; otherwise
+ returns \c false.
+
+ \warning This function does not check for strict inequality; instead,
+ it uses a fuzzy comparison to compare the margins.
- Returns \c true if \a lhs and \a rhs are different; otherwise returns \c false.
+ \sa qFuzzyCompare
*/
/*!
@@ -603,8 +589,8 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\fn const QMarginsF operator+(const QMarginsF &lhs, qreal rhs)
\relates QMarginsF
- Returns a QMarginsF object that is formed by adding \a rhs to
- \a lhs.
+ Returns a QMarginsF object that is formed by adding \a rhs (which must be
+ finite) to each component of \a lhs.
\sa QMarginsF::operator+=(), QMarginsF::operator-=()
*/
@@ -613,8 +599,8 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\fn const QMarginsF operator+(qreal lhs, const QMarginsF &rhs)
\relates QMarginsF
- Returns a QMarginsF object that is formed by adding \a lhs to
- \a rhs.
+ Returns a QMarginsF object that is formed by adding \a lhs (which must be
+ finite) to each component of \a rhs.
\sa QMarginsF::operator+=(), QMarginsF::operator-=()
*/
@@ -623,8 +609,8 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\fn const QMarginsF operator-(const QMarginsF &lhs, qreal rhs)
\relates QMarginsF
- Returns a QMarginsF object that is formed by subtracting \a rhs from
- \a lhs.
+ Returns a QMarginsF object that is formed by subtracting \a rhs (which must
+ be finite) from each component of \a lhs.
\sa QMarginsF::operator+=(), QMarginsF::operator-=()
*/
@@ -635,7 +621,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\overload
Returns a QMarginsF object that is formed by multiplying each component
- of the given \a lhs margins by \a rhs factor.
+ of the given \a lhs margins by finite factor \a rhs.
\sa QMarginsF::operator*=(), QMarginsF::operator/=()
*/
@@ -646,7 +632,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\overload
Returns a QMarginsF object that is formed by multiplying each component
- of the given \a lhs margins by \a rhs factor.
+ of the given \a lhs margins by finite factor \a rhs.
\sa QMarginsF::operator*=(), QMarginsF::operator/=()
*/
@@ -659,6 +645,8 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
Returns a QMarginsF object that is formed by dividing the components of
the given \a lhs margins by the given \a rhs divisor.
+ The divisor must not be either zero or NaN.
+
\sa QMarginsF::operator*=(), QMarginsF::operator/=()
*/
@@ -711,7 +699,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\fn QMarginsF &QMarginsF::operator+=(qreal addend)
\overload
- Adds the \a addend to each component of this object
+ Adds the given finite \a addend to each component of this object
and returns a reference to it.
\sa operator-=()
@@ -721,7 +709,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
\fn QMarginsF &QMarginsF::operator-=(qreal subtrahend)
\overload
- Subtracts the \a subtrahend from each component of this object
+ Subtracts the given finite \a subtrahend from each component of this object
and returns a reference to it.
\sa operator+=()
@@ -730,8 +718,8 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
/*!
\fn QMarginsF &QMarginsF::operator*=(qreal factor)
- Multiplies each component of this object by \a factor
- and returns a reference to it.
+ Multiplies each component of this object by the given finite \a factor
+ and returns a reference to this object.
\sa operator/=()
*/
@@ -739,8 +727,10 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
/*!
\fn QMarginsF &QMarginsF::operator/=(qreal divisor)
- Divides each component of this object by \a divisor
- and returns a reference to it.
+ Divides each component of this object by \a divisor and returns a reference
+ to this object.
+
+ The \a divisor must not be either zero or NaN.
\sa operator*=()
*/
@@ -748,12 +738,12 @@ QDebug operator<<(QDebug dbg, const QMargins &m)
/*!
\fn QMargins QMarginsF::toMargins() const
- Returns an integer based copy of this margins object.
+ Returns an integer-based copy of this margins object.
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 de7a96e458..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,17 +46,46 @@ public:
constexpr QMargins &operator*=(qreal) noexcept;
constexpr QMargins &operator/=(qreal);
+ [[nodiscard]] constexpr inline QMarginsF toMarginsF() const noexcept;
+
private:
int m_left;
int m_top;
int m_right;
int m_bottom;
- friend constexpr inline bool operator==(const QMargins &, const QMargins &) noexcept;
- friend constexpr inline bool operator!=(const QMargins &, const QMargins &) noexcept;
+ friend constexpr inline bool operator==(const QMargins &m1, const QMargins &m2) noexcept
+ {
+ return
+ m1.m_left == m2.m_left &&
+ m1.m_top == m2.m_top &&
+ m1.m_right == m2.m_right &&
+ m1.m_bottom == m2.m_bottom;
+ }
+
+ friend constexpr inline bool operator!=(const QMargins &m1, const QMargins &m2) noexcept
+ {
+ return !(m1 == m2);
+ }
+
+ template <std::size_t I,
+ typename M,
+ std::enable_if_t<(I < 4), 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 q23::forward_like<M>(m.m_left);
+ else if constexpr (I == 1)
+ return q23::forward_like<M>(m.m_top);
+ else if constexpr (I == 2)
+ return q23::forward_like<M>(m.m_right);
+ else if constexpr (I == 3)
+ return q23::forward_like<M>(m.m_bottom);
+ }
};
-Q_DECLARE_TYPEINFO(QMargins, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QMargins, Q_RELOCATABLE_TYPE);
/*****************************************************************************
QMargins stream functions
@@ -132,24 +132,6 @@ constexpr inline void QMargins::setRight(int aright) noexcept
constexpr inline void QMargins::setBottom(int abottom) noexcept
{ m_bottom = abottom; }
-constexpr inline bool operator==(const QMargins &m1, const QMargins &m2) noexcept
-{
- return
- m1.m_left == m2.m_left &&
- m1.m_top == m2.m_top &&
- m1.m_right == m2.m_right &&
- m1.m_bottom == m2.m_bottom;
-}
-
-constexpr inline bool operator!=(const QMargins &m1, const QMargins &m2) noexcept
-{
- return
- m1.m_left != m2.m_left ||
- m1.m_top != m2.m_top ||
- m1.m_right != m2.m_right ||
- m1.m_bottom != m2.m_bottom;
-}
-
constexpr inline QMargins operator+(const QMargins &m1, const QMargins &m2) noexcept
{
return QMargins(m1.left() + m2.left(), m1.top() + m2.top(),
@@ -302,10 +284,10 @@ public:
constexpr qreal right() const noexcept;
constexpr qreal bottom() const noexcept;
- constexpr void setLeft(qreal left) noexcept;
- constexpr void setTop(qreal top) noexcept;
- constexpr void setRight(qreal right) noexcept;
- constexpr void setBottom(qreal bottom) noexcept;
+ constexpr void setLeft(qreal aleft) noexcept;
+ constexpr void setTop(qreal atop) noexcept;
+ constexpr void setRight(qreal aright) noexcept;
+ constexpr void setBottom(qreal abottom) noexcept;
constexpr QMarginsF &operator+=(const QMarginsF &margins) noexcept;
constexpr QMarginsF &operator-=(const QMarginsF &margins) noexcept;
@@ -321,9 +303,38 @@ private:
qreal m_top;
qreal m_right;
qreal m_bottom;
+
+ friend constexpr inline bool operator==(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
+ {
+ return qFuzzyCompare(lhs.left(), rhs.left())
+ && qFuzzyCompare(lhs.top(), rhs.top())
+ && qFuzzyCompare(lhs.right(), rhs.right())
+ && qFuzzyCompare(lhs.bottom(), rhs.bottom());
+ }
+
+ friend constexpr inline bool operator!=(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ template <std::size_t I,
+ typename M,
+ std::enable_if_t<(I < 4), 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 q23::forward_like<M>(m.m_left);
+ else if constexpr (I == 1)
+ return q23::forward_like<M>(m.m_top);
+ else if constexpr (I == 2)
+ return q23::forward_like<M>(m.m_right);
+ else if constexpr (I == 3)
+ return q23::forward_like<M>(m.m_bottom);
+ }
};
-Q_DECLARE_TYPEINFO(QMarginsF, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QMarginsF, Q_RELOCATABLE_TYPE);
/*****************************************************************************
QMarginsF stream functions
@@ -375,19 +386,6 @@ constexpr inline void QMarginsF::setRight(qreal aright) noexcept
constexpr inline void QMarginsF::setBottom(qreal abottom) noexcept
{ m_bottom = abottom; }
-constexpr inline bool operator==(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
-{
- return qFuzzyCompare(lhs.left(), rhs.left())
- && qFuzzyCompare(lhs.top(), rhs.top())
- && qFuzzyCompare(lhs.right(), rhs.right())
- && qFuzzyCompare(lhs.bottom(), rhs.bottom());
-}
-
-constexpr inline bool operator!=(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
-{
- return !operator==(lhs, rhs);
-}
-
constexpr inline QMarginsF operator+(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
return QMarginsF(lhs.left() + rhs.left(), lhs.top() + rhs.top(),
@@ -432,6 +430,7 @@ constexpr inline QMarginsF operator*(qreal lhs, const QMarginsF &rhs) noexcept
constexpr inline QMarginsF operator/(const QMarginsF &lhs, qreal divisor)
{
+ Q_ASSERT(divisor < 0 || divisor > 0);
return QMarginsF(lhs.left() / divisor, lhs.top() / divisor,
lhs.right() / divisor, lhs.bottom() / divisor);
}
@@ -490,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));
@@ -501,4 +502,32 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QMarginsF &);
QT_END_NAMESPACE
+/*****************************************************************************
+ QMargins/QMarginsF tuple protocol
+ *****************************************************************************/
+
+namespace std {
+ template <>
+ class tuple_size<QT_PREPEND_NAMESPACE(QMargins)> : public integral_constant<size_t, 4> {};
+ template <>
+ class tuple_element<0, QT_PREPEND_NAMESPACE(QMargins)> { public: using type = int; };
+ template <>
+ class tuple_element<1, QT_PREPEND_NAMESPACE(QMargins)> { public: using type = int; };
+ template <>
+ class tuple_element<2, QT_PREPEND_NAMESPACE(QMargins)> { public: using type = int; };
+ template <>
+ class tuple_element<3, QT_PREPEND_NAMESPACE(QMargins)> { public: using type = int; };
+
+ template <>
+ class tuple_size<QT_PREPEND_NAMESPACE(QMarginsF)> : public integral_constant<size_t, 4> {};
+ template <>
+ class tuple_element<0, QT_PREPEND_NAMESPACE(QMarginsF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+ template <>
+ class tuple_element<1, QT_PREPEND_NAMESPACE(QMarginsF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+ template <>
+ class tuple_element<2, QT_PREPEND_NAMESPACE(QMarginsF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+ template <>
+ class tuple_element<3, QT_PREPEND_NAMESPACE(QMarginsF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+}
+
#endif // QMARGINS_H
diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp
deleted file mode 100644
index ada502ecb8..0000000000
--- a/src/corelib/tools/qmessageauthenticationcode.cpp
+++ /dev/null
@@ -1,323 +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"
-
-/*
- These #defines replace the typedefs needed by the RFC6234 code. Normally
- the typedefs would come from from stdint.h, but since this header is not
- available on all platforms (MSVC 2008, for example), we #define them to the
- Qt equivalents.
-*/
-
-#ifdef uint64_t
-#undef uint64_t
-#endif
-
-#define uint64_t QT_PREPEND_NAMESPACE(quint64)
-
-#ifdef uint32_t
-#undef uint32_t
-#endif
-
-#define uint32_t QT_PREPEND_NAMESPACE(quint32)
-
-#ifdef uint8_t
-#undef uint8_t
-#endif
-
-#define uint8_t QT_PREPEND_NAMESPACE(quint8)
-
-#ifdef int_least16_t
-#undef int_least16_t
-#endif
-
-#define int_least16_t QT_PREPEND_NAMESPACE(qint16)
-
-// Header from rfc6234 with 1 modification:
-// sha1.h - commented out '#include <stdint.h>' on line 74
-#include "../../3rdparty/rfc6234/sha.h"
-
-#if QT_CONFIG(system_libb2)
-#include <blake2.h>
-#else
-#include "../../3rdparty/blake2/src/blake2.h"
-#endif
-
-#undef uint64_t
-#undef uint32_t
-#undef uint68_t
-#undef int_least16_t
-
-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) {
- QCryptographicHash hash(method);
- hash.addData(key);
- key = hash.result();
- hash.reset();
- }
-
- 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.data(), iKeyPad.size());
-}
-
-/*!
- \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, int 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);
-
- QByteArray hashedMessage = d->messageHash.result();
-
- 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.data(), oKeyPad.size());
- 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 a13a3d2acf..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, int length);
+ 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 01b2f17c73..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
@@ -49,8 +13,7 @@
\reentrant
QMultiMap\<Key, T\> is one of Qt's generic \l{container classes}. It
- stores (key, value) pairs and provides fast lookup of the
- value associated with a key.
+ stores (key, value) pairs and provides fast lookup by key.
QMultiMap and QMultiHash provide very similar functionality. The
differences are:
@@ -129,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
@@ -242,12 +205,12 @@
*/
/*! \fn template <class Key, class T> std::multimap<Key, T> QMultiMap<Key, T>::toStdMap() const
- \obsolete Use toStdMultiMap() instead.
+ \deprecated Use toStdMultiMap() instead.
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.
*/
@@ -259,9 +222,9 @@
fast and never fails.
*/
-/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::operator==(const QMultiMap<Key, T> &other) const
+/*! \fn template<class Key, class T> bool QMultiMap<Key, T>::operator==(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
- Returns \c true if \a other is equal to this multi map; otherwise returns
+ Returns \c true if \a lhs is equal to \a rhs; otherwise returns
false.
Two multi maps are considered equal if they contain the same (key,
@@ -273,9 +236,9 @@
\sa operator!=()
*/
-/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::operator!=(const QMultiMap<Key, T> &other) const
+/*! \fn template<class Key, class T> bool QMultiMap<Key, T>::operator!=(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
- Returns \c true if \a other is not equal to this multi map; otherwise
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise
returns \c false.
Two multi maps are considered equal if they contain the same (key,
@@ -352,6 +315,21 @@
\sa clear(), take()
*/
+/*! \fn template <class Key, class T> template <typename Predicate> size_type QMultiMap<Key, T>::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the multi map.
+
+ The function supports predicates which take either an argument of
+ type \c{QMultiMap<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ Returns the number of elements removed, if any.
+
+ \sa clear(), take()
+*/
+
/*! \fn template <class Key, class T> T QMultiMap<Key, T>::take(const Key &key)
Removes the item with the key \a key from the multi map and returns
@@ -411,7 +389,7 @@
items for \a key in the multi map, the value of the most recently
inserted one is returned.
- \sa key(), values(), contains(), operator[]()
+ \sa key(), values(), contains()
*/
/*! \fn template <class Key, class T> QList<Key> QMultiMap<Key, T>::keys() const
@@ -679,12 +657,33 @@
\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
from the multi map, and returns an iterator to the next item in the
map.
+ \note The iterator \a pos must be valid and dereferenceable.
+
\sa remove()
*/
@@ -696,6 +695,8 @@
Returns an iterator to the item in the multi map following the last
removed element.
+ \note The range \c {[first, last)} \e must be a valid range in \c {*this}.
+
\sa remove()
*/
@@ -816,10 +817,12 @@
different from replace(), which overwrites the value of an
existing item.)
+ Returns an iterator pointing to the new element.
+
\sa replace()
*/
-/*! \fn [qmultimap-insert-pos] template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const_iterator pos, const Key &key, const T &value)
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const_iterator pos, const Key &key, const T &value)
\overload
\since 5.1
Inserts a new item with the key \a key and value \a value and with hint \a pos
@@ -838,26 +841,44 @@
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.
*/
+#if QT_DEPRECATED_SINCE(6, 0)
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insertMulti(const Key &key, const T &value)
+ \deprecated Use insert() instead.
- Same as insert().
+ Inserts a new item with the key \a key and a value of \a value, and returns an iterator pointing to the new item.
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insertMulti(const_iterator pos, const Key &key, const T &value)
+ \deprecated Use insert() instead.
\overload
- Same as insert().
+ Inserts a new item with the key \a key and value \a value and with hint \a pos
+ suggesting where to do the insert.
*/
/*! \fn template <class Key, class T> void QMultiMap<Key, T>::insert(const QMultiMap<Key, T> &map)
\since 5.15
+ \deprecated Use unite() instead.
+
+ Inserts all the items in \a map into this map.
+*/
+
+/*! \fn template <class Key, class T> void QMultiMap<Key, T>::insert(QMultiMap<Key, T> &&map)
+ \since 5.15
+ \deprecated Use unite() instead.
+ \overload
+
+ Moves all the items from \a map into this map.
- Same as unite().
+ If \a map is shared, then the items will be copied instead.
*/
+#endif
/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::replace(const Key &key, const T &value)
@@ -869,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
@@ -911,38 +934,50 @@
*/
/*!
- \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
*/
/*!
- \fn [qmultimap-unite] template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::unite(const QMultiMap<Key, T> &other)
+ \fn template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::unite(const QMultiMap<Key, T> &other)
Inserts all the items in the \a other map into this map. If a
key is common to both maps, the resulting map will contain the
key multiple times.
*/
-/*! \fn template <class Key, class T> QMultiMap &QMultiMap<Key, T>::operator+=(const QMultiMap &other)
+/*!
+ \fn template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::unite(QMultiMap<Key, T> &&other)
+
+ Moves all the items from the \a other map into this map. If a
+ key is common to both maps, the resulting map will contain the
+ key multiple times.
+
+ If \a other is shared, then the items will be copied instead.
+*/
+
+/*! \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 other map into this map and
- returns a reference to this map.
+ Inserts all the items in the \a rhs map into the \a lhs map and
+ returns the resulting map.
\sa insert(), operator+()
*/
-/*! \fn template <class Key, class T> QMultiMap QMultiMap<Key, T>::operator+(const QMultiMap &other) const
+/*! \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 this map in
- addition to all the items in \a other. If a key is common to both
+ 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
maps, the resulting map will contain the key multiple times.
\sa operator+=()
@@ -952,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
@@ -972,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
@@ -1014,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
@@ -1094,28 +1105,28 @@
*/
/*!
- \fn template <class Key, class T> bool QMultiMap<Key, T>::iterator::operator==(const iterator &other) const
- \fn template <class Key, class T> bool QMultiMap<Key, T>::iterator::operator==(const const_iterator &other) const
+ \fn template<class Key, class T> bool QMultiMap<Key, T>::iterator::operator==(const iterator &lhs, const iterator &rhs)
+ \fn template<class Key, class T> bool QMultiMap<Key, T>::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to the same item as the \a rhs iterator;
+ otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn template <class Key, class T> bool QMultiMap<Key, T>::iterator::operator!=(const iterator &other) const
- \fn template <class Key, class T> bool QMultiMap<Key, T>::iterator::operator!=(const const_iterator &other) const
+ \fn template<class Key, class T> bool QMultiMap<Key, T>::iterator::operator!=(const iterator &lhs, const iterator &rhs)
+ \fn template<class Key, class T> bool QMultiMap<Key, T>::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different item than the \a rhs iterator;
+ otherwise returns \c false.
\sa operator==()
*/
/*! \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.
@@ -1128,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
@@ -1148,21 +1159,33 @@
\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.
*/
+/*!
+ //! friends
+ \fn [qmultimap-op-it-plus-step] template <class Key, class T> typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator+(QMultiMap<Key, T>::iterator, difference_type n)
+ \fn [qmultimap-op-step-plus-it] template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator+(difference_type n, QMultiMap<Key, T>::iterator)
+ \fn [qmultimap-op-it-minus-step] template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator-(QMultiMap<Key, T>::iterator, difference_type n)
+ \fn [qmultimap-op-step-minus-it] template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator-(difference_type n, QMultiMap<Key, T>::iterator)
+
+ //! members
+ \fn template <class Key, class T> typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator+=(QMultiMap<Key, T>::iterator::difference_type n)
+ \fn template <class Key, class T> typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator-=(QMultiMap<Key, T>::iterator::difference_type n)
+
+ \deprecated [6.2] Use \c{std::next}, \c{std::prev} or \c{std::advance} instead.
+
+ Move an iterator by \e{n} positions. These operations can be
+ expensive for large values of \e{n}; QMultiMap iterators are not
+ random access.
+*/
+
/*! \class QMultiMap::const_iterator
\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
@@ -1173,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,
@@ -1194,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
@@ -1269,25 +1296,9 @@
\sa value()
*/
-/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::const_iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::const_iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
/*! \fn template <class Key, class T> 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.
@@ -1300,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
@@ -1320,11 +1331,29 @@
\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.
*/
+/*!
+ //! friends
+ \fn [qmultimap-op-it-plus-step-const] template <class Key, class T> typename QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator+(QMultiMap<Key, T>::const_iterator, difference_type n)
+ \fn [qmultimap-op-step-plus-it-const] template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator+(difference_type n, QMultiMap<Key, T>::const_iterator)
+ \fn [qmultimap-op-it-minus-step-const] template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator-(QMultiMap<Key, T>::const_iterator, difference_type n)
+ \fn [qmultimap-op-step-minus-it-const] template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator-(difference_type n, QMultiMap<Key, T>::const_iterator)
+
+ //! members
+ \fn template <class Key, class T> typename QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator+=(QMultiMap<Key, T>::const_iterator::difference_type n)
+ \fn template <class Key, class T> typename QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator-=(QMultiMap<Key, T>::const_iterator::difference_type n)
+
+ \deprecated [6.2] Use \c{std::next}, \c{std::prev} or \c{std::advance} instead.
+
+ Move an iterator by \e{n} positions. These operations can be
+ expensive for large values of \e{n}. QMultiMap iterators are not
+ random access.
+*/
+
/*! \class QMultiMap::key_iterator
\inmodule QtCore
\since 5.6
@@ -1411,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.
@@ -1424,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
@@ -1444,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.
*/
@@ -1498,3 +1527,17 @@
\sa{Serializing Qt Data Types}{Format of the QDataStream operators}
*/
+
+/*! \fn template <typename Key, typename T, typename Predicate> qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
+ \relates QMultiMap
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the multi map \a map.
+
+ The function supports predicates which take either an argument of
+ type \c{QMultiMap<Key, T>::iterator}, or an argument of type
+ \c{std::pair<const Key &, T &>}.
+
+ Returns the number of elements removed, if any.
+*/
diff --git a/src/corelib/tools/qoffsetstringarray_p.h b/src/corelib/tools/qoffsetstringarray_p.h
index 678e410250..9103606a13 100644
--- a/src/corelib/tools/qoffsetstringarray_p.h
+++ b/src/corelib/tools/qoffsetstringarray_p.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** 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.
+// 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
@@ -53,146 +18,143 @@
#include "private/qglobal_p.h"
-#include <tuple>
+#include <QByteArrayView>
+
+#include <QtCore/q20algorithm.h>
#include <array>
+#include <limits>
+#include <string_view>
+#include <tuple>
-QT_BEGIN_NAMESPACE
+class tst_QOffsetStringArray;
-namespace QtPrivate {
-template<int N, int O, int I, int ... Idx>
-struct OffsetSequenceHelper : OffsetSequenceHelper<N - 1, O + I, Idx..., O> { };
+QT_BEGIN_NAMESPACE
-template<int Last, int I, int S, int ... Idx>
-struct OffsetSequenceHelper<1, Last, I, S, Idx...> : IndexesList<Last + I, Idx..., Last>
-{
- static const constexpr auto Length = Last + I;
- using Type = typename std::conditional<
- Last <= std::numeric_limits<quint8>::max(),
- quint8,
- typename std::conditional<
- Last <= std::numeric_limits<quint16>::max(),
- quint16,
- int>::type
- >::type;
-};
+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<int ... Idx>
-struct OffsetSequence : OffsetSequenceHelper<sizeof ... (Idx), 0, Idx..., 0> { };
-template<int N>
-struct StaticString
+template <typename StaticString, typename OffsetList>
+class QOffsetStringArray
{
- const char data[N];
-};
+public:
+ constexpr QOffsetStringArray(const StaticString &string, const OffsetList &offsets)
+ : m_string(string), m_offsets(offsets)
+ {}
+ constexpr const char *operator[](const int index) const noexcept
+ {
+ return m_string.data() + m_offsets[qBound(int(0), index, count())];
+ }
-template<>
-struct StaticString<0>
-{
- static constexpr int size() noexcept
+ constexpr const char *at(const int index) const noexcept
{
- return 0;
+ return m_string.data() + m_offsets[index];
}
-};
-template<typename, typename>
-struct StaticStringBuilder;
+ constexpr QByteArrayView viewAt(qsizetype index) const noexcept
+ {
+ return { m_string.data() + m_offsets[index],
+ qsizetype(m_offsets[index + 1]) - qsizetype(m_offsets[index]) - 1 };
+ }
-template<int ... I1, int ... I2>
-struct StaticStringBuilder<IndexesList<I1...>, IndexesList<I2...>>
-{
+ constexpr int count() const { return int(m_offsets.size()) - 1; }
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4100) // The formal parameter is not referenced in the body of the function.
- // The unreferenced parameter is ignored.
- // It happens when 'rs' is StaticString<0>
- template<int N1, int N2>
- static constexpr StaticString<N1 + N2> concatenate(
- const char (&ls)[N1], const StaticString<N2> &rs) noexcept
+ bool contains(QByteArrayView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{
- return StaticString<N1 + N2>{{ls[I1]..., rs.data[I2]...}};
+ for (qsizetype i = 0; i < count(); ++i) {
+ if (viewAt(i).compare(needle, cs) == 0)
+ return true;
+ }
+ return false;
}
-QT_WARNING_POP
+
+private:
+ StaticString m_string;
+ OffsetList m_offsets;
+ friend tst_QOffsetStringArray;
};
-template<int Sum>
-constexpr StaticString<0> staticString() noexcept
+namespace QtPrivate {
+template <size_t Highest> constexpr auto minifyValue()
{
- return StaticString<0>{};
+ 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 <= max16) {
+ return quint16(Highest);
+ } else {
+ // int is probably enough for everyone
+ return int(Highest);
+ }
}
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4503)
-template<int Sum, int I, int ... Ix>
-constexpr StaticString<Sum> staticString(const char (&s)[I], const char (&...sx)[Ix]) noexcept
+template <size_t StringLength, typename Extractor, typename... T>
+constexpr auto makeStaticString(Extractor extract, const T &... entries)
{
- return StaticStringBuilder<
- makeIndexSequence<I>,
- makeIndexSequence<Sum - I>>::concatenate(s, staticString<Sum - I>(sx...));
+ std::array<char, StringLength> result = {};
+ qptrdiff offset = 0;
+
+ const char *strings[] = { extract(entries).operator const char *()... };
+ size_t lengths[] = { sizeof(extract(T{}))... };
+ for (size_t i = 0; i < std::size(strings); ++i) {
+ q20::copy_n(strings[i], lengths[i], result.begin() + offset);
+ offset += lengths[i];
+ }
+ return result;
}
-QT_WARNING_POP
-} // namespace QtPrivate
-template<typename T, int SizeString, int SizeOffsets>
-class QOffsetStringArray
+template <size_t N> struct StaticString
{
-public:
- using Type = T;
-
- template<int ... Ox>
- constexpr QOffsetStringArray(const QtPrivate::StaticString<SizeString> &str,
- QtPrivate::IndexesList<SizeString, Ox...>) noexcept
- : m_string(str),
- m_offsets{Ox...}
- { }
-
- constexpr inline const char *operator[](const int index) const noexcept
- {
- return m_string.data + m_offsets[qBound(int(0), index, SizeOffsets - 1)];
- }
+ char value[N] = {};
+ constexpr StaticString() = default;
+ constexpr StaticString(const char (&s)[N]) { q20::copy_n(s, N, value); }
+ constexpr operator const char *() const { return value; }
+};
- constexpr inline const char *at(const int index) const noexcept
- {
- return m_string.data + m_offsets[index];
- }
+template <size_t KL, size_t VL> struct StaticMapEntry
+{
+ StaticString<KL> key = {};
+ StaticString<VL> value = {};
+ constexpr StaticMapEntry() = default;
+ constexpr StaticMapEntry(const char (&k)[KL], const char (&v)[VL])
+ : key(k), value(v)
+ {}
+};
- constexpr inline const char *str() const { return m_string.data; }
- constexpr inline const T *offsets() const { return m_offsets; }
- constexpr inline int count() const { return SizeOffsets; }
+template <typename StringExtractor, typename... T>
+constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries)
+{
+ constexpr size_t Count = sizeof...(T);
+ constexpr size_t StringLength = (sizeof(extractString(T{})) + ...);
+ using MinifiedOffsetType = decltype(QtPrivate::minifyValue<StringLength>());
- static constexpr const auto sizeString = SizeString;
- static constexpr const auto sizeOffsets = SizeOffsets;
+ size_t offset = 0;
+ std::array fullOffsetList = { offset += sizeof(extractString(T{}))... };
-private:
- QtPrivate::StaticString<SizeString> m_string;
- const T m_offsets[SizeOffsets];
-};
+ // prepend zero
+ std::array<MinifiedOffsetType, Count + 1> minifiedOffsetList = {};
+ q20::transform(fullOffsetList.begin(), fullOffsetList.end(),
+ minifiedOffsetList.begin() + 1,
+ [] (auto e) { return MinifiedOffsetType(e); });
-template<typename T, int N, int ... Ox>
-constexpr QOffsetStringArray<T, N, sizeof ... (Ox)> qOffsetStringArray(
- const QtPrivate::StaticString<N> &string,
- QtPrivate::IndexesList<N, Ox...> offsets) noexcept
-{
- return QOffsetStringArray<T, N, sizeof ... (Ox)>(
- string,
- offsets);
+ std::array staticString = QtPrivate::makeStaticString<StringLength>(extractString, entries...);
+ return QOffsetStringArray(staticString, minifiedOffsetList);
}
+} // namespace QtPrivate
template<int ... Nx>
-struct QOffsetStringArrayRet
-{
- using Offsets = QtPrivate::OffsetSequence<Nx...>;
- using Type = QOffsetStringArray<typename Offsets::Type, Offsets::Length, sizeof ... (Nx)>;
-};
-
-template<int ... Nx>
-constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept -> typename QOffsetStringArrayRet<Nx...>::Type
+constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept
{
- using Offsets = QtPrivate::OffsetSequence<Nx...>;
- return qOffsetStringArray<typename Offsets::Type>(
- QtPrivate::staticString<Offsets::Length>(strings...), Offsets{});
+ auto extractString = [](const auto &s) -> decltype(auto) { return s; };
+ 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 0e17b6c3b9..3aaee157d4 100644
--- a/src/corelib/tools/qpair.qdoc
+++ b/src/corelib/tools/qpair.qdoc
@@ -1,48 +1,16 @@
-/****************************************************************************
-**
-** 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 QPair
- \inmodule QtCore
- \obsolete
- \brief QPair is an alias for std::pair.
-
- \ingroup tools
-
- QPair\<T1, T2\> is a typedef for std::pair\<T1, T2\>.
- It is provided for backwards compatibility. Use std::pair directly
- instead.
-
- \sa {Container Classes}
+ \typealias QPair
+ \relates QPair
+ \since 6.0
+ Typedef for std::pair\<T1, T2\>.
*/
/*!
\fn template <class T1, class T2> QPair<T1, T2> qMakePair(T1 &&value1, T2 &&value2)
- \obsolete
+ \deprecated
\relates QPair
qMakePair forwards its arguments to std::make_pair, and returns
diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp
index eca1b5a0ac..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"
@@ -244,23 +208,20 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool operator==(const QPoint &p1, const QPoint &p2)
- \relates QPoint
+ \fn bool QPoint::operator==(const QPoint &p1, const QPoint &p2)
Returns \c true if \a p1 and \a p2 are equal; otherwise returns
false.
*/
/*!
- \fn bool operator!=(const QPoint &p1, const QPoint &p2)
- \relates QPoint
+ \fn bool QPoint::operator!=(const QPoint &p1, const QPoint &p2)
Returns \c true if \a p1 and \a p2 are not equal; otherwise returns \c false.
*/
/*!
- \fn const QPoint operator+(const QPoint &p1, const QPoint &p2)
- \relates QPoint
+ \fn QPoint QPoint::operator+(const QPoint &p1, const QPoint &p2)
Returns a QPoint object that is the sum of the given points, \a p1
and \a p2; each component is added separately.
@@ -269,8 +230,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator-(const QPoint &p1, const QPoint &p2)
- \relates QPoint
+ \fn Point QPoint::operator-(const QPoint &p1, const QPoint &p2)
Returns a QPoint object that is formed by subtracting \a p2 from
\a p1; each component is subtracted separately.
@@ -279,8 +239,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator*(const QPoint &point, float factor)
- \relates QPoint
+ \fn QPoint QPoint::operator*(const QPoint &point, float factor)
Returns a copy of the given \a point multiplied by the given \a factor.
@@ -291,8 +250,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator*(const QPoint &point, double factor)
- \relates QPoint
+ \fn QPoint QPoint::operator*(const QPoint &point, double factor)
Returns a copy of the given \a point multiplied by the given \a factor.
@@ -303,8 +261,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator*(const QPoint &point, int factor)
- \relates QPoint
+ \fn QPoint QPoint::operator*(const QPoint &point, int factor)
Returns a copy of the given \a point multiplied by the given \a factor.
@@ -312,9 +269,8 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator*(float factor, const QPoint &point)
+ \fn QPoint QPoint::operator*(float factor, const QPoint &point)
\overload
- \relates QPoint
Returns a copy of the given \a point multiplied by the given \a factor.
@@ -325,9 +281,8 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator*(double factor, const QPoint &point)
+ \fn QPoint QPoint::operator*(double factor, const QPoint &point)
\overload
- \relates QPoint
Returns a copy of the given \a point multiplied by the given \a factor.
@@ -338,9 +293,8 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator*(int factor, const QPoint &point)
+ \fn QPoint QPoint::operator*(int factor, const QPoint &point)
\overload
- \relates QPoint
Returns a copy of the given \a point multiplied by the given \a factor.
@@ -348,17 +302,15 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator+(const QPoint &point)
- \relates QPoint
+ \fn QPoint QPoint::operator+(const QPoint &point)
\since 5.0
Returns \a point unmodified.
*/
/*!
- \fn const QPoint operator-(const QPoint &point)
+ \fn QPoint QPoint::operator-(const QPoint &point)
\overload
- \relates QPoint
Returns a QPoint object that is formed by changing the sign of
both components of the given \a point.
@@ -382,8 +334,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QPoint operator/(const QPoint &point, qreal divisor)
- \relates QPoint
+ \fn const QPoint QPoint::operator/(const QPoint &point, qreal divisor)
Returns the QPoint formed by dividing both components of the given \a point
by the given \a divisor.
@@ -394,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
*****************************************************************************/
@@ -508,7 +468,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
A point is specified by a x coordinate and an y coordinate which
can be accessed using the x() and y() functions. The coordinates
- of the point are specified using floating point numbers for
+ of the point are specified using finite floating point numbers for
accuracy. The isNull() function returns \c true if both x and y are
set to 0.0. The coordinates can be set (or altered) using the setX()
and setY() functions, or alternatively the rx() and ry() functions which
@@ -545,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()
*/
/*!
@@ -594,7 +554,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
/*!
\fn void QPointF::setX(qreal x)
- Sets the x coordinate of this point to the given \a x coordinate.
+ Sets the x coordinate of this point to the given finite \a x coordinate.
\sa x(), setY()
*/
@@ -602,7 +562,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
/*!
\fn void QPointF::setY(qreal y)
- Sets the y coordinate of this point to the given \a y coordinate.
+ Sets the y coordinate of this point to the given finite \a y coordinate.
\sa y(), setX()
*/
@@ -668,7 +628,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
/*!
\fn QPointF& QPointF::operator*=(qreal factor)
- Multiplies this point's coordinates by the given \a factor, and
+ Multiplies this point's coordinates by the given finite \a factor, and
returns a reference to this point. For example:
\snippet code/src_corelib_tools_qpoint.cpp 14
@@ -684,12 +644,13 @@ size_t qHash(QPoint key, size_t seed) noexcept
\snippet code/src_corelib_tools_qpoint.cpp 15
+ The \a divisor must not be zero or NaN.
+
\sa operator*=()
*/
/*!
- \fn const QPointF operator+(const QPointF &p1, const QPointF &p2)
- \relates QPointF
+ \fn QPointF QPointF::operator+(const QPointF &p1, const QPointF &p2)
Returns a QPointF object that is the sum of the given points, \a p1
and \a p2; each component is added separately.
@@ -698,8 +659,7 @@ size_t qHash(QPoint key, size_t seed) noexcept
*/
/*!
- \fn const QPointF operator-(const QPointF &p1, const QPointF &p2)
- \relates QPointF
+ \fn QPointF QPointF::operator-(const QPointF &p1, const QPointF &p2)
Returns a QPointF object that is formed by subtracting \a p2 from \a p1;
each component is subtracted separately.
@@ -708,49 +668,46 @@ size_t qHash(QPoint key, size_t seed) noexcept
*/
/*!
- \fn const QPointF operator*(const QPointF &point, qreal factor)
- \relates QPointF
+ \fn QPointF QPointF::operator*(const QPointF &point, qreal factor)
- Returns a copy of the given \a point, multiplied by the given \a factor.
+ Returns a copy of the given \a point, multiplied by the given finite \a factor.
\sa QPointF::operator*=()
*/
/*!
- \fn const QPointF operator*(qreal factor, const QPointF &point)
- \relates QPointF
+ \fn QPointF QPointF::operator*(qreal factor, const QPointF &point)
\overload
- Returns a copy of the given \a point, multiplied by the given \a factor.
+ Returns a copy of the given \a point, multiplied by the given finite \a factor.
*/
/*!
- \fn const QPointF operator+(const QPointF &point)
- \relates QPointF
+ \fn QPointF QPointF::operator+(const QPointF &point)
\since 5.0
Returns \a point unmodified.
*/
/*!
- \fn const QPointF operator-(const QPointF &point)
- \relates QPointF
+ \fn QPointF QPointF::operator-(const QPointF &point)
\overload
Returns a QPointF object that is formed by changing the sign of
- both components of the given \a point.
+ each component of the given \a point.
Equivalent to \c {QPointF(0,0) - point}.
*/
/*!
- \fn const QPointF operator/(const QPointF &point, qreal divisor)
- \relates QPointF
+ \fn QPointF QPointF::operator/(const QPointF &point, qreal divisor)
- Returns the QPointF object formed by dividing both components of
+ Returns the QPointF object formed by dividing each component of
the given \a point by the given \a divisor.
+ The \a divisor must not be zero or NaN.
+
\sa QPointF::operator/=()
*/
@@ -760,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()
*/
/*!
@@ -773,17 +730,27 @@ size_t qHash(QPoint key, size_t seed) noexcept
*/
/*!
- \fn bool operator==(const QPointF &p1, const QPointF &p2)
- \relates QPointF
+ \fn bool QPointF::operator==(const QPointF &p1, const QPointF &p2)
+
+ Returns \c true if \a p1 is approximately equal to \a p2; otherwise
+ returns \c false.
+
+ \warning This function does not check for strict equality; instead,
+ it uses a fuzzy comparison to compare the points' coordinates.
- Returns \c true if \a p1 is equal to \a p2; otherwise returns \c false.
+ \sa qFuzzyCompare
*/
/*!
- \fn bool operator!=(const QPointF &p1, const QPointF &p2);
- \relates QPointF
+ \fn bool QPointF::operator!=(const QPointF &p1, const QPointF &p2);
+
+ Returns \c true if \a p1 is sufficiently different from \a p2;
+ otherwise returns \c false.
+
+ \warning This function does not check for strict inequality; instead,
+ it uses a fuzzy comparison to compare the points' coordinates.
- Returns \c true if \a p1 is not equal to \a p2; otherwise returns \c false.
+ \sa qFuzzyCompare
*/
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qpoint.h b/src/corelib/tools/qpoint.h
index e854e77198..7df4d49005 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -1,53 +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) 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
{
@@ -67,7 +37,7 @@ public:
constexpr QPoint transposed() const noexcept { return {yp, xp}; }
constexpr inline int &rx() noexcept;
- constexpr inline int &ry()noexcept;
+ constexpr inline int &ry() noexcept;
constexpr inline QPoint &operator+=(const QPoint &p);
constexpr inline QPoint &operator-=(const QPoint &p);
@@ -81,31 +51,57 @@ public:
constexpr static inline int dotProduct(const QPoint &p1, const QPoint &p2)
{ return p1.xp * p2.xp + p1.yp * p2.yp; }
- friend constexpr inline bool operator==(const QPoint &, const QPoint &) noexcept;
- friend constexpr inline bool operator!=(const QPoint &, const QPoint &) noexcept;
- friend constexpr inline const QPoint operator+(const QPoint &, const QPoint &);
- friend constexpr inline const QPoint operator-(const QPoint &, const QPoint &);
- friend constexpr inline const QPoint operator*(const QPoint &, float);
- friend constexpr inline const QPoint operator*(float, const QPoint &);
- friend constexpr inline const QPoint operator*(const QPoint &, double);
- friend constexpr inline const QPoint operator*(double, const QPoint &);
- friend constexpr inline const QPoint operator*(const QPoint &, int);
- friend constexpr inline const QPoint operator*(int, const QPoint &);
- friend constexpr inline const QPoint operator+(const QPoint &);
- friend constexpr inline const QPoint operator-(const QPoint &);
- friend constexpr inline const QPoint operator/(const QPoint &, qreal);
+ friend constexpr inline bool operator==(const QPoint &p1, const QPoint &p2) noexcept
+ { return p1.xp == p2.xp && p1.yp == p2.yp; }
+ friend constexpr inline bool operator!=(const QPoint &p1, const QPoint &p2) noexcept
+ { return p1.xp != p2.xp || p1.yp != p2.yp; }
+ friend constexpr inline QPoint operator+(const QPoint &p1, const QPoint &p2) noexcept
+ { return QPoint(p1.xp + p2.xp, p1.yp + p2.yp); }
+ friend constexpr inline QPoint operator-(const QPoint &p1, const QPoint &p2) noexcept
+ { return QPoint(p1.xp - p2.xp, p1.yp - p2.yp); }
+ friend constexpr inline QPoint operator*(const QPoint &p, float factor)
+ { return QPoint(qRound(p.xp * factor), qRound(p.yp * factor)); }
+ friend constexpr inline QPoint operator*(const QPoint &p, double factor)
+ { return QPoint(qRound(p.xp * factor), qRound(p.yp * factor)); }
+ friend constexpr inline QPoint operator*(const QPoint &p, int factor) noexcept
+ { return QPoint(p.xp * factor, p.yp * factor); }
+ friend constexpr inline QPoint operator*(float factor, const QPoint &p)
+ { return QPoint(qRound(p.xp * factor), qRound(p.yp * factor)); }
+ friend constexpr inline QPoint operator*(double factor, const QPoint &p)
+ { return QPoint(qRound(p.xp * factor), qRound(p.yp * factor)); }
+ friend constexpr inline QPoint operator*(int factor, const QPoint &p) noexcept
+ { return QPoint(p.xp * factor, p.yp * factor); }
+ friend constexpr inline QPoint operator+(const QPoint &p) noexcept
+ { return p; }
+ friend constexpr inline QPoint operator-(const QPoint &p) noexcept
+ { return QPoint(-p.xp, -p.yp); }
+ friend constexpr inline QPoint operator/(const QPoint &p, qreal c)
+ { return QPoint(qRound(p.xp / c), qRound(p.yp / c)); }
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
- Q_REQUIRED_RESULT Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
+ [[nodiscard]] Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
#endif
+ [[nodiscard]] constexpr inline QPointF toPointF() const noexcept;
private:
friend class QTransform;
int xp;
int yp;
+
+ template <std::size_t I,
+ typename P,
+ std::enable_if_t<(I < 2), 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 q23::forward_like<P>(p.xp);
+ else if constexpr (I == 1)
+ return q23::forward_like<P>(p.yp);
+ }
};
-Q_DECLARE_TYPEINFO(QPoint, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QPoint, Q_PRIMITIVE_TYPE);
/*****************************************************************************
QPoint stream functions
@@ -124,90 +120,85 @@ constexpr inline QPoint::QPoint() noexcept : xp(0), yp(0) {}
constexpr inline QPoint::QPoint(int xpos, int ypos) noexcept : xp(xpos), yp(ypos) {}
constexpr inline bool QPoint::isNull() const noexcept
-{ return xp == 0 && yp == 0; }
+{
+ return xp == 0 && yp == 0;
+}
constexpr inline int QPoint::x() const noexcept
-{ return xp; }
+{
+ return xp;
+}
constexpr inline int QPoint::y() const noexcept
-{ return yp; }
+{
+ return yp;
+}
constexpr inline void QPoint::setX(int xpos) noexcept
-{ xp = xpos; }
+{
+ xp = xpos;
+}
constexpr inline void QPoint::setY(int ypos) noexcept
-{ yp = ypos; }
+{
+ yp = ypos;
+}
inline int constexpr QPoint::manhattanLength() const
-{ return qAbs(x())+qAbs(y()); }
+{
+ return qAbs(x()) + qAbs(y());
+}
constexpr inline int &QPoint::rx() noexcept
-{ return xp; }
+{
+ return xp;
+}
constexpr inline int &QPoint::ry() noexcept
-{ return yp; }
+{
+ return yp;
+}
constexpr inline QPoint &QPoint::operator+=(const QPoint &p)
-{ xp+=p.xp; yp+=p.yp; return *this; }
+{
+ xp += p.xp;
+ yp += p.yp;
+ return *this;
+}
constexpr inline QPoint &QPoint::operator-=(const QPoint &p)
-{ xp-=p.xp; yp-=p.yp; return *this; }
+{
+ xp -= p.xp;
+ yp -= p.yp;
+ return *this;
+}
constexpr inline QPoint &QPoint::operator*=(float factor)
-{ xp = qRound(xp*factor); yp = qRound(yp*factor); return *this; }
+{
+ xp = qRound(xp * factor);
+ yp = qRound(yp * factor);
+ return *this;
+}
constexpr inline QPoint &QPoint::operator*=(double factor)
-{ xp = qRound(xp*factor); yp = qRound(yp*factor); return *this; }
+{
+ xp = qRound(xp * factor);
+ yp = qRound(yp * factor);
+ return *this;
+}
constexpr inline QPoint &QPoint::operator*=(int factor)
-{ xp = xp*factor; yp = yp*factor; return *this; }
-
-constexpr inline bool operator==(const QPoint &p1, const QPoint &p2) noexcept
-{ return p1.xp == p2.xp && p1.yp == p2.yp; }
-
-constexpr inline bool operator!=(const QPoint &p1, const QPoint &p2) noexcept
-{ return p1.xp != p2.xp || p1.yp != p2.yp; }
-
-constexpr inline const QPoint operator+(const QPoint &p1, const QPoint &p2)
-{ return QPoint(p1.xp+p2.xp, p1.yp+p2.yp); }
-
-constexpr inline const QPoint operator-(const QPoint &p1, const QPoint &p2)
-{ return QPoint(p1.xp-p2.xp, p1.yp-p2.yp); }
-
-constexpr inline const QPoint operator*(const QPoint &p, float factor)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
-
-constexpr inline const QPoint operator*(const QPoint &p, double factor)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
-
-constexpr inline const QPoint operator*(const QPoint &p, int factor)
-{ return QPoint(p.xp*factor, p.yp*factor); }
-
-constexpr inline const QPoint operator*(float factor, const QPoint &p)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
-
-constexpr inline const QPoint operator*(double factor, const QPoint &p)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
-
-constexpr inline const QPoint operator*(int factor, const QPoint &p)
-{ return QPoint(p.xp*factor, p.yp*factor); }
-
-constexpr inline const QPoint operator+(const QPoint &p)
-{ return p; }
-
-constexpr inline const QPoint operator-(const QPoint &p)
-{ return QPoint(-p.xp, -p.yp); }
-
-constexpr inline QPoint &QPoint::operator/=(qreal c)
{
- xp = qRound(xp/c);
- yp = qRound(yp/c);
+ xp = xp * factor;
+ yp = yp * factor;
return *this;
}
-constexpr inline const QPoint operator/(const QPoint &p, qreal c)
+constexpr inline QPoint &QPoint::operator/=(qreal c)
{
- return QPoint(qRound(p.xp/c), qRound(p.yp/c));
+ xp = qRound(xp / c);
+ yp = qRound(yp / c);
+ return *this;
}
#ifndef QT_NO_DEBUG_STREAM
@@ -246,23 +237,46 @@ public:
constexpr inline QPointF &operator/=(qreal c);
constexpr static inline qreal dotProduct(const QPointF &p1, const QPointF &p2)
- { return p1.xp * p2.xp + p1.yp * p2.yp; }
-
- friend constexpr inline bool operator==(const QPointF &, const QPointF &);
- friend constexpr inline bool operator!=(const QPointF &, const QPointF &);
- friend constexpr inline const QPointF operator+(const QPointF &, const QPointF &);
- friend constexpr inline const QPointF operator-(const QPointF &, const QPointF &);
- friend constexpr inline const QPointF operator*(qreal, const QPointF &);
- friend constexpr inline const QPointF operator*(const QPointF &, qreal);
- friend constexpr inline const QPointF operator+(const QPointF &);
- friend constexpr inline const QPointF operator-(const QPointF &);
- friend constexpr inline const QPointF operator/(const QPointF &, qreal);
+ {
+ return p1.xp * p2.xp + p1.yp * p2.yp;
+ }
+
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_FLOAT_COMPARE
+ friend constexpr inline bool operator==(const QPointF &p1, const QPointF &p2)
+ {
+ return ((!p1.xp || !p2.xp) ? qFuzzyIsNull(p1.xp - p2.xp) : qFuzzyCompare(p1.xp, p2.xp))
+ && ((!p1.yp || !p2.yp) ? qFuzzyIsNull(p1.yp - p2.yp) : qFuzzyCompare(p1.yp, p2.yp));
+ }
+ friend constexpr inline bool operator!=(const QPointF &p1, const QPointF &p2)
+ {
+ return !(p1 == p2);
+ }
+ QT_WARNING_POP
+
+ friend constexpr inline QPointF operator+(const QPointF &p1, const QPointF &p2)
+ { return QPointF(p1.xp + p2.xp, p1.yp + p2.yp); }
+ friend constexpr inline QPointF operator-(const QPointF &p1, const QPointF &p2)
+ { return QPointF(p1.xp - p2.xp, p1.yp - p2.yp); }
+ friend constexpr inline QPointF operator*(const QPointF &p, qreal c)
+ { return QPointF(p.xp * c, p.yp * c); }
+ friend constexpr inline QPointF operator*(qreal c, const QPointF &p)
+ { return QPointF(p.xp * c, p.yp * c); }
+ friend constexpr inline QPointF operator+(const QPointF &p)
+ { return p; }
+ friend constexpr inline QPointF operator-(const QPointF &p)
+ { return QPointF(-p.xp, -p.yp); }
+ friend constexpr inline QPointF operator/(const QPointF &p, qreal divisor)
+ {
+ Q_ASSERT(divisor < 0 || divisor > 0);
+ return QPointF(p.xp / divisor, p.yp / divisor);
+ }
constexpr QPoint toPoint() const;
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
- Q_REQUIRED_RESULT Q_CORE_EXPORT static QPointF fromCGPoint(CGPoint point) noexcept;
- Q_REQUIRED_RESULT Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
+ [[nodiscard]] Q_CORE_EXPORT static QPointF fromCGPoint(CGPoint point) noexcept;
+ [[nodiscard]] Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
#endif
private:
@@ -270,9 +284,23 @@ private:
qreal xp;
qreal yp;
+
+ template <std::size_t I,
+ typename P,
+ std::enable_if_t<(I < 2), 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 q23::forward_like<P>(p.xp);
+ else if constexpr (I == 1)
+ return q23::forward_like<P>(p.yp);
+ }
};
-Q_DECLARE_TYPEINFO(QPointF, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QPointF, Q_PRIMITIVE_TYPE);
+
+size_t qHash(QPointF, size_t seed = 0) = delete;
/*****************************************************************************
QPointF stream functions
@@ -294,7 +322,7 @@ constexpr inline QPointF::QPointF(const QPoint &p) noexcept : xp(p.x()), yp(p.y(
constexpr inline qreal QPointF::manhattanLength() const
{
- return qAbs(x())+qAbs(y());
+ return qAbs(x()) + qAbs(y());
}
inline bool QPointF::isNull() const noexcept
@@ -334,78 +362,34 @@ constexpr inline qreal &QPointF::ry() noexcept
constexpr inline QPointF &QPointF::operator+=(const QPointF &p)
{
- xp+=p.xp;
- yp+=p.yp;
+ xp += p.xp;
+ yp += p.yp;
return *this;
}
constexpr inline QPointF &QPointF::operator-=(const QPointF &p)
{
- xp-=p.xp; yp-=p.yp; return *this;
+ xp -= p.xp;
+ yp -= p.yp;
+ return *this;
}
constexpr inline QPointF &QPointF::operator*=(qreal c)
{
- xp*=c; yp*=c; return *this;
-}
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_FLOAT_COMPARE
-
-constexpr inline bool operator==(const QPointF &p1, const QPointF &p2)
-{
- return ((!p1.xp || !p2.xp) ? qFuzzyIsNull(p1.xp - p2.xp) : qFuzzyCompare(p1.xp, p2.xp))
- && ((!p1.yp || !p2.yp) ? qFuzzyIsNull(p1.yp - p2.yp) : qFuzzyCompare(p1.yp, p2.yp));
-}
-
-constexpr inline bool operator!=(const QPointF &p1, const QPointF &p2)
-{
- return !(p1 == p2);
-}
-
-QT_WARNING_POP
-
-constexpr inline const QPointF operator+(const QPointF &p1, const QPointF &p2)
-{
- return QPointF(p1.xp+p2.xp, p1.yp+p2.yp);
-}
-
-constexpr inline const QPointF operator-(const QPointF &p1, const QPointF &p2)
-{
- return QPointF(p1.xp-p2.xp, p1.yp-p2.yp);
-}
-
-constexpr inline const QPointF operator*(const QPointF &p, qreal c)
-{
- return QPointF(p.xp*c, p.yp*c);
-}
-
-constexpr inline const QPointF operator*(qreal c, const QPointF &p)
-{
- return QPointF(p.xp*c, p.yp*c);
-}
-
-constexpr inline const QPointF operator+(const QPointF &p)
-{
- return p;
-}
-
-constexpr inline const QPointF operator-(const QPointF &p)
-{
- return QPointF(-p.xp, -p.yp);
+ xp *= c;
+ yp *= c;
+ return *this;
}
constexpr inline QPointF &QPointF::operator/=(qreal divisor)
{
- xp/=divisor;
- yp/=divisor;
+ Q_ASSERT(divisor > 0 || divisor < 0);
+ xp /= divisor;
+ yp /= divisor;
return *this;
}
-constexpr inline const QPointF operator/(const QPointF &p, qreal divisor)
-{
- return QPointF(p.xp/divisor, p.yp/divisor);
-}
+constexpr QPointF QPoint::toPointF() const noexcept { return *this; }
constexpr inline QPoint QPointF::toPoint() const
{
@@ -418,4 +402,24 @@ Q_CORE_EXPORT QDebug operator<<(QDebug d, const QPointF &p);
QT_END_NAMESPACE
+/*****************************************************************************
+ QPoint/QPointF tuple protocol
+ *****************************************************************************/
+
+namespace std {
+ template <>
+ class tuple_size<QT_PREPEND_NAMESPACE(QPoint)> : public integral_constant<size_t, 2> {};
+ template <>
+ class tuple_element<0, QT_PREPEND_NAMESPACE(QPoint)> { public: using type = int; };
+ template <>
+ class tuple_element<1, QT_PREPEND_NAMESPACE(QPoint)> { public: using type = int; };
+
+ template <>
+ class tuple_size<QT_PREPEND_NAMESPACE(QPointF)> : public integral_constant<size_t, 2> {};
+ template <>
+ class tuple_element<0, QT_PREPEND_NAMESPACE(QPointF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+ template <>
+ class tuple_element<1, QT_PREPEND_NAMESPACE(QPointF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+}
+
#endif // QPOINT_H
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 79d00a6fde..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"
@@ -1141,8 +1105,7 @@ bool QRect::intersects(const QRect &r) const noexcept
}
/*!
- \fn bool operator==(const QRect &r1, const QRect &r2)
- \relates QRect
+ \fn bool QRect::operator==(const QRect &r1, const QRect &r2)
Returns \c true if the rectangles \a r1 and \a r2 are equal,
otherwise returns \c false.
@@ -1150,8 +1113,7 @@ bool QRect::intersects(const QRect &r) const noexcept
/*!
- \fn bool operator!=(const QRect &r1, const QRect &r2)
- \relates QRect
+ \fn bool QRect::operator!=(const QRect &r1, const QRect &r2)
Returns \c true if the rectangles \a r1 and \a r2 are different, otherwise
returns \c false.
@@ -1234,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
*****************************************************************************/
@@ -1305,8 +1279,8 @@ QDebug operator<<(QDebug dbg, const QRect &r)
\ingroup painting
\reentrant
- \brief The QRectF class defines a rectangle in the plane using floating
- point precision.
+ \brief The QRectF class defines a finite rectangle in the plane using
+ floating point precision.
A rectangle is normally expressed as a top-left corner and a
size. The size (width and height) of a QRectF is always equivalent
@@ -1471,8 +1445,8 @@ QDebug operator<<(QDebug dbg, const QRect &r)
/*!
\fn QRectF::QRectF(qreal x, qreal y, qreal width, qreal height)
- Constructs a rectangle with (\a x, \a y) as its top-left corner
- and the given \a width and \a height.
+ Constructs a rectangle with (\a x, \a y) as its top-left corner and the
+ given \a width and \a height. All parameters must be finite.
\sa setRect()
*/
@@ -1482,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()
*/
/*!
@@ -1571,7 +1548,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setLeft(qreal x)
- Sets the left edge of the rectangle to the given \a x
+ Sets the left edge of the rectangle to the given finite \a x
coordinate. May change the width, but will never change the right
edge of the rectangle.
@@ -1583,7 +1560,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setTop(qreal y)
- Sets the top edge of the rectangle to the given \a y coordinate. May
+ Sets the top edge of the rectangle to the given finite \a y coordinate. May
change the height, but will never change the bottom edge of the
rectangle.
@@ -1595,7 +1572,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setRight(qreal x)
- Sets the right edge of the rectangle to the given \a x
+ Sets the right edge of the rectangle to the given finite \a x
coordinate. May change the width, but will never change the left
edge of the rectangle.
@@ -1605,7 +1582,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setBottom(qreal y)
- Sets the bottom edge of the rectangle to the given \a y
+ Sets the bottom edge of the rectangle to the given finite \a y
coordinate. May change the height, but will never change the top
edge of the rectangle.
@@ -1615,7 +1592,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setX(qreal x)
- Sets the left edge of the rectangle to the given \a x
+ Sets the left edge of the rectangle to the given finite \a x
coordinate. May change the width, but will never change the right
edge of the rectangle.
@@ -1627,7 +1604,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setY(qreal y)
- Sets the top edge of the rectangle to the given \a y
+ Sets the top edge of the rectangle to the given finite \a y
coordinate. May change the height, but will never change the
bottom edge of the rectangle.
@@ -1709,7 +1686,7 @@ QRectF QRectF::normalized() const noexcept
\fn void QRectF::moveLeft(qreal x)
Moves the rectangle horizontally, leaving the rectangle's left
- edge at the given \a x coordinate. The rectangle's size is
+ edge at the given finite \a x coordinate. The rectangle's size is
unchanged.
\sa left(), setLeft(), moveRight()
@@ -1719,7 +1696,7 @@ QRectF QRectF::normalized() const noexcept
\fn void QRectF::moveTop(qreal y)
Moves the rectangle vertically, leaving the rectangle's top line
- at the given \a y coordinate. The rectangle's size is unchanged.
+ at the given finite \a y coordinate. The rectangle's size is unchanged.
\sa top(), setTop(), moveBottom()
*/
@@ -1729,7 +1706,7 @@ QRectF QRectF::normalized() const noexcept
\fn void QRectF::moveRight(qreal x)
Moves the rectangle horizontally, leaving the rectangle's right
- edge at the given \a x coordinate. The rectangle's size is
+ edge at the given finite \a x coordinate. The rectangle's size is
unchanged.
\sa right(), setRight(), moveLeft()
@@ -1740,7 +1717,7 @@ QRectF QRectF::normalized() const noexcept
\fn void QRectF::moveBottom(qreal y)
Moves the rectangle vertically, leaving the rectangle's bottom
- edge at the given \a y coordinate. The rectangle's size is
+ edge at the given finite \a y coordinate. The rectangle's size is
unchanged.
\sa bottom(), setBottom(), moveTop()
@@ -1790,8 +1767,8 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::moveTo(qreal x, qreal y)
- Moves the rectangle, leaving the top-left corner at the given
- position (\a x, \a y). The rectangle's size is unchanged.
+ Moves the rectangle, leaving the top-left corner at the given position (\a
+ x, \a y). The rectangle's size is unchanged. Both parameters must be finite.
\sa translate(), moveTopLeft()
*/
@@ -1809,7 +1786,7 @@ QRectF QRectF::normalized() const noexcept
Moves the rectangle \a dx along the x-axis and \a dy along the y-axis,
relative to the current position. Positive values move the rectangle to the
- right and downwards.
+ right and downwards. Both parameters must be finite.
\sa moveTopLeft(), moveTo(), translated()
*/
@@ -1831,7 +1808,7 @@ QRectF QRectF::normalized() const noexcept
Returns a copy of the rectangle that is translated \a dx along the
x axis and \a dy along the y axis, relative to the current
position. Positive values move the rectangle to the right and
- down.
+ down. Both parameters must be finite.
\sa translate()
*/
@@ -1862,8 +1839,8 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setRect(qreal x, qreal y, qreal width, qreal height)
- Sets the coordinates of the rectangle's top-left corner to (\a x,
- \a y), and its size to the given \a width and \a height.
+ Sets the coordinates of the rectangle's top-left corner to (\a x, \a y), and
+ its size to the given \a width and \a height. All parameters must be finite.
\sa getRect(), setCoords()
*/
@@ -1874,7 +1851,7 @@ QRectF QRectF::normalized() const noexcept
Sets the coordinates of the rectangle's top-left corner to (\a x1,
\a y1), and the coordinates of its bottom-right corner to (\a x2,
- \a y2).
+ \a y2). All parameters must be finite.
\sa getCoords(), setRect()
*/
@@ -1884,6 +1861,7 @@ QRectF QRectF::normalized() const noexcept
Returns a new rectangle with \a dx1, \a dy1, \a dx2 and \a dy2
added respectively to the existing coordinates of this rectangle.
+ All parameters must be finite.
\sa adjust()
*/
@@ -1891,7 +1869,7 @@ QRectF QRectF::normalized() const noexcept
/*! \fn void QRectF::adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
Adds \a dx1, \a dy1, \a dx2 and \a dy2 respectively to the
- existing coordinates of the rectangle.
+ existing coordinates of the rectangle. All parameters must be finite.
\sa adjusted(), setRect()
*/
@@ -1922,7 +1900,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setWidth(qreal width)
- Sets the width of the rectangle to the given \a width. The right
+ Sets the width of the rectangle to the given finite \a width. The right
edge is changed, but not the left one.
\sa width(), setSize()
@@ -1932,7 +1910,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setHeight(qreal height)
- Sets the height of the rectangle to the given \a height. The bottom
+ Sets the height of the rectangle to the given finite \a height. The bottom
edge is changed, but not the top one.
\sa height(), setSize()
@@ -1942,7 +1920,7 @@ QRectF QRectF::normalized() const noexcept
/*!
\fn void QRectF::setSize(const QSizeF &size)
- Sets the size of the rectangle to the given \a size. The top-left
+ Sets the size of the rectangle to the given finite \a size. The top-left
corner is not moved.
\sa size(), setWidth(), setHeight()
@@ -2130,7 +2108,7 @@ bool QRectF::contains(const QRectF &r) const noexcept
Intersects this rectangle with the given \a rectangle.
- \sa intersected(), operator|=()
+ \sa intersected(), operator&()
*/
@@ -2335,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()
*/
/*!
@@ -2368,20 +2346,26 @@ QRect QRectF::toAlignedRect() const noexcept
*/
/*!
- \fn bool operator==(const QRectF &r1, const QRectF &r2)
- \relates QRectF
+ \fn bool QRectF::operator==(const QRectF &r1, const QRectF &r2)
- Returns \c true if the rectangles \a r1 and \a r2 are equal,
+ Returns \c true if the rectangles \a r1 and \a r2 are \b approximately equal,
otherwise returns \c false.
+
+ \warning This function does not check for strict equality; instead,
+ it uses a fuzzy comparison to compare the rectangles' coordinates.
+
+ \sa qFuzzyCompare
*/
/*!
- \fn bool operator!=(const QRectF &r1, const QRectF &r2)
- \relates QRectF
+ \fn bool QRectF::operator!=(const QRectF &r1, const QRectF &r2)
- Returns \c true if the rectangles \a r1 and \a r2 are different, otherwise
- returns \c false.
+ Returns \c true if the rectangles \a r1 and \a r2 are sufficiently
+ different, otherwise returns \c false.
+
+ \warning This function does not check for strict inequality; instead,
+ it uses a fuzzy comparison to compare the rectangles' coordinates.
*/
/*!
diff --git a/src/corelib/tools/qrect.h b/src/corelib/tools/qrect.h
index 5deb220b2d..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:
@@ -71,7 +42,7 @@ public:
constexpr inline int top() const noexcept;
constexpr inline int right() const noexcept;
constexpr inline int bottom() const noexcept;
- Q_REQUIRED_RESULT QRect normalized() const noexcept;
+ [[nodiscard]] QRect normalized() const noexcept;
constexpr inline int x() const noexcept;
constexpr inline int y() const noexcept;
@@ -105,9 +76,9 @@ public:
constexpr inline void translate(int dx, int dy) noexcept;
constexpr inline void translate(const QPoint &p) noexcept;
- Q_REQUIRED_RESULT constexpr inline QRect translated(int dx, int dy) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QRect translated(const QPoint &p) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QRect transposed() const noexcept;
+ [[nodiscard]] constexpr inline QRect translated(int dx, int dy) const noexcept;
+ [[nodiscard]] constexpr inline QRect translated(const QPoint &p) const noexcept;
+ [[nodiscard]] constexpr inline QRect transposed() const noexcept;
constexpr inline void moveTo(int x, int t) noexcept;
constexpr inline void moveTo(const QPoint &p) noexcept;
@@ -119,7 +90,7 @@ public:
constexpr inline void getCoords(int *x1, int *y1, int *x2, int *y2) const;
constexpr inline void adjust(int x1, int y1, int x2, int y2) noexcept;
- Q_REQUIRED_RESULT constexpr inline QRect adjusted(int x1, int y1, int x2, int y2) const noexcept;
+ [[nodiscard]] constexpr inline QRect adjusted(int x1, int y1, int x2, int y2) const noexcept;
constexpr inline QSize size() const noexcept;
constexpr inline int width() const noexcept;
@@ -130,15 +101,15 @@ public:
QRect operator|(const QRect &r) const noexcept;
QRect operator&(const QRect &r) const noexcept;
- inline QRect& operator|=(const QRect &r) noexcept;
- inline QRect& operator&=(const QRect &r) noexcept;
+ inline QRect &operator|=(const QRect &r) noexcept;
+ inline QRect &operator&=(const QRect &r) noexcept;
bool contains(const QRect &r, bool proper = false) const noexcept;
- bool contains(const QPoint &p, bool proper=false) const noexcept;
+ bool contains(const QPoint &p, bool proper = false) const noexcept;
inline bool contains(int x, int y) const noexcept;
inline bool contains(int x, int y, bool proper) const noexcept;
- Q_REQUIRED_RESULT inline QRect united(const QRect &other) const noexcept;
- Q_REQUIRED_RESULT inline QRect intersected(const QRect &other) const noexcept;
+ [[nodiscard]] inline QRect united(const QRect &other) const noexcept;
+ [[nodiscard]] inline QRect intersected(const QRect &other) const noexcept;
bool intersects(const QRect &r) const noexcept;
constexpr inline QRect marginsAdded(const QMargins &margins) const noexcept;
@@ -146,15 +117,18 @@ public:
constexpr inline QRect &operator+=(const QMargins &margins) noexcept;
constexpr inline QRect &operator-=(const QMargins &margins) noexcept;
- Q_REQUIRED_RESULT static constexpr inline QRect span(const QPoint &p1, const QPoint &p2) noexcept;
+ [[nodiscard]] static constexpr inline QRect span(const QPoint &p1, const QPoint &p2) noexcept;
- friend constexpr inline bool operator==(const QRect &, const QRect &) noexcept;
- friend constexpr inline bool operator!=(const QRect &, const QRect &) noexcept;
+ friend constexpr inline bool operator==(const QRect &r1, const QRect &r2) noexcept
+ { return r1.x1==r2.x1 && r1.x2==r2.x2 && r1.y1==r2.y1 && r1.y2==r2.y2; }
+ friend constexpr inline bool operator!=(const QRect &r1, const QRect &r2) noexcept
+ { return r1.x1!=r2.x1 || r1.x2!=r2.x2 || r1.y1!=r2.y1 || r1.y2!=r2.y2; }
friend constexpr inline size_t qHash(const QRect &, size_t) noexcept;
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
- Q_REQUIRED_RESULT CGRect toCGRect() const noexcept;
+ [[nodiscard]] CGRect toCGRect() const noexcept;
#endif
+ [[nodiscard]] constexpr inline QRectF toRectF() const noexcept;
private:
int x1;
@@ -162,10 +136,7 @@ private:
int x2;
int y2;
};
-Q_DECLARE_TYPEINFO(QRect, Q_MOVABLE_TYPE);
-
-constexpr inline bool operator==(const QRect &, const QRect &) noexcept;
-constexpr inline bool operator!=(const QRect &, const QRect &) noexcept;
+Q_DECLARE_TYPEINFO(QRect, Q_RELOCATABLE_TYPE);
/*****************************************************************************
@@ -428,13 +399,13 @@ inline bool QRect::contains(int ax, int ay) const noexcept
return contains(QPoint(ax, ay), false);
}
-inline QRect& QRect::operator|=(const QRect &r) noexcept
+inline QRect &QRect::operator|=(const QRect &r) noexcept
{
*this = *this | r;
return *this;
}
-inline QRect& QRect::operator&=(const QRect &r) noexcept
+inline QRect &QRect::operator&=(const QRect &r) noexcept
{
*this = *this & r;
return *this;
@@ -450,16 +421,6 @@ inline QRect QRect::united(const QRect &r) const noexcept
return *this | r;
}
-constexpr inline bool operator==(const QRect &r1, const QRect &r2) noexcept
-{
- return r1.x1==r2.x1 && r1.x2==r2.x2 && r1.y1==r2.y1 && r1.y2==r2.y2;
-}
-
-constexpr inline bool operator!=(const QRect &r1, const QRect &r2) noexcept
-{
- return r1.x1!=r2.x1 || r1.x2!=r2.x2 || r1.y1!=r2.y1 || r1.y2!=r2.y2;
-}
-
constexpr inline size_t qHash(const QRect &r, size_t seed = 0) noexcept
{
return qHashMulti(seed, r.x1, r.x2, r.y1, r.y2);
@@ -530,7 +491,7 @@ public:
constexpr inline bool isNull() const noexcept;
constexpr inline bool isEmpty() const noexcept;
constexpr inline bool isValid() const noexcept;
- Q_REQUIRED_RESULT QRectF normalized() const noexcept;
+ [[nodiscard]] QRectF normalized() const noexcept;
constexpr inline qreal left() const noexcept { return xp; }
constexpr inline qreal top() const noexcept { return yp; }
@@ -570,10 +531,10 @@ public:
constexpr inline void translate(qreal dx, qreal dy) noexcept;
constexpr inline void translate(const QPointF &p) noexcept;
- Q_REQUIRED_RESULT constexpr inline QRectF translated(qreal dx, qreal dy) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QRectF translated(const QPointF &p) const noexcept;
+ [[nodiscard]] constexpr inline QRectF translated(qreal dx, qreal dy) const noexcept;
+ [[nodiscard]] constexpr inline QRectF translated(const QPointF &p) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QRectF transposed() const noexcept;
+ [[nodiscard]] constexpr inline QRectF transposed() const noexcept;
constexpr inline void moveTo(qreal x, qreal y) noexcept;
constexpr inline void moveTo(const QPointF &p) noexcept;
@@ -585,7 +546,7 @@ public:
constexpr inline void getCoords(qreal *x1, qreal *y1, qreal *x2, qreal *y2) const;
constexpr inline void adjust(qreal x1, qreal y1, qreal x2, qreal y2) noexcept;
- Q_REQUIRED_RESULT constexpr inline QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept;
+ [[nodiscard]] constexpr inline QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept;
constexpr inline QSizeF size() const noexcept;
constexpr inline qreal width() const noexcept;
@@ -596,14 +557,14 @@ public:
QRectF operator|(const QRectF &r) const noexcept;
QRectF operator&(const QRectF &r) const noexcept;
- inline QRectF& operator|=(const QRectF &r) noexcept;
- inline QRectF& operator&=(const QRectF &r) noexcept;
+ inline QRectF &operator|=(const QRectF &r) noexcept;
+ inline QRectF &operator&=(const QRectF &r) noexcept;
bool contains(const QRectF &r) const noexcept;
bool contains(const QPointF &p) const noexcept;
inline bool contains(qreal x, qreal y) const noexcept;
- Q_REQUIRED_RESULT inline QRectF united(const QRectF &other) const noexcept;
- Q_REQUIRED_RESULT inline QRectF intersected(const QRectF &other) const noexcept;
+ [[nodiscard]] inline QRectF united(const QRectF &other) const noexcept;
+ [[nodiscard]] inline QRectF intersected(const QRectF &other) const noexcept;
bool intersects(const QRectF &r) const noexcept;
constexpr inline QRectF marginsAdded(const QMarginsF &margins) const noexcept;
@@ -611,15 +572,28 @@ public:
constexpr inline QRectF &operator+=(const QMarginsF &margins) noexcept;
constexpr inline QRectF &operator-=(const QMarginsF &margins) noexcept;
- friend constexpr inline bool operator==(const QRectF &, const QRectF &) noexcept;
- friend constexpr inline bool operator!=(const QRectF &, const QRectF &) noexcept;
+ friend constexpr inline bool operator==(const QRectF &r1, const QRectF &r2) noexcept
+ {
+ return r1.topLeft() == r2.topLeft()
+ && r1.size() == r2.size();
+ }
+ friend constexpr inline bool operator!=(const QRectF &r1, const QRectF &r2) noexcept
+ {
+ return r1.topLeft() != r2.topLeft()
+ || r1.size() != r2.size();
+ }
- Q_REQUIRED_RESULT constexpr inline QRect toRect() const noexcept;
- Q_REQUIRED_RESULT QRect toAlignedRect() const noexcept;
+ [[nodiscard]] constexpr inline QRect toRect() const noexcept;
+ [[nodiscard]] QRect toAlignedRect() const noexcept;
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
- Q_REQUIRED_RESULT static QRectF fromCGRect(CGRect rect) noexcept;
- Q_REQUIRED_RESULT CGRect toCGRect() const noexcept;
+ [[nodiscard]] static QRectF fromCGRect(CGRect rect) noexcept;
+ [[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:
@@ -628,10 +602,7 @@ private:
qreal w;
qreal h;
};
-Q_DECLARE_TYPEINFO(QRectF, Q_MOVABLE_TYPE);
-
-constexpr inline bool operator==(const QRectF &, const QRectF &) noexcept;
-constexpr inline bool operator!=(const QRectF &, const QRectF &) noexcept;
+Q_DECLARE_TYPEINFO(QRectF, Q_RELOCATABLE_TYPE);
/*****************************************************************************
@@ -775,7 +746,9 @@ constexpr inline void QRectF::moveTo(const QPointF &p) noexcept
}
constexpr inline QRectF QRectF::translated(qreal dx, qreal dy) const noexcept
-{ return QRectF(xp + dx, yp + dy, w, h); }
+{
+ return QRectF(xp + dx, yp + dy, w, h);
+}
constexpr inline QRectF QRectF::translated(const QPointF &p) const noexcept
{ return QRectF(xp + p.x(), yp + p.y(), w, h); }
@@ -816,10 +789,17 @@ constexpr inline void QRectF::setCoords(qreal xp1, qreal yp1, qreal xp2, qreal y
}
constexpr inline void QRectF::adjust(qreal xp1, qreal yp1, qreal xp2, qreal yp2) noexcept
-{ xp += xp1; yp += yp1; w += xp2 - xp1; h += yp2 - yp1; }
+{
+ xp += xp1;
+ yp += yp1;
+ w += xp2 - xp1;
+ h += yp2 - yp1;
+}
constexpr inline QRectF QRectF::adjusted(qreal xp1, qreal yp1, qreal xp2, qreal yp2) const noexcept
-{ return QRectF(xp + xp1, yp + yp1, w + xp2 - xp1, h + yp2 - yp1); }
+{
+ return QRectF(xp + xp1, yp + yp1, w + xp2 - xp1, h + yp2 - yp1);
+}
constexpr inline void QRectF::setWidth(qreal aw) noexcept
{ this->w = aw; }
@@ -838,13 +818,13 @@ inline bool QRectF::contains(qreal ax, qreal ay) const noexcept
return contains(QPointF(ax, ay));
}
-inline QRectF& QRectF::operator|=(const QRectF &r) noexcept
+inline QRectF &QRectF::operator|=(const QRectF &r) noexcept
{
*this = *this | r;
return *this;
}
-inline QRectF& QRectF::operator&=(const QRectF &r) noexcept
+inline QRectF &QRectF::operator&=(const QRectF &r) noexcept
{
*this = *this & r;
return *this;
@@ -860,21 +840,18 @@ inline QRectF QRectF::united(const QRectF &r) const noexcept
return *this | r;
}
-constexpr inline bool operator==(const QRectF &r1, const QRectF &r2) noexcept
-{
- return qFuzzyCompare(r1.xp, r2.xp) && qFuzzyCompare(r1.yp, r2.yp)
- && qFuzzyCompare(r1.w, r2.w) && qFuzzyCompare(r1.h, r2.h);
-}
-
-constexpr inline bool operator!=(const QRectF &r1, const QRectF &r2) noexcept
-{
- return !qFuzzyCompare(r1.xp, r2.xp) || !qFuzzyCompare(r1.yp, r2.yp)
- || !qFuzzyCompare(r1.w, r2.w) || !qFuzzyCompare(r1.h, r2.h);
-}
+constexpr QRectF QRect::toRectF() const noexcept { return *this; }
constexpr inline QRect QRectF::toRect() const noexcept
{
- return QRect(QPoint(qRound(xp), qRound(yp)), QPoint(qRound(xp + w) - 1, qRound(yp + h) - 1));
+ // This rounding is designed to minimize the maximum possible difference
+ // in topLeft(), bottomRight(), and size() after rounding.
+ // All dimensions are at most off by 0.75, and topLeft by at most 0.5.
+ const int nxp = qRound(xp);
+ const int nyp = qRound(yp);
+ const int nw = qRound(w + (xp - nxp) / 2);
+ const int nh = qRound(h + (yp - nyp) / 2);
+ return QRect(nxp, nyp, nw, nh);
}
constexpr inline QRectF operator+(const QRectF &lhs, const QMarginsF &rhs) noexcept
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 311058a776..0645759118 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -1,50 +1,20 @@
-/****************************************************************************
-**
-** 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
-void QRingChunk::allocate(int alloc)
+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);
@@ -56,32 +26,24 @@ void QRingChunk::detach()
{
Q_ASSERT(isShared());
- const int chunkSize = size();
- QByteArray x(chunkSize, Qt::Uninitialized);
- ::memcpy(x.data(), chunk.constData() + headOffset, chunkSize);
- chunk = std::move(x);
+ const qsizetype chunkSize = size();
+ 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,10 +105,10 @@ 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 int chunkSize = qMax(basicBlockSize, int(bytes));
- int tail = 0;
+ const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
+ qsizetype tail = 0;
if (bufferSize == 0) {
if (buffers.isEmpty())
buffers.append(QRingChunk(chunkSize));
@@ -173,9 +135,9 @@ 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 int chunkSize = qMax(basicBlockSize, int(bytes));
+ const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
if (bufferSize == 0) {
if (buffers.isEmpty())
buffers.prepend(QRingChunk(chunkSize));
@@ -204,7 +166,7 @@ void QRingBuffer::chop(qint64 bytes)
Q_ASSERT(bytes <= bufferSize);
while (bytes > 0) {
- const qint64 chunkSize = buffers.constLast().size();
+ const qsizetype chunkSize = buffers.constLast().size();
if (buffers.size() == 1 || chunkSize > bytes) {
QRingChunk &chunk = buffers.last();
@@ -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 85a3882a3c..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,39 +29,18 @@ 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)
- {
- }
- explicit inline QRingChunk(int alloc) :
- chunk(alloc, Qt::Uninitialized), headOffset(0), tailOffset(0)
+ QRingChunk() noexcept = default;
+ explicit inline QRingChunk(qsizetype alloc) :
+ 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
- {
- 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)
+ explicit QRingChunk(QByteArray &&qba) noexcept :
+ chunk(std::move(qba)), tailOffset(chunk.size())
{
- other.headOffset = other.tailOffset = 0;
- }
- inline QRingChunk &operator=(QRingChunk &&other) noexcept
- {
- swap(other);
- return *this;
}
inline void swap(QRingChunk &other) noexcept
@@ -108,28 +51,28 @@ public:
}
// allocating and sharing
- void allocate(int alloc);
+ void allocate(qsizetype alloc);
inline bool isShared() const
{
return !chunk.isDetached();
}
Q_CORE_EXPORT void detach();
- QByteArray toByteArray();
+ QByteArray toByteArray() &&;
// getters
- inline int head() const
+ inline qsizetype head() const
{
return headOffset;
}
- inline int size() const
+ inline qsizetype size() const
{
return tailOffset - headOffset;
}
- inline int capacity() const
+ inline qsizetype capacity() const
{
return chunk.size();
}
- inline int available() const
+ inline qsizetype available() const
{
return chunk.size() - tailOffset;
}
@@ -145,14 +88,14 @@ public:
}
// array management
- inline void advance(int offset)
+ inline void advance(qsizetype offset)
{
Q_ASSERT(headOffset + offset >= 0);
Q_ASSERT(size() - offset > 0);
headOffset += offset;
}
- inline void grow(int offset)
+ inline void grow(qsizetype offset)
{
Q_ASSERT(size() + offset > 0);
Q_ASSERT(head() + size() + offset <= capacity());
@@ -165,26 +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;
- int headOffset, 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;
}
@@ -250,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);
@@ -270,8 +226,7 @@ private:
int basicBlockSize;
};
-Q_DECLARE_SHARED(QRingChunk)
-Q_DECLARE_TYPEINFO(QRingBuffer, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRingBuffer, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qscopedpointer.cpp b/src/corelib/tools/qscopedpointer.cpp
index eb08bdba62..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"
@@ -126,7 +90,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> QScopedPointer<T, Cleanup>::QScopedPointer(T *p = 0)
+ \fn template <typename T, typename Cleanup> QScopedPointer<T, Cleanup>::QScopedPointer(T *p = nullptr)
Constructs this QScopedPointer instance and sets its pointer to \a p.
*/
@@ -183,21 +147,20 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> bool operator==(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs)
+ \fn template <typename T, typename Cleanup> bool QScopedPointer<T, Cleanup>::operator==(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs)
- Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
+ Returns \c true if \a lhs and \a rhs refer to the same pointer.
*/
/*!
- \fn template <typename T, typename Cleanup> bool operator!=(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs)
+ \fn template <typename T, typename Cleanup> bool QScopedPointer<T, Cleanup>::operator!=(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs)
Returns \c true if \a lhs and \a rhs refer to distinct pointers.
*/
/*!
- \fn template <typename T, typename Cleanup> bool operator==(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t)
- \relates QScopedPointer
+ \fn template <typename T, typename Cleanup> bool QScopedPointer<T, Cleanup>::operator==(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t)
\since 5.8
Returns \c true if \a lhs refers to \nullptr.
@@ -206,8 +169,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> bool operator==(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs)
- \relates QScopedPointer
+ \fn template <typename T, typename Cleanup> bool QScopedPointer<T, Cleanup>::operator==(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs)
\since 5.8
Returns \c true if \a rhs refers to \nullptr.
@@ -216,8 +178,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> bool operator!=(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t)
- \relates QScopedPointer
+ \fn template <typename T, typename Cleanup> bool QScopedPointer<T, Cleanup>::operator!=(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t)
\since 5.8
Returns \c true if \a lhs refers to a valid (i.e. non-null) pointer.
@@ -226,8 +187,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> bool operator!=(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs)
- \relates QScopedPointer
+ \fn template <typename T, typename Cleanup> bool QScopedPointer<T, Cleanup>::operator!=(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs)
\since 5.8
Returns \c true if \a rhs refers to a valid (i.e. non-null) pointer.
@@ -242,19 +202,18 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> void QScopedPointer<T, Cleanup>::reset(T *other = 0)
+ \fn template <typename T, typename Cleanup> void QScopedPointer<T, Cleanup>::reset(T *other = nullptr)
Deletes the existing object it is pointing to (if any), and sets its pointer to
\a other. QScopedPointer now owns \a other and will delete it in its
destructor.
-
- To clear the pointer held without deleting the object it points to (and hence take ownership
- of the object), use \l take() instead.
*/
/*!
\fn template <typename T, typename Cleanup> T *QScopedPointer<T, Cleanup>::take()
+ \deprecated [6.1] Use \c std::unique_ptr and \c release() instead.
+
Returns the value of the pointer referenced by this object. The pointer of this
QScopedPointer object will be reset to \nullptr.
@@ -268,8 +227,12 @@ QT_BEGIN_NAMESPACE
\sa isNull()
*/
-/*! \fn template <typename T, typename Cleanup> void QScopedPointer<T, Cleanup>::swap(QScopedPointer<T, Cleanup> &other)
- Swap this pointer with \a other.
+/*! \fn template <typename T, typename Cleanup> void QScopedPointer<T, Cleanup>::swap(QScopedPointer<T, Cleanup> &lhs, QScopedPointer<T, Cleanup> &rhs)
+
+ \deprecated [6.1] Use \c std::unique_ptr instead; this function may let a pointer
+ escape its scope.
+
+ Swaps \a lhs with \a rhs.
*/
/*!
@@ -306,36 +269,46 @@ 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()
*/
/*! \fn template <typename T, typename Cleanup> void QScopedArrayPointer<T, Cleanup>::swap(QScopedArrayPointer<T, Cleanup> &other)
- Swap this pointer with \a other.
+
+ \deprecated [6.1] Use \c std::unique_ptr instead; this function may let a pointer
+ escape its scope.
+
+ Swap this pointer with \a other.
*/
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qscopedpointer.h b/src/corelib/tools/qscopedpointer.h
index 4acec9c1f6..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
@@ -49,7 +13,7 @@ QT_BEGIN_NAMESPACE
template <typename T>
struct QScopedPointerDeleter
{
- static inline void cleanup(T *pointer)
+ static inline void cleanup(T *pointer) noexcept
{
// Enforce a complete type.
// If you get a compile error here, read the section on forward declared
@@ -59,12 +23,16 @@ struct QScopedPointerDeleter
delete pointer;
}
+ void operator()(T *pointer) const noexcept
+ {
+ cleanup(pointer);
+ }
};
template <typename T>
struct QScopedPointerArrayDeleter
{
- static inline void cleanup(T *pointer)
+ static inline void cleanup(T *pointer) noexcept
{
// Enforce a complete type.
// If you get a compile error here, read the section on forward declared
@@ -72,13 +40,18 @@ struct QScopedPointerArrayDeleter
typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
(void) sizeof(IsIncompleteType);
- delete [] pointer;
+ delete[] pointer;
+ }
+ void operator()(T *pointer) const noexcept
+ {
+ cleanup(pointer);
}
};
struct QScopedPointerPodDeleter
{
- static inline void cleanup(void *pointer) { if (pointer) free(pointer); }
+ static inline void cleanup(void *pointer) noexcept { free(pointer); }
+ void operator()(void *pointer) const noexcept { cleanup(pointer); }
};
#ifndef QT_NO_QOBJECT
@@ -86,6 +59,7 @@ template <typename T>
struct QScopedPointerObjectDeleteLater
{
static inline void cleanup(T *pointer) { if (pointer) pointer->deleteLater(); }
+ void operator()(T *pointer) const { cleanup(pointer); }
};
class QObject;
@@ -96,6 +70,7 @@ template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer
{
public:
+ Q_NODISCARD_CTOR
explicit QScopedPointer(T *p = nullptr) noexcept : d(p)
{
}
@@ -146,71 +121,71 @@ public:
{
if (d == other)
return;
- T *oldD = d;
- d = other;
+ T *oldD = std::exchange(d, other);
Cleanup::cleanup(oldD);
}
+#if QT_DEPRECATED_SINCE(6, 1)
+ QT_DEPRECATED_VERSION_X_6_1("Use std::unique_ptr instead, and call release().")
T *take() noexcept
{
- T *oldD = d;
- d = nullptr;
+ T *oldD = std::exchange(d, nullptr);
return oldD;
}
+#endif
+#if QT_DEPRECATED_SINCE(6, 2)
+ 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
typedef T *pointer;
-protected:
- T *d;
+ friend bool operator==(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs) noexcept
+ {
+ return lhs.data() == rhs.data();
+ }
-private:
- Q_DISABLE_COPY(QScopedPointer)
-};
+ friend bool operator!=(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs) noexcept
+ {
+ return lhs.data() != rhs.data();
+ }
-template <class T, class Cleanup>
-inline bool operator==(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs) noexcept
-{
- return lhs.data() == rhs.data();
-}
+ friend bool operator==(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t) noexcept
+ {
+ return lhs.isNull();
+ }
-template <class T, class Cleanup>
-inline bool operator!=(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs) noexcept
-{
- return lhs.data() != rhs.data();
-}
+ friend bool operator==(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs) noexcept
+ {
+ return rhs.isNull();
+ }
-template <class T, class Cleanup>
-inline bool operator==(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t) noexcept
-{
- return lhs.isNull();
-}
+ friend bool operator!=(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t) noexcept
+ {
+ return !lhs.isNull();
+ }
-template <class T, class Cleanup>
-inline bool operator==(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs) noexcept
-{
- return rhs.isNull();
-}
+ friend bool operator!=(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs) noexcept
+ {
+ return !rhs.isNull();
+ }
-template <class T, class Cleanup>
-inline bool operator!=(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t) noexcept
-{
- return !lhs.isNull();
-}
+#if QT_DEPRECATED_SINCE(6, 2)
+ QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedPointer.")
+ friend void swap(QScopedPointer<T, Cleanup> &p1, QScopedPointer<T, Cleanup> &p2) noexcept
+ { p1.swap(p2); }
+#endif
-template <class T, class Cleanup>
-inline bool operator!=(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs) noexcept
-{
- return !rhs.isNull();
-}
+protected:
+ T *d;
-template <class T, class Cleanup>
-inline void swap(QScopedPointer<T, Cleanup> &p1, QScopedPointer<T, Cleanup> &p2) noexcept
-{ p1.swap(p2); }
+private:
+ Q_DISABLE_COPY_MOVE(QScopedPointer)
+};
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
@@ -218,29 +193,36 @@ 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];
}
+#if QT_DEPRECATED_SINCE(6, 2)
+ QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedArrayPointer.")
void swap(QScopedArrayPointer &other) noexcept // prevent QScopedPointer <->QScopedArrayPointer swaps
{ QScopedPointer<T, Cleanup>::swap(other); }
+#endif
private:
- explicit inline QScopedArrayPointer(void *) {
+ explicit inline QScopedArrayPointer(void *)
+ {
// Enforce the same type.
// If you get a compile error here, make sure you declare
@@ -251,12 +233,15 @@ private:
// allowed and results in undefined behavior.
}
- Q_DISABLE_COPY(QScopedArrayPointer)
+ Q_DISABLE_COPY_MOVE(QScopedArrayPointer)
};
+#if QT_DEPRECATED_SINCE(6, 2)
template <typename T, typename Cleanup>
+QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedArrayPointer.")
inline void swap(QScopedArrayPointer<T, Cleanup> &lhs, QScopedArrayPointer<T, Cleanup> &rhs) noexcept
{ lhs.swap(rhs); }
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qscopedpointer_p.h b/src/corelib/tools/qscopedpointer_p.h
deleted file mode 100644
index c1c44e7695..0000000000
--- a/src/corelib/tools/qscopedpointer_p.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of internal files. This header file may change from version to version
-// without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/private/qglobal_p.h>
-
-#ifndef QSCOPEDPOINTER_P_H
-#define QSCOPEDPOINTER_P_H
-
-#include "QtCore/qscopedpointer.h"
-
-QT_BEGIN_NAMESPACE
-
-
-/* Internal helper class - exposes the data through data_ptr (legacy from QShared).
- Required for some internal Qt classes, do not use otherwise. */
-template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
-class QCustomScopedPointer : public QScopedPointer<T, Cleanup>
-{
-public:
- explicit inline QCustomScopedPointer(T *p = 0)
- : QScopedPointer<T, Cleanup>(p)
- {
- }
-
- inline T *&data_ptr()
- {
- return this->d;
- }
-
- inline bool operator==(const QCustomScopedPointer<T, Cleanup> &other) const
- {
- return this->d == other.d;
- }
-
- inline bool operator!=(const QCustomScopedPointer<T, Cleanup> &other) const
- {
- return this->d != other.d;
- }
-
-private:
- Q_DISABLE_COPY(QCustomScopedPointer)
-};
-
-/* Internal helper class - a handler for QShared* classes, to be used in QCustomScopedPointer */
-template <typename T>
-class QScopedPointerSharedDeleter
-{
-public:
- static inline void cleanup(T *d)
- {
- if (d && !d->ref.deref())
- delete d;
- }
-};
-
-/* Internal.
- This class is basically a scoped pointer pointing to a ref-counted object
- */
-template <typename T>
-class QScopedSharedPointer : public QCustomScopedPointer<T, QScopedPointerSharedDeleter<T> >
-{
-public:
- explicit inline QScopedSharedPointer(T *p = 0)
- : QCustomScopedPointer<T, QScopedPointerSharedDeleter<T> >(p)
- {
- }
-
- inline void detach()
- {
- qAtomicDetach(this->d);
- }
-
- inline void assign(T *other)
- {
- if (this->d == other)
- return;
- if (other)
- other->ref.ref();
- T *oldD = this->d;
- this->d = other;
- QScopedPointerSharedDeleter<T>::cleanup(oldD);
- }
-
- inline bool operator==(const QScopedSharedPointer<T> &other) const
- {
- return this->d == other.d;
- }
-
- inline bool operator!=(const QScopedSharedPointer<T> &other) const
- {
- return this->d != other.d;
- }
-
-private:
- Q_DISABLE_COPY(QScopedSharedPointer)
-};
-
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/corelib/tools/qscopedvaluerollback.cpp b/src/corelib/tools/qscopedvaluerollback.cpp
index baca7c8229..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"
@@ -58,7 +22,7 @@ QT_BEGIN_NAMESPACE
The template can only be instantiated with a type that supports assignment.
- \sa QScopedPointer
+ \sa QScopedPointer, QScopeGuard
*/
/*!
diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h
index b8ceff6665..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,30 +9,31 @@
QT_BEGIN_NAMESPACE
template <typename T>
-class
-#if QT_HAS_CPP_ATTRIBUTE(nodiscard) && __cplusplus >= 201703L
-[[nodiscard]]
-#endif
-QScopedValueRollback
+class QScopedValueRollback
{
public:
- explicit QScopedValueRollback(T &var)
+ Q_NODISCARD_CTOR
+ explicit constexpr QScopedValueRollback(T &var)
: varRef(var), oldValue(var)
{
}
- explicit QScopedValueRollback(T &var, T value)
- : varRef(var), oldValue(std::move(var))
+ Q_NODISCARD_CTOR
+ explicit constexpr QScopedValueRollback(T &var, T value)
+ : varRef(var), oldValue(std::move(var)) // ### C++20: std::exchange(var, std::move(value))
{
- varRef = std::move(value);
+ var = std::move(value);
}
+#if __cpp_constexpr >= 201907L
+ constexpr
+#endif
~QScopedValueRollback()
{
varRef = std::move(oldValue);
}
- void commit()
+ constexpr void commit()
{
oldValue = varRef;
}
@@ -77,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 d288fd63fc..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,28 +13,25 @@
QT_BEGIN_NAMESPACE
template <typename F>
-class
-#if __has_cpp_attribute(nodiscard)
-// Q_REQUIRED_RESULT can be defined as __warn_unused_result__ or as [[nodiscard]]
-// but the 1st one has some limitations for example can be placed only on functions.
-Q_REQUIRED_RESULT
-#endif
-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))
{
}
@@ -92,16 +53,11 @@ private:
bool m_invoke = true;
};
-#ifdef __cpp_deduction_guides
template <typename F> QScopeGuard(F(&)()) -> QScopeGuard<F(*)()>;
-#endif
//! [qScopeGuard]
template <typename F>
-#if __has_cpp_attribute(nodiscard)
-Q_REQUIRED_RESULT
-#endif
-QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f)
+[[nodiscard]] QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f)
{
return QScopeGuard<typename std::decay<F>::type>(std::forward<F>(f));
}
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 5f1500e747..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,12 +35,17 @@ public:
inline void swap(QSet<T> &other) noexcept { q_hash.swap(other.q_hash); }
+#ifndef Q_QDOC
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator==(const QSet<T> &other) const
+ QTypeTraits::compare_eq_result_container<QSet, U> operator==(const QSet<T> &other) const
{ return q_hash == other.q_hash; }
template <typename U = T>
- QTypeTraits::compare_eq_result<U> operator!=(const QSet<T> &other) const
+ QTypeTraits::compare_eq_result_container<QSet, U> operator!=(const QSet<T> &other) const
{ return q_hash != other.q_hash; }
+#else
+ bool operator==(const QSet &other) const;
+ bool operator!=(const QSet &other) const;
+#endif
inline qsizetype size() const { return q_hash.size(); }
@@ -93,6 +62,12 @@ public:
inline bool remove(const T &value) { return q_hash.remove(value) != 0; }
+ template <typename Pred>
+ inline qsizetype removeIf(Pred predicate)
+ {
+ return QtPrivate::qset_erase_if(*this, predicate);
+ }
+
inline bool contains(const T &value) const { return q_hash.contains(value); }
bool contains(const QSet<T> &set) const;
@@ -176,9 +151,11 @@ 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 static_cast<typename Hash::iterator>(q_hash.insert(value, QHashDummyValue())); }
+ { return q_hash.insert(value, QHashDummyValue()); }
+ inline iterator insert(T &&value)
+ { return q_hash.emplace(std::move(value), QHashDummyValue()); }
iterator find(const T &value) { return q_hash.find(value); }
const_iterator find(const T &value) const { return q_hash.find(value); }
inline const_iterator constFind(const T &value) const { return find(value); }
@@ -198,6 +175,9 @@ public:
typedef qsizetype size_type;
inline bool empty() const { return isEmpty(); }
+
+ iterator insert(const_iterator, const T &value) { return insert(value); }
+
// comfort
inline QSet<T> &operator<<(const T &value) { insert(value); return *this; }
inline QSet<T> &operator|=(const QSet<T> &other) { unite(other); return *this; }
@@ -209,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;
@@ -224,12 +208,10 @@ private:
Hash q_hash;
};
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
template <typename InputIterator,
typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
QtPrivate::IfIsInputIterator<InputIterator> = true>
QSet(InputIterator, InputIterator) -> QSet<ValueType>;
-#endif
template <typename T>
size_t qHash(const QSet<T> &key, size_t seed = 0)
@@ -246,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;
}
@@ -266,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);
}
@@ -358,6 +343,12 @@ public:
};
#endif // QT_NO_JAVA_STYLE_ITERATORS
+template <typename T, typename Predicate>
+qsizetype erase_if(QSet<T> &set, Predicate pred)
+{
+ return QtPrivate::qset_erase_if(set, pred);
+}
+
QT_END_NAMESPACE
#endif // QSET_H
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
index b6aae2c7ca..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
@@ -47,7 +23,7 @@
\snippet code/doc_src_qset.cpp 1
- Another way to insert items into the set is to use operator<<():
+ Another way to insert items into the set is to use \l operator<<():
\snippet code/doc_src_qset.cpp 2
@@ -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).
@@ -185,7 +161,7 @@
\sa reserve(), squeeze()
*/
-/*! \fn template <class T> void QSet<T>::reserve(int size)
+/*! \fn template <class T> void QSet<T>::reserve(qsizetype size)
Ensures that the set's internal hash table consists of at
least \a size buckets.
@@ -275,13 +251,12 @@
internal data structure. This means that it can safely be called
while iterating, and won't affect the order of items in the set.
- \sa remove(), find()
-*/
+ \note The iterator \a pos \e must be valid and dereferenceable. Calling this
+ method on any other iterator, including its own \l end(), results in
+ undefined behavior. In particular, even the \l begin() iterator of an empty
+ set cannot be dereferenced.
-/*!
- \fn template <class T> QSet<T>::iterator QSet<T>::erase(iterator pos)
- \since 4.2
- \overload
+ \sa remove(), find()
*/
/*! \fn template <class T> QSet<T>::const_iterator QSet<T>::find(const T &value) const
@@ -398,58 +373,6 @@
\sa constBegin(), end()
*/
-/*! \fn template <class T> QSet<T>::reverse_iterator QSet<T>::rbegin()
- \obsolete Deprecated in order to align with std::unordered_set functionality.
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the set, in reverse order.
-
- \sa begin(), crbegin(), rend()
-*/
-
-/*! \fn template <class T> QSet<T>::const_reverse_iterator QSet<T>::rbegin() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QSet<T>::const_reverse_iterator QSet<T>::crbegin() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the set, in reverse order.
-
- \sa begin(), rbegin(), rend()
-*/
-
-/*! \fn template <class T> QSet<T>::reverse_iterator QSet<T>::rend()
- \obsolete Deprecated in order to align with std::unordered_set functionality.
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last item in the set, in reverse order.
-
- \sa end(), crend(), rbegin()
-*/
-
-/*! \fn template <class T> QSet<T>::const_reverse_iterator QSet<T>::rend() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QSet<T>::const_reverse_iterator QSet<T>::crend() const
- \obsolete Deprecated in order to align with std::unordered_set functionality.
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last item in the set, in reverse order.
-
- \sa end(), rend(), rbegin()
-*/
-
/*!
\typedef QSet::Iterator
\since 4.2
@@ -511,42 +434,8 @@
Typedef for T. Provided for STL compatibility.
*/
-/*! \typedef QSet::reverse_iterator
- \since 5.6
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- The QSet::reverse_iterator typedef provides an STL-style non-const
- reverse iterator for QSet.
-
- It is simply a typedef for \c{std::reverse_iterator<QSet::iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QSet::rbegin(), QSet::rend(), QSet::const_reverse_iterator, QSet::iterator
-*/
-
-/*! \typedef QSet::const_reverse_iterator
- \since 5.6
- \obsolete Deprecated in order to align with std::unordered_set functionality.
-
- The QSet::const_reverse_iterator typedef provides an STL-style const
- reverse iterator for QSet.
-
- It is simply a typedef for \c{std::reverse_iterator<QSet::const_iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QSet::rbegin(), QSet::rend(), QSet::reverse_iterator, QSet::const_iterator
-*/
-
/*!
- \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
@@ -600,6 +489,22 @@
*/
/*!
+ \fn template <class T> QSet<T>::iterator QSet<T>::insert(const_iterator it, const T &value)
+ \overload
+ \since 6.1
+
+ Inserts item \a value into the set, if \a value isn't already
+ in the set, and returns an iterator pointing at the inserted
+ item.
+
+ The iterator \a it is ignored.
+
+ This function is provided for compatibility with the STL.
+
+ \sa operator<<(), remove(), contains()
+*/
+
+/*!
\fn template <class T> bool QSet<T>::count() const
Same as size().
@@ -630,7 +535,7 @@
\fn template <class T> QSet<T> &QSet<T>::operator|=(const QSet<T> &other)
\fn template <class T> QSet<T> &QSet<T>::operator+=(const QSet<T> &other)
- Same as unite(\a other).
+ Same as \l {unite()} {unite(\a other)}.
\sa operator|(), operator&=(), operator-=()
*/
@@ -638,7 +543,7 @@
/*!
\fn template <class T> QSet<T> &QSet<T>::operator&=(const QSet<T> &other)
- Same as intersect(\a other).
+ Same as \l {intersect()} {intersect(\a other)}.
\sa operator&(), operator|=(), operator-=()
*/
@@ -648,7 +553,7 @@
\overload
- Same as intersect(\e{other}), if we consider \e{other} to be a set
+ Same as \l {intersect()} {intersect(\e{other})}, if we consider \e other to be a set
that contains the singleton \a value.
*/
@@ -656,35 +561,36 @@
/*!
\fn template <class T> QSet<T> &QSet<T>::operator-=(const QSet<T> &other)
- Same as subtract(\a{other}).
+ Same as \l {subtract()} {subtract(\a{other})}.
\sa 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<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&()
*/
@@ -927,196 +833,19 @@
current item.
*/
-/*!
- \fn template <class T> QSet<T>::iterator &QSet<T>::iterator::operator--()
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QSet::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*!
- \fn template <class T> QSet<T>::const_iterator &QSet<T>::const_iterator::operator--()
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QSet::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*!
- \fn template <class T> QSet<T>::iterator QSet<T>::iterator::operator--(int)
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*!
- \fn template <class T> QSet<T>::const_iterator QSet<T>::const_iterator::operator--(int)
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*!
- \fn template <class T> QSet<T>::iterator QSet<T>::iterator::operator+(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*!
- \fn template <class T> QSet<T>::const_iterator QSet<T>::const_iterator::operator+(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*!
- \fn template <class T> QSet<T>::iterator QSet<T>::iterator::operator-(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*!
- \fn template <class T> QSet<T>::const_iterator QSet<T>::const_iterator::operator-(int j) const
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*!
- \fn template <class T> QSet<T>::iterator &QSet<T>::iterator::operator+=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-
-*/
-
-/*!
- \fn template <class T> QSet<T>::const_iterator &QSet<T>::const_iterator::operator+=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-*/
-
-/*!
- \fn template <class T> QSet<T>::iterator &QSet<T>::iterator::operator-=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
-*/
-
-/*!
- \fn template <class T> QSet<T>::const_iterator &QSet<T>::const_iterator::operator-=(int j)
- \obsolete This operator is deprecated in order to align with std::unordered_set functionality.
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
-*/
-
-/*! \fn template <class T> QList<T> QSet<T>::toList() const
-
- Returns a new QList containing the elements in the set. The
- order of the elements in the QList is undefined.
-
- Example:
-
- \snippet code/doc_src_qset.cpp 13
-
- \include containers-range-constructor.qdocinc
-
- \sa fromList(), QList::fromSet()
-*/
-
/*! \fn template <class T> QList<T> QSet<T>::values() const
Returns a new QList containing the elements in the set. The
order of the elements in the QList is undefined.
- This is the same as toList().
-
\include containers-range-constructor.qdocinc
This function creates a new list, in \l {linear time}. The time and memory
use that entails can be avoided by iterating from \l constBegin() to
\l constEnd().
-
- \sa fromList(), QList::fromSet()
*/
-/*! \fn template <class T> QSet<T> QSet<T>::fromList(const QList<T> &list)
-
- Returns a new QSet object containing the data contained in \a
- list. Since QSet doesn't allow duplicates, the resulting QSet
- might be smaller than the \a list, because QList can contain
- duplicates.
-
- Example:
-
- \snippet code/doc_src_qset.cpp 14
-
- \include containers-range-constructor.qdocinc
-
- \sa toList(), QList::toSet()
-*/
-
/*!
\fn template <class T> QDataStream &operator<<(QDataStream &out, const QSet<T> &set)
\relates QSet
@@ -1149,3 +878,19 @@
The hash value is independent of the order of elements in \a key, that is, sets
that contain the same elements hash to the same value.
*/
+
+/*! \fn template <class T, class Predicate> qsizetype erase_if(QSet<T> &set, Predicate pred)
+ \relates QSet
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ 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 187bfa7a5d..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>
@@ -65,6 +29,20 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \class QAdoptSharedDataTag
+ \inmodule QtCore
+ \threadsafe
+ \brief The QAdoptSharedDataTag is a helper tag class.
+ \since 6.0
+
+ QAdoptSharedDataTag objects are used in QSharedDataPointer
+ and QExplicitlySharedDataPointer to adopt a pointer to
+ shared data.
+
+ See QSharedDataPointer and QExplicitlySharedDataPointer for details.
+*/
+
+/*!
\class QSharedDataPointer
\inmodule QtCore
\brief The QSharedDataPointer class represents a pointer to an implicitly shared object.
@@ -302,6 +280,18 @@ QT_BEGIN_NAMESPACE
Same as data(). This function is provided for STL compatibility.
*/
+/*! \fn template <class T> const T* QSharedDataPointer<T>::take()
+ \since 6.0
+
+ Returns a pointer to the shared object, and resets \e this to be \nullptr.
+ (That is, this function sets the \e{d pointer} of \e this to \nullptr.)
+
+ \note The reference count of the returned object will \b{not} be
+ decremented. This function can be used together with the
+ constructor that takes a QAdoptSharedDataTag tag object to transfer
+ the shared data object without intervening atomic operations.
+*/
+
/*! \fn template <class T> const T* QSharedDataPointer<T>::constData() const
Returns a const pointer to the shared data object.
This function does \e not call detach().
@@ -309,6 +299,15 @@ QT_BEGIN_NAMESPACE
\sa data()
*/
+/*! \fn template <class T> void QSharedDataPointer<T>::reset(T *ptr = nullptr)
+ \since 6.0
+
+ Sets the \e{d pointer} of \e this to \a ptr and increments \a{ptr}'s reference
+ count if \a ptr is not \nullptr.
+ The reference count of the old shared data object is decremented,
+ and the object deleted if the reference count reaches 0.
+ */
+
/*! \fn template <class T> void QSharedDataPointer<T>::swap(QSharedDataPointer &other)
Swap this instance's shared data pointer with the shared
data pointer in \a other.
@@ -322,13 +321,23 @@ QT_BEGIN_NAMESPACE
\since 5.2
*/
-/*! \fn template <class T> bool QSharedDataPointer<T>::operator==(const QSharedDataPointer<T>& other) const
- Returns \c true if \a other and \e this have the same \e{d pointer}.
+/*! \fn template <class T> bool QSharedDataPointer<T>::operator==(const QSharedDataPointer<T>& lhs, const QSharedDataPointer<T>& rhs)
+ Returns \c true if \a lhs and \a rhs have the same \e{d pointer}.
+ This function does \e not call detach().
+*/
+
+/*! \fn template <class T> bool QSharedDataPointer<T>::operator!=(const QSharedDataPointer<T>& lhs, const QSharedDataPointer<T>& rhs)
+ Returns \c true if \a lhs and \a rhs do \e not have the same
+ \e{d pointer}. This function does \e not call detach().
+*/
+
+/*! \fn template <class T> bool QSharedDataPointer<T>::operator==(const T *ptr, const QSharedDataPointer<T>& rhs)
+ Returns \c true if the \e{d pointer} of \a rhs is \a ptr.
This function does \e not call detach().
*/
-/*! \fn template <class T> bool QSharedDataPointer<T>::operator!=(const QSharedDataPointer<T>& other) const
- Returns \c true if \a other and \e this do \e not have the same
+/*! \fn template <class T> bool QSharedDataPointer<T>::operator!=(const T *ptr, const QSharedDataPointer<T>& rhs)
+ Returns \c true if the \e{d pointer} of \a rhs is \e not \a ptr.
\e{d pointer}. This function does \e not call detach().
*/
@@ -356,6 +365,15 @@ QT_BEGIN_NAMESPACE
\a data and increments \a{data}'s reference count.
*/
+/*! \fn template <class T> QSharedDataPointer<T>::QSharedDataPointer(T* data, QAdoptSharedDataTag)
+ \since 6.0
+ Constructs a QSharedDataPointer with \e{d pointer} set to
+ \a data. \a data's reference counter is \b{not} incremented;
+ this can be used to adopt pointers obtained from take().
+
+ \sa take()
+*/
+
/*! \fn template <class T> QSharedDataPointer<T>::QSharedDataPointer(const QSharedDataPointer<T>& o)
Sets the \e{d pointer} of \e this to the \e{d pointer} in
\a o and increments the reference count of the shared
@@ -486,8 +504,8 @@ QT_BEGIN_NAMESPACE
the explicitly shared data pointer in \a other.
*/
-/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator==(const QExplicitlySharedDataPointer<T>& other) const
- Returns \c true if \a other and \e this have the same \e{d pointer}.
+/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator==(const QExplicitlySharedDataPointer<T>& lhs, const QExplicitlySharedDataPointer<T>& rhs)
+ Returns \c true if \a lhs and \a rhs have the same \e{d pointer}.
*/
/*!
@@ -498,17 +516,17 @@ QT_BEGIN_NAMESPACE
\since 5.2
*/
-/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator==(const T* ptr) const
- Returns \c true if the \e{d pointer} of \e this is \a ptr.
+/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator==(const T* ptr, const QExplicitlySharedDataPointer<T>& rhs)
+ Returns \c true if the \e{d pointer} of \a rhs is \a ptr.
*/
-/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator!=(const QExplicitlySharedDataPointer<T>& other) const
- Returns \c true if \a other and \e this do \e not have the same
+/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator!=(const QExplicitlySharedDataPointer<T>& lhs, const QExplicitlySharedDataPointer<T>& rhs)
+ Returns \c true if \a lhs and \a rhs do \e not have the same
\e{d pointer}.
*/
-/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator!=(const T* ptr) const
- Returns \c true if the \e{d pointer} of \e this is \e not \a ptr.
+/*! \fn template <class T> bool QExplicitlySharedDataPointer<T>::operator!=(const T* ptr, const QExplicitlySharedDataPointer<T>& rhs)
+ Returns \c true if the \e{d pointer} of \a rhs is \e not \a ptr.
*/
/*! \fn template <class T> QExplicitlySharedDataPointer<T>::QExplicitlySharedDataPointer()
@@ -590,18 +608,25 @@ QT_BEGIN_NAMESPACE
0, the old shared data object is deleted.
*/
-/*! \fn template <class T> void QExplicitlySharedDataPointer<T>::reset()
- Resets \e this to be null - i.e., this function sets the
- \e{d pointer} of \e this to \nullptr, but first it decrements
- the reference count of the shared data object and deletes
- the shared data object if the reference count became 0.
+/*! \fn template <class T> void QExplicitlySharedDataPointer<T>::reset(T *ptr = nullptr)
+ \since 6.0
+
+ Sets the \e{d pointer} of \e this to \a ptr and increments \a{ptr}'s reference
+ count if \a ptr is not \nullptr.
+ The reference count of the old shared data object is decremented,
+ and the object deleted if the reference count reaches 0.
*/
/*! \fn template <class T> T *QExplicitlySharedDataPointer<T>::take()
\since 5.12
Returns a pointer to the shared object, and resets \e this to be \nullptr.
- That is, this function sets the \e{d pointer} of \e this to \nullptr.
+ (That is, this function sets the \e{d pointer} of \e this to \nullptr.)
+
+ \note The reference count of the returned object will \b{not} be
+ decremented. This function can be used together with the
+ constructor that takes a QAdoptSharedDataTag tag object to transfer
+ the shared data object without intervening atomic operations.
*/
/*! \fn template <class T> QExplicitlySharedDataPointer<T>::operator bool () const
diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h
index 85078670e9..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
@@ -44,6 +8,8 @@
#include <QtCore/qatomic.h>
#include <QtCore/qhashfunctions.h>
+#include <functional>
+
QT_BEGIN_NAMESPACE
@@ -54,75 +20,101 @@ class QSharedData
public:
mutable QAtomicInt ref;
- inline QSharedData() noexcept : ref(0) { }
- inline QSharedData(const QSharedData &) noexcept : ref(0) { }
+ QSharedData() noexcept : ref(0) { }
+ QSharedData(const QSharedData &) noexcept : ref(0) { }
// using the assignment operator would lead to corruption in the ref-counting
QSharedData &operator=(const QSharedData &) = delete;
~QSharedData() = default;
};
-template <class T> class QSharedDataPointer
+struct QAdoptSharedDataTag { explicit constexpr QAdoptSharedDataTag() = default; };
+
+template <typename T>
+class QSharedDataPointer
{
public:
typedef T Type;
typedef T *pointer;
- inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
- inline T &operator*() { detach(); return *d; }
- inline const T &operator*() const { return *d; }
- inline T *operator->() { detach(); return d; }
- inline const T *operator->() const { return d; }
- inline operator T *() { detach(); return d; }
- inline operator const T *() const { return d; }
- inline T *data() { detach(); return d; }
- inline T *get() { detach(); return d; }
- inline const T *data() const { return d; }
- inline const T *get() const { return d; }
- inline const T *constData() const { return d; }
-
- inline bool operator==(const QSharedDataPointer<T> &other) const { return d == other.d; }
- inline bool operator!=(const QSharedDataPointer<T> &other) const { return d != other.d; }
-
- inline QSharedDataPointer() { d = nullptr; }
- inline ~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
-
- explicit QSharedDataPointer(T *data) noexcept;
- inline QSharedDataPointer(const QSharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
- inline QSharedDataPointer<T> & operator=(const QSharedDataPointer<T> &o) {
- if (o.d != d) {
- if (o.d)
- o.d->ref.ref();
- T *old = d;
- d = o.d;
+ void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
+ T &operator*() { detach(); return *d; }
+ const T &operator*() const { return *d; }
+ T *operator->() { detach(); return d; }
+ const T *operator->() const noexcept { return d; }
+ operator T *() { detach(); return d; }
+ operator const T *() const noexcept { return d; }
+ T *data() { detach(); return d; }
+ T *get() { detach(); return d; }
+ 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 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(); }
+
+ void reset(T *ptr = nullptr) noexcept
+ {
+ if (ptr != d) {
+ if (ptr)
+ ptr->ref.ref();
+ T *old = std::exchange(d, ptr);
if (old && !old->ref.deref())
delete old;
}
- return *this;
}
- inline QSharedDataPointer &operator=(T *o) {
- if (o != d) {
- if (o)
- o->ref.ref();
- T *old = d;
- d = o;
- if (old && !old->ref.deref())
- delete old;
- }
+
+ QSharedDataPointer &operator=(const QSharedDataPointer &o) noexcept
+ {
+ reset(o.d);
return *this;
}
- QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(o.d) { o.d = nullptr; }
- inline QSharedDataPointer<T> &operator=(QSharedDataPointer<T> &&other) noexcept
+ inline QSharedDataPointer &operator=(T *o) noexcept
{
- QSharedDataPointer moved(std::move(other));
- swap(moved);
+ reset(o);
return *this;
}
-
- inline bool operator!() const { return !d; }
-
- inline void swap(QSharedDataPointer &other) noexcept
- { qSwap(d, other.d); }
+ 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
+ { qt_ptr_swap(d, other.d); }
+
+#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \
+ friend bool operator<(T1, T2) noexcept \
+ { return std::less<T*>{}(A1, A2); } \
+ friend bool operator<=(T1, T2) noexcept \
+ { return !std::less<T*>{}(A2, A1); } \
+ friend bool operator>(T1, T2) noexcept \
+ { return std::less<T*>{}(A2, A1); } \
+ friend bool operator>=(T1, T2) noexcept \
+ { return !std::less<T*>{}(A1, A2); } \
+ friend bool operator==(T1, T2) noexcept \
+ { return A1 == A2; } \
+ friend bool operator!=(T1, T2) noexcept \
+ { return A1 != A2; } \
+
+ DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, const QSharedDataPointer &p2, p2.d)
+ DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, const T *ptr, ptr)
+ DECLARE_COMPARE_SET(const T *ptr, ptr, const QSharedDataPointer &p2, p2.d)
+ DECLARE_COMPARE_SET(const QSharedDataPointer &p1, p1.d, std::nullptr_t, nullptr)
+ DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QSharedDataPointer &p2, p2.d)
protected:
T *clone();
@@ -133,101 +125,87 @@ private:
T *d;
};
-template <class T> inline bool operator==(std::nullptr_t p1, const QSharedDataPointer<T> &p2)
-{
- Q_UNUSED(p1);
- return !p2;
-}
-
-template <class T> inline bool operator==(const QSharedDataPointer<T> &p1, std::nullptr_t p2)
-{
- Q_UNUSED(p2);
- return !p1;
-}
-
-template <class T> class QExplicitlySharedDataPointer
+template <typename T>
+class QExplicitlySharedDataPointer
{
public:
typedef T Type;
typedef T *pointer;
- inline T &operator*() const { return *d; }
- inline T *operator->() { return d; }
- inline T *operator->() const { return d; }
- inline T *data() const { return d; }
- inline T *get() const { return d; }
- inline const T *constData() const { return d; }
- inline T *take() { T *x = d; d = nullptr; return x; }
-
- inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
-
- inline void reset()
- {
- if(d && !d->ref.deref())
- delete d;
-
- d = nullptr;
- }
-
- inline operator bool () const { return d != nullptr; }
-
- inline bool operator==(const QExplicitlySharedDataPointer<T> &other) const { return d == other.d; }
- inline bool operator!=(const QExplicitlySharedDataPointer<T> &other) const { return d != other.d; }
- inline bool operator==(const T *ptr) const { return d == ptr; }
- inline bool operator!=(const T *ptr) const { return d != ptr; }
-
- inline QExplicitlySharedDataPointer() { d = nullptr; }
- inline ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
-
- explicit QExplicitlySharedDataPointer(T *data) noexcept;
- inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
-
- template<class X>
- inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o)
+ T &operator*() const { return *d; }
+ T *operator->() noexcept { return d; }
+ T *operator->() const noexcept { return d; }
+ explicit operator T *() { return d; }
+ explicit operator const T *() const noexcept { return d; }
+ T *data() const noexcept { return d; }
+ T *get() const noexcept { return d; }
+ const T *constData() const noexcept { return d; }
+ 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()))
#else
: d(o.data())
#endif
- {
- if(d)
- d->ref.ref();
- }
+ { if (d) d->ref.ref(); }
- inline QExplicitlySharedDataPointer<T> & operator=(const QExplicitlySharedDataPointer<T> &o) {
- if (o.d != d) {
- if (o.d)
- o.d->ref.ref();
- T *old = d;
- d = o.d;
+ void reset(T *ptr = nullptr) noexcept
+ {
+ if (ptr != d) {
+ if (ptr)
+ ptr->ref.ref();
+ T *old = std::exchange(d, ptr);
if (old && !old->ref.deref())
delete old;
}
- return *this;
}
- inline QExplicitlySharedDataPointer &operator=(T *o) {
- if (o != d) {
- if (o)
- o->ref.ref();
- T *old = d;
- d = o;
- if (old && !old->ref.deref())
- delete old;
- }
+
+ QExplicitlySharedDataPointer &operator=(const QExplicitlySharedDataPointer &o) noexcept
+ {
+ reset(o.d);
return *this;
}
- inline QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(o.d) { o.d = nullptr; }
- inline QExplicitlySharedDataPointer<T> &operator=(QExplicitlySharedDataPointer<T> &&other) noexcept
+ QExplicitlySharedDataPointer &operator=(T *o) noexcept
{
- QExplicitlySharedDataPointer moved(std::move(other));
- swap(moved);
+ reset(o);
return *this;
}
+ 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
+ { qt_ptr_swap(d, other.d); }
- inline bool operator!() const { return !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)
+ DECLARE_COMPARE_SET(const T *ptr, ptr, const QExplicitlySharedDataPointer &p2, p2.d)
+ DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, std::nullptr_t, nullptr)
+ DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QExplicitlySharedDataPointer &p2, p2.d)
- inline void swap(QExplicitlySharedDataPointer &other) noexcept
- { qSwap(d, other.d); }
+#undef DECLARE_COMPARE_SET
protected:
T *clone();
@@ -238,18 +216,14 @@ private:
T *d;
};
-template <class T>
-Q_INLINE_TEMPLATE QSharedDataPointer<T>::QSharedDataPointer(T *adata) noexcept
- : d(adata)
-{ if (d) d->ref.ref(); }
-
-template <class T>
+// Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time.
+template <typename T>
Q_INLINE_TEMPLATE T *QSharedDataPointer<T>::clone()
{
return new T(*d);
}
-template <class T>
+template <typename T>
Q_OUTOFLINE_TEMPLATE void QSharedDataPointer<T>::detach_helper()
{
T *x = clone();
@@ -259,13 +233,13 @@ Q_OUTOFLINE_TEMPLATE void QSharedDataPointer<T>::detach_helper()
d = x;
}
-template <class T>
+template <typename T>
Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer<T>::clone()
{
return new T(*d);
}
-template <class T>
+template <typename T>
Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer<T>::detach_helper()
{
T *x = clone();
@@ -275,44 +249,53 @@ Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer<T>::detach_helper()
d = x;
}
-template <class T>
-Q_INLINE_TEMPLATE QExplicitlySharedDataPointer<T>::QExplicitlySharedDataPointer(T *adata) noexcept
- : d(adata)
-{ if (d) d->ref.ref(); }
-
-template <class T> inline bool operator==(std::nullptr_t p1, const QExplicitlySharedDataPointer<T> &p2)
-{
- Q_UNUSED(p1);
- return !p2;
-}
-
-template <class T> inline bool operator==(const QExplicitlySharedDataPointer<T> &p1, std::nullptr_t p2)
-{
- Q_UNUSED(p2);
- return !p1;
-}
-
-template <class T>
-Q_INLINE_TEMPLATE void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2)
+template <typename T>
+void swap(QSharedDataPointer<T> &p1, QSharedDataPointer<T> &p2) noexcept
{ p1.swap(p2); }
-template <class T>
-Q_INLINE_TEMPLATE void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2)
+template <typename T>
+void swap(QExplicitlySharedDataPointer<T> &p1, QExplicitlySharedDataPointer<T> &p2) noexcept
{ p1.swap(p2); }
-template <class T>
-Q_INLINE_TEMPLATE size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept
+template <typename T>
+size_t qHash(const QSharedDataPointer<T> &ptr, size_t seed = 0) noexcept
{
return qHash(ptr.data(), seed);
}
-template <class T>
-Q_INLINE_TEMPLATE size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept
+template <typename T>
+size_t qHash(const QExplicitlySharedDataPointer<T> &ptr, size_t seed = 0) noexcept
{
return qHash(ptr.data(), seed);
}
-template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_MOVABLE_TYPE);
-template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_MOVABLE_TYPE);
+template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_RELOCATABLE_TYPE);
+template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_RELOCATABLE_TYPE);
+
+#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR(Class) \
+ template<> QSharedDataPointer<Class>::~QSharedDataPointer();
+
+#define QT_DECLARE_QSDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \
+ template<> ExportMacro QSharedDataPointer<Class>::~QSharedDataPointer();
+
+#define QT_DEFINE_QSDP_SPECIALIZATION_DTOR(Class) \
+ template<> QSharedDataPointer<Class>::~QSharedDataPointer() \
+ { \
+ if (d && !d->ref.deref()) \
+ delete d; \
+ }
+
+#define QT_DECLARE_QESDP_SPECIALIZATION_DTOR(Class) \
+ template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer();
+
+#define QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(Class, ExportMacro) \
+ template<> ExportMacro QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer();
+
+#define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class) \
+ template<> QExplicitlySharedDataPointer<Class>::~QExplicitlySharedDataPointer() \
+ { \
+ if (d && !d->ref.deref()) \
+ delete d; \
+ }
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qshareddata_impl.h b/src/corelib/tools/qshareddata_impl.h
index 0a218b0b4b..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
@@ -46,6 +10,7 @@
#define QSHAREDDATA_IMPL_H
#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
@@ -66,6 +31,11 @@ public:
d->ref.ref();
}
+ QExplicitlySharedDataPointerV2(T *t, QAdoptSharedDataTag) noexcept
+ : d(t)
+ {
+ }
+
QExplicitlySharedDataPointerV2(const QExplicitlySharedDataPointerV2 &other) noexcept
: d(other.d)
{
@@ -81,7 +51,7 @@ public:
}
QExplicitlySharedDataPointerV2(QExplicitlySharedDataPointerV2 &&other) noexcept
- : d(qExchange(other.d, nullptr))
+ : d(std::exchange(other.d, nullptr))
{
}
@@ -120,6 +90,11 @@ public:
d->ref.ref();
}
+ constexpr T *take() noexcept
+ {
+ return std::exchange(d, nullptr);
+ }
+
bool isShared() const noexcept
{
return d && d->ref.loadRelaxed() != 1;
@@ -127,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 44cbad94f7..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.
@@ -848,7 +893,7 @@
/*!
\fn template <class T> T *QWeakPointer<T>::data() const
\since 4.6
- \obsolete Use toStrongRef() instead, and data() on the returned QSharedPointer.
+ \deprecated Use toStrongRef() instead, and data() on the returned QSharedPointer.
Returns the value of the pointer being tracked by this QWeakPointer,
\b without ensuring that it cannot get deleted. To have that guarantee,
@@ -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)
{
@@ -1400,7 +1458,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
}
// we can create the refcount data because it doesn't exist
- ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized);
+ ExternalRefCountData *x = ::new ExternalRefCountData(Qt::Uninitialized);
x->strongref.storeRelaxed(-1);
x->weakref.storeRelaxed(2); // the QWeakPointer that called us plus the QObject itself
@@ -1411,7 +1469,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
// ~ExternalRefCountData has a Q_ASSERT, so we use this trick to
// only execute this if Q_ASSERTs are enabled
Q_ASSERT((x->weakref.storeRelaxed(0), true));
- delete x;
+ ::delete x;
ret->weakref.ref();
}
return ret;
@@ -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 5d47369687..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
@@ -66,7 +30,7 @@ public:
operator bool() const;
bool operator!() const;
T &operator*() const;
- T *operator ->() const;
+ T *operator->() const;
// constructors
QSharedPointer();
@@ -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 30bccb66a4..456be91d03 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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,12 +116,20 @@ 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(...) { }
+ // Normally, only subclasses of ExternalRefCountData are allocated
+ // One exception exists in getAndRef; that uses the global operator new
+ // to prevent a mismatch with the custom operator delete
+ inline void *operator new(std::size_t) = delete;
+ // placement new
+ inline void *operator new(std::size_t, void *ptr) noexcept { return ptr; }
inline void operator delete(void *ptr) { ::operator delete(ptr); }
inline void operator delete(void *, void *) { }
};
@@ -302,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
@@ -327,20 +310,17 @@ public:
swap(copy);
return *this;
}
+ Q_NODISCARD_CTOR
QSharedPointer(QSharedPointer &&other) noexcept
: value(other.value), d(other.d)
{
other.d = nullptr;
other.value = nullptr;
}
- QSharedPointer &operator=(QSharedPointer &&other) noexcept
- {
- QSharedPointer moved(std::move(other));
- swap(moved);
- return *this;
- }
+ 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)
{
@@ -357,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(); }
@@ -369,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; }
@@ -414,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
@@ -442,7 +424,47 @@ public:
return result;
}
+#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \
+ friend bool operator==(T1, T2) noexcept \
+ { return A1 == A2; } \
+ friend bool operator!=(T1, T2) noexcept \
+ { return A1 != A2; }
+
+#define DECLARE_TEMPLATE_COMPARE_SET(T1, A1, T2, A2) \
+ template <typename X> \
+ friend bool operator==(T1, T2) noexcept \
+ { return A1 == A2; } \
+ template <typename X> \
+ friend bool operator!=(T1, T2) noexcept \
+ { return A1 != A2; }
+
+ DECLARE_TEMPLATE_COMPARE_SET(const QSharedPointer &p1, p1.data(), const QSharedPointer<X> &p2, p2.data())
+ DECLARE_TEMPLATE_COMPARE_SET(const QSharedPointer &p1, p1.data(), X *ptr, ptr)
+ DECLARE_TEMPLATE_COMPARE_SET(X *ptr, ptr, const QSharedPointer &p2, p2.data())
+ DECLARE_COMPARE_SET(const QSharedPointer &p1, p1.data(), std::nullptr_t, nullptr)
+ DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QSharedPointer &p2, p2.data())
+#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
@@ -479,23 +501,18 @@ 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);
}
-#if defined(Q_NO_TEMPLATE_FRIENDS)
-public:
-#else
template <class X> friend class QSharedPointer;
template <class X> friend class QWeakPointer;
template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src);
-#endif
void ref() const noexcept { d->weakref.ref(); d->strongref.ref(); }
inline void internalSet(Data *o, T *actual)
@@ -511,16 +528,14 @@ public:
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;
@@ -539,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;
@@ -552,19 +573,47 @@ 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)
{
other.d = nullptr;
other.value = nullptr;
}
- QWeakPointer &operator=(QWeakPointer &&other) noexcept
- { QWeakPointer moved(std::move(other)); swap(moved); return *this; }
+ 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);
@@ -574,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)
@@ -587,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; }
@@ -599,15 +650,8 @@ public:
return *this;
}
- template <class X>
- bool operator==(const QWeakPointer<X> &o) const noexcept
- { return d == o.d && value == static_cast<const T *>(o.value); }
-
- template <class X>
- bool operator!=(const QWeakPointer<X> &o) const noexcept
- { return !(*this == o); }
-
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr)
{ *this = o; }
@@ -618,6 +662,20 @@ public:
return *this;
}
+ inline void clear() { *this = QWeakPointer(); }
+
+ [[nodiscard]] QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
+ // std::weak_ptr compatibility:
+ [[nodiscard]] QSharedPointer<T> lock() const { return toStrongRef(); }
+
+ template <class X>
+ bool operator==(const QWeakPointer<X> &o) const noexcept
+ { return d == o.d && value == static_cast<const T *>(o.value); }
+
+ template <class X>
+ bool operator!=(const QWeakPointer<X> &o) const noexcept
+ { return !(*this == o); }
+
template <class X>
bool operator==(const QSharedPointer<X> &o) const noexcept
{ return d == o.d; }
@@ -626,31 +684,52 @@ public:
bool operator!=(const QSharedPointer<X> &o) const noexcept
{ return !(*this == o); }
- inline void clear() { *this = QWeakPointer(); }
+ template <typename X>
+ friend bool operator==(const QSharedPointer<X> &p1, const QWeakPointer &p2) noexcept
+ { return p2 == p1; }
+ template <typename X>
+ friend bool operator!=(const QSharedPointer<X> &p1, const QWeakPointer &p2) noexcept
+ { return p2 != p1; }
+
+ friend bool operator==(const QWeakPointer &p, std::nullptr_t)
+ { return p.isNull(); }
+ friend bool operator==(std::nullptr_t, const QWeakPointer &p)
+ { return p.isNull(); }
+ friend bool operator!=(const QWeakPointer &p, std::nullptr_t)
+ { return !p.isNull(); }
+ friend bool operator!=(std::nullptr_t, const QWeakPointer &p)
+ { return !p.isNull(); }
- inline QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
- // std::weak_ptr compatibility:
- inline QSharedPointer<T> lock() const { return toStrongRef(); }
+ 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); }
-#if defined(QWEAKPOINTER_ENABLE_ARROW)
- inline T *operator->() const { return data(); }
-#endif
+ 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;
-#if defined(Q_NO_TEMPLATE_FRIENDS)
-public:
-#else
template <class X> friend class QSharedPointer;
+ template <class X> friend class QWeakPointer;
template <class X> friend class QPointer;
-#endif
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
@@ -666,8 +745,8 @@ public:
value = actual;
}
- // ### Qt 6: remove users of this API; no one should ever access
- // a weak pointer's data but the weak pointer itself
+ // ### TODO - QTBUG-88102: remove all users of this API; no one should ever
+ // access a weak pointer's data but the weak pointer itself
inline T *internalData() const noexcept
{
return d == nullptr || d->strongref.loadRelaxed() == 0 ? nullptr : value;
@@ -700,12 +779,8 @@ public:
inline QSharedPointer<T> sharedFromThis() { return QSharedPointer<T>(weakPointer); }
inline QSharedPointer<const T> sharedFromThis() const { return QSharedPointer<const T>(weakPointer); }
-#ifndef Q_NO_TEMPLATE_FRIENDS
private:
template <class X> friend class QSharedPointer;
-#else
-public:
-#endif
template <class X>
inline void initializeFromSharedPointer(const QSharedPointer<X> &ptr) const
{
@@ -716,100 +791,6 @@ public:
};
//
-// operator== and operator!=
-//
-template <class T, class X>
-bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2) noexcept
-{
- return ptr1.data() == ptr2.data();
-}
-template <class T, class X>
-bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2) noexcept
-{
- return ptr1.data() != ptr2.data();
-}
-
-template <class T, class X>
-bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2) noexcept
-{
- return ptr1.data() == ptr2;
-}
-template <class T, class X>
-bool operator==(const T *ptr1, const QSharedPointer<X> &ptr2) noexcept
-{
- return ptr1 == ptr2.data();
-}
-template <class T, class X>
-bool operator!=(const QSharedPointer<T> &ptr1, const X *ptr2) noexcept
-{
- return !(ptr1 == ptr2);
-}
-template <class T, class X>
-bool operator!=(const T *ptr1, const QSharedPointer<X> &ptr2) noexcept
-{
- return !(ptr2 == ptr1);
-}
-
-template <class T, class X>
-bool operator==(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2) noexcept
-{
- return ptr2 == ptr1;
-}
-template <class T, class X>
-bool operator!=(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2) noexcept
-{
- return ptr2 != ptr1;
-}
-
-template<class T>
-inline bool operator==(const QSharedPointer<T> &lhs, std::nullptr_t) noexcept
-{
- return lhs.isNull();
-}
-
-template<class T>
-inline bool operator!=(const QSharedPointer<T> &lhs, std::nullptr_t) noexcept
-{
- return !lhs.isNull();
-}
-
-template<class T>
-inline bool operator==(std::nullptr_t, const QSharedPointer<T> &rhs) noexcept
-{
- return rhs.isNull();
-}
-
-template<class T>
-inline bool operator!=(std::nullptr_t, const QSharedPointer<T> &rhs) noexcept
-{
- return !rhs.isNull();
-}
-
-template<class T>
-inline bool operator==(const QWeakPointer<T> &lhs, std::nullptr_t) noexcept
-{
- return lhs.isNull();
-}
-
-template<class T>
-inline bool operator!=(const QWeakPointer<T> &lhs, std::nullptr_t) noexcept
-{
- return !lhs.isNull();
-}
-
-template<class T>
-inline bool operator==(std::nullptr_t, const QWeakPointer<T> &rhs) noexcept
-{
- return rhs.isNull();
-}
-
-template<class T>
-inline bool operator!=(std::nullptr_t, const QWeakPointer<T> &rhs) noexcept
-{
- return !rhs.isNull();
-}
-
-//
// operator-
//
template <class T, class X>
@@ -856,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);
}
@@ -957,8 +938,8 @@ qobject_cast(const QWeakPointer<T> &src)
return qSharedPointerObjectCast<typename QtSharedPointer::RemovePointer<X>::Type, T>(src);
}
-/// ### Qt 6: make this use toStrongRef() (once support for storing
-/// non-managed QObjects in QWeakPointer is removed)
+/// ### TODO - QTBUG-88102: make this use toStrongRef() (once support for
+/// storing non-managed QObjects in QWeakPointer is removed)
template<typename T>
QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qWeakPointerFromVariant(const QVariant &variant)
@@ -987,15 +968,11 @@ std::shared_ptr<X> qobject_pointer_cast(std::shared_ptr<T> &&src)
using element_type = typename std::shared_ptr<X>::element_type;
auto castResult = qobject_cast<element_type *>(src.get());
if (castResult) {
- auto result = std::shared_ptr<X>(std::move(src), castResult);
-#if __cplusplus <= 201703L
// C++2a's move aliasing constructor will leave src empty.
// Before C++2a we don't really know if the compiler has support for it.
// The move aliasing constructor is the resolution for LWG2996,
// which does not impose a feature-testing macro. So: clear src.
- src.reset();
-#endif
- return result;
+ return std::shared_ptr<X>(std::exchange(src, nullptr), castResult);
}
return std::shared_ptr<X>();
}
@@ -1014,8 +991,8 @@ std::shared_ptr<X> qSharedPointerObjectCast(std::shared_ptr<T> &&src)
#endif
-template<typename T> Q_DECLARE_TYPEINFO_BODY(QWeakPointer<T>, Q_MOVABLE_TYPE);
-template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedPointer<T>, Q_MOVABLE_TYPE);
+template<typename T> Q_DECLARE_TYPEINFO_BODY(QWeakPointer<T>, Q_RELOCATABLE_TYPE);
+template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedPointer<T>, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp
index 2cbaae117d..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"
@@ -302,37 +266,32 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept
*/
/*!
- \fn bool operator==(const QSize &s1, const QSize &s2)
- \relates QSize
+ \fn bool QSize::operator==(const QSize &s1, const QSize &s2)
Returns \c true if \a s1 and \a s2 are equal; otherwise returns \c false.
*/
/*!
- \fn bool operator!=(const QSize &s1, const QSize &s2)
- \relates QSize
+ \fn bool QSize::operator!=(const QSize &s1, const QSize &s2)
Returns \c true if \a s1 and \a s2 are different; otherwise returns \c false.
*/
/*!
- \fn const QSize operator+(const QSize &s1, const QSize &s2)
- \relates QSize
+ \fn QSize QSize::operator+(const QSize &s1, const QSize &s2)
Returns the sum of \a s1 and \a s2; each component is added separately.
*/
/*!
- \fn const QSize operator-(const QSize &s1, const QSize &s2)
- \relates QSize
+ \fn QSize QSize::operator-(const QSize &s1, const QSize &s2)
Returns \a s2 subtracted from \a s1; each component is subtracted
separately.
*/
/*!
- \fn const QSize operator*(const QSize &size, qreal factor)
- \relates QSize
+ \fn QSize QSize::operator*(const QSize &size, qreal factor)
Multiplies the given \a size by the given \a factor, and returns
the result rounded to the nearest integer.
@@ -341,9 +300,8 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept
*/
/*!
- \fn const QSize operator*(qreal factor, const QSize &size)
+ \fn QSize QSize::operator*(qreal factor, const QSize &size)
\overload
- \relates QSize
Multiplies the given \a size by the given \a factor, and returns
the result rounded to the nearest integer.
@@ -362,8 +320,7 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept
*/
/*!
- \fn const QSize operator/(const QSize &size, qreal divisor)
- \relates QSize
+ \fn QSize QSize::operator/(const QSize &size, qreal divisor)
\overload
Divides the given \a size by the given \a divisor, and returns the
@@ -410,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
*****************************************************************************/
@@ -527,13 +493,13 @@ 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()
*/
/*!
\fn QSizeF::QSizeF(qreal width, qreal height)
- Constructs a size with the given \a width and \a height.
+ Constructs a size with the given finite \a width and \a height.
*/
/*!
@@ -557,7 +523,7 @@ QDebug operator<<(QDebug dbg, const QSize &s)
/*!
\fn bool QSizeF::isValid() const
- Returns \c true if both the width and height is equal to or greater
+ Returns \c true if both the width and height are equal to or greater
than 0; otherwise returns \c false.
\sa isNull(), isEmpty()
@@ -582,7 +548,7 @@ QDebug operator<<(QDebug dbg, const QSize &s)
/*!
\fn void QSizeF::setWidth(qreal width)
- Sets the width to the given \a width.
+ Sets the width to the given finite \a width.
\sa width(), rwidth(), setHeight()
*/
@@ -590,7 +556,7 @@ QDebug operator<<(QDebug dbg, const QSize &s)
/*!
\fn void QSizeF::setHeight(qreal height)
- Sets the height to the given \a height.
+ Sets the height to the given finite \a height.
\sa height(), rheight(), setWidth()
*/
@@ -603,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()
*/
/*!
@@ -741,61 +707,64 @@ QSizeF QSizeF::scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept
\fn QSizeF &QSizeF::operator*=(qreal factor)
\overload
- Multiplies both the width and height by the given \a factor and
+ Multiplies both the width and height by the given finite \a factor and
returns a reference to the size.
\sa scale()
*/
/*!
- \fn bool operator==(const QSizeF &s1, const QSizeF &s2)
- \relates QSizeF
+ \fn bool QSizeF::operator==(const QSizeF &s1, const QSizeF &s2)
- Returns \c true if \a s1 and \a s2 are equal; otherwise returns
- false.
+ Returns \c true if \a s1 and \a s2 are approximately equal; otherwise
+ returns false.
+
+ \warning This function does not check for strict equality; instead,
+ it uses a fuzzy comparison to compare the sizes' extents.
+
+ \sa qFuzzyCompare
*/
/*!
- \fn bool operator!=(const QSizeF &s1, const QSizeF &s2)
- \relates QSizeF
+ \fn bool QSizeF::operator!=(const QSizeF &s1, const QSizeF &s2)
- Returns \c true if \a s1 and \a s2 are different; otherwise returns \c false.
+ Returns \c true if \a s1 and \a s2 are sufficiently different; otherwise
+ returns \c false.
+
+ \warning This function does not check for strict inequality; instead,
+ it uses a fuzzy comparison to compare the sizes' extents.
*/
/*!
- \fn const QSizeF operator+(const QSizeF &s1, const QSizeF &s2)
- \relates QSizeF
+ \fn QSizeF QSizeF::operator+(const QSizeF &s1, const QSizeF &s2)
Returns the sum of \a s1 and \a s2; each component is added separately.
*/
/*!
- \fn const QSizeF operator-(const QSizeF &s1, const QSizeF &s2)
- \relates QSizeF
+ \fn QSizeF QSizeF::operator-(const QSizeF &s1, const QSizeF &s2)
Returns \a s2 subtracted from \a s1; each component is subtracted
separately.
*/
/*!
- \fn const QSizeF operator*(const QSizeF &size, qreal factor)
+ \fn QSizeF QSizeF::operator*(const QSizeF &size, qreal factor)
\overload
- \relates QSizeF
- Multiplies the given \a size by the given \a factor and returns
+ Multiplies the given \a size by the given finite \a factor and returns
the result.
\sa QSizeF::scale()
*/
/*!
- \fn const QSizeF operator*(qreal factor, const QSizeF &size)
+ \fn QSizeF QSizeF::operator*(qreal factor, const QSizeF &size)
\overload
- \relates QSizeF
- Multiplies the given \a size by the given \a factor and returns
+ Multiplies the given \a size by the given finite \a factor and returns
the result.
*/
@@ -804,20 +773,19 @@ QSizeF QSizeF::scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept
\overload
- Divides both the width and height by the given \a divisor and
- returns a reference to the size.
+ Divides both the width and height by the given \a divisor and returns a
+ reference to the size. The \a divisor must not be either zero or NaN.
\sa scale()
*/
/*!
- \fn const QSizeF operator/(const QSizeF &size, qreal divisor)
+ \fn QSizeF QSizeF::operator/(const QSizeF &size, qreal divisor)
- \relates QSizeF
\overload
Divides the given \a size by the given \a divisor and returns the
- result.
+ result. The \a divisor must not be either zero or NaN.
\sa QSizeF::scale()
*/
diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h
index d2598afbea..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
{
@@ -66,19 +36,19 @@ public:
constexpr inline void setWidth(int w) noexcept;
constexpr inline void setHeight(int h) noexcept;
void transpose() noexcept;
- Q_REQUIRED_RESULT constexpr inline QSize transposed() const noexcept;
+ [[nodiscard]] constexpr inline QSize transposed() const noexcept;
inline void scale(int w, int h, Qt::AspectRatioMode mode) noexcept;
inline void scale(const QSize &s, Qt::AspectRatioMode mode) noexcept;
- Q_REQUIRED_RESULT QSize scaled(int w, int h, Qt::AspectRatioMode mode) const noexcept;
- Q_REQUIRED_RESULT QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept;
+ [[nodiscard]] QSize scaled(int w, int h, Qt::AspectRatioMode mode) const noexcept;
+ [[nodiscard]] QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QSize expandedTo(const QSize &) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QSize boundedTo(const QSize &) const noexcept;
+ [[nodiscard]] constexpr inline QSize expandedTo(const QSize &) const noexcept;
+ [[nodiscard]] constexpr inline QSize boundedTo(const QSize &) const noexcept;
- Q_REQUIRED_RESULT constexpr QSize grownBy(QMargins m) const noexcept
+ [[nodiscard]] constexpr QSize grownBy(QMargins m) const noexcept
{ return {width() + m.left() + m.right(), height() + m.top() + m.bottom()}; }
- Q_REQUIRED_RESULT constexpr QSize shrunkBy(QMargins m) const noexcept
+ [[nodiscard]] constexpr QSize shrunkBy(QMargins m) const noexcept
{ return {width() - m.left() - m.right(), height() - m.top() - m.bottom()}; }
constexpr inline int &rwidth() noexcept;
@@ -89,24 +59,45 @@ public:
constexpr inline QSize &operator*=(qreal c) noexcept;
inline QSize &operator/=(qreal c);
- friend inline constexpr bool operator==(const QSize &, const QSize &) noexcept;
- friend inline constexpr bool operator!=(const QSize &, const QSize &) noexcept;
+ friend inline constexpr bool operator==(const QSize &s1, const QSize &s2) noexcept
+ { return s1.wd == s2.wd && s1.ht == s2.ht; }
+ friend inline constexpr bool operator!=(const QSize &s1, const QSize &s2) noexcept
+ { return s1.wd != s2.wd || s1.ht != s2.ht; }
+ friend inline constexpr QSize operator+(const QSize &s1, const QSize &s2) noexcept
+ { return QSize(s1.wd + s2.wd, s1.ht + s2.ht); }
+ friend inline constexpr QSize operator-(const QSize &s1, const QSize &s2) noexcept
+ { return QSize(s1.wd - s2.wd, s1.ht - s2.ht); }
+ friend inline constexpr QSize operator*(const QSize &s, qreal c) noexcept
+ { return QSize(qRound(s.wd * c), qRound(s.ht * c)); }
+ friend inline constexpr QSize operator*(qreal c, const QSize &s) noexcept
+ { return s * c; }
+ friend inline QSize operator/(const QSize &s, qreal c)
+ { Q_ASSERT(!qFuzzyIsNull(c)); return QSize(qRound(s.wd / c), qRound(s.ht / c)); }
friend inline constexpr size_t qHash(const QSize &, size_t) noexcept;
- friend inline constexpr const QSize operator+(const QSize &, const QSize &) noexcept;
- friend inline constexpr const QSize operator-(const QSize &, const QSize &) noexcept;
- friend inline constexpr const QSize operator*(const QSize &, qreal) noexcept;
- friend inline constexpr const QSize operator*(qreal, const QSize &) noexcept;
- friend inline const QSize operator/(const QSize &, qreal);
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
- Q_REQUIRED_RESULT CGSize toCGSize() const noexcept;
+ [[nodiscard]] CGSize toCGSize() const noexcept;
#endif
+ [[nodiscard]] inline constexpr QSizeF toSizeF() const noexcept;
+
private:
int wd;
int ht;
+
+ template <std::size_t I,
+ typename S,
+ std::enable_if_t<(I < 2), 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 q23::forward_like<S>(s.wd);
+ else if constexpr (I == 1)
+ return q23::forward_like<S>(s.ht);
+ }
};
-Q_DECLARE_TYPEINFO(QSize, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QSize, Q_RELOCATABLE_TYPE);
/*****************************************************************************
QSize stream functions
@@ -127,13 +118,13 @@ constexpr inline QSize::QSize() noexcept : wd(-1), ht(-1) {}
constexpr inline QSize::QSize(int w, int h) noexcept : wd(w), ht(h) {}
constexpr inline bool QSize::isNull() const noexcept
-{ return wd==0 && ht==0; }
+{ return wd == 0 && ht == 0; }
constexpr inline bool QSize::isEmpty() const noexcept
-{ return wd<1 || ht<1; }
+{ return wd < 1 || ht < 1; }
constexpr inline bool QSize::isValid() const noexcept
-{ return wd>=0 && ht>=0; }
+{ return wd >= 0 && ht >= 0; }
constexpr inline int QSize::width() const noexcept
{ return wd; }
@@ -166,48 +157,37 @@ constexpr inline int &QSize::rheight() noexcept
{ return ht; }
constexpr inline QSize &QSize::operator+=(const QSize &s) noexcept
-{ wd+=s.wd; ht+=s.ht; return *this; }
+{
+ wd += s.wd;
+ ht += s.ht;
+ return *this;
+}
constexpr inline QSize &QSize::operator-=(const QSize &s) noexcept
-{ wd-=s.wd; ht-=s.ht; return *this; }
+{
+ wd -= s.wd;
+ ht -= s.ht;
+ return *this;
+}
constexpr inline QSize &QSize::operator*=(qreal c) noexcept
-{ wd = qRound(wd*c); ht = qRound(ht*c); return *this; }
-
-constexpr inline bool operator==(const QSize &s1, const QSize &s2) noexcept
-{ return s1.wd == s2.wd && s1.ht == s2.ht; }
-
-constexpr inline bool operator!=(const QSize &s1, const QSize &s2) noexcept
-{ return s1.wd != s2.wd || s1.ht != s2.ht; }
+{
+ wd = qRound(wd * c);
+ ht = qRound(ht * c);
+ return *this;
+}
constexpr inline size_t qHash(const QSize &s, size_t seed = 0) noexcept
{ return qHashMulti(seed, s.wd, s.ht); }
-constexpr inline const QSize operator+(const QSize & s1, const QSize & s2) noexcept
-{ return QSize(s1.wd+s2.wd, s1.ht+s2.ht); }
-
-constexpr inline const QSize operator-(const QSize &s1, const QSize &s2) noexcept
-{ return QSize(s1.wd-s2.wd, s1.ht-s2.ht); }
-
-constexpr inline const QSize operator*(const QSize &s, qreal c) noexcept
-{ return QSize(qRound(s.wd*c), qRound(s.ht*c)); }
-
-constexpr inline const QSize operator*(qreal c, const QSize &s) noexcept
-{ return QSize(qRound(s.wd*c), qRound(s.ht*c)); }
-
inline QSize &QSize::operator/=(qreal c)
{
Q_ASSERT(!qFuzzyIsNull(c));
- wd = qRound(wd/c); ht = qRound(ht/c);
+ wd = qRound(wd / c);
+ ht = qRound(ht / c);
return *this;
}
-inline const QSize operator/(const QSize &s, qreal c)
-{
- Q_ASSERT(!qFuzzyIsNull(c));
- return QSize(qRound(s.wd/c), qRound(s.ht/c));
-}
-
constexpr inline QSize QSize::expandedTo(const QSize & otherSize) const noexcept
{
return QSize(qMax(wd,otherSize.wd), qMax(ht,otherSize.ht));
@@ -239,19 +219,19 @@ public:
constexpr inline void setWidth(qreal w) noexcept;
constexpr inline void setHeight(qreal h) noexcept;
void transpose() noexcept;
- Q_REQUIRED_RESULT constexpr inline QSizeF transposed() const noexcept;
+ [[nodiscard]] constexpr inline QSizeF transposed() const noexcept;
inline void scale(qreal w, qreal h, Qt::AspectRatioMode mode) noexcept;
inline void scale(const QSizeF &s, Qt::AspectRatioMode mode) noexcept;
- Q_REQUIRED_RESULT QSizeF scaled(qreal w, qreal h, Qt::AspectRatioMode mode) const noexcept;
- Q_REQUIRED_RESULT QSizeF scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept;
+ [[nodiscard]] QSizeF scaled(qreal w, qreal h, Qt::AspectRatioMode mode) const noexcept;
+ [[nodiscard]] QSizeF scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QSizeF expandedTo(const QSizeF &) const noexcept;
- Q_REQUIRED_RESULT constexpr inline QSizeF boundedTo(const QSizeF &) const noexcept;
+ [[nodiscard]] constexpr inline QSizeF expandedTo(const QSizeF &) const noexcept;
+ [[nodiscard]] constexpr inline QSizeF boundedTo(const QSizeF &) const noexcept;
- Q_REQUIRED_RESULT constexpr QSizeF grownBy(QMarginsF m) const noexcept
+ [[nodiscard]] constexpr QSizeF grownBy(QMarginsF m) const noexcept
{ return {width() + m.left() + m.right(), height() + m.top() + m.bottom()}; }
- Q_REQUIRED_RESULT constexpr QSizeF shrunkBy(QMarginsF m) const noexcept
+ [[nodiscard]] constexpr QSizeF shrunkBy(QMarginsF m) const noexcept
{ return {width() - m.left() - m.right(), height() - m.top() - m.bottom()}; }
constexpr inline qreal &rwidth() noexcept;
@@ -262,26 +242,51 @@ public:
constexpr inline QSizeF &operator*=(qreal c) noexcept;
inline QSizeF &operator/=(qreal c);
- friend constexpr inline bool operator==(const QSizeF &, const QSizeF &) noexcept;
- friend constexpr inline bool operator!=(const QSizeF &, const QSizeF &) noexcept;
- friend constexpr inline const QSizeF operator+(const QSizeF &, const QSizeF &) noexcept;
- friend constexpr inline const QSizeF operator-(const QSizeF &, const QSizeF &) noexcept;
- friend constexpr inline const QSizeF operator*(const QSizeF &, qreal) noexcept;
- friend constexpr inline const QSizeF operator*(qreal, const QSizeF &) noexcept;
- friend inline const QSizeF operator/(const QSizeF &, qreal);
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_FLOAT_COMPARE
+ friend constexpr inline bool operator==(const QSizeF &s1, const QSizeF &s2)
+ {
+ return ((!s1.wd || !s2.wd) ? qFuzzyIsNull(s1.wd - s2.wd) : qFuzzyCompare(s1.wd, s2.wd))
+ && ((!s1.ht || !s2.ht) ? qFuzzyIsNull(s1.ht - s2.ht) : qFuzzyCompare(s1.ht, s2.ht));
+ }
+ QT_WARNING_POP
+ friend constexpr inline bool operator!=(const QSizeF &s1, const QSizeF &s2)
+ { return !(s1 == s2); }
+ friend constexpr inline QSizeF operator+(const QSizeF &s1, const QSizeF &s2) noexcept
+ { return QSizeF(s1.wd + s2.wd, s1.ht + s2.ht); }
+ friend constexpr inline QSizeF operator-(const QSizeF &s1, const QSizeF &s2) noexcept
+ { return QSizeF(s1.wd - s2.wd, s1.ht - s2.ht); }
+ friend constexpr inline QSizeF operator*(const QSizeF &s, qreal c) noexcept
+ { return QSizeF(s.wd * c, s.ht * c); }
+ friend constexpr inline QSizeF operator*(qreal c, const QSizeF &s) noexcept
+ { return s * c; }
+ friend inline QSizeF operator/(const QSizeF &s, qreal c)
+ { Q_ASSERT(!qFuzzyIsNull(c)); return QSizeF(s.wd / c, s.ht / c); }
constexpr inline QSize toSize() const noexcept;
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
- Q_REQUIRED_RESULT static QSizeF fromCGSize(CGSize size) noexcept;
- Q_REQUIRED_RESULT CGSize toCGSize() const noexcept;
+ [[nodiscard]] static QSizeF fromCGSize(CGSize size) noexcept;
+ [[nodiscard]] CGSize toCGSize() const noexcept;
#endif
private:
qreal wd;
qreal ht;
+
+ template <std::size_t I,
+ typename S,
+ std::enable_if_t<(I < 2), 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 q23::forward_like<S>(s.wd);
+ else if constexpr (I == 1)
+ return q23::forward_like<S>(s.ht);
+ }
};
-Q_DECLARE_TYPEINFO(QSizeF, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QSizeF, Q_RELOCATABLE_TYPE);
/*****************************************************************************
@@ -344,53 +349,42 @@ constexpr inline qreal &QSizeF::rheight() noexcept
{ return ht; }
constexpr inline QSizeF &QSizeF::operator+=(const QSizeF &s) noexcept
-{ wd += s.wd; ht += s.ht; return *this; }
+{
+ wd += s.wd;
+ ht += s.ht;
+ return *this;
+}
constexpr inline QSizeF &QSizeF::operator-=(const QSizeF &s) noexcept
-{ wd -= s.wd; ht -= s.ht; return *this; }
+{
+ wd -= s.wd;
+ ht -= s.ht;
+ return *this;
+}
constexpr inline QSizeF &QSizeF::operator*=(qreal c) noexcept
-{ wd *= c; ht *= c; return *this; }
-
-constexpr inline bool operator==(const QSizeF &s1, const QSizeF &s2) noexcept
-{ return qFuzzyCompare(s1.wd, s2.wd) && qFuzzyCompare(s1.ht, s2.ht); }
-
-constexpr inline bool operator!=(const QSizeF &s1, const QSizeF &s2) noexcept
-{ return !qFuzzyCompare(s1.wd, s2.wd) || !qFuzzyCompare(s1.ht, s2.ht); }
-
-constexpr inline const QSizeF operator+(const QSizeF & s1, const QSizeF & s2) noexcept
-{ return QSizeF(s1.wd+s2.wd, s1.ht+s2.ht); }
-
-constexpr inline const QSizeF operator-(const QSizeF &s1, const QSizeF &s2) noexcept
-{ return QSizeF(s1.wd-s2.wd, s1.ht-s2.ht); }
-
-constexpr inline const QSizeF operator*(const QSizeF &s, qreal c) noexcept
-{ return QSizeF(s.wd*c, s.ht*c); }
-
-constexpr inline const QSizeF operator*(qreal c, const QSizeF &s) noexcept
-{ return QSizeF(s.wd*c, s.ht*c); }
-
-inline QSizeF &QSizeF::operator/=(qreal c)
{
- Q_ASSERT(!qFuzzyIsNull(c));
- wd = wd/c; ht = ht/c;
+ wd *= c;
+ ht *= c;
return *this;
}
-inline const QSizeF operator/(const QSizeF &s, qreal c)
+inline QSizeF &QSizeF::operator/=(qreal c)
{
- Q_ASSERT(!qFuzzyIsNull(c));
- return QSizeF(s.wd/c, s.ht/c);
+ Q_ASSERT(!qFuzzyIsNull(c) && qIsFinite(c));
+ wd = wd / c;
+ ht = ht / c;
+ return *this;
}
-constexpr inline QSizeF QSizeF::expandedTo(const QSizeF & otherSize) const noexcept
+constexpr inline QSizeF QSizeF::expandedTo(const QSizeF &otherSize) const noexcept
{
- return QSizeF(qMax(wd,otherSize.wd), qMax(ht,otherSize.ht));
+ return QSizeF(qMax(wd, otherSize.wd), qMax(ht, otherSize.ht));
}
-constexpr inline QSizeF QSizeF::boundedTo(const QSizeF & otherSize) const noexcept
+constexpr inline QSizeF QSizeF::boundedTo(const QSizeF &otherSize) const noexcept
{
- return QSizeF(qMin(wd,otherSize.wd), qMin(ht,otherSize.ht));
+ return QSizeF(qMin(wd, otherSize.wd), qMin(ht, otherSize.ht));
}
constexpr inline QSize QSizeF::toSize() const noexcept
@@ -398,10 +392,32 @@ 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
QT_END_NAMESPACE
+/*****************************************************************************
+ QSize/QSizeF tuple protocol
+ *****************************************************************************/
+
+namespace std {
+ template <>
+ class tuple_size<QT_PREPEND_NAMESPACE(QSize)> : public integral_constant<size_t, 2> {};
+ template <>
+ class tuple_element<0, QT_PREPEND_NAMESPACE(QSize)> { public: using type = int; };
+ template <>
+ class tuple_element<1, QT_PREPEND_NAMESPACE(QSize)> { public: using type = int; };
+
+ template <>
+ class tuple_size<QT_PREPEND_NAMESPACE(QSizeF)> : public integral_constant<size_t, 2> {};
+ template <>
+ class tuple_element<0, QT_PREPEND_NAMESPACE(QSizeF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+ template <>
+ class tuple_element<1, QT_PREPEND_NAMESPACE(QSizeF)> { public: using type = QT_PREPEND_NAMESPACE(qreal); };
+}
+
#endif // QSIZE_H
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 819ebb2387..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,18 +43,17 @@ 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
- : d(quintptr(pointer))
+ Q_NODISCARD_CTOR explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
+ : d(quintptr(pointer) | quintptr(tag))
{
static_assert(sizeof(Type*) == sizeof(QTaggedPointer));
- Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0,
- "QTaggedPointer<T, Tag>", "Pointer is not aligned");
-
- setTag(tag);
+ Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0, "QTaggedPointer<T, Tag>", "Pointer is not aligned");
+ 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");
}
Type &operator*() const noexcept
@@ -109,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()));
@@ -122,10 +104,12 @@ 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<typename QtPrivate::TagInfo<T>::TagType>(tag) & tagMask());
+ d = (d & pointerMask()) | static_cast<quintptr>(tag);
}
Tag tag() const noexcept
@@ -145,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 303b89232c..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
@@ -123,9 +99,9 @@
*/
/*!
- \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!() const noexcept
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!(QTaggedPointer<T, Tag> pointer) noexcept
- Returns \c true if the pointer is \nullptr.
+ Returns \c true if \a pointer is \nullptr.
*/
/*!
@@ -153,7 +129,7 @@
*/
/*!
- \fn template <typename T, typename Tag> Tag QTaggedPointer<T, Tag>::pointer() const noexcept
+ \fn template <typename T, typename Tag> T *QTaggedPointer<T, Tag>::data() const noexcept
Returns the pointer stored in the tagged pointer.
*/
@@ -171,8 +147,7 @@
*/
/*!
- \fn template <typename T, typename Tag> inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
- \relates QTaggedPointer
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator==(QTaggedPointer<T, Tag> lhs, QTaggedPointer<T, Tag> rhs) noexcept
Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
@@ -180,8 +155,7 @@
*/
/*!
- \fn template <typename T, typename Tag> inline bool operator!=(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
- \relates QTaggedPointer
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!=(QTaggedPointer<T, Tag> lhs, QTaggedPointer<T, Tag> rhs) noexcept
Returns \c true if \a lhs is not equal to \a rhs; otherwise returns \c false.
@@ -189,35 +163,31 @@
*/
/*!
- \fn template <typename T, typename Tag> inline bool operator==(QTaggedPointer lhs, std::nullptr_t) noexcept
- \relates QTaggedPointer
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator==(QTaggedPointer<T, Tag> lhs, std::nullptr_t) noexcept
Returns \c true if \a lhs refers to \c nullptr.
*/
/*!
- \fn template <typename T, typename Tag> inline bool operator==(std::nullptr_t, QTaggedPointer rhs) noexcept
- \relates QTaggedPointer
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator==(std::nullptr_t, QTaggedPointer<T, Tag> rhs) noexcept
Returns \c true if \a rhs refers to \c nullptr.
*/
/*!
- \fn template <typename T, typename Tag> inline bool operator!=(QTaggedPointerlhs, std::nullptr_t) noexcept
- \relates QTaggedPointer
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!=(QTaggedPointer<T, Tag> lhs, std::nullptr_t) noexcept
Returns \c true if \a lhs refers to a valid (i.e. non-null) pointer.
*/
/*!
- \fn template <typename T, typename Tag> inline bool operator!=(std::nullptr_t, QTaggedPointer rhs) noexcept
- \relates QTaggedPointer
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!=(std::nullptr_t, QTaggedPointer<T, Tag> rhs) noexcept
Returns \c true if \a rhs refers to a valid (i.e. non-null) pointer.
*/
/*!
- \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 f8e78170c4..5512da867f 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** 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"
+#include <private/qproperty_p.h>
#include <private/qobject_p.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qmath.h>
@@ -50,31 +15,29 @@ class QTimeLinePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QTimeLine)
public:
- inline QTimeLinePrivate()
- : easingCurve(QEasingCurve::InOutSine),
- startTime(0), duration(1000), startFrame(0), endFrame(0),
- updateInterval(1000 / 25),
- totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0),
- direction(QTimeLine::Forward),
- state(QTimeLine::NotRunning)
- { }
-
QElapsedTimer timer;
- QEasingCurve easingCurve;
-
- int startTime;
- int duration;
- int startFrame;
- int endFrame;
- int updateInterval;
- int totalLoopCount;
- int currentLoopCount;
-
- int currentTime;
- int timerId;
-
- QTimeLine::Direction direction;
- QTimeLine::State state;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, QEasingCurve, easingCurve,
+ QEasingCurve::InOutSine)
+
+ int startTime = 0;
+ void setDuration(int duration) { q_func()->setDuration(duration); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, duration,
+ &QTimeLinePrivate::setDuration, 1000)
+ int startFrame = 0;
+ int endFrame = 0;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, updateInterval, 1000 / 25)
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, loopCount, 1)
+ int currentLoopCount = 0;
+
+ void setCurrentTimeForwardToQ(int time) { q_func()->setCurrentTime(time); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, currentTime,
+ &QTimeLinePrivate::setCurrentTimeForwardToQ, 0)
+ int timerId = 0;
+
+ void setDirection(QTimeLine::Direction direction) { q_func()->setDirection(direction); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, QTimeLine::Direction, direction,
+ &QTimeLinePrivate::setDirection, QTimeLine::Forward)
+ QTimeLine::State state = QTimeLine::NotRunning;
inline void setState(QTimeLine::State newState)
{
Q_Q(QTimeLine);
@@ -91,42 +54,45 @@ public:
void QTimeLinePrivate::setCurrentTime(int msecs)
{
Q_Q(QTimeLine);
+ currentTime.removeBindingUnlessInWrapper();
+ 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 loopCount = elapsed / duration;
+ const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
+ const int loopCountNow = elapsed / duration;
- bool looping = (loopCount != currentLoopCount);
+ const bool looping = (loopCountNow != currentLoopCount);
#ifdef QTIMELINE_DEBUG
- qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCount" << loopCount
- << "currentLoopCount" << currentLoopCount
- << "looping" << looping;
+ qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow"
+ << loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping;
#endif
if (looping)
- currentLoopCount = loopCount;
+ currentLoopCount = loopCountNow;
// Normalize msecs to be between 0 and duration, inclusive.
- currentTime = elapsed % duration;
- if (direction == QTimeLine::Backward)
- currentTime = duration - currentTime;
+ currentTime.setValueBypassingBindings(elapsed % duration);
+ if (direction.value() == QTimeLine::Backward)
+ currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
// Check if we have reached the end of loopcount.
bool finished = false;
- if (totalLoopCount && currentLoopCount >= totalLoopCount) {
+ if (loopCount && currentLoopCount >= loopCount) {
finished = true;
- currentTime = (direction == QTimeLine::Backward) ? 0 : duration;
- currentLoopCount = totalLoopCount - 1;
+ currentTime.setValueBypassingBindings((direction == QTimeLine::Backward) ? 0 : duration);
+ 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,6 +125,13 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
q->stop();
emit q->finished(QTimeLine::QPrivateSignal());
}
+ if (currentTime.valueBypassingBindings() != previousCurrentTime)
+ currentTime.notify();
+}
+QBindable<int> QTimeLine::bindableCurrentTime()
+{
+ Q_D(QTimeLine);
+ return &d->currentTime;
}
/*!
@@ -319,19 +292,26 @@ 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.
*/
int QTimeLine::loopCount() const
{
Q_D(const QTimeLine);
- return d->totalLoopCount;
+ return d->loopCount;
}
+
void QTimeLine::setLoopCount(int count)
{
Q_D(QTimeLine);
- d->totalLoopCount = count;
+ d->loopCount = count;
+}
+
+QBindable<int> QTimeLine::bindableLoopCount()
+{
+ Q_D(QTimeLine);
+ return &d->loopCount;
}
/*!
@@ -343,6 +323,9 @@ void QTimeLine::setLoopCount(int count)
timeline duration, or from the value of the duration and towards 0 after
start() has been called.
+ Any binding of direction will be removed not only by setDirection(),
+ but also by toggleDirection().
+
By default, this property is set to \l Forward.
*/
QTimeLine::Direction QTimeLine::direction() const
@@ -353,9 +336,19 @@ QTimeLine::Direction QTimeLine::direction() const
void QTimeLine::setDirection(Direction direction)
{
Q_D(QTimeLine);
- d->direction = 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.valueBypassingBindings())
+ d->direction.notify();
+}
+
+QBindable<QTimeLine::Direction> QTimeLine::bindableDirection()
+{
+ Q_D(QTimeLine);
+ return &d->direction;
}
/*!
@@ -382,7 +375,17 @@ void QTimeLine::setDuration(int duration)
qWarning("QTimeLine::setDuration: cannot set duration <= 0");
return;
}
- d->duration = duration;
+ d->duration.removeBindingUnlessInWrapper();
+ if (duration != d->duration.valueBypassingBindings()) {
+ d->duration.setValueBypassingBindings(duration);
+ d->duration.notify();
+ }
+}
+
+QBindable<int> QTimeLine::bindableDuration()
+{
+ Q_D(QTimeLine);
+ return &d->duration;
}
/*!
@@ -472,6 +475,11 @@ void QTimeLine::setUpdateInterval(int interval)
Q_D(QTimeLine);
d->updateInterval = interval;
}
+QBindable<int> QTimeLine::bindableUpdateInterval()
+{
+ Q_D(QTimeLine);
+ return &d->updateInterval;
+}
/*!
\property QTimeLine::easingCurve
@@ -490,12 +498,18 @@ QEasingCurve QTimeLine::easingCurve() const
return d->easingCurve;
}
-void QTimeLine::setEasingCurve(const QEasingCurve& curve)
+void QTimeLine::setEasingCurve(const QEasingCurve &curve)
{
Q_D(QTimeLine);
d->easingCurve = curve;
}
+QBindable<QEasingCurve> QTimeLine::bindableEasingCurve()
+{
+ Q_D(QTimeLine);
+ return &d->easingCurve;
+}
+
/*!
\property QTimeLine::currentTime
\brief the current time of the time line.
@@ -505,6 +519,10 @@ void QTimeLine::setEasingCurve(const QEasingCurve& curve)
value that was current when stop() was called last, or the value set by
setCurrentTime().
+ \note You can bind other properties to currentTime, but it is not
+ recommended setting bindings to it. As animation progresses, the currentTime
+ is updated automatically, which cancels its bindings.
+
By default, this property contains a value of 0.
*/
int QTimeLine::currentTime() const
@@ -571,10 +589,10 @@ int QTimeLine::frameForTime(int msec) const
qreal QTimeLine::valueForTime(int msec) const
{
Q_D(const QTimeLine);
- msec = qMin(qMax(msec, 0), d->duration);
+ msec = qBound(0, msec, d->duration.value());
- qreal value = msec / qreal(d->duration);
- return d->easingCurve.valueForProgress(value);
+ qreal value = msec / qreal(d->duration.value());
+ return d->easingCurve.value().valueForProgress(value);
}
/*!
@@ -678,6 +696,8 @@ void QTimeLine::setPaused(bool paused)
Toggles the direction of the timeline. If the direction was Forward, it
becomes Backward, and vice verca.
+ Existing bindings of \l direction are removed.
+
\sa setDirection()
*/
void QTimeLine::toggleDirection()
diff --git a/src/corelib/tools/qtimeline.h b/src/corelib/tools/qtimeline.h
index 193c372c6a..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
@@ -54,12 +18,14 @@ class QTimeLinePrivate;
class Q_CORE_EXPORT QTimeLine : public QObject
{
Q_OBJECT
- Q_PROPERTY(int duration READ duration WRITE setDuration)
- Q_PROPERTY(int updateInterval READ updateInterval WRITE setUpdateInterval)
- Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime)
- Q_PROPERTY(Direction direction READ direction WRITE setDirection)
- Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount)
- Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve)
+ Q_PROPERTY(int duration READ duration WRITE setDuration BINDABLE bindableDuration)
+ Q_PROPERTY(int updateInterval READ updateInterval WRITE setUpdateInterval
+ BINDABLE bindableUpdateInterval)
+ Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime BINDABLE bindableCurrentTime)
+ Q_PROPERTY(Direction direction READ direction WRITE setDirection BINDABLE bindableDirection)
+ Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount BINDABLE bindableLoopCount)
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve
+ BINDABLE bindableEasingCurve)
public:
enum State {
NotRunning,
@@ -78,12 +44,15 @@ public:
int loopCount() const;
void setLoopCount(int count);
+ QBindable<int> bindableLoopCount();
Direction direction() const;
void setDirection(Direction direction);
+ QBindable<Direction> bindableDirection();
int duration() const;
void setDuration(int duration);
+ QBindable<int> bindableDuration();
int startFrame() const;
void setStartFrame(int frame);
@@ -93,11 +62,14 @@ public:
int updateInterval() const;
void setUpdateInterval(int interval);
+ QBindable<int> bindableUpdateInterval();
QEasingCurve easingCurve() const;
void setEasingCurve(const QEasingCurve &curve);
+ QBindable<QEasingCurve> bindableEasingCurve();
int currentTime() const;
+ QBindable<int> bindableCurrentTime();
int currentFrame() const;
qreal currentValue() const;
diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h
index 5b6be12820..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,21 +49,74 @@ 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';
+}
+
+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 ((c >= '0') && (c <= '7')) ? int(c - '0') : -1;
+ return isAsciiDigit(c) || isAsciiLower(c) || isAsciiUpper(c);
}
+
+constexpr inline char toAsciiLower(char ch) noexcept
+{
+ return isAsciiUpper(ch) ? ch - 'A' + 'a' : ch;
}
-// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size.
-constexpr qsizetype MaxAllocSize = (std::numeric_limits<qsizetype>::max)();
+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));
+}
-struct CalculateGrowingBlockSizeResult {
+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 ;
+}
+
+} // namespace QtMiscUtils
+
+struct CalculateGrowingBlockSizeResult
+{
qsizetype size;
qsizetype elementCount;
};
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 b240f8d450..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,39 +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
}
@@ -96,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()
{
@@ -104,14 +354,12 @@ public:
std::copy(first, last, std::back_inserter(*this));
}
- inline ~QVarLengthArray() {
- if (QTypeInfo<T>::isComplex) {
- T *i = ptr + s;
- while (i-- != ptr)
- i->~T();
- }
- if (ptr != reinterpret_cast<T *>(array))
- free(ptr);
+ inline ~QVarLengthArray()
+ {
+ if constexpr (QTypeInfo<T>::isComplex)
+ 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,96 +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 (QTypeInfo<T>::isComplex)
- ptr[s - 1].~T();
- --s;
+ inline void removeLast()
+ {
+ Base::pop_back();
}
- inline qsizetype size() const { return s; }
- inline qsizetype count() const { return s; }
- inline qsizetype length() const { return s; }
- inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T& first() const { Q_ASSERT(!isEmpty()); return *begin(); }
- T& last() { Q_ASSERT(!isEmpty()); return *(end() - 1); }
- const T& last() const { Q_ASSERT(!isEmpty()); return *(end() - 1); }
- inline bool isEmpty() const { return (s == 0); }
- inline void resize(qsizetype size);
+#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()
+ {
+ return front();
+ }
+ inline const T &first() const
+ {
+ return front();
+ }
+ T &last()
+ {
+ return back();
+ }
+ const T &last() const
+ {
+ return back();
+ }
+ 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();
-
- inline qsizetype capacity() const { return a; }
- inline void reserve(qsizetype size);
+#endif
+ void squeeze() { reallocate(size(), size()); }
- inline qsizetype indexOf(const T &t, qsizetype from = 0) const;
- inline qsizetype lastIndexOf(const T &t, qsizetype from = -1) const;
- inline bool contains(const T &t) const;
+ 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;
- inline T &operator[](qsizetype idx) {
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
+#ifdef Q_QDOC
+ inline T &operator[](qsizetype idx)
+ {
+ verify(idx);
+ return data()[idx];
}
- inline const T &operator[](qsizetype idx) const {
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
+ inline const T &operator[](qsizetype idx) const
+ {
+ 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++;
- if (QTypeInfo<T>::isComplex) {
- new (ptr + idx) T(std::move(copy));
- } else {
- ptr[idx] = std::move(copy);
- }
- } else {
- const qsizetype idx = s++;
- if (QTypeInfo<T>::isComplex) {
- new (ptr + idx) T(t);
- } else {
- ptr[idx] = t;
- }
- }
+ inline void append(const 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++;
- if (QTypeInfo<T>::isComplex)
- new (ptr + idx) T(std::move(t));
- else
- ptr[idx] = std::move(t);
+ void append(T &&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)
@@ -229,139 +500,233 @@ 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);
-
-
- 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; }
+ 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;
+
+#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);
- iterator insert(const_iterator before, 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); }
+ 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)
+ { return Base::emplace_impl(Prealloc, this->array, pos, std::forward<Args>(args)...); }
+ template <typename...Args>
+ T &emplace_back(Args &&...args)
+ { return Base::emplace_back_impl(Prealloc, this->array, std::forward<Args>(args)...); }
+
+
+#ifdef Q_QDOC
+ template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+ friend inline bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
+ template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+ friend inline bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
+ template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+ friend inline bool operator< (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
+ template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+ friend inline bool operator> (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
+ template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+ friend inline bool operator<=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
+ template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+ friend inline bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r);
+#else
+ template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
+ QTypeTraits::compare_eq_result<U> operator==(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
+ {
+ return l.equal(r);
+ }
-private:
- void reallocate(qsizetype size, qsizetype alloc);
+ template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
+ QTypeTraits::compare_eq_result<U> operator!=(const QVarLengthArray<T, Prealloc> &l, const QVarLengthArray<T, Prealloc2> &r)
+ {
+ return !(l == r);
+ }
- qsizetype a; // capacity
- qsizetype s; // size
- T *ptr; // data
- std::aligned_storage_t<sizeof(T), alignof(T)> array[Prealloc];
+ template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
+ QTypeTraits::compare_lt_result<U> operator<(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
+ noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
+ rhs.begin(), rhs.end())))
+ {
+ return lhs.less_than(rhs);
+ }
- bool isValidIterator(const const_iterator &i) const
+ template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
+ QTypeTraits::compare_lt_result<U> operator>(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
+ noexcept(noexcept(lhs < rhs))
{
- const std::less<const T*> less = {};
- return !less(cend(), i) && !less(i, cbegin());
+ return rhs < lhs;
}
+
+ template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
+ QTypeTraits::compare_lt_result<U> operator<=(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
+ noexcept(noexcept(lhs < rhs))
+ {
+ return !(lhs > rhs);
+ }
+
+ template <typename U = T, qsizetype Prealloc2 = Prealloc> friend
+ QTypeTraits::compare_lt_result<U> operator>=(const QVarLengthArray<T, Prealloc> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
+ noexcept(noexcept(lhs < rhs))
+ {
+ return !(lhs < rhs);
+ }
+#endif
+
+private:
+ 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); }
+
+ void reallocate(qsizetype sz, qsizetype alloc)
+ { Base::reallocate_impl(Prealloc, this->array, sz, alloc); }
+
+ using Base::isValidIterator;
};
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
template <typename InputIterator,
typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
QtPrivate::IfIsInputIterator<InputIterator> = true>
QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray<ValueType>;
-#endif
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>
-Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::indexOf(const T &t, qsizetype from) const
+template <class T>
+template <typename AT>
+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>
-Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, qsizetype from) const
+template <class T>
+template <typename AT>
+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;
@@ -370,11 +735,12 @@ Q_INLINE_TEMPLATE qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t
return -1;
}
-template <class T, qsizetype Prealloc>
-Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const T &t) const
+template <class T>
+template <typename AT>
+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;
@@ -382,276 +748,275 @@ Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const T &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 (QTypeInfo<T>::isComplex) {
- // call constructor for new objects (which can throw)
- while (s < asize)
- new (ptr+(s++)) T(*abuf++);
+ if constexpr (QTypeInfo<T>::isComplex)
+ std::uninitialized_copy_n(abuf, increment, end());
+ else
+ memcpy(static_cast<void *>(end()), static_cast<const void *>(abuf), increment * sizeof(T));
+
+ this->s = asize;
+}
+
+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 {
- memcpy(static_cast<void *>(&ptr[s]), static_cast<const void *>(abuf), increment * sizeof(T));
- s = asize;
+ 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_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::squeeze()
-{ reallocate(s, s); }
+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
+ }
-template <class T, qsizetype Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reallocate(qsizetype asize, qsizetype aalloc)
+ 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);
- 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;
- if (QTypeInfo<T>::isComplex) {
- // destroy remaining old objects
- while (osize > asize)
- (oldPtr+(--osize))->~T();
+ // destroy remaining old objects
+ if constexpr (QTypeInfo<T>::isComplex) {
+ if (osize > asize)
+ 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>
+template <typename AT>
+inline qsizetype QVLABase<T>::removeAll(const AT &t)
+{ return QtPrivate::sequential_erase_with_copy(*this, t); }
+template <class T>
+template <typename AT>
+inline bool QVLABase<T>::removeOne(const AT &t)
+{ return QtPrivate::sequential_erase_one(*this, t); }
+template <class T>
+template <typename Predicate>
+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>
-Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&t)
+template <class T>
+template <typename...Args>
+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 = std::move(t);
- } else {
- new (b) T(std::move(t));
- }
- } else {
- T *b = ptr + offset;
- memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (s - offset) * sizeof(T));
- new (b) T(std::move(t));
- }
- 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) {
- resize(s + n);
- const T copy(t);
- 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 (QTypeInfo<T>::isComplex) {
- std::copy(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f));
- T *i = ptr + s;
- T *b = ptr + s - n;
- while (i != b) {
- --i;
- i->~T();
- }
+
+ 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(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
+// Fake definitions for qdoc, only the redeclaration is used.
template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
-QTypeTraits::compare_eq_result<T> operator==(const QVarLengthArray<T, Prealloc1> &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()));
-}
-
+bool operator==(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
-QTypeTraits::compare_eq_result<T> operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
-{
- return !(l == r);
-}
-
+bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
-QTypeTraits::compare_lt_result<T> operator<(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end())))
-{
- return std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end());
-}
-
+bool operator< (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
-QTypeTraits::compare_lt_result<T> operator>(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return rhs < lhs;
-}
-
+bool operator> (const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
+bool operator<=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
-QTypeTraits::compare_lt_result<T> operator<=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(lhs < rhs))
+bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
+#endif
+
+template <typename T, qsizetype Prealloc>
+size_t qHash(const QVarLengthArray<T, Prealloc> &key, size_t seed = 0)
+ noexcept(QtPrivate::QNothrowHashable_v<T>)
{
- return !(lhs > rhs);
+ return key.hash(seed);
}
-template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
-QTypeTraits::compare_lt_result<T> operator>=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(lhs < rhs))
+template <typename T, qsizetype Prealloc, typename AT>
+qsizetype erase(QVarLengthArray<T, Prealloc> &array, const AT &t)
{
- return !(lhs < rhs);
+ return array.removeAll(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)))
+template <typename T, qsizetype Prealloc, typename Predicate>
+qsizetype erase_if(QVarLengthArray<T, Prealloc> &array, Predicate pred)
{
- return qHashRange(key.cbegin(), key.cend(), seed);
+ return array.removeIf(pred);
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 5970081d85..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
@@ -90,6 +66,11 @@
\sa QList
*/
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray()
+
+ Constructs an array with an initial size of zero.
+*/
+
/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype size)
Constructs an array with an initial size of \a size elements.
@@ -100,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.
*/
@@ -146,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
@@ -240,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
@@ -414,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)
@@ -458,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
@@ -540,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.
@@ -564,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
@@ -753,6 +767,27 @@
\a before. Returns an iterator pointing at the inserted item.
*/
+/*!
+ \fn template <class T, qsizetype Prealloc> template <typename...Args> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::emplace(const_iterator pos, Args &&...args)
+
+ \since 6.3
+
+ Inserts an item in front of the item pointed to by the iterator
+ \a pos, passing \a args to its constructor.
+
+ Returns an iterator pointing at the emplaced item.
+*/
+
+/*!
+ \fn template <class T, qsizetype Prealloc> template <typename...Args> T &QVarLengthArray<T, Prealloc>::emplace_back(Args &&...args)
+ \since 6.3
+
+ Inserts an item at the back of this QVarLengthArray, passing
+ \a args to its constructor.
+
+ Returns a reference to the emplaced item.
+*/
+
/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, qsizetype count, const T &value)
\since 4.8
@@ -775,7 +810,7 @@
This function requires the value type to have an implementation
of \c operator==().
- \sa operator!=()
+ \sa {operator!=(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)}{operator!=()}
*/
/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator!=(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
@@ -790,7 +825,7 @@
This function requires the value type to have an implementation
of \c operator==().
- \sa operator==()
+ \sa {operator==(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)}{operator==()}
*/
/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator<(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
@@ -874,7 +909,7 @@
\sa append(), operator<<()
*/
-/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::indexOf(const T &value, qsizetype from = 0) const
+/*! \fn template<class T, qsizetype Prealloc> template <typename AT = T> qsizetype QVarLengthArray<T, Prealloc>::indexOf(const AT &value, qsizetype from = 0) const
\since 5.3
Returns the index position of the first occurrence of \a value in
@@ -887,7 +922,7 @@
\sa lastIndexOf(), contains()
*/
-/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const T &value, qsizetype from = -1) const
+/*! \fn template<class T, qsizetype Prealloc> template <typename AT = T> qsizetype QVarLengthArray<T, Prealloc>::lastIndexOf(const AT &value, qsizetype from = -1) const
\since 5.3
Returns the index position of the last occurrence of the value \a
@@ -901,7 +936,7 @@
\sa indexOf(), contains()
*/
-/*! \fn template<class T, qsizetype Prealloc> bool QVarLengthArray<T, Prealloc>::contains(const T &value) const
+/*! \fn template<class T, qsizetype Prealloc> template <typename AT = T> bool QVarLengthArray<T, Prealloc>::contains(const AT &value) const
\since 5.3
Returns \c true if the array contains an occurrence of \a value;
@@ -921,3 +956,92 @@
Returns the hash value for \a key, using \a seed to seed the
calculation.
*/
+
+/*! \fn template <typename T, qsizetype Prealloc> template <typename AT = T> qsizetype QVarLengthArray<T, Prealloc>::removeAll(const AT &t)
+ \since 6.1
+
+ Removes all elements that compare equal to \a t from the
+ array. Returns the number of elements removed, if any.
+
+ \sa removeOne()
+*/
+
+/*! \fn template <typename T, qsizetype Prealloc> template <typename AT = T> bool QVarLengthArray<T, Prealloc>::removeOne(const AT &t)
+ \since 6.1
+
+ Removes the first element that compares equal to \a t from the
+ array. Returns whether an element was, in fact, removed.
+
+ \sa removeAll()
+*/
+
+/*! \fn template <typename T, qsizetype Prealloc> template <typename Predicate> qsizetype QVarLengthArray<T, Prealloc>::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the array. Returns the number of elements removed, if any.
+
+ \sa removeAll()
+*/
+
+/*! \fn template <typename T, qsizetype Prealloc, typename AT> qsizetype erase(QVarLengthArray<T, Prealloc> &array, const AT &t)
+ \relates QVarLengthArray
+ \since 6.1
+
+ Removes all elements that compare equal to \a t from the
+ array \a array. Returns the number of elements removed, if any.
+
+ \note \a t is not allowed to be a reference to an element inside \a
+ array. If you cannot be sure that this is not the case, take a copy
+ of \a t and call this function with the copy.
+
+ \sa erase_if()
+*/
+
+/*! \fn template <typename T, qsizetype Prealloc, typename Predicate> qsizetype erase_if(QVarLengthArray<T, Prealloc> &array, Predicate pred)
+ \relates QVarLengthArray
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the list \a array. Returns the number of elements removed, if
+ any.
+
+ \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 517f026547..4b8ace71cc 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** 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) 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,22 +152,22 @@ 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 segement value at \a index. If the index does not exist,
+ Returns the segment value at \a index. If the index does not exist,
returns 0.
\sa segments(), segmentCount()
*/
/*!
- \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;
@@ -328,8 +348,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
}
/*!
- \fn bool operator<(const QVersionNumber &lhs, const QVersionNumber &rhs)
- \relates QVersionNumber
+ \fn bool QVersionNumber::operator<(const QVersionNumber &lhs, const QVersionNumber &rhs)
Returns \c true if \a lhs is less than \a rhs; otherwise returns \c false.
@@ -337,8 +356,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
*/
/*!
- \fn bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs)
- \relates QVersionNumber
+ \fn bool QVersionNumber::operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs)
Returns \c true if \a lhs is less than or equal to \a rhs; otherwise
returns \c false.
@@ -347,8 +365,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
*/
/*!
- \fn bool operator>(const QVersionNumber &lhs, const QVersionNumber &rhs)
- \relates QVersionNumber
+ \fn bool QVersionNumber::operator>(const QVersionNumber &lhs, const QVersionNumber &rhs)
Returns \c true if \a lhs is greater than \a rhs; otherwise returns \c
false.
@@ -357,8 +374,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
*/
/*!
- \fn bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs)
- \relates QVersionNumber
+ \fn bool QVersionNumber::operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs)
Returns \c true if \a lhs is greater than or equal to \a rhs; otherwise
returns \c false.
@@ -367,8 +383,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
*/
/*!
- \fn bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs)
- \relates QVersionNumber
+ \fn bool QVersionNumber::operator==(const QVersionNumber &lhs, const QVersionNumber &rhs)
Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
@@ -376,8 +391,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
*/
/*!
- \fn bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs)
- \relates QVersionNumber
+ \fn bool QVersionNumber::operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs)
Returns \c true if \a lhs is not equal to \a rhs; otherwise returns
\c false.
@@ -397,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{.}).
@@ -415,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 = qstrtoull(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)
@@ -535,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
@@ -556,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. Valid segments need to be \c {>= 0} and \c {< 255}.
-*/
-
-/*!
- \fn QTypeRevision::QTypeRevision()
-
- Produces an invalid revision.
-
- \sa isValid()
-*/
-
-/*!
- \fn template <typename Major, typename Minor> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion)
-
- Produces a QTypeRevision from the given \a majorVersion and \a minorVersion,
- both of which need to be a valid segments.
-
- \sa isValidSegment()
-*/
-
-/*!
- \fn template <typename Major> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion)
-
- Produces a QTypeRevision from the given \a majorVersion with an invalid minor
- version. \a majorVersion needs to be a valid segment.
-
- \sa isValidSegment()
-*/
-
-/*!
- \fn template <typename Minor> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion)
-
- Produces a QTypeRevision from the given \a minorVersion with an invalid major
- version. \a minorVersion needs to be a valid segment.
-
- \sa isValidSegment()
-*/
-
-/*!
- \fn template <typename Integer> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value)
-
- Produces a QTypeRevision from the given \a value. \a value encodes both the
- minor and major versions in the least significant and second least
- significant byte, respectively.
-
- \a value must not have any bits outside the least significant two bytes set.
- \c Integer needs to be at least 16 bits wide, and must not have a sign bit
- in the least significant 16 bits.
-
- \sa toEncodedVersion()
-*/
-
-/*!
- \fn static QTypeRevision QTypeRevision::zero()
-
- Produces a QTypeRevision with major and minor version \c{0}.
-*/
-
-/*!
- \fn bool QTypeRevision::hasMajorVersion() const
-
- Returns true if the major version is known, otherwise false.
-
- \sa majorVersion(), hasMinorVersion()
-*/
-
-/*!
- \fn quint8 QTypeRevision::majorVersion() const
-
- Returns the major version encoded in the revision.
-
- \sa hasMajorVersion(), minorVersion()
-*/
-
-/*!
- \fn bool QTypeRevision::hasMinorVersion() const
-
- Returns true if the minor version is known, otherwise false.
-
- \sa minorVersion(), hasMajorVersion()
-*/
-
-/*!
- \fn quint8 QTypeRevision::minorVersion() const
-
- Returns the minor version encoded in the revision.
-
- \sa hasMinorVersion(), majorVersion()
-*/
-
-/*!
- \fn bool QTypeRevision::isValid() const
-
- Returns true if the major version or the minor version is known,
- otherwise false.
-
- \sa hasMajorVersion(), hasMinorVersion()
-*/
-
-/*!
- \fn template<typename Integer> Integer QTypeRevision::toEncodedVersion() const
-
- Transforms the revision into an integer value, encoding the minor
- version into the least significant byte, and the major version into
- the second least significant byte.
-
- \c Integer needs to be at least 16 bits wide, and must not have a sign bit
- in the least significant 16 bits.
-
- \sa fromEncodedVersion()
-*/
-
-#ifndef QT_NO_DATASTREAM
-/*!
- \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision)
- \relates QTypeRevision
- \since 6.0
-
- Writes the revision \a revision to stream \a out.
- */
-QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision)
-{
- return out << revision.toEncodedVersion<quint16>();
-}
-
-/*!
- \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision)
- \relates QTypeRevision
- \since 6.0
-
- Reads a revision from stream \a in and stores it in \a revision.
- */
-QDataStream& operator>>(QDataStream &in, QTypeRevision &revision)
-{
- quint16 value;
- in >> value;
- revision = QTypeRevision::fromEncodedVersion(value);
- return in;
-}
-#endif
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug debug, const QTypeRevision &revision)
-{
- QDebugStateSaver saver(debug);
- if (revision.hasMajorVersion()) {
- if (revision.hasMinorVersion())
- debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion();
- else
- debug.nospace().noquote() << revision.majorVersion() << ".x";
- } else {
- if (revision.hasMinorVersion())
- debug << revision.minorVersion();
- else
- debug.noquote() << "invalid";
- }
- return debug;
-}
-#endif
-
-/*!
- \fn size_t qHash(const QTypeRevision &key, size_t seed)
- \relates QHash
- \since 6.0
-
- Returns the hash value for the \a key, using \a seed to seed the
- calculation.
-*/
-size_t qHash(const QTypeRevision &key, size_t seed)
-{
- return qHash(key.toEncodedVersion<quint16>(), seed);
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index 4704db2c10..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
@@ -55,8 +23,8 @@ class QVersionNumber;
Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed = 0);
#ifndef QT_NO_DATASTREAM
-Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QVersionNumber &version);
-Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
+Q_CORE_EXPORT QDataStream &operator<<(QDataStream &out, const QVersionNumber &version);
+Q_CORE_EXPORT QDataStream &operator>>(QDataStream &in, QVersionNumber &version);
#endif
class QVersionNumber
@@ -71,19 +39,20 @@ class QVersionNumber
enum {
// in little-endian, inline_segments[0] is shared with the pointer's LSB, while
// in big-endian, it's inline_segments[7]
- InlineSegmentMarker = Q_BYTE_ORDER == Q_LITTLE_ENDIAN ? 0 : sizeof(void*) - 1,
+ InlineSegmentMarker = Q_BYTE_ORDER == Q_LITTLE_ENDIAN ? 0 : sizeof(void *) - 1,
InlineSegmentStartIdx = !InlineSegmentMarker, // 0 for BE, 1 for LE
- InlineSegmentCount = sizeof(void*) - 1
+ InlineSegmentCount = sizeof(void *) - 1
};
static_assert(InlineSegmentCount >= 3); // at least major, minor, micro
- struct SegmentStorage {
+ struct SegmentStorage
+ {
// Note: we alias the use of dummy and inline_segments in the use of the
// union below. This is undefined behavior in C++98, but most compilers implement
// the C++11 behavior. The one known exception is older versions of Sun Studio.
union {
quintptr dummy;
- qint8 inline_segments[sizeof(void*)];
+ qint8 inline_segments[sizeof(void *)];
QList<int> *pointer_segments;
};
@@ -92,16 +61,18 @@ class QVersionNumber
SegmentStorage(const QList<int> &seg)
{
- if (dataFitsInline(seg.begin(), seg.size()))
- setInlineData(seg.begin(), seg.size());
+ 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;
}
@@ -111,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;
@@ -126,48 +97,54 @@ class QVersionNumber
other.dummy = 1;
}
- SegmentStorage &operator=(SegmentStorage &&other) noexcept
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(SegmentStorage)
+
+ void swap(SegmentStorage &other) noexcept
{
- qSwap(dummy, other.dummy);
- return *this;
+ std::swap(dummy, other.dummy);
}
explicit SegmentStorage(QList<int> &&seg)
{
- if (dataFitsInline(seg.begin(), seg.size()))
- setInlineData(seg.begin(), 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(args.begin(), int(args.size()))) {
- setInlineData(args.begin(), 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) :
@@ -185,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
}
@@ -214,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)
{}
@@ -237,229 +282,112 @@ public:
inline explicit QVersionNumber(int maj, int min, int mic)
{ m_segments.setSegments(3, maj, min, mic); }
- Q_REQUIRED_RESULT inline bool isNull() const noexcept
+ [[nodiscard]] inline bool isNull() const noexcept
{ return segmentCount() == 0; }
- Q_REQUIRED_RESULT inline bool isNormalized() const noexcept
+ [[nodiscard]] inline bool isNormalized() const noexcept
{ return isNull() || segmentAt(segmentCount() - 1) != 0; }
- Q_REQUIRED_RESULT inline int majorVersion() const noexcept
+ [[nodiscard]] inline int majorVersion() const noexcept
{ return segmentAt(0); }
- Q_REQUIRED_RESULT inline int minorVersion() const noexcept
+ [[nodiscard]] inline int minorVersion() const noexcept
{ return segmentAt(1); }
- Q_REQUIRED_RESULT inline int microVersion() const noexcept
+ [[nodiscard]] inline int microVersion() const noexcept
{ return segmentAt(2); }
- Q_REQUIRED_RESULT Q_CORE_EXPORT QVersionNumber normalized() const;
+ [[nodiscard]] Q_CORE_EXPORT QVersionNumber normalized() const;
- Q_REQUIRED_RESULT Q_CORE_EXPORT QList<int> segments() const;
+ [[nodiscard]] Q_CORE_EXPORT QList<int> segments() const;
- Q_REQUIRED_RESULT 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; }
- Q_REQUIRED_RESULT inline int segmentCount() const noexcept
+ [[nodiscard]] inline qsizetype segmentCount() const noexcept
{ return m_segments.size(); }
- Q_REQUIRED_RESULT Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const noexcept;
-
- Q_REQUIRED_RESULT Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept;
-
- Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
-
- Q_REQUIRED_RESULT Q_CORE_EXPORT QString toString() const;
-#if QT_STRINGVIEW_LEVEL < 2
- Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr);
-#endif
- Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex = nullptr);
- Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex = nullptr);
-
-private:
-#ifndef QT_NO_DATASTREAM
- friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
-#endif
- friend Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed);
-};
-
-Q_DECLARE_TYPEINFO(QVersionNumber, Q_MOVABLE_TYPE);
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version);
-#endif
+ [[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(); }
-Q_REQUIRED_RESULT inline bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) > 0; }
+ [[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(); }
-Q_REQUIRED_RESULT inline bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) >= 0; }
+ [[nodiscard]] const_iterator constBegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator constEnd() const noexcept { return end(); }
-Q_REQUIRED_RESULT inline bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) < 0; }
+ [[nodiscard]] Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const noexcept;
-Q_REQUIRED_RESULT inline bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) <= 0; }
+ [[nodiscard]] Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept;
-Q_REQUIRED_RESULT inline bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) == 0; }
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
-Q_REQUIRED_RESULT inline bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) != 0; }
+ [[nodiscard]] Q_CORE_EXPORT QString toString() const;
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex = nullptr);
-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)
+#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)
{
- // 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);
+ 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
- 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));
- }
+#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
- static constexpr QTypeRevision zero() { return QTypeRevision(0, 0); }
+ [[nodiscard]] friend bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) > 0; }
- constexpr QTypeRevision() = default;
+ [[nodiscard]] friend bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) >= 0; }
- constexpr bool hasMajorVersion() const { return m_majorVersion != SegmentUnknown; }
- constexpr quint8 majorVersion() const { return m_majorVersion; }
+ [[nodiscard]] friend bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) < 0; }
- constexpr bool hasMinorVersion() const { return m_minorVersion != SegmentUnknown; }
- constexpr quint8 minorVersion() const { return m_minorVersion; }
+ [[nodiscard]] friend bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) <= 0; }
- constexpr bool isValid() const { return hasMajorVersion() || hasMinorVersion(); }
+ [[nodiscard]] friend bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) == 0; }
- template<typename Integer, if_valid_value_type<Integer> = true>
- constexpr Integer toEncodedVersion() const
- {
- return Integer(m_majorVersion << 8) | Integer(m_minorVersion);
- }
+ [[nodiscard]] friend bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) != 0; }
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;
+#ifndef QT_NO_DATASTREAM
+ friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
#endif
+ friend Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed);
};
-inline constexpr bool operator==(QTypeRevision lhs, QTypeRevision rhs)
-{
- return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>();
-}
-
-inline constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs)
-{
- return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>();
-}
-
-inline constexpr bool operator<(QTypeRevision lhs, QTypeRevision rhs)
-{
- return (!lhs.hasMajorVersion() && rhs.hasMajorVersion())
- // non-0 major > unspecified major > major 0
- ? rhs.majorVersion() != 0
- : ((lhs.hasMajorVersion() && !rhs.hasMajorVersion())
- // major 0 < unspecified major < non-0 major
- ? lhs.majorVersion() == 0
- : (lhs.majorVersion() != rhs.majorVersion()
- // both majors specified and non-0
- ? lhs.majorVersion() < rhs.majorVersion()
- : ((!lhs.hasMinorVersion() && rhs.hasMinorVersion())
- // non-0 minor > unspecified minor > minor 0
- ? rhs.minorVersion() != 0
- : ((lhs.hasMinorVersion() && !rhs.hasMinorVersion())
- // minor 0 < unspecified minor < non-0 minor
- ? lhs.minorVersion() == 0
- // both minors specified and non-0
- : lhs.minorVersion() < rhs.minorVersion()))));
-}
-
-inline constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs)
-{
- return lhs != rhs && !(lhs < rhs);
-}
-
-inline constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs)
-{
- return lhs == rhs || lhs < rhs;
-}
-
-inline constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs)
-{
- return lhs == rhs || !(lhs < rhs);
-}
-
-static_assert(sizeof(QTypeRevision) == 2);
-Q_DECLARE_TYPEINFO(QTypeRevision, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QVersionNumber, Q_RELOCATABLE_TYPE);
#ifndef QT_NO_DEBUG_STREAM
-Q_CORE_EXPORT QDebug operator<<(QDebug, const QTypeRevision &revision);
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version);
#endif
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QVersionNumber)
-Q_DECLARE_METATYPE(QTypeRevision)
+QT_DECL_METATYPE_EXTERN(QVersionNumber, Q_CORE_EXPORT)
-#endif //QVERSIONNUMBER_H
+#endif // QVERSIONNUMBER_H
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
deleted file mode 100644
index e57fa6e8ed..0000000000
--- a/src/corelib/tools/tools.pri
+++ /dev/null
@@ -1,117 +0,0 @@
-# Qt tools module
-
-intel_icc: QMAKE_CXXFLAGS += -fp-model strict
-
-HEADERS += \
- tools/qalgorithms.h \
- tools/qarraydata.h \
- tools/qarraydataops.h \
- tools/qarraydatapointer.h \
- tools/qbitarray.h \
- tools/qcache.h \
- tools/qcontainerfwd.h \
- tools/qcontainertools_impl.h \
- tools/qcryptographichash.h \
- tools/qduplicatetracker_p.h \
- tools/qflatmap_p.h \
- tools/qfreelist_p.h \
- tools/qhash.h \
- tools/qhashfunctions.h \
- tools/qiterator.h \
- tools/qline.h \
- tools/qlist.h \
- tools/qmakearray_p.h \
- tools/qmap.h \
- tools/qmargins.h \
- tools/qmessageauthenticationcode.h \
- tools/qcontiguouscache.h \
- tools/qoffsetstringarray_p.h \
- tools/qpair.h \
- tools/qpoint.h \
- tools/qqueue.h \
- tools/qrect.h \
- tools/qringbuffer_p.h \
- tools/qrefcount.h \
- tools/qscopeguard.h \
- tools/qscopedpointer.h \
- tools/qscopedpointer_p.h \
- tools/qscopedvaluerollback.h \
- tools/qshareddata.h \
- tools/qshareddata_impl.h \
- tools/qsharedpointer.h \
- tools/qsharedpointer_impl.h \
- tools/qset.h \
- tools/qsize.h \
- tools/qstack.h \
- tools/qtools_p.h \
- tools/qtaggedpointer.h \
- tools/qvarlengtharray.h \
- tools/qvector.h \
- tools/qversionnumber.h
-
-SOURCES += \
- tools/qarraydata.cpp \
- tools/qbitarray.cpp \
- tools/qcryptographichash.cpp \
- tools/qfreelist.cpp \
- tools/qhash.cpp \
- tools/qline.cpp \
- tools/qpoint.cpp \
- tools/qmargins.cpp \
- tools/qmessageauthenticationcode.cpp \
- tools/qcontiguouscache.cpp \
- tools/qrect.cpp \
- tools/qrefcount.cpp \
- tools/qringbuffer.cpp \
- tools/qshareddata.cpp \
- tools/qsharedpointer.cpp \
- tools/qsize.cpp \
- tools/qversionnumber.cpp
-
-qtConfig(system-zlib) {
- include($$PWD/../../3rdparty/zlib_dependency.pri)
-} else {
- CONFIG += no_core_dep
- include($$PWD/../../3rdparty/zlib.pri)
-}
-
-qtConfig(commandlineparser) {
- HEADERS += \
- tools/qcommandlineoption.h \
- tools/qcommandlineparser.h
- SOURCES += \
- tools/qcommandlineoption.cpp \
- tools/qcommandlineparser.cpp
-}
-
-INCLUDEPATH += ../3rdparty/md5 \
- ../3rdparty/md4 \
- ../3rdparty/sha3
-
-qtConfig(system-doubleconversion) {
- QMAKE_USE_PRIVATE += doubleconversion
-} else: qtConfig(doubleconversion) {
- include($$PWD/../../3rdparty/double-conversion/double-conversion.pri)
-}
-
-qtConfig(system-libb2) {
- QMAKE_USE_PRIVATE += libb2
-}
-
-qtConfig(easingcurve) {
- HEADERS += \
- tools/qeasingcurve.h \
- tools/qtimeline.h
-
- SOURCES += \
- tools/qeasingcurve.cpp \
- tools/qtimeline.cpp
-}
-
-# Note: libm should be present by default becaue this is C++
-unix:!macx-icc:!vxworks:!haiku:!integrity:!wasm: LIBS_PRIVATE += -lm
-
-TR_EXCLUDE += ../3rdparty/*
-
-# MIPS DSP
-MIPS_DSP_HEADERS += ../gui/painting/qt_mips_asm_dsp_p.h