summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/LICENSE.siphash116
-rw-r--r--src/corelib/tools/qalgorithms.h665
-rw-r--r--src/corelib/tools/qalgorithms.qdoc642
-rw-r--r--src/corelib/tools/qarraydata.cpp324
-rw-r--r--src/corelib/tools/qarraydata.h439
-rw-r--r--src/corelib/tools/qarraydataops.h1073
-rw-r--r--src/corelib/tools/qarraydatapointer.h545
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.h127
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.qdoc123
-rw-r--r--src/corelib/tools/qbitarray.cpp513
-rw-r--r--src/corelib/tools/qbitarray.h228
-rw-r--r--src/corelib/tools/qcache.h374
-rw-r--r--src/corelib/tools/qcache.qdoc42
-rw-r--r--src/corelib/tools/qcommandlineoption.cpp88
-rw-r--r--src/corelib/tools/qcommandlineoption.h53
-rw-r--r--src/corelib/tools/qcommandlineparser.cpp251
-rw-r--r--src/corelib/tools/qcommandlineparser.h40
-rw-r--r--src/corelib/tools/qcontainerfwd.h106
-rw-r--r--src/corelib/tools/qcontainertools_impl.h478
-rw-r--r--src/corelib/tools/qcontiguouscache.cpp72
-rw-r--r--src/corelib/tools/qcontiguouscache.h410
-rw-r--r--src/corelib/tools/qcryptographichash.cpp1552
-rw-r--r--src/corelib/tools/qcryptographichash.h79
-rw-r--r--src/corelib/tools/qduplicatetracker_p.h124
-rw-r--r--src/corelib/tools/qeasingcurve.cpp157
-rw-r--r--src/corelib/tools/qeasingcurve.h57
-rw-r--r--src/corelib/tools/qflatmap_p.h1109
-rw-r--r--src/corelib/tools/qfreelist.cpp58
-rw-r--r--src/corelib/tools/qfreelist_p.h52
-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.cpp3431
-rw-r--r--src/corelib/tools/qhash.h3059
-rw-r--r--src/corelib/tools/qhashfunctions.h405
-rw-r--r--src/corelib/tools/qiterator.h175
-rw-r--r--src/corelib/tools/qiterator.qdoc937
-rw-r--r--src/corelib/tools/qline.cpp182
-rw-r--r--src/corelib/tools/qline.h226
-rw-r--r--src/corelib/tools/qlinkedlist.cpp1224
-rw-r--r--src/corelib/tools/qlinkedlist.h596
-rw-r--r--src/corelib/tools/qlist.cpp66
-rw-r--r--src/corelib/tools/qlist.h1056
-rw-r--r--src/corelib/tools/qlist.qdoc1629
-rw-r--r--src/corelib/tools/qmakearray_p.h50
-rw-r--r--src/corelib/tools/qmap.h2353
-rw-r--r--src/corelib/tools/qmap.qdoc (renamed from src/corelib/tools/qmap.cpp)1284
-rw-r--r--src/corelib/tools/qmargins.cpp197
-rw-r--r--src/corelib/tools/qmargins.h393
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.cpp305
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.h69
-rw-r--r--src/corelib/tools/qminimalflatset_p.h156
-rw-r--r--src/corelib/tools/qmultimap.qdoc1543
-rw-r--r--src/corelib/tools/qoffsetstringarray_p.h246
-rw-r--r--src/corelib/tools/qpair.h152
-rw-r--r--src/corelib/tools/qpair.qdoc283
-rw-r--r--src/corelib/tools/qpoint.cpp169
-rw-r--r--src/corelib/tools/qpoint.h519
-rw-r--r--src/corelib/tools/qqueue.cpp40
-rw-r--r--src/corelib/tools/qqueue.h45
-rw-r--r--src/corelib/tools/qrect.cpp346
-rw-r--r--src/corelib/tools/qrect.h715
-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.h113
-rw-r--r--src/corelib/tools/qscopedpointer.cpp93
-rw-r--r--src/corelib/tools/qscopedpointer.h175
-rw-r--r--src/corelib/tools/qscopedpointer_p.h148
-rw-r--r--src/corelib/tools/qscopedvaluerollback.cpp42
-rw-r--r--src/corelib/tools/qscopedvaluerollback.h57
-rw-r--r--src/corelib/tools/qscopeguard.h87
-rw-r--r--src/corelib/tools/qscopeguard.qdoc71
-rw-r--r--src/corelib/tools/qset.h207
-rw-r--r--src/corelib/tools/qset.qdoc303
-rw-r--r--src/corelib/tools/qshareddata.cpp155
-rw-r--r--src/corelib/tools/qshareddata.h381
-rw-r--r--src/corelib/tools/qshareddata_impl.h142
-rw-r--r--src/corelib/tools/qsharedpointer.cpp210
-rw-r--r--src/corelib/tools/qsharedpointer.h88
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h417
-rw-r--r--src/corelib/tools/qsimd.cpp718
-rw-r--r--src/corelib/tools/qsimd_p.h396
-rw-r--r--src/corelib/tools/qsimd_x86.cpp116
-rw-r--r--src/corelib/tools/qsimd_x86_p.h222
-rw-r--r--src/corelib/tools/qsize.cpp130
-rw-r--r--src/corelib/tools/qsize.h413
-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.cpp50
-rw-r--r--src/corelib/tools/qstack.h68
-rw-r--r--src/corelib/tools/qt_attribution.json15
-rw-r--r--src/corelib/tools/qtaggedpointer.h189
-rw-r--r--src/corelib/tools/qtaggedpointer.qdoc194
-rw-r--r--src/corelib/tools/qtimeline.cpp293
-rw-r--r--src/corelib/tools/qtimeline.h72
-rw-r--r--src/corelib/tools/qtools_p.h135
-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.h1217
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc406
-rw-r--r--src/corelib/tools/qvector.h1145
-rw-r--r--src/corelib/tools/qvector.qdoc1424
-rw-r--r--src/corelib/tools/qvector_msvc.cpp51
-rw-r--r--src/corelib/tools/qversionnumber.cpp289
-rw-r--r--src/corelib/tools/qversionnumber.h337
-rw-r--r--src/corelib/tools/tools.pri119
108 files changed, 24540 insertions, 19941 deletions
diff --git a/src/corelib/tools/LICENSE.siphash b/src/corelib/tools/LICENSE.siphash
new file mode 100644
index 0000000000..670154e353
--- /dev/null
+++ b/src/corelib/tools/LICENSE.siphash
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+<http://creativecommons.org/publicdomain/zero/1.0/>
diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h
index b01ce0db58..8889effece 100644
--- a/src/corelib/tools/qalgorithms.h
+++ b/src/corelib/tools/qalgorithms.h
@@ -1,317 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 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
-#include <QtCore/qglobal.h>
-
-#ifdef Q_CC_MSVC
-#include <intrin.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-
-/*
- Warning: The contents of QAlgorithmsPrivate is not a part of the public Qt API
- and may be changed from version to version or even be completely removed.
-*/
-namespace QAlgorithmsPrivate {
-
-#if QT_DEPRECATED_SINCE(5, 2)
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::sort") Q_OUTOFLINE_TEMPLATE void qSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan);
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::sort") inline void qSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy);
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::stable_sort") Q_OUTOFLINE_TEMPLATE void qStableSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan);
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::stable_sort") inline void qStableSortHelper(RandomAccessIterator, RandomAccessIterator, const T &);
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::lower_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan);
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::upper_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan);
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan);
-#endif // QT_DEPRECATED_SINCE(5, 2)
-
-}
-
-#if QT_DEPRECATED_SINCE(5, 2)
-template <typename InputIterator, typename OutputIterator>
-QT_DEPRECATED_X("Use std::copy") inline OutputIterator qCopy(InputIterator begin, InputIterator end, OutputIterator dest)
-{
- while (begin != end)
- *dest++ = *begin++;
- return dest;
-}
-
-template <typename BiIterator1, typename BiIterator2>
-QT_DEPRECATED_X("Use std::copy_backward") inline BiIterator2 qCopyBackward(BiIterator1 begin, BiIterator1 end, BiIterator2 dest)
-{
- while (begin != end)
- *--dest = *--end;
- return dest;
-}
-
-template <typename InputIterator1, typename InputIterator2>
-QT_DEPRECATED_X("Use std::equal") inline bool qEqual(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2)
-{
- for (; first1 != last1; ++first1, ++first2)
- if (!(*first1 == *first2))
- return false;
- return true;
-}
-
-template <typename ForwardIterator, typename T>
-QT_DEPRECATED_X("Use std::fill") inline void qFill(ForwardIterator first, ForwardIterator last, const T &val)
-{
- for (; first != last; ++first)
- *first = val;
-}
-
-template <typename Container, typename T>
-QT_DEPRECATED_X("Use std::fill") inline void qFill(Container &container, const T &val)
-{
- qFill(container.begin(), container.end(), val);
-}
-
-template <typename InputIterator, typename T>
-QT_DEPRECATED_X("Use std::find") inline InputIterator qFind(InputIterator first, InputIterator last, const T &val)
-{
- while (first != last && !(*first == val))
- ++first;
- return first;
-}
-
-template <typename Container, typename T>
-QT_DEPRECATED_X("Use std::find") inline typename Container::const_iterator qFind(const Container &container, const T &val)
-{
- return qFind(container.constBegin(), container.constEnd(), val);
-}
-
-template <typename InputIterator, typename T, typename Size>
-QT_DEPRECATED_X("Use std::count") inline void qCount(InputIterator first, InputIterator last, const T &value, Size &n)
-{
- for (; first != last; ++first)
- if (*first == value)
- ++n;
-}
-
-template <typename Container, typename T, typename Size>
-QT_DEPRECATED_X("Use std::count") inline void qCount(const Container &container, const T &value, Size &n)
-{
- qCount(container.constBegin(), container.constEnd(), value, n);
-}
-
-#ifdef Q_QDOC
-typedef void* LessThan;
-template <typename T> LessThan qLess();
-template <typename T> LessThan qGreater();
-#else
-template <typename T>
-class QT_DEPRECATED_X("Use std::less") qLess
-{
-public:
- inline bool operator()(const T &t1, const T &t2) const
- {
- return (t1 < t2);
- }
-};
-
-template <typename T>
-class QT_DEPRECATED_X("Use std::greater") qGreater
-{
-public:
- inline bool operator()(const T &t1, const T &t2) const
- {
- return (t2 < t1);
- }
-};
+#if 0
+#pragma qt_class(QtAlgorithms)
#endif
-template <typename RandomAccessIterator>
-QT_DEPRECATED_X("Use std::sort") inline void qSort(RandomAccessIterator start, RandomAccessIterator end)
-{
- if (start != end)
- QAlgorithmsPrivate::qSortHelper(start, end, *start);
-}
-
-template <typename RandomAccessIterator, typename LessThan>
-QT_DEPRECATED_X("Use std::sort") inline void qSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan)
-{
- if (start != end)
- QAlgorithmsPrivate::qSortHelper(start, end, *start, lessThan);
-}
+#include <QtCore/qglobal.h>
-template<typename Container>
-QT_DEPRECATED_X("Use std::sort") inline void qSort(Container &c)
-{
-#ifdef Q_CC_BOR
- // Work around Borland 5.5 optimizer bug
- c.detach();
+#if __has_include(<bit>) && __cplusplus > 201703L
+#include <bit>
#endif
- if (!c.empty())
- QAlgorithmsPrivate::qSortHelper(c.begin(), c.end(), *c.begin());
-}
-
-template <typename RandomAccessIterator>
-QT_DEPRECATED_X("Use std::stable_sort") inline void qStableSort(RandomAccessIterator start, RandomAccessIterator end)
-{
- if (start != end)
- QAlgorithmsPrivate::qStableSortHelper(start, end, *start);
-}
-template <typename RandomAccessIterator, typename LessThan>
-QT_DEPRECATED_X("Use std::stable_sort") inline void qStableSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan)
-{
- if (start != end)
- QAlgorithmsPrivate::qStableSortHelper(start, end, *start, lessThan);
-}
-
-template<typename Container>
-QT_DEPRECATED_X("Use std::stable_sort") inline void qStableSort(Container &c)
-{
-#ifdef Q_CC_BOR
- // Work around Borland 5.5 optimizer bug
- c.detach();
+#ifdef Q_CC_MSVC
+#include <intrin.h>
#endif
- if (!c.empty())
- QAlgorithmsPrivate::qStableSortHelper(c.begin(), c.end(), *c.begin());
-}
-
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::lower_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
-{
- // Implementation is duplicated from QAlgorithmsPrivate to keep existing code
- // compiling. We have to allow using *begin and value with different types,
- // and then implementing operator< for those types.
- RandomAccessIterator middle;
- int n = end - begin;
- int half;
-
- while (n > 0) {
- half = n >> 1;
- middle = begin + half;
- if (*middle < value) {
- begin = middle + 1;
- n -= half + 1;
- } else {
- n = half;
- }
- }
- return begin;
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::lower_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
-{
- return QAlgorithmsPrivate::qLowerBoundHelper(begin, end, value, lessThan);
-}
-
-template <typename Container, typename T>
-QT_DEPRECATED_X("Use std::lower_bound") Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qLowerBound(const Container &container, const T &value)
-{
- return QAlgorithmsPrivate::qLowerBoundHelper(container.constBegin(), container.constEnd(), value, qLess<T>());
-}
-
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::upper_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
-{
- // Implementation is duplicated from QAlgorithmsPrivate.
- RandomAccessIterator middle;
- int n = end - begin;
- int half;
-
- while (n > 0) {
- half = n >> 1;
- middle = begin + half;
- if (value < *middle) {
- n = half;
- } else {
- begin = middle + 1;
- n -= half + 1;
- }
- }
- return begin;
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::upper_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
-{
- return QAlgorithmsPrivate::qUpperBoundHelper(begin, end, value, lessThan);
-}
-
-template <typename Container, typename T>
-QT_DEPRECATED_X("Use std::upper_bound") Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qUpperBound(const Container &container, const T &value)
-{
- return QAlgorithmsPrivate::qUpperBoundHelper(container.constBegin(), container.constEnd(), value, qLess<T>());
-}
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
-{
- // Implementation is duplicated from QAlgorithmsPrivate.
- RandomAccessIterator it = qLowerBound(begin, end, value);
-
- if (it == end || value < *it)
- return end;
-
- return it;
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
-{
- return QAlgorithmsPrivate::qBinaryFindHelper(begin, end, value, lessThan);
-}
-
-template <typename Container, typename T>
-QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qBinaryFind(const Container &container, const T &value)
-{
- return QAlgorithmsPrivate::qBinaryFindHelper(container.constBegin(), container.constEnd(), value, qLess<T>());
-}
-#endif // QT_DEPRECATED_SINCE(5, 2)
+QT_BEGIN_NAMESPACE
template <typename ForwardIterator>
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
@@ -334,263 +41,68 @@ inline void qDeleteAll(const Container &c)
*/
namespace QAlgorithmsPrivate {
-#if QT_DEPRECATED_SINCE(5, 2)
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::sort") Q_OUTOFLINE_TEMPLATE void qSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan)
-{
-top:
- int span = int(end - start);
- if (span < 2)
- return;
-
- --end;
- RandomAccessIterator low = start, high = end - 1;
- RandomAccessIterator pivot = start + span / 2;
-
- if (lessThan(*end, *start))
- qSwap(*end, *start);
- if (span == 2)
- return;
-
- if (lessThan(*pivot, *start))
- qSwap(*pivot, *start);
- if (lessThan(*end, *pivot))
- qSwap(*end, *pivot);
- if (span == 3)
- return;
-
- qSwap(*pivot, *end);
-
- while (low < high) {
- while (low < high && lessThan(*low, *end))
- ++low;
-
- while (high > low && lessThan(*end, *high))
- --high;
-
- if (low < high) {
- qSwap(*low, *high);
- ++low;
- --high;
- } else {
- break;
- }
- }
-
- if (lessThan(*low, *end))
- ++low;
-
- qSwap(*end, *low);
- qSortHelper(start, low, t, lessThan);
-
- start = low + 1;
- ++end;
- goto top;
-}
-
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::sort") inline void qSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy)
-{
- qSortHelper(begin, end, dummy, qLess<T>());
-}
-
-template <typename RandomAccessIterator>
-QT_DEPRECATED_X("Use std::reverse") Q_OUTOFLINE_TEMPLATE void qReverse(RandomAccessIterator begin, RandomAccessIterator end)
-{
- --end;
- while (begin < end)
- qSwap(*begin++, *end--);
-}
-
-template <typename RandomAccessIterator>
-QT_DEPRECATED_X("Use std::rotate") Q_OUTOFLINE_TEMPLATE void qRotate(RandomAccessIterator begin, RandomAccessIterator middle, RandomAccessIterator end)
-{
- qReverse(begin, middle);
- qReverse(middle, end);
- qReverse(begin, end);
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::merge") Q_OUTOFLINE_TEMPLATE void qMerge(RandomAccessIterator begin, RandomAccessIterator pivot, RandomAccessIterator end, T &t, LessThan lessThan)
-{
- const int len1 = pivot - begin;
- const int len2 = end - pivot;
-
- if (len1 == 0 || len2 == 0)
- return;
-
- if (len1 + len2 == 2) {
- if (lessThan(*(begin + 1), *(begin)))
- qSwap(*begin, *(begin + 1));
- return;
- }
-
- RandomAccessIterator firstCut;
- RandomAccessIterator secondCut;
- int len2Half;
- if (len1 > len2) {
- const int len1Half = len1 / 2;
- firstCut = begin + len1Half;
- secondCut = qLowerBound(pivot, end, *firstCut, lessThan);
- len2Half = secondCut - pivot;
- } else {
- len2Half = len2 / 2;
- secondCut = pivot + len2Half;
- firstCut = qUpperBound(begin, pivot, *secondCut, lessThan);
- }
-
- qRotate(firstCut, pivot, secondCut);
- const RandomAccessIterator newPivot = firstCut + len2Half;
- qMerge(begin, firstCut, newPivot, t, lessThan);
- qMerge(newPivot, secondCut, end, t, lessThan);
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::stable_sort") Q_OUTOFLINE_TEMPLATE void qStableSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &t, LessThan lessThan)
-{
- const int span = end - begin;
- if (span < 2)
- return;
-
- const RandomAccessIterator middle = begin + span / 2;
- qStableSortHelper(begin, middle, t, lessThan);
- qStableSortHelper(middle, end, t, lessThan);
- qMerge(begin, middle, end, t, lessThan);
-}
-
-template <typename RandomAccessIterator, typename T>
-QT_DEPRECATED_X("Use std::stable_sort") inline void qStableSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy)
-{
- qStableSortHelper(begin, end, dummy, qLess<T>());
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::lower_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
-{
- RandomAccessIterator middle;
- int n = int(end - begin);
- int half;
-
- while (n > 0) {
- half = n >> 1;
- middle = begin + half;
- if (lessThan(*middle, value)) {
- begin = middle + 1;
- n -= half + 1;
- } else {
- n = half;
- }
- }
- return begin;
-}
-
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::upper_bound") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
-{
- RandomAccessIterator middle;
- int n = end - begin;
- int half;
-
- while (n > 0) {
- half = n >> 1;
- middle = begin + half;
- if (lessThan(value, *middle)) {
- n = half;
- } else {
- begin = middle + 1;
- n -= half + 1;
- }
- }
- return begin;
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
-{
- RandomAccessIterator it = qLowerBoundHelper(begin, end, value, lessThan);
-
- if (it == end || lessThan(value, *it))
- return end;
-
- return it;
-}
-
-#endif // QT_DEPRECATED_SINCE(5, 2)
-
-#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
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept
{
-# if QT_HAS_BUILTIN(__builtin_ctzs)
+# if __has_builtin(__builtin_ctzs)
return __builtin_ctzs(v);
# else
return __builtin_ctz(v);
# endif
}
#define QT_HAS_BUILTIN_CLZS
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept
{
-# if QT_HAS_BUILTIN(__builtin_clzs)
+# if __has_builtin(__builtin_clzs)
return __builtin_clzs(v);
# else
return __builtin_clz(v) - 16U;
# endif
}
#define QT_HAS_BUILTIN_CTZ
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctz(quint32 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_ctz(quint32 v) noexcept
{
return __builtin_ctz(v);
}
#define QT_HAS_BUILTIN_CLZ
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clz(quint32 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_clz(quint32 v) noexcept
{
return __builtin_clz(v);
}
#define QT_HAS_BUILTIN_CTZLL
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzll(quint64 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_ctzll(quint64 v) noexcept
{
return __builtin_ctzll(v);
}
#define QT_HAS_BUILTIN_CLZLL
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzll(quint64 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_clzll(quint64 v) noexcept
{
return __builtin_clzll(v);
}
#define QALGORITHMS_USE_BUILTIN_POPCOUNT
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcount(quint32 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_popcount(quint32 v) noexcept
{
return __builtin_popcount(v);
}
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcount(quint8 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_popcount(quint8 v) noexcept
{
return __builtin_popcount(v);
}
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcount(quint16 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_popcount(quint16 v) noexcept
{
return __builtin_popcount(v);
}
#define QALGORITHMS_USE_BUILTIN_POPCOUNTLL
-Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcountll(quint64 v) noexcept
+constexpr Q_ALWAYS_INLINE uint qt_builtin_popcountll(quint64 v) noexcept
{
return __builtin_popcountll(v);
}
#elif defined(Q_CC_MSVC) && !defined(Q_PROCESSOR_ARM)
-#define QT_POPCOUNT_CONSTEXPR
-#define QT_POPCOUNT_RELAXED_CONSTEXPR
#define QT_HAS_BUILTIN_CTZ
Q_ALWAYS_INLINE unsigned long qt_builtin_ctz(quint32 val)
{
@@ -650,6 +162,8 @@ Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept
// to generate code for those processors.
// So it's an acceptable compromise.
#if defined(__AVX__) || defined(__SSE4_2__) || defined(__POPCNT__)
+#define QT_POPCOUNT_CONSTEXPR
+#define QT_POPCOUNT_RELAXED_CONSTEXPR
#define QALGORITHMS_USE_BUILTIN_POPCOUNT
#define QALGORITHMS_USE_BUILTIN_POPCOUNTLL
Q_ALWAYS_INLINE uint qt_builtin_popcount(quint32 v) noexcept
@@ -676,18 +190,19 @@ 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 Q_DECL_CONSTEXPR
-#define QT_POPCOUNT_RELAXED_CONSTEXPR Q_DECL_RELAXED_CONSTEXPR
+#define QT_POPCOUNT_CONSTEXPR constexpr
+#define QT_POPCOUNT_RELAXED_CONSTEXPR constexpr
#endif
} //namespace QAlgorithmsPrivate
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint32 v) noexcept
{
-#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::popcount(v);
+#elif defined QALGORITHMS_USE_BUILTIN_POPCOUNT
return QAlgorithmsPrivate::qt_builtin_popcount(v);
#else
// See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
@@ -700,7 +215,9 @@ Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint32
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint8 v) noexcept
{
-#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::popcount(v);
+#elif defined QALGORITHMS_USE_BUILTIN_POPCOUNT
return QAlgorithmsPrivate::qt_builtin_popcount(v);
#else
return
@@ -710,7 +227,9 @@ Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint8
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint16 v) noexcept
{
-#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::popcount(v);
+#elif defined QALGORITHMS_USE_BUILTIN_POPCOUNT
return QAlgorithmsPrivate::qt_builtin_popcount(v);
#else
return
@@ -721,7 +240,9 @@ Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint16
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint64 v) noexcept
{
-#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNTLL
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::popcount(v);
+#elif defined QALGORITHMS_USE_BUILTIN_POPCOUNTLL
return QAlgorithmsPrivate::qt_builtin_popcountll(v);
#else
return
@@ -739,16 +260,14 @@ Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(long un
return qPopulationCount(static_cast<quint64>(v));
}
-#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
+#if defined(QALGORITHMS_USE_BUILTIN_POPCOUNT)
#undef QALGORITHMS_USE_BUILTIN_POPCOUNT
#endif
#undef QT_POPCOUNT_CONSTEXPR
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint32 v) noexcept
+namespace QtPrivate {
+constexpr inline uint qConstexprCountTrailingZeroBits(quint32 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZ)
- return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 32U;
-#else
// see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
@@ -759,59 +278,98 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint32 v) noexcept
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
-#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint8 v) noexcept
+constexpr inline uint qConstexprCountTrailingZeroBits(quint64 v) noexcept
+{
+ quint32 x = static_cast<quint32>(v);
+ return x ? qConstexprCountTrailingZeroBits(x)
+ : 32 + qConstexprCountTrailingZeroBits(static_cast<quint32>(v >> 32));
+}
+
+constexpr inline uint qConstexprCountTrailingZeroBits(quint8 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZ)
- return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 8U;
-#else
unsigned int c = 8; // c will be the number of zero bits on the right
- v &= -signed(v);
+ v &= quint8(-signed(v));
if (v) c--;
if (v & 0x0000000F) c -= 4;
if (v & 0x00000033) c -= 2;
if (v & 0x00000055) c -= 1;
return c;
-#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint16 v) noexcept
+constexpr inline uint qConstexprCountTrailingZeroBits(quint16 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZS)
- return v ? QAlgorithmsPrivate::qt_builtin_ctzs(v) : 16U;
-#else
unsigned int c = 16; // c will be the number of zero bits on the right
- v &= -signed(v);
+ v &= quint16(-signed(v));
if (v) c--;
if (v & 0x000000FF) c -= 8;
if (v & 0x00000F0F) c -= 4;
if (v & 0x00003333) c -= 2;
if (v & 0x00005555) c -= 1;
return c;
+}
+
+constexpr inline uint qConstexprCountTrailingZeroBits(unsigned long v) noexcept
+{
+ return qConstexprCountTrailingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
+}
+}
+
+constexpr inline uint qCountTrailingZeroBits(quint32 v) noexcept
+{
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countr_zero(v);
+#elif defined(QT_HAS_BUILTIN_CTZ)
+ return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 32U;
+#else
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint64 v) noexcept
+constexpr inline uint qCountTrailingZeroBits(quint8 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CTZLL)
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countr_zero(v);
+#elif defined(QT_HAS_BUILTIN_CTZ)
+ return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 8U;
+#else
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
+#endif
+}
+
+constexpr inline uint qCountTrailingZeroBits(quint16 v) noexcept
+{
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countr_zero(v);
+#elif defined(QT_HAS_BUILTIN_CTZS)
+ return v ? QAlgorithmsPrivate::qt_builtin_ctzs(v) : 16U;
+#else
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
+#endif
+}
+
+constexpr inline uint qCountTrailingZeroBits(quint64 v) noexcept
+{
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countr_zero(v);
+#elif defined(QT_HAS_BUILTIN_CTZLL)
return v ? QAlgorithmsPrivate::qt_builtin_ctzll(v) : 64;
#else
- quint32 x = static_cast<quint32>(v);
- return x ? qCountTrailingZeroBits(x)
- : 32 + qCountTrailingZeroBits(static_cast<quint32>(v >> 32));
+ return QtPrivate::qConstexprCountTrailingZeroBits(v);
#endif
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(unsigned long v) noexcept
+constexpr inline uint qCountTrailingZeroBits(unsigned long v) noexcept
{
return qCountTrailingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
}
-Q_DECL_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint32 v) noexcept
+QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint32 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CLZ)
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countl_zero(v);
+#elif defined(QT_HAS_BUILTIN_CLZ)
return v ? QAlgorithmsPrivate::qt_builtin_clz(v) : 32U;
#else
// Hacker's Delight, 2nd ed. Fig 5-16, p. 102
@@ -826,7 +384,9 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint32 v) noexcept
QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint8 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CLZ)
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countl_zero(v);
+#elif defined(QT_HAS_BUILTIN_CLZ)
return v ? QAlgorithmsPrivate::qt_builtin_clz(v)-24U : 8U;
#else
v = v | (v >> 1);
@@ -838,7 +398,9 @@ QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint8 v) noexce
QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint16 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CLZS)
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countl_zero(v);
+#elif defined(QT_HAS_BUILTIN_CLZS)
return v ? QAlgorithmsPrivate::qt_builtin_clzs(v) : 16U;
#else
v = v | (v >> 1);
@@ -851,7 +413,9 @@ QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint16 v) noexc
QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint64 v) noexcept
{
-#if defined(QT_HAS_BUILTIN_CLZLL)
+#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+ return std::countl_zero(v);
+#elif defined(QT_HAS_BUILTIN_CLZLL)
return v ? QAlgorithmsPrivate::qt_builtin_clzll(v) : 64U;
#else
v = v | (v >> 1);
@@ -869,7 +433,8 @@ QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(unsigned long v)
return qCountLeadingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
}
-QT_WARNING_POP
+#undef QT_POPCOUNT_RELAXED_CONSTEXPR
+
QT_END_NAMESPACE
#endif // QALGORITHMS_H
diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc
index c86e69f9c3..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
@@ -39,7 +16,7 @@
on all items in a given container or in a given range.
You can use these algorithms with any \l {container
class} that provides STL-style iterators, including Qt's QList,
- QLinkedList, QVector, QMap, and QHash classes.
+ QMap, and QHash classes.
Most algorithms take \l {STL-style iterators} as parameters. The
algorithms are generic in the sense that they aren't bound to a
@@ -47,38 +24,22 @@
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
compiler error, although not necessarily a very informative one.
- Some algorithms have special requirements on the value type
- stored in the containers. For example,
- qDeleteAll() requires that the value type is a
- non-const pointer type (for example, QWidget *). The value type
- requirements are specified for each algorithm, and the compiler
- will produce an error if a requirement isn't met.
+ Some algorithms have special requirements on the value type stored
+ in the containers. For example, qDeleteAll() requires that the
+ value type is a non-const pointer type (for example, QWidget
+ *). The value type requirements are specified for each algorithm,
+ and the compiler will produce an error if a requirement isn't met.
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
@@ -143,555 +104,11 @@
\row \li \c{i < j} \li returns \c true if iterator \c j comes after iterator \c i
\endtable
- QList and QVector's non-const iterator types are random access iterators.
-
- \section1 Qt and the STL Algorithms
-
- Historically, Qt used to provide functions which were direct equivalents of
- many STL algorithmic functions. Starting with Qt 5.0, you are instead
- encouraged to use directly the implementations available in the STL; most
- of the Qt ones have been deprecated (although they are still available to
- keep the old code compiling).
-
- \section2 Porting guidelines
-
- Most of the time, an application using the deprecated Qt algorithmic functions
- can be easily ported to use the equivalent STL functions. You need to:
-
- \list 1
- \li add the \c{#include <algorithm>} preprocessor directive;
- \li replace the Qt functions with the STL counterparts, according to the table below.
- \endlist
-
- \table
- \header
- \li Qt function
- \li STL function
- \row
- \li qBinaryFind
- \li \c std::binary_search or \c std::lower_bound
- \row
- \li qCopy
- \li \c std::copy
- \row
- \li qCopyBackward
- \li \c std::copy_backward
- \row
- \li qEqual
- \li \c std::equal
- \row
- \li qFill
- \li \c std::fill
- \row
- \li qFind
- \li \c std::find
- \row
- \li qCount
- \li \c std::count
- \row
- \li qSort
- \li \c std::sort
- \row
- \li qStableSort
- \li \c std::stable_sort
- \row
- \li qLowerBound
- \li \c std::lower_bound
- \row
- \li qUpperBound
- \li \c std::upper_bound
- \row
- \li qLess
- \li \c std::less
- \row
- \li qGreater
- \li \c std::greater
-
- \endtable
-
- The only cases in which the port may not be straightforward is if the old
- code relied on template specializations of the qLess() and/or the qSwap()
- functions, which were used internally by the implementations of the Qt
- algorithmic functions, but are instead ignored by the STL ones.
-
- In case the old code relied on the specialization of the qLess() functor,
- then a workaround is explicitly passing an instance of the qLess() class
- to the STL function, for instance like this:
-
- \code
- std::sort(container.begin(), container.end(), qLess<T>());
- \endcode
-
- Instead, since it's not possible to pass a custom swapper functor to STL
- functions, the only workaround for a template specialization for qSwap() is
- providing the same specialization for \c std::swap().
+ QList's non-const iterator type is random access iterator.
\sa {container classes}, <QtGlobal>
*/
-/*! \fn template <typename InputIterator, typename OutputIterator> OutputIterator qCopy(InputIterator begin1, InputIterator end1, OutputIterator begin2)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::copy instead.
-
- Copies the items from range [\a begin1, \a end1) to range [\a
- begin2, ...), in the order in which they appear.
-
- The item at position \a begin1 is assigned to that at position \a
- begin2; the item at position \a begin1 + 1 is assigned to that at
- position \a begin2 + 1; and so on.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 4
-
- \sa qCopyBackward(), {input iterators}, {output iterators}
-*/
-
-/*! \fn template <typename BiIterator1, typename BiIterator2> BiIterator2 qCopyBackward(BiIterator1 begin1, BiIterator1 end1, BiIterator2 end2)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::copy_backward instead.
-
- Copies the items from range [\a begin1, \a end1) to range [...,
- \a end2).
-
- The item at position \a end1 - 1 is assigned to that at position
- \a end2 - 1; the item at position \a end1 - 2 is assigned to that
- at position \a end2 - 2; and so on.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 5
-
- \sa qCopy(), {bidirectional iterators}
-*/
-
-/*! \fn template <typename InputIterator1, typename InputIterator2> bool qEqual(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::equal instead.
-
- Compares the items in the range [\a begin1, \a end1) with the
- items in the range [\a begin2, ...). Returns \c true if all the
- items compare equal; otherwise returns \c false.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 6
-
- This function requires the item type (in the example above,
- QString) to implement \c operator==().
-
- \sa {input iterators}
-*/
-
-/*! \fn template <typename ForwardIterator, typename T> void qFill(ForwardIterator begin, ForwardIterator end, const T &value)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::fill instead.
-
- Fills the range [\a begin, \a end) with \a value.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 7
-
- \sa qCopy(), {forward iterators}
-*/
-
-/*! \fn template <typename Container, typename T> void qFill(Container &container, const T &value)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::fill instead.
-
- This is the same as qFill(\a{container}.begin(), \a{container}.end(), \a value);
-*/
-
-/*! \fn template <typename InputIterator, typename T> InputIterator qFind(InputIterator begin, InputIterator end, const T &value)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::find instead.
-
- Returns an iterator to the first occurrence of \a value in a
- container in the range [\a begin, \a end). Returns \a end if \a
- value isn't found.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 8
-
- This function requires the item type (in the example above,
- QString) to implement \c operator==().
-
- If the items in the range are in ascending order, you can get
- faster results by using qLowerBound() or qBinaryFind() instead of
- qFind().
-
- \sa qBinaryFind(), {input iterators}
-*/
-
-/*! \fn template <typename Container, typename T> void qFind(const Container &container, const T &value)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::find instead.
-
- This is the same as qFind(\a{container}.constBegin(), \a{container}.constEnd(), \a value);
-*/
-
-/*! \fn template <typename InputIterator, typename T, typename Size> void qCount(InputIterator begin, InputIterator end, const T &value, Size &n)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::count instead.
-
- Returns the number of occurrences of \a value in the range [\a begin, \a end),
- which is returned in \a n. \a n is never initialized, the count is added to \a n.
- It is the caller's responsibility to initialize \a n.
-
- Example:
-
- \snippet code/doc_src_qalgorithms.cpp 9
-
- This function requires the item type (in the example above,
- \c int) to implement \c operator==().
-
- \sa {input iterators}
-*/
-
-/*! \fn template <typename Container, typename T, typename Size> void qCount(const Container &container, const T &value, Size &n)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::count instead.
-
- Instead of operating on iterators, as in the other overload, this function
- operates on the specified \a container to obtain the number of instances
- of \a value in the variable passed as a reference in argument \a n.
-*/
-
-/*! \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 RandomAccessIterator> void qSort(RandomAccessIterator begin, RandomAccessIterator end)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::sort instead.
-
- Sorts the items in range [\a begin, \a end) in ascending order
- using the quicksort algorithm.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 11
-
- The sort algorithm is efficient on large data sets. It operates
- in \l {linear-logarithmic time}, O(\e{n} log \e{n}).
-
- This function requires the item type (in the example above,
- \c{int}) to implement \c operator<().
-
- If neither of the two items is "less than" the other, the items are
- taken to be equal. It is then undefined which one of the two
- items will appear before the other after the sort.
-
- \sa qStableSort(), {random access iterators}
-*/
-
-/*! \fn template <typename RandomAccessIterator, typename LessThan> void qSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::sort instead.
-
- Uses the \a lessThan function instead of \c operator<() to
- compare the items.
-
- For example, here's how to sort the strings in a QStringList
- in case-insensitive alphabetical order:
-
- \snippet code/doc_src_qalgorithms.cpp 12
-
- To sort values in reverse order, pass
- \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For
- example:
-
- \snippet code/doc_src_qalgorithms.cpp 13
-
- If neither of the two items is "less than" the other, the items are
- taken to be equal. It is then undefined which one of the two
- items will appear before the other after the sort.
-
- An alternative to using qSort() is to put the items to sort in a
- QMap, using the sort key as the QMap key. This is often more
- convenient than defining a \a lessThan function. For example, the
- following code shows how to sort a list of strings case
- insensitively using QMap:
-
- \snippet code/doc_src_qalgorithms.cpp 14
-
- \sa QMap
-*/
-
-/*! \fn template<typename Container> void qSort(Container &container)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::sort instead.
-
- This is the same as qSort(\a{container}.begin(), \a{container}.end());
-*/
-
-/*!
- \fn template <typename RandomAccessIterator> void qStableSort(RandomAccessIterator begin, RandomAccessIterator end)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::stable_sort instead.
-
- Sorts the items in range [\a begin, \a end) in ascending order
- using a stable sorting algorithm.
-
- If neither of the two items is "less than" the other, the items are
- taken to be equal. The item that appeared before the other in the
- original container will still appear first after the sort. This
- property is often useful when sorting user-visible data.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 15
-
- The sort algorithm is efficient on large data sets. It operates
- in \l {linear-logarithmic time}, O(\e{n} log \e{n}).
-
- This function requires the item type (in the example above,
- \c{int}) to implement \c operator<().
-
- \sa qSort(), {random access iterators}
-*/
-
-/*!
- \fn template <typename RandomAccessIterator, typename LessThan> void qStableSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::stable_sort instead.
-
- Uses the \a lessThan function instead of \c operator<() to
- compare the items.
-
- For example, here's how to sort the strings in a QStringList
- in case-insensitive alphabetical order:
-
- \snippet code/doc_src_qalgorithms.cpp 16
-
- Note that earlier versions of Qt allowed using a lessThan function that took its
- arguments by non-const reference. From 4.3 and on this is no longer possible,
- the arguments has to be passed by const reference or value.
-
- To sort values in reverse order, pass
- \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For
- example:
-
- \snippet code/doc_src_qalgorithms.cpp 17
-
- If neither of the two items is "less than" the other, the items are
- taken to be equal. The item that appeared before the other in the
- original container will still appear first after the sort. This
- property is often useful when sorting user-visible data.
-*/
-
-/*!
- \fn template <typename Container> void qStableSort(Container &container)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::stable_sort instead.
-
- This is the same as qStableSort(\a{container}.begin(), \a{container}.end());
-*/
-
-/*! \fn template <typename RandomAccessIterator, typename T> RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::lower_bound instead.
-
- Performs a binary search of the range [\a begin, \a end) and
- returns the position of the first occurrence of \a value. If no
- such item is found, returns the position where it should be
- inserted.
-
- The items in the range [\a begin, \e end) must be sorted in
- ascending order; see qSort().
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 18
-
- This function requires the item type (in the example above,
- \c{int}) to implement \c operator<().
-
- qLowerBound() can be used in conjunction with qUpperBound() to
- iterate over all occurrences of the same value:
-
- \snippet code/doc_src_qalgorithms.cpp 19
-
- \sa qUpperBound(), qBinaryFind()
-*/
-
-/*!
- \fn template <typename RandomAccessIterator, typename T, typename LessThan> RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::lower_bound instead.
-
- Uses the \a lessThan function instead of \c operator<() to
- compare the items.
-
- Note that the items in the range must be sorted according to the order
- specified by the \a lessThan object.
-*/
-
-/*!
- \fn template <typename Container, typename T> void qLowerBound(const Container &container, const T &value)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::lower_bound instead.
-
- For read-only iteration over containers, this function is broadly equivalent to
- qLowerBound(\a{container}.begin(), \a{container}.end(), value). However, since it
- returns a const iterator, you cannot use it to modify the container; for example,
- to insert items.
-*/
-
-/*! \fn template <typename RandomAccessIterator, typename T> RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::upper_bound instead.
-
- Performs a binary search of the range [\a begin, \a end) and
- returns the position of the one-past-the-last occurrence of \a
- value. If no such item is found, returns the position where the
- item should be inserted.
-
- The items in the range [\a begin, \e end) must be sorted in
- ascending order; see qSort().
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 20
-
- This function requires the item type (in the example above,
- \c{int}) to implement \c operator<().
-
- qUpperBound() can be used in conjunction with qLowerBound() to
- iterate over all occurrences of the same value:
-
- \snippet code/doc_src_qalgorithms.cpp 21
-
- \sa qLowerBound(), qBinaryFind()
-*/
-
-/*!
- \fn template <typename RandomAccessIterator, typename T, typename LessThan> RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::upper_bound instead.
-
- Uses the \a lessThan function instead of \c operator<() to
- compare the items.
-
- Note that the items in the range must be sorted according to the order
- specified by the \a lessThan object.
-*/
-
-/*!
- \fn template <typename Container, typename T> void qUpperBound(const Container &container, const T &value)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::upper_bound instead.
-
- This is the same as qUpperBound(\a{container}.begin(), \a{container}.end(), \a value);
-*/
-
-
-/*! \fn template <typename RandomAccessIterator, typename T> RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value)
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::binary_search or \c std::lower_bound instead.
-
- Performs a binary search of the range [\a begin, \a end) and
- returns the position of an occurrence of \a value. If there are
- no occurrences of \a value, returns \a end.
-
- The items in the range [\a begin, \a end) must be sorted in
- ascending order; see qSort().
-
- If there are many occurrences of the same value, any one of them
- could be returned. Use qLowerBound() or qUpperBound() if you need
- finer control.
-
- Example:
- \snippet code/doc_src_qalgorithms.cpp 22
-
- This function requires the item type (in the example above,
- QString) to implement \c operator<().
-
- \sa qLowerBound(), qUpperBound(), {random access iterators}
-*/
-
-/*! \fn template <typename RandomAccessIterator, typename T, typename LessThan> RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::binary_search or \c std::lower_bound instead.
-
- Uses the \a lessThan function instead of \c operator<() to
- compare the items.
-
- Note that the items in the range must be sorted according to the order
- specified by the \a lessThan object.
-*/
-
-/*!
- \fn template <typename Container, typename T> void qBinaryFind(const Container &container, const T &value)
- \relates <QtAlgorithms>
- \deprecated
- \overload
-
- Use \c std::binary_search or \c std::lower_bound instead.
-
- This is the same as qBinaryFind(\a{container}.begin(), \a{container}.end(), \a value);
-*/
-
-
/*!
\fn template <typename ForwardIterator> void qDeleteAll(ForwardIterator begin, ForwardIterator end)
\relates <QtAlgorithms>
@@ -701,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
@@ -724,39 +141,6 @@
This is the same as qDeleteAll(\a{c}.begin(), \a{c}.end()).
*/
-/*! \fn template <typename LessThan> LessThan qLess()
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::less instead.
-
- Returns a functional object, or functor, that can be passed to qSort()
- or qStableSort().
-
- Example:
-
- \snippet code/doc_src_qalgorithms.cpp 24
-
- \sa {qGreater()}{qGreater<T>()}
-*/
-
-/*! \fn template <typename LessThan> LessThan qGreater()
- \relates <QtAlgorithms>
- \deprecated
-
- Use \c std::greater instead.
-
- Returns a functional object, or functor, that can be passed to qSort()
- or qStableSort().
-
- Example:
-
- \snippet code/doc_src_qalgorithms.cpp 25
-
- \sa {qLess()}{qLess<T>()}
-*/
-
-
/*!
\fn uint qPopulationCount(quint8 v)
\relates <QtAlgorithms>
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index ed7dfe2e41..6aebd4306a 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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>
#include <QtCore/private/qtools_p.h>
#include <QtCore/qmath.h>
+#include <QtCore/qbytearray.h> // QBA::value_type
+#include <QtCore/qstring.h> // QString::value_type
+
#include <stdlib.h>
QT_BEGIN_NAMESPACE
@@ -52,7 +19,7 @@ QT_BEGIN_NAMESPACE
* containers to allocate memory and grow the memory block during append
* operations.
*
- * They take size_t parameters and return size_t so they will change sizes
+ * They take qsizetype parameters and return qsizetype so they will change sizes
* according to the pointer width. However, knowing Qt containers store the
* container size and element indexes in ints, these functions never return a
* size larger than INT_MAX. This is done by casting the element count and
@@ -79,29 +46,21 @@ QT_BEGIN_NAMESPACE
Both \a elementCount and \a headerSize can be zero, but \a elementSize
cannot.
- This function returns SIZE_MAX (~0) on overflow or if the memory block size
- would not fit an int.
+ This function returns -1 on overflow or if the memory block size
+ would not fit a qsizetype.
*/
-size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t headerSize) noexcept
+qsizetype qCalculateBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize) noexcept
{
- unsigned count = unsigned(elementCount);
- unsigned size = unsigned(elementSize);
- unsigned header = unsigned(headerSize);
Q_ASSERT(elementSize);
- Q_ASSERT(size == elementSize);
- Q_ASSERT(header == headerSize);
-
- if (Q_UNLIKELY(count != elementCount))
- return std::numeric_limits<size_t>::max();
- unsigned bytes;
- if (Q_UNLIKELY(mul_overflow(size, count, &bytes)) ||
- Q_UNLIKELY(add_overflow(bytes, header, &bytes)))
- return std::numeric_limits<size_t>::max();
- if (Q_UNLIKELY(int(bytes) < 0)) // catches bytes >= 2GB
- return std::numeric_limits<size_t>::max();
+ size_t 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;
- return bytes;
+ return qsizetype(bytes);
}
/*!
@@ -116,171 +75,192 @@ size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t heade
Both \a elementCount and \a headerSize can be zero, but \a elementSize
cannot.
- This function returns SIZE_MAX (~0) on overflow or if the memory block size
- would not fit an int.
+ This function returns -1 on overflow or if the memory block size
+ would not fit a qsizetype.
\note The memory block may contain up to \a elementSize - 1 bytes more than
needed.
*/
CalculateGrowingBlockSizeResult
-qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t headerSize) noexcept
+qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize) noexcept
{
CalculateGrowingBlockSizeResult result = {
- std::numeric_limits<size_t>::max(),std::numeric_limits<size_t>::max()
+ qsizetype(-1), qsizetype(-1)
};
- unsigned bytes = unsigned(qCalculateBlockSize(elementCount, elementSize, headerSize));
- if (int(bytes) < 0) // catches std::numeric_limits<size_t>::max()
+ qsizetype bytes = qCalculateBlockSize(elementCount, elementSize, headerSize);
+ if (bytes < 0)
return result;
- unsigned morebytes = qNextPowerOfTwo(bytes);
- if (Q_UNLIKELY(int(morebytes) < 0)) {
- // catches morebytes == 2GB
+ size_t morebytes = static_cast<size_t>(qNextPowerOfTwo(quint64(bytes)));
+ if (Q_UNLIKELY(qsizetype(morebytes) < 0)) {
// grow by half the difference between bytes and morebytes
+ // this slows the growth and avoids trying to allocate exactly
+ // 2G of memory (on 32bit), something that many OSes can't deliver
bytes += (morebytes - bytes) / 2;
} else {
- bytes = morebytes;
+ bytes = qsizetype(morebytes);
}
- result.elementCount = (bytes - unsigned(headerSize)) / unsigned(elementSize);
+ result.elementCount = (bytes - headerSize) / elementSize;
result.size = result.elementCount * elementSize + headerSize;
return result;
}
-// End of qtools_p.h implementation
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
-
-const QArrayData QArrayData::shared_null[2] = {
- { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared null
- /* zero initialized terminator */};
-
-static const QArrayData qt_array[3] = {
- { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared empty
- { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, sizeof(QArrayData) }, // unsharable empty
- /* zero initialized terminator */};
-
-QT_WARNING_POP
+/*
+ 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.
-static const QArrayData &qt_array_empty = qt_array[0];
-static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
- uint options)
+ Returns a structure containing the size in bytes and elements available.
+*/
+static inline CalculateGrowingBlockSizeResult
+calculateBlockSize(qsizetype capacity, qsizetype objectSize, qsizetype headerSize, QArrayData::AllocationOption option)
{
- // Calculate the byte size
+ // 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;
+
// allocSize = objectSize * capacity + headerSize, but checked for overflow
// plus padded to grow in size
- if (options & QArrayData::Grow) {
- 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 *reallocateData(QArrayData *header, size_t allocSize, uint options)
+static QArrayData *allocateData(qsizetype allocSize)
{
- header = static_cast<QArrayData *>(::realloc(header, allocSize));
- if (header)
- header->capacityReserved = bool(options & QArrayData::CapacityReserved);
+ QArrayData *header = static_cast<QArrayData *>(::malloc(size_t(allocSize)));
+ if (header) {
+ header->ref_.storeRelaxed(1);
+ header->flags = {};
+ header->alloc = 0;
+ }
return header;
}
-QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
- size_t capacity, AllocationOptions options) noexcept
-{
- // Alignment is a power of two
- Q_ASSERT(alignment >= alignof(QArrayData)
- && !(alignment & (alignment - 1)));
-
- // Don't allocate empty headers
- if (!(options & RawData) && !capacity)
- return const_cast<QArrayData *>(&qt_array_empty);
-
- size_t headerSize = sizeof(QArrayData);
+namespace {
+struct AllocationResult {
+ void *data;
+ QArrayData *header;
+};
+}
+using QtPrivate::AlignedQArrayData;
- // Allocate extra (alignment - alignof(QArrayData)) padding bytes so we
- // can properly align the data array. This assumes malloc is able to
- // provide appropriate alignment for the header -- as it should!
- // Padding is skipped when allocating a header for RawData.
- if (!(options & RawData))
- headerSize += (alignment - alignof(QArrayData));
+static inline AllocationResult
+allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
+ QArrayData::AllocationOption option) noexcept
+{
+ if (capacity == 0)
+ return {};
+
+ qsizetype headerSize = sizeof(AlignedQArrayData);
+ const qsizetype headerAlignment = alignof(AlignedQArrayData);
+
+ if (alignment > headerAlignment) {
+ // 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);
- if (headerSize > size_t(MaxAllocSize))
- 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 {};
- size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
- QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
+ QArrayData *header = allocateData(allocSize);
+ void *data = nullptr;
if (header) {
- quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
- & ~(alignment - 1);
-
- header->ref.atomic.storeRelaxed(1);
- header->size = 0;
- header->alloc = capacity;
- header->capacityReserved = bool(options & CapacityReserved);
- header->offset = data - quintptr(header);
+ // find where offset should point to so that data() is aligned to alignment bytes
+ data = QTypedArrayData<void>::dataStart(header, alignment);
+ header->alloc = qsizetype(capacity);
}
- return header;
+ return { data, header };
}
-QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity,
- AllocationOptions options) noexcept
+// Generic size and alignment allocation function
+void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
+ qsizetype capacity, AllocationOption option) noexcept
{
- Q_ASSERT(data);
- Q_ASSERT(data->isMutable());
- Q_ASSERT(!data->ref.isShared());
-
- size_t headerSize = sizeof(QArrayData);
- size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
- QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options));
- if (header)
- header->alloc = capacity;
- return header;
+ 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;
}
-void QArrayData::deallocate(QArrayData *data, size_t objectSize,
- size_t alignment) noexcept
+// Fixed size and alignment allocation functions
+void *QArrayData::allocate1(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
{
- // Alignment is a power of two
- Q_ASSERT(alignment >= alignof(QArrayData)
- && !(alignment & (alignment - 1)));
- Q_UNUSED(objectSize) Q_UNUSED(alignment)
+ Q_ASSERT(dptr);
- Q_ASSERT_X(data == 0 || !data->ref.isStatic(), "QArrayData::deallocate",
- "Static data cannot be deleted");
- ::free(data);
+ auto r = allocateHelper(1, alignof(AlignedQArrayData), capacity, option);
+ *dptr = r.header;
+ return r.data;
}
-namespace QtPrivate {
-/*!
- \internal
-*/
-QContainerImplHelper::CutResult QContainerImplHelper::mid(int originalLength, int *_position, int *_length)
+void *QArrayData::allocate2(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
{
- int &position = *_position;
- int &length = *_length;
- if (position > originalLength)
- return Null;
-
- if (position < 0) {
- if (length < 0 || length + position >= originalLength)
- return Full;
- if (length + position <= 0)
- return Null;
- length += position;
- position = 0;
- } else if (uint(length) > uint(originalLength - position)) {
- length = originalLength - position;
- }
+ Q_ASSERT(dptr);
- if (position == 0 && length == originalLength)
- return Full;
+ auto r = allocateHelper(2, alignof(AlignedQArrayData), capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
- return length > 0 ? Subset : Empty;
+std::pair<QArrayData *, void *>
+QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
+ qsizetype objectSize, qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(!data || !data->isShared());
+
+ const qsizetype headerSize = sizeof(AlignedQArrayData);
+ auto r = calculateBlockSize(capacity, objectSize, headerSize, option);
+ qsizetype allocSize = r.size;
+ capacity = r.elementCount;
+ if (Q_UNLIKELY(allocSize < 0))
+ return {};
+
+ 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->alloc = capacity;
+ dataPointer = reinterpret_cast<char *>(header) + offset;
+ } else {
+ dataPointer = nullptr;
+ }
+ return {header, dataPointer};
}
+
+void QArrayData::deallocate(QArrayData *data, qsizetype objectSize,
+ qsizetype alignment) noexcept
+{
+ // Alignment is a power of two
+ Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
+ && !(alignment & (alignment - 1)));
+ Q_UNUSED(objectSize);
+ Q_UNUSED(alignment);
+
+ ::free(data);
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index 0063cf046f..da83fc1a21 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -1,346 +1,223 @@
-/****************************************************************************
-**
-** 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.
+// 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/qrefcount.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qatomic.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qcontainerfwd.h>
#include <string.h>
QT_BEGIN_NAMESPACE
-struct Q_CORE_EXPORT QArrayData
+#if __has_cpp_attribute(gnu::malloc)
+# define Q_DECL_MALLOCLIKE [[nodiscard, gnu::malloc]]
+#else
+# define Q_DECL_MALLOCLIKE [[nodiscard]]
+#endif
+
+template <class T> struct QTypedArrayData;
+
+struct QArrayData
{
- QtPrivate::RefCount ref;
- int size;
- uint alloc : 31;
- uint capacityReserved : 1;
+ enum AllocationOption {
+ Grow,
+ KeepSize
+ };
- qptrdiff offset; // in bytes from beginning of header
+ enum GrowthPosition {
+ GrowsAtEnd,
+ GrowsAtBeginning
+ };
- void *data()
+ enum ArrayOption {
+ ArrayOptionDefault = 0,
+ CapacityReserved = 0x1 //!< the capacity was reserved by the user, try to keep it
+ };
+ Q_DECLARE_FLAGS(ArrayOptions, ArrayOption)
+
+ QBasicAtomicInt ref_;
+ ArrayOptions flags;
+ qsizetype alloc;
+
+ qsizetype allocatedCapacity() noexcept
{
- Q_ASSERT(size == 0
- || offset < 0 || size_t(offset) >= sizeof(QArrayData));
- return reinterpret_cast<char *>(this) + offset;
+ return alloc;
}
- const void *data() const
+ qsizetype constAllocatedCapacity() const noexcept
{
- Q_ASSERT(size == 0
- || offset < 0 || size_t(offset) >= sizeof(QArrayData));
- return reinterpret_cast<const char *>(this) + offset;
+ return alloc;
}
- // This refers to array data mutability, not "header data" represented by
- // data members in QArrayData. Shared data (array and header) must still
- // follow COW principles.
- bool isMutable() const
+ /// Returns true if sharing took place
+ bool ref() noexcept
{
- return alloc != 0;
+ ref_.ref();
+ return true;
}
- enum AllocationOption {
- CapacityReserved = 0x1,
- RawData = 0x4,
- Grow = 0x8,
-
- Default = 0
- };
-
- Q_DECLARE_FLAGS(AllocationOptions, AllocationOption)
-
- size_t detachCapacity(size_t newSize) const
+ /// Returns false if deallocation is necessary
+ bool deref() noexcept
{
- if (capacityReserved && newSize < alloc)
- return alloc;
- return newSize;
+ return ref_.deref();
}
- AllocationOptions detachFlags() const
+ bool isShared() const noexcept
{
- AllocationOptions result;
- if (capacityReserved)
- result |= CapacityReserved;
- return result;
+ return ref_.loadRelaxed() != 1;
}
- AllocationOptions cloneFlags() const
+ // 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() noexcept
{
- AllocationOptions result;
- if (capacityReserved)
- result |= CapacityReserved;
- return result;
+ return ref_.loadRelaxed() > 1;
}
- Q_REQUIRED_RESULT static QArrayData *allocate(size_t objectSize, size_t alignment,
- size_t capacity, AllocationOptions options = Default) noexcept;
- Q_REQUIRED_RESULT static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,
- size_t newCapacity, AllocationOptions newOptions = Default) noexcept;
- static void deallocate(QArrayData *data, size_t objectSize,
- size_t alignment) noexcept;
+ qsizetype detachCapacity(qsizetype newSize) const noexcept
+ {
+ if (flags & CapacityReserved && newSize < constAllocatedCapacity())
+ return constAllocatedCapacity();
+ return newSize;
+ }
- static const QArrayData shared_null[2];
- static QArrayData *sharedNull() noexcept { return const_cast<QArrayData*>(shared_null); }
+ 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::AllocationOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions)
-template <class T>
-struct QTypedArrayData
- : QArrayData
-{
-#ifdef QT_STRICT_ITERATORS
- class iterator {
- public:
- T *i;
- typedef std::random_access_iterator_tag iterator_category;
- typedef int difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
-
- inline iterator() : i(nullptr) {}
- inline iterator(T *n) : i(n) {}
- inline iterator(const iterator &o): i(o.i){} // #### Qt 6: remove, the implicit version is fine
- inline T &operator*() const { return *i; }
- inline T *operator->() const { return i; }
- inline T &operator[](int j) const { return *(i + j); }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
- inline bool operator<(const iterator& other) const { return i < other.i; }
- inline bool operator<=(const iterator& other) const { return i <= other.i; }
- inline bool operator>(const iterator& other) const { return i > other.i; }
- inline bool operator>=(const iterator& other) const { return i >= other.i; }
- inline iterator &operator++() { ++i; return *this; }
- inline iterator operator++(int) { T *n = i; ++i; return n; }
- inline iterator &operator--() { i--; return *this; }
- inline iterator operator--(int) { T *n = i; i--; return n; }
- inline iterator &operator+=(int j) { i+=j; return *this; }
- inline iterator &operator-=(int j) { i-=j; return *this; }
- inline iterator operator+(int j) const { return iterator(i+j); }
- inline iterator operator-(int j) const { return iterator(i-j); }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
- inline int operator-(iterator j) const { return i - j.i; }
- inline operator T*() const { return i; }
- };
- friend class iterator;
-
- class const_iterator {
- public:
- const T *i;
- typedef std::random_access_iterator_tag iterator_category;
- typedef int difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
-
- inline const_iterator() : i(nullptr) {}
- inline const_iterator(const T *n) : i(n) {}
- inline const_iterator(const const_iterator &o): i(o.i) {} // #### Qt 6: remove, the default version is fine
- inline explicit const_iterator(const iterator &o): i(o.i) {}
- inline const T &operator*() const { return *i; }
- inline const T *operator->() const { return i; }
- inline const T &operator[](int j) const { return *(i + j); }
- inline bool operator==(const const_iterator &o) const { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const { return i != o.i; }
- inline bool operator<(const const_iterator& other) const { return i < other.i; }
- inline bool operator<=(const const_iterator& other) const { return i <= other.i; }
- inline bool operator>(const const_iterator& other) const { return i > other.i; }
- inline bool operator>=(const const_iterator& other) const { return i >= other.i; }
- inline const_iterator &operator++() { ++i; return *this; }
- inline const_iterator operator++(int) { const T *n = i; ++i; return n; }
- inline const_iterator &operator--() { i--; return *this; }
- inline const_iterator operator--(int) { const T *n = i; i--; return n; }
- inline const_iterator &operator+=(int j) { i+=j; return *this; }
- inline const_iterator &operator-=(int j) { i-=j; return *this; }
- inline const_iterator operator+(int j) const { return const_iterator(i+j); }
- inline const_iterator operator-(int j) const { return const_iterator(i-j); }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
- inline int operator-(const_iterator j) const { return i - j.i; }
- inline operator const T*() const { return i; }
- };
- friend class const_iterator;
+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
- typedef T* iterator;
- typedef const T* const_iterator;
+constexpr size_t MaxPrimitiveAlignment = alignof(std::max_align_t);
#endif
- T *data() { return static_cast<T *>(QArrayData::data()); }
- const T *data() const { return static_cast<const T *>(QArrayData::data()); }
-
- iterator begin(iterator = iterator()) { return data(); }
- iterator end(iterator = iterator()) { return data() + size; }
- const_iterator begin(const_iterator = const_iterator()) const { return data(); }
- const_iterator end(const_iterator = const_iterator()) const { return data() + size; }
- const_iterator constBegin(const_iterator = const_iterator()) const { return data(); }
- const_iterator constEnd(const_iterator = const_iterator()) const { return data() + size; }
+struct alignas(MaxPrimitiveAlignment) AlignedQArrayData : QArrayData
+{
+};
+}
- class AlignmentDummy { QArrayData header; T data; };
+template <class T>
+struct QTypedArrayData
+ : QArrayData
+{
+ struct AlignmentDummy { QtPrivate::AlignedQArrayData header; T data; };
- Q_REQUIRED_RESULT static QTypedArrayData *allocate(size_t capacity,
- AllocationOptions options = Default)
+ [[nodiscard]] static std::pair<QTypedArrayData *, T *> allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize)
{
- Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T),
- alignof(AlignmentDummy), capacity, options));
+ static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ QArrayData *d;
+ 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 {static_cast<QTypedArrayData *>(d), static_cast<T *>(result)};
}
- static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,
- AllocationOptions options = Default)
+ static std::pair<QTypedArrayData *, T *>
+ reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity, AllocationOption option)
{
- Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),
- capacity, options));
+ static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ 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)
+ static void deallocate(QArrayData *data) noexcept
{
- Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
QArrayData::deallocate(data, sizeof(T), alignof(AlignmentDummy));
}
- static QTypedArrayData *fromRawData(const T *data, size_t n,
- AllocationOptions options = Default)
+ static T *dataStart(QArrayData *data, qsizetype alignment) noexcept
{
- Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- QTypedArrayData *result = allocate(0, options | RawData);
- if (result) {
- Q_ASSERT(!result->ref.isShared()); // No shared empty, please!
-
- result->offset = reinterpret_cast<const char *>(data)
- - reinterpret_cast<const char *>(result);
- result->size = int(n);
- }
- return result;
+ // Alignment is a power of two
+ Q_ASSERT(alignment >= qsizetype(alignof(QArrayData)) && !(alignment & (alignment - 1)));
+ void *start = reinterpret_cast<void *>(
+ (quintptr(data) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1));
+ return static_cast<T *>(start);
}
- static QTypedArrayData *sharedNull() noexcept
+ constexpr static qsizetype max_size() noexcept
{
- Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return static_cast<QTypedArrayData *>(QArrayData::sharedNull());
- }
-
- static QTypedArrayData *sharedEmpty()
- {
- Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
- return allocate(/* capacity */ 0);
+ // -1 to deal with the pointer one-past-the-end
+ return (QtPrivate::MaxAllocSize - sizeof(QtPrivate::AlignedQArrayData) - 1) / sizeof(T);
}
};
-template <class T, size_t N>
-struct QStaticArrayData
-{
- QArrayData header;
- T data[N];
-};
-
-// Support for returning QArrayDataPointer<T> from functions
-template <class T>
-struct QArrayDataPointerRef
-{
- QTypedArrayData<T> *ptr;
-};
-
-#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
- { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
- /**/
-
-#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) \
- Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size,\
- ((sizeof(QArrayData) + (alignof(type) - 1)) & ~(alignof(type) - 1) )) \
- /**/
-
-////////////////////////////////////////////////////////////////////////////////
-// Q_ARRAY_LITERAL
-
-// The idea here is to place a (read-only) copy of header and array data in an
-// mmappable portion of the executable (typically, .rodata section). This is
-// accomplished by hiding a static const instance of QStaticArrayData, which is
-// POD.
-
-// Hide array inside a lambda
-#define Q_ARRAY_LITERAL(Type, ...) \
- ([]() -> QArrayDataPointerRef<Type> { \
- /* MSVC 2010 Doesn't support static variables in a lambda, but */ \
- /* happily accepts them in a static function of a lambda-local */ \
- /* struct :-) */ \
- struct StaticWrapper { \
- static QArrayDataPointerRef<Type> get() \
- { \
- Q_ARRAY_LITERAL_IMPL(Type, __VA_ARGS__) \
- return ref; \
- } \
- }; \
- return StaticWrapper::get(); \
- }()) \
- /**/
-
-#ifdef Q_COMPILER_CONSTEXPR
-#define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) Q_STATIC_ASSERT(std::is_literal_type<Type>::value)
-#else
-#define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) do {} while (0)
-#endif
-
-#define Q_ARRAY_LITERAL_IMPL(Type, ...) \
- Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type); \
- \
- /* Portable compile-time array size computation */ \
- Q_CONSTEXPR Type data[] = { __VA_ARGS__ }; Q_UNUSED(data); \
- enum { Size = sizeof(data) / sizeof(data[0]) }; \
- \
- static const QStaticArrayData<Type, Size> literal = { \
- Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } }; \
- \
- QArrayDataPointerRef<Type> ref = \
- { static_cast<QTypedArrayData<Type> *>( \
- const_cast<QArrayData *>(&literal.header)) }; \
- /**/
-
namespace QtPrivate {
struct Q_CORE_EXPORT QContainerImplHelper
{
enum CutResult { Null, Empty, Full, Subset };
- static CutResult mid(int originalLength, int *position, int *length);
+ static constexpr CutResult mid(qsizetype originalLength, qsizetype *_position, qsizetype *_length)
+ {
+ qsizetype &position = *_position;
+ qsizetype &length = *_length;
+ if (position > originalLength) {
+ position = 0;
+ length = 0;
+ return Null;
+ }
+
+ if (position < 0) {
+ if (length < 0 || length + position >= originalLength) {
+ position = 0;
+ length = originalLength;
+ return Full;
+ }
+ if (length + position <= 0) {
+ position = length = 0;
+ return Null;
+ }
+ length += position;
+ position = 0;
+ } else if (size_t(length) > size_t(originalLength - position)) {
+ length = originalLength - position;
+ }
+
+ if (position == 0 && length == originalLength)
+ return Full;
+
+ return length > 0 ? Subset : Empty;
+ }
};
}
+#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 8e19525f07..c3e9821e81 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -1,187 +1,378 @@
-/****************************************************************************
-**
-** 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.
+// 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 <memory>
#include <new>
#include <string.h>
+#include <utility>
+#include <iterator>
+#include <tuple>
+#include <type_traits>
QT_BEGIN_NAMESPACE
-namespace QtPrivate {
+template <class T> struct QArrayDataPointer;
-QT_WARNING_PUSH
-#if defined(Q_CC_GNU) && Q_CC_GNU >= 700
-QT_WARNING_DISABLE_GCC("-Wstringop-overflow")
-#endif
+namespace QtPrivate {
template <class T>
struct QPodArrayOps
- : QTypedArrayData<T>
+ : public QArrayDataPointer<T>
{
- void appendInitialize(size_t newSize)
+ 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:
+ typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
+
+ using QArrayDataPointer<T>::QArrayDataPointer;
+
+ void appendInitialize(qsizetype newSize) noexcept
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(newSize > uint(this->size));
- Q_ASSERT(newSize <= this->alloc);
-
- ::memset(static_cast<void *>(this->end()), 0, (newSize - this->size) * sizeof(T));
- this->size = int(newSize);
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
+
+ T *where = this->end();
+ this->size = newSize;
+ const T *e = this->end();
+ while (where != e)
+ *where++ = T();
}
- void copyAppend(const T *b, const T *e)
+ void copyAppend(const T *b, const T *e) noexcept
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(b < e);
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(b <= e);
+ Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
+
+ if (b == e)
+ return;
- ::memcpy(static_cast<void *>(this->end()), static_cast<const void *>(b),
- (e - b) * sizeof(T));
- this->size += e - b;
+ ::memcpy(static_cast<void *>(this->end()), static_cast<const void *>(b), (e - b) * sizeof(T));
+ this->size += (e - b);
}
- void copyAppend(size_t n, const T &t)
+ void copyAppend(qsizetype n, parameter_type t) noexcept
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(n <= this->alloc - uint(this->size));
+ 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;
+ }
- T *iter = this->end();
- const T *const end = iter + n;
- for (; iter != end; ++iter)
- ::memcpy(iter, &t, sizeof(T));
- this->size += int(n);
+ void moveAppend(T *b, T *e) noexcept
+ {
+ copyAppend(b, e);
}
- void truncate(size_t newSize)
+ void truncate(size_t newSize) noexcept
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(newSize < size_t(this->size));
- this->size = int(newSize);
+ this->size = qsizetype(newSize);
}
- void destroyAll() // Call from destructors, ONLY!
+ void destroyAll() noexcept // Call from destructors, ONLY!
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(this->ref.atomic.loadRelaxed() == 0);
+ Q_ASSERT(this->d);
+ Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
// As this is to be called only from destructor, it doesn't need to be
// exception safe; size not updated.
}
- void insert(T *where, const T *b, const T *e)
+ T *createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
- Q_ASSERT(b < e);
- Q_ASSERT(e <= where || b > this->end()); // No overlap
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ Q_ASSERT((pos == QArrayData::GrowsAtBeginning && n <= this->freeSpaceAtBegin()) ||
+ (pos == QArrayData::GrowsAtEnd && n <= this->freeSpaceAtEnd()));
+
+ 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;
+ }
- ::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(qsizetype i, const T *data, qsizetype n)
+ {
+ typename Data::GrowthPosition pos = Data::GrowsAtEnd;
+ if (this->size != 0 && i == 0)
+ pos = Data::GrowsAtBeginning;
+
+ DataPointer oldData;
+ this->detachAndGrow(pos, n, &data, &oldData);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
+
+ T *where = createHole(pos, i, n);
+ ::memcpy(static_cast<void *>(where), static_cast<const void *>(data), n * sizeof(T));
}
- void erase(T *b, T *e)
+ void insert(qsizetype i, qsizetype n, parameter_type t)
{
+ T copy(t);
+
+ typename Data::GrowthPosition pos = Data::GrowsAtEnd;
+ if (this->size != 0 && i == 0)
+ pos = Data::GrowsAtBeginning;
+
+ this->detachAndGrow(pos, n, nullptr, nullptr);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
+
+ T *where = createHole(pos, i, n);
+ while (n--)
+ *where++ = copy;
+ }
+
+ 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)...);
+ typename QArrayData::GrowthPosition pos = QArrayData::GrowsAtEnd;
+ if (this->size != 0 && i == 0)
+ pos = QArrayData::GrowsAtBeginning;
+
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
+
+ T *where = createHole(pos, i, 1);
+ new (where) T(std::move(tmp));
+ }
+
+ 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());
+ Q_ASSERT(e > this->begin() && e <= this->end());
+
+ // 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 eraseFirst() noexcept
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->size);
+ ++this->ptr;
+ --this->size;
+ }
+
+ void eraseLast() noexcept
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->size);
+ --this->size;
+ }
+
+ template <typename Predicate>
+ qsizetype eraseIf(Predicate pred)
+ {
+ qsizetype result = 0;
+ if (this->size == 0)
+ return result;
+
+ if (!this->needsDetach()) {
+ auto end = this->end();
+ auto it = std::remove_if(this->begin(), end, pred);
+ if (it != end) {
+ result = std::distance(it, end);
+ erase(it, result);
+ }
+ } else {
+ const auto begin = this->begin();
+ const auto end = this->end();
+ auto it = std::find_if(begin, end, pred);
+ if (it == end)
+ return result;
+
+ QPodArrayOps<T> other(this->size);
+ Q_CHECK_PTR(other.data());
+ auto dest = other.begin();
+ // std::uninitialized_copy will fallback to ::memcpy/memmove()
+ dest = std::uninitialized_copy(begin, it, dest);
+ dest = q_uninitialized_remove_copy_if(std::next(it), end, dest, pred);
+ other.size = std::distance(other.data(), dest);
+ result = this->size - other.size;
+ this->swap(other);
+ }
+ return result;
+ }
+
+ struct Span { T *begin; T *end; };
+
+ void copyRanges(std::initializer_list<Span> ranges)
+ {
+ auto it = this->begin();
+ std::for_each(ranges.begin(), ranges.end(), [&it](const auto &span) {
+ it = std::copy(span.begin, span.end, it);
+ });
+ this->size = std::distance(this->begin(), it);
+ }
+
+ void assign(T *b, T *e, parameter_type t) noexcept
+ {
+ Q_ASSERT(b <= e);
+ Q_ASSERT(b >= this->begin() && e <= this->end());
+
+ while (b != e)
+ ::memcpy(static_cast<void *>(b++), static_cast<const void *>(&t), sizeof(T));
+ }
+
+ bool compare(const T *begin1, const T *begin2, size_t n) const
+ {
+ // only use memcmp for fundamental types or pointers.
+ // Other types could have padding in the data structure or custom comparison
+ // operators that would break the comparison using memcmp
+ if constexpr (QArrayDataPointer<T>::pass_parameter_by_value) {
+ return ::memcmp(begin1, begin2, n * sizeof(T)) == 0;
+ } else {
+ const T *end1 = begin1 + n;
+ while (begin1 != end1) {
+ if (*begin1 == *begin2) {
+ ++begin1;
+ ++begin2;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
- ::memmove(static_cast<void *>(b), static_cast<void *>(e),
- (static_cast<T *>(this->end()) - e) * sizeof(T));
- this->size -= (e - b);
+ 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;
}
};
-QT_WARNING_POP
template <class T>
struct QGenericArrayOps
- : QTypedArrayData<T>
+ : public QArrayDataPointer<T>
{
- void appendInitialize(size_t newSize)
+ 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:
+ typedef typename QArrayDataPointer<T>::parameter_type parameter_type;
+
+ void appendInitialize(qsizetype newSize)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(newSize > uint(this->size));
- Q_ASSERT(newSize <= this->alloc);
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
- T *const begin = this->begin();
+ T *const b = this->begin();
do {
- new (begin + this->size) T;
- } while (uint(++this->size) != newSize);
+ new (b + this->size) T;
+ } while (++this->size != newSize);
}
void copyAppend(const T *b, const T *e)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(b < e);
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
-
- T *iter = this->end();
- for (; b != e; ++iter, ++b) {
- new (iter) T(*b);
+ Q_ASSERT(this->isMutable() || b == e);
+ Q_ASSERT(!this->isShared() || b == e);
+ Q_ASSERT(b <= e);
+ Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
+
+ 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(size_t n, const T &t)
+ void copyAppend(qsizetype n, parameter_type t)
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(n <= this->alloc - uint(this->size));
+ 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;
+ }
+ }
- T *iter = this->end();
- const T *const end = iter + n;
- for (; iter != end; ++iter) {
- new (iter) T(t);
+ 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());
+
+ if (b == e)
+ return;
+
+ T *data = this->begin();
+ while (b < e) {
+ new (data + this->size) T(std::move(*b));
+ ++b;
++this->size;
}
}
@@ -189,114 +380,300 @@ struct QGenericArrayOps
void truncate(size_t newSize)
{
Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
+ Q_ASSERT(!this->isShared());
Q_ASSERT(newSize < size_t(this->size));
- const T *const b = this->begin();
- do {
- (b + --this->size)->~T();
- } while (uint(this->size) != newSize);
+ std::destroy(this->begin() + newSize, this->end());
+ this->size = newSize;
}
void destroyAll() // Call from destructors, ONLY
{
- Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->d);
// As this is to be called only from destructor, it doesn't need to be
// exception safe; size not updated.
- Q_ASSERT(this->ref.atomic.loadRelaxed() == 0);
-
- const T *const b = this->begin();
- const T *i = this->end();
+ Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
- while (i != b)
- (--i)->~T();
+ std::destroy(this->begin(), this->end());
}
- void insert(T *where, const T *b, const T *e)
+ struct Inserter
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
- Q_ASSERT(b < e);
- Q_ASSERT(e <= where || b > this->end()); // No overlap
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ QArrayDataPointer<T> *data;
+ T *begin;
+ qsizetype size;
- // Array may be truncated at where in case of exceptions
+ qsizetype sourceCopyConstruct = 0, nSource = 0, move = 0, sourceCopyAssign = 0;
+ T *end = nullptr, *last = nullptr, *where = nullptr;
- T *const end = this->end();
- const T *readIter = end;
- T *writeIter = end + (e - b);
+ Inserter(QArrayDataPointer<T> *d) : data(d)
+ {
+ begin = d->ptr;
+ size = d->size;
+ }
+ ~Inserter() {
+ data->ptr = begin;
+ data->size = size;
+ }
+ Q_DISABLE_COPY(Inserter)
- const T *const step1End = where + qMax(e - b, end - where);
+ 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;
+ }
+ }
- struct Destructor
+ void insert(qsizetype pos, const T *source, qsizetype n)
{
- Destructor(T *&it)
- : iter(&it)
- , end(it)
- {
+ qsizetype oldSize = size;
+ Q_UNUSED(oldSize);
+
+ setup(pos, 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(source[nSource - sourceCopyConstruct + i]);
+ ++size;
}
+ Q_ASSERT(size <= oldSize + n);
- void commit()
- {
- iter = &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);
+
+ // now move assign existing elements towards the end
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - nSource]);
+
+ // finally copy the remaining elements from source over
+ for (qsizetype i = 0; i != sourceCopyAssign; ++i)
+ where[i] = source[i];
+ }
+
+ void insert(qsizetype pos, const T &t, qsizetype n)
+ {
+ const qsizetype oldSize = size;
+ Q_UNUSED(oldSize);
- ~Destructor()
- {
- for (; *iter != end; --*iter)
- (*iter)->~T();
+ setup(pos, 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);
- T **iter;
- T *end;
- } destroyer(writeIter);
+ // 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);
- // Construct new elements in array
- do {
- --readIter, --writeIter;
- new (writeIter) T(*readIter);
- } while (writeIter != step1End);
+ // now move assign existing elements towards the end
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - nSource]);
- while (writeIter != end) {
- --e, --writeIter;
- new (writeIter) T(*e);
+ // finally copy the remaining elements from source over
+ for (qsizetype i = 0; i != sourceCopyAssign; ++i)
+ where[i] = t;
}
- destroyer.commit();
- this->size += destroyer.end - end;
+ void insertOne(qsizetype pos, T &&t)
+ {
+ setup(pos, 1);
+
+ 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;
+
+ // now move assign existing elements towards the end
+ for (qsizetype i = 0; i != move; --i)
+ last[i] = std::move(last[i - 1]);
+
+ // and move the new item into place
+ *where = std::move(t);
+ }
+ }
+ };
+
+ void insert(qsizetype i, const T *data, qsizetype n)
+ {
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ DataPointer oldData;
+ this->detachAndGrow(pos, n, &data, &oldData);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
+
+ 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(qsizetype i, qsizetype n, parameter_type t)
+ {
+ T copy(t);
+
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ this->detachAndGrow(pos, n, nullptr, nullptr);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
+
+ 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);
+ }
+ }
- // Copy assign over existing elements
- while (readIter != where) {
- --readIter, --writeIter;
- *writeIter = *readIter;
+ 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;
+
+ this->detachAndGrow(pos, 1, nullptr, nullptr);
- while (writeIter != where) {
- --e, --writeIter;
- *writeIter = *e;
+ 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)
+ 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());
+ Q_ASSERT(e > this->begin() && e <= this->end());
+
+ // 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;
+ }
+ }
+ this->size -= n;
+ std::destroy(b, e);
+ }
- const T *const end = this->end();
+ void eraseFirst() noexcept
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->size);
+ this->begin()->~T();
+ ++this->ptr;
+ --this->size;
+ }
- do {
- *b = *e;
- ++b, ++e;
- } while (e != end);
+ void eraseLast() noexcept
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(this->size);
+ (this->end() - 1)->~T();
+ --this->size;
+ }
- do {
- (--e)->~T();
- --this->size;
- } while (e != b);
+
+ void assign(T *b, T *e, parameter_type t)
+ {
+ Q_ASSERT(b <= e);
+ Q_ASSERT(b >= this->begin() && e <= this->end());
+
+ while (b != e)
+ *b++ = t;
+ }
+
+ bool compare(const T *begin1, const T *begin2, size_t n) const
+ {
+ const T *end1 = begin1 + n;
+ while (begin1 != end1) {
+ if (*begin1 == *begin2) {
+ ++begin1;
+ ++begin2;
+ } else {
+ return false;
+ }
+ }
+ return true;
}
};
@@ -304,111 +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)
+ struct Inserter
{
- Q_ASSERT(this->isMutable());
- Q_ASSERT(!this->ref.isShared());
- Q_ASSERT(where >= this->begin() && where < this->end()); // Use copyAppend at end
- Q_ASSERT(b < e);
- Q_ASSERT(e <= where || b > this->end()); // No overlap
- Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size));
+ QArrayDataPointer<T> *data;
+ T *displaceFrom;
+ T *displaceTo;
+ qsizetype nInserts = 0;
+ qsizetype bytes;
+
+ 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;
+ }
- struct ReversibleDisplace
+ void insert(qsizetype pos, const T *source, qsizetype n)
{
- ReversibleDisplace(T *start, T *finish, size_t diff)
- : begin(start)
- , end(finish)
- , displace(diff)
- {
- ::memmove(static_cast<void *>(begin + displace), static_cast<void *>(begin),
- (end - begin) * sizeof(T));
+ T *where = displace(pos, n);
+
+ while (n--) {
+ new (where) T(*source);
+ ++where;
+ ++source;
+ ++displaceFrom;
}
+ }
- void commit() { displace = 0; }
+ void insert(qsizetype pos, const T &t, qsizetype n)
+ {
+ T *where = displace(pos, n);
- ~ReversibleDisplace()
- {
- if (displace)
- ::memmove(static_cast<void *>(begin), static_cast<void *>(begin + displace),
- (end - begin) * sizeof(T));
+ while (n--) {
+ new (where) T(t);
+ ++where;
+ ++displaceFrom;
}
+ }
- T *const begin;
- T *const end;
- size_t displace;
+ void insertOne(qsizetype pos, T &&t)
+ {
+ T *where = displace(pos, 1);
+ new (where) T(std::move(t));
+ ++displaceFrom;
+ Q_ASSERT(displaceFrom == displaceTo);
+ }
- } displace(where, this->end(), size_t(e - b));
+ };
- struct CopyConstructor
- {
- CopyConstructor(T *w) : where(w) {}
-
- void copy(const T *src, const T *const srcEnd)
- {
- n = 0;
- for (; src != srcEnd; ++src) {
- new (where + n) T(*src);
- ++n;
- }
- n = 0;
- }
- ~CopyConstructor()
- {
- while (n)
- where[--n].~T();
+ void insert(qsizetype i, const T *data, qsizetype n)
+ {
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ DataPointer oldData;
+ this->detachAndGrow(pos, n, &data, &oldData);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
+
+ 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);
+ }
+ }
- T *const where;
- size_t n;
- } copier(where);
+ void insert(qsizetype i, qsizetype n, parameter_type t)
+ {
+ T copy(t);
+
+ const bool growsAtBegin = this->size != 0 && i == 0;
+ const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
+
+ this->detachAndGrow(pos, n, nullptr, nullptr);
+ Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
+ (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
+
+ 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);
+ }
+ }
- copier.copy(b, e);
- displace.commit();
- this->size += (e - b);
+ 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;
+
+ 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(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());
-
- struct Mover
- {
- Mover(T *&start, const T *finish, int &sz)
- : destination(start)
- , source(start)
- , n(finish - start)
- , size(sz)
- {
- }
-
- ~Mover()
- {
- ::memmove(static_cast<void *>(destination), static_cast<const void *>(source), n * sizeof(T));
- size -= (source - destination);
- }
-
- T *&destination;
- const T *const source;
- size_t n;
- int &size;
- } mover(e, this->end(), this->size);
+ Q_ASSERT(e > this->begin() && e <= this->end());
+
+ // 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.
+
+ 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;
+ }
- do {
- // Exceptions or not, dtor called once per instance
- (--e)->~T();
- } while (e != b);
+ 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;
}
};
@@ -421,7 +882,7 @@ struct QArrayOpsSelector
template <class T>
struct QArrayOpsSelector<T,
typename std::enable_if<
- !QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ !QTypeInfo<T>::isComplex && QTypeInfo<T>::isRelocatable
>::type>
{
typedef QPodArrayOps<T> Type;
@@ -430,17 +891,101 @@ struct QArrayOpsSelector<T,
template <class T>
struct QArrayOpsSelector<T,
typename std::enable_if<
- QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ QTypeInfo<T>::isComplex && QTypeInfo<T>::isRelocatable
>::type>
{
typedef QMovableArrayOps<T> Type;
};
+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;
+
+protected:
+ using Self = QCommonArrayOps<T>;
+
+public:
+ // using Base::truncate;
+ // using Base::destroyAll;
+ // using Base::assign;
+ // using Base::compare;
+
+ template<typename It>
+ 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 && 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;
+ }
+ }
+ }
+
+ // slightly higher level API than copyAppend() that also preallocates space
+ void growAppend(const T *b, const T *e)
+ {
+ if (b == e)
+ return;
+ Q_ASSERT(b < e);
+ const qsizetype n = e - b;
+ DataPointer old;
+
+ // 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);
+ }
+
+ void appendUninitialized(qsizetype newSize)
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
+
+ T *const b = this->begin();
+ do {
+ auto ptr = b + this->size;
+
+ if constexpr (std::is_constructible_v<T, Qt::Initialization>)
+ new (ptr) T(Qt::Uninitialized);
+ else
+ new (ptr) T; // not T() -- default-construct
+ } while (++this->size != newSize);
+ }
+};
+
} // namespace QtPrivate
template <class T>
struct QArrayDataOps
- : QtPrivate::QArrayOpsSelector<T>::Type
+ : QtPrivate::QCommonArrayOps<T>
{
};
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index b8a1ef5d68..6657d40cf9 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -1,46 +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) 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
#include <QtCore/qarraydataops.h>
+#include <QtCore/qcontainertools_impl.h>
+
+#include <QtCore/q20functional.h>
+#include <QtCore/q20memory.h>
QT_BEGIN_NAMESPACE
@@ -52,143 +20,510 @@ private:
typedef QArrayDataOps<T> DataOps;
public:
- QArrayDataPointer() noexcept
- : d(Data::sharedNull())
+ 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();
}
- QArrayDataPointer(const QArrayDataPointer &other)
- : d(other.d->ref.ref()
- ? other.d
- : other.clone(other.d->cloneFlags()))
+ Q_NODISCARD_CTOR
+ constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0) noexcept
+ : d(header), ptr(adata), size(n)
{
}
- explicit QArrayDataPointer(QTypedArrayData<T> *ptr)
- : d(ptr)
+ Q_NODISCARD_CTOR
+ explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
+ : d(adata.first), ptr(adata.second), size(n)
{
- Q_CHECK_PTR(ptr);
}
- QArrayDataPointer(QArrayDataPointerRef<T> ref)
- : d(ref.ptr)
+ Q_NODISCARD_CTOR explicit
+ QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
+ QArrayData::AllocationOption option = QArrayData::KeepSize)
+ : QArrayDataPointer(Data::allocate(alloc, option), n)
{
}
- QArrayDataPointer &operator=(const QArrayDataPointer &other)
+ Q_NODISCARD_CTOR
+ static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
+ {
+ Q_ASSERT(rawData || !length);
+ return { nullptr, const_cast<T *>(rawData), length };
+ }
+
+ QArrayDataPointer &operator=(const QArrayDataPointer &other) noexcept
{
QArrayDataPointer tmp(other);
this->swap(tmp);
return *this;
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(QArrayDataPointer &&other) noexcept
- : d(other.d)
+ : d(std::exchange(other.d, nullptr)),
+ ptr(std::exchange(other.ptr, nullptr)),
+ size(std::exchange(other.size, 0))
{
- other.d = Data::sharedNull();
}
- QArrayDataPointer &operator=(QArrayDataPointer &&other) noexcept
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
+
+ DataOps &operator*() noexcept
{
- QArrayDataPointer moved(std::move(other));
- this->swap(moved);
- return *this;
+ return *static_cast<DataOps *>(this);
+ }
+
+ DataOps *operator->() noexcept
+ {
+ return static_cast<DataOps *>(this);
}
- DataOps &operator*() const
+ const DataOps &operator*() const noexcept
{
- Q_ASSERT(d);
- return *static_cast<DataOps *>(d);
+ return *static_cast<const DataOps *>(this);
}
- DataOps *operator->() const
+ const DataOps *operator->() const noexcept
{
- Q_ASSERT(d);
- return static_cast<DataOps *>(d);
+ return static_cast<const DataOps *>(this);
}
~QArrayDataPointer()
{
- if (!d->ref.deref()) {
- if (d->isMutable())
- (*this)->destroyAll();
- Data::deallocate(d);
+ if (!deref()) {
+ (*this)->destroyAll();
+ free(d);
}
}
- bool isNull() const
+ bool isNull() const noexcept
{
- return d == Data::sharedNull();
+ return !ptr;
}
- Data *data() const
+ T *data() noexcept { return ptr; }
+ const T *data() const noexcept { return ptr; }
+
+ 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
{
- return d;
+ qt_ptr_swap(d, other.d);
+ qt_ptr_swap(ptr, other.ptr);
+ std::swap(size, other.size);
}
- bool needsDetach() const
+ void clear() noexcept(std::is_nothrow_destructible<T>::value)
{
- return (!d->isMutable() || d->ref.isShared());
+ QArrayDataPointer tmp;
+ swap(tmp);
}
- void swap(QArrayDataPointer &other) noexcept
+ void detach(QArrayDataPointer *old = nullptr)
{
- qSwap(d, other.d);
+ if (needsDetach())
+ reallocateAndGrow(QArrayData::GrowsAtEnd, 0, old);
}
- void clear()
+ /*! \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() &&
{
- QArrayDataPointer tmp(d);
- d = Data::sharedNull();
+ 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) };
}
- bool detach()
+ /*! \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)
{
- if (needsDetach()) {
- Data *copy = clone(d->detachFlags());
- QArrayDataPointer old(d);
- d = copy;
- return true;
+ 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));
}
- return false;
+ if (!readjusted)
+ reallocateAndGrow(where, n, old);
}
-private:
- Q_REQUIRED_RESULT Data *clone(QArrayData::AllocationOptions options) const
+ /*! \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)
{
- Data *x = Data::allocate(d->detachCapacity(d->size), options);
- Q_CHECK_PTR(x);
- QArrayDataPointer copy(x);
+ 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.
- if (d->size)
- copy->copyAppend(d->begin(), d->end());
+ 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.
- Data *result = copy.d;
- copy.d = Data::sharedNull();
+ \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 = {})
+ {
+ // This function only provides the basic exception guarantee.
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag>;
+ constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
+
+ if constexpr (IsFwdIt) {
+ const qsizetype n = std::distance(first, last);
+ if (needsDetach() || n > constAllocatedCapacity()) {
+ QArrayDataPointer allocated(detachCapacity(n));
+ swap(allocated);
+ }
+ } else if (needsDetach()) {
+ QArrayDataPointer allocated(allocatedCapacity());
+ swap(allocated);
+ // We don't want to copy data that we know we'll overwrite
+ }
+
+ auto offset = freeSpaceAtBegin();
+ const auto capacityBegin = begin() - offset;
+ const auto prependBufferEnd = begin();
+
+ if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ // If construction can throw, and we have freeSpaceAtBegin(),
+ // it's easiest to just clear the container and start fresh.
+ // The alternative would be to keep track of two active, disjoint ranges.
+ if (offset) {
+ (*this)->truncate(0);
+ setBegin(capacityBegin);
+ offset = 0;
+ }
+ }
+
+ auto dst = capacityBegin;
+ const auto dend = end();
+ if (offset) { // avoids dead stores
+ setBegin(capacityBegin); // undo prepend optimization
+
+ // By construction, the following loop is nothrow!
+ // (otherwise, we can't reach here)
+ // Assumes InputIterator operations don't throw.
+ // (but we can't statically assert that, as these operations
+ // have preconditons, so typically aren't noexcept)
+ while (true) {
+ if (dst == prependBufferEnd) { // ran out of prepend buffer space
+ size += offset;
+ // we now have a contiguous buffer, continue with the main loop:
+ break;
+ }
+ if (first == last) { // ran out of elements to assign
+ std::destroy(prependBufferEnd, dend);
+ size = dst - begin();
+ return;
+ }
+ // construct element in prepend buffer
+ q20::construct_at(dst, std::invoke(proj, *first));
+ ++dst;
+ ++first;
+ }
+ }
+
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt && IsIdentity) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else if constexpr (IsFwdIt && !IsIdentity
+ && std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ for (; first != last; ++dst, ++first) // uninitialized_copy with projection
+ q20::construct_at(dst, std::invoke(proj, *first));
+ break;
+ } else {
+ do {
+ (*this)->emplace(size, std::invoke(proj, *first));
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = std::invoke(proj, *first); // overwrite existing element
+ ++dst;
+ ++first;
+ }
+ size = dst - begin();
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
+ {
+ QArrayDataPointer result(n);
+ std::uninitialized_copy_n(begin() + pos, n, result.begin());
+ result.size = n;
return result;
}
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
+ {
+ if (needsDetach())
+ return sliced(pos, n);
+ T *newBeginning = begin() + pos;
+ std::destroy(begin(), newBeginning);
+ std::destroy(newBeginning + n, end());
+ setBegin(newBeginning);
+ size = n;
+ return std::move(*this);
+ }
+
+ // forwards from QArrayData
+ qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
+ qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
+ 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(); }
+ 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 { if (d) d->flags &= ~f; }
+
+ Data *d_ptr() noexcept { return d; }
+ void setBegin(T *begin) noexcept { ptr = begin; }
+
+ qsizetype freeSpaceAtBegin() const noexcept
+ {
+ if (d == nullptr)
+ return 0;
+ return this->ptr - Data::dataStart(d, alignof(typename Data::AlignmentDummy));
+ }
+
+ qsizetype freeSpaceAtEnd() const noexcept
+ {
+ if (d == nullptr)
+ return 0;
+ return d->constAllocatedCapacity() - freeSpaceAtBegin() - this->size;
+ }
+
+ // 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)
+ {
+ // 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;
+ if (!valid)
+ return QArrayDataPointer(header, dataPtr);
+
+ // 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);
+ }
+
+ friend bool operator==(const QArrayDataPointer &lhs, const QArrayDataPointer &rhs) noexcept
+ {
+ 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;
+ }
+
Data *d;
+ T *ptr;
+ qsizetype size;
};
template <class T>
-inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs)
+inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2) noexcept
{
- return lhs.data() == rhs.data();
+ p1.swap(p2);
}
-template <class T>
-inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs)
-{
- return lhs.data() != rhs.data();
-}
+////////////////////////////////////////////////////////////////////////////////
+// Q_ARRAY_LITERAL
-template <class T>
-inline void swap(QArrayDataPointer<T> &p1, QArrayDataPointer<T> &p2)
-{
- p1.swap(p2);
-}
+// The idea here is to place a (read-only) copy of header and array data in an
+// mmappable portion of the executable (typically, .rodata section).
+
+// Hide array inside a lambda
+#define Q_ARRAY_LITERAL(Type, ...) \
+ ([]() -> QArrayDataPointer<Type> { \
+ static Type const data[] = { __VA_ARGS__ }; \
+ return QArrayDataPointer<Type>::fromRawData(const_cast<Type *>(data), std::size(data)); \
+ }())
+/**/
QT_END_NAMESPACE
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 f0b81cce66..e4276d383d 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
@@ -56,6 +23,8 @@ QT_BEGIN_NAMESPACE
\ingroup shared
\reentrant
+ \compares equality
+
A QBitArray is an array that gives access to individual bits and
provides operators (\l{operator&()}{AND}, \l{operator|()}{OR},
\l{operator^()}{XOR}, and \l{operator~()}{NOT}) that work on
@@ -107,9 +76,10 @@ QT_BEGIN_NAMESPACE
QBitArray(0). We recommend that you always use isEmpty() and
avoid isNull().
- \sa QByteArray, QVector
+ \sa QByteArray, QList
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
\fn QBitArray::QBitArray(QBitArray &&other)
@@ -118,6 +88,7 @@ QT_BEGIN_NAMESPACE
\since 5.2
*/
+#endif
/*! \fn QBitArray::QBitArray()
@@ -137,35 +108,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 +163,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 +175,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 +205,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 +239,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 +268,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)
@@ -305,7 +288,7 @@ void QBitArray::fill(bool value, int begin, int end)
\since 5.11
Returns a pointer to a dense bit array for this QBitArray. Bits are counted
- upwards from the least significant bit in each byte. The the number of bits
+ upwards from the least significant bit in each byte. The number of bits
relevant in the last byte is given by \c{size() % 8}.
\sa fromBits(), size()
@@ -325,21 +308,48 @@ 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);
+ 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;
+}
- // clear any unused bits from the last byte
- if (size & 7)
- bits[nbytes] &= 0xffU >> (8 - (size & 7));
+/*!
+ \since 6.0
- *bits = result.d.size() * 8 - size;
- return result;
+ Returns the array of bit converted to an int. The conversion is based on \a endianness.
+ Converts up to the first 32 bits of the array to \c quint32 and returns it,
+ obeying \a endianness. If \a ok is not a null pointer, and the array has more
+ than 32 bits, \a ok is set to false and this function returns zero; otherwise,
+ it's set to true.
+*/
+quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcept
+{
+ const qsizetype _size = size();
+ if (_size > 32) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ if (ok)
+ *ok = true;
+
+ quint32 factor = 1;
+ quint32 total = 0;
+ for (qsizetype i = 0; i < _size; ++i, factor *= 2) {
+ const auto index = endianness == QSysInfo::Endian::LittleEndian ? i : (_size - i - 1);
+ if (testBit(index))
+ total += factor;
+ }
+
+ return total;
}
/*! \fn bool QBitArray::isDetached() const
@@ -359,7 +369,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\sa resize(), isEmpty()
*/
-/*! \fn void QBitArray::truncate(int pos)
+/*! \fn void QBitArray::truncate(qsizetype pos)
Truncates the bit array at index position \a pos.
@@ -368,7 +378,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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
@@ -383,7 +393,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -394,7 +404,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -404,14 +414,14 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -421,7 +431,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -431,7 +441,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -452,22 +462,13 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\sa at(), testBit(), setBit(), clearBit()
*/
-/*! \fn bool QBitArray::operator[](int i) const
-
- \overload
-*/
-
-/*! \fn QBitRef QBitArray::operator[](uint i)
+/*! \fn bool QBitArray::operator[](qsizetype i) const
\overload
*/
-/*! \fn bool QBitArray::operator[](uint 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.
@@ -479,7 +480,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -491,6 +492,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
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
@@ -499,23 +501,145 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
fast and never fails.
*/
-/*! \fn bool QBitArray::operator==(const QBitArray &other) const
+/*! \fn bool QBitArray::operator==(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is equal to this bit array; otherwise
+ Returns \c true if \a lhs is equal to \a rhs bit array; otherwise
returns \c false.
\sa operator!=()
*/
-/*! \fn bool QBitArray::operator!=(const QBitArray &other) const
+/*! \fn bool QBitArray::operator!=(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is not equal to this bit array;
+ Returns \c true if \a lhs is not equal to \a rhs bit array;
otherwise returns \c false.
\sa operator==()
*/
+// Returns a new QBitArray that has the same size as the bigger of \a a1 and
+// \a a2, but whose contents are uninitialized.
+static QBitArray sizedForOverwrite(const QBitArray &a1, const QBitArray &a2)
+{
+ QBitArray result;
+ const QByteArrayData &d1 = a1.data_ptr();
+ const QByteArrayData &d2 = a2.data_ptr();
+ qsizetype n1 = d1.size;
+ qsizetype n2 = d2.size;
+ qsizetype n = qMax(n1, n2);
+
+ QByteArrayData bytes(n, n);
+
+ // initialize the count of bits in the last byte (see construction note)
+ if (n1 > n2)
+ *bytes.ptr = *d1.ptr;
+ else if (n2 > n1)
+ *bytes.ptr = *d2.ptr;
+ else if (n1) // n1 == n2
+ *bytes.ptr = qMin(*d1.ptr, *d2.ptr);
+
+ result.data_ptr() = std::move(bytes);
+ return result;
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationHelper(QBitArray &out, const QBitArray &a1,
+ const QBitArray &a2, BitwiseOp op)
+{
+ const QByteArrayData &d1 = a1.data_ptr();
+ const QByteArrayData &d2 = a2.data_ptr();
+
+ // Sizes in bytes (including the initial bit difference counter)
+ qsizetype n1 = d1.size;
+ qsizetype n2 = d2.size;
+ Q_ASSERT(out.data_ptr().size == qMax(n1, n2));
+ Q_ASSERT(out.data_ptr().size == 0 || !out.data_ptr().needsDetach());
+
+ // Bypass QByteArray's emptiness verification; we won't dereference
+ // these pointers if their size is zero.
+ auto dst = reinterpret_cast<uchar *>(out.data_ptr().data());
+ auto p1 = reinterpret_cast<const uchar *>(d1.data());
+ auto p2 = reinterpret_cast<const uchar *>(d2.data());
+
+ // Main: perform the operation in the range where both arrays have data
+ if (n1 < n2) {
+ std::swap(n1, n2);
+ std::swap(p1, p2);
+ }
+ for (qsizetype i = 1; i < n2; ++i)
+ dst[i] = op(p1[i], p2[i]);
+
+ // Tail: operate as if both arrays had the same data by padding zeroes to
+ // the end of the shorter of the two (for std::bit_or and std::bit_xor, this is
+ // a memmove; for std::bit_and, it's memset to 0).
+ for (qsizetype i = qMax(n2, qsizetype(1)); i < n1; ++i)
+ dst[i] = op(p1[i], uchar(0));
+
+ return out;
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationInCopy(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ QBitArray tmp(std::move(self));
+ self = sizedForOverwrite(tmp, other);
+ return performBitwiseOperationHelper(self, tmp, other, op);
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationInPlace(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ if (self.size() < other.size())
+ self.resize(other.size());
+ return performBitwiseOperationHelper(self, self, other, op);
+}
+
+template <typename BitwiseOp> static
+QBitArray &performBitwiseOperation(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ if (self.data_ptr().needsDetach())
+ return performBitwiseOperationInCopy(self, other, op);
+ return performBitwiseOperationInPlace(self, other, op);
+}
+
+// SCARY helper
+enum { InCopy, InPlace };
+static auto prepareForBitwiseOperation(QBitArray &self, QBitArray &other)
+{
+ QByteArrayData &d1 = self.data_ptr();
+ QByteArrayData &d2 = other.data_ptr();
+ bool detached1 = !d1.needsDetach();
+ bool detached2 = !d2.needsDetach();
+ if (!detached1 && !detached2)
+ return InCopy;
+
+ // at least one of the two is detached, we'll reuse its buffer
+ bool swap = false;
+ if (detached1 && detached2) {
+ // both are detached, so choose the larger of the two
+ swap = d1.allocatedCapacity() < d2.allocatedCapacity();
+ } else if (detached2) {
+ // we can re-use other's buffer but not self's, so swap the two
+ swap = true;
+ }
+ if (swap)
+ self.swap(other);
+ return InPlace;
+}
+
+template <typename BitwiseOp> static
+QBitArray &performBitwiseOperation(QBitArray &self, QBitArray &other, BitwiseOp op)
+{
+ auto choice = prepareForBitwiseOperation(self, other);
+ if (choice == InCopy)
+ return performBitwiseOperationInCopy(self, other, std::move(op));
+ return performBitwiseOperationInPlace(self, other, std::move(op));
+}
+
/*!
+ \fn QBitArray &QBitArray::operator&=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator&=(QBitArray &&other)
+
Performs the AND operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -530,21 +654,20 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
\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.
@@ -559,18 +682,20 @@ QBitArray &QBitArray::operator&=(const QBitArray &other)
\sa operator|(), operator&=(), operator^=(), operator~()
*/
+QBitArray &QBitArray::operator|=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_or<uchar>());
+}
+
QBitArray &QBitArray::operator|=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar*>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- 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.
@@ -585,20 +710,20 @@ QBitArray &QBitArray::operator|=(const QBitArray &other)
\sa operator^(), operator&=(), operator|=(), operator~()
*/
+QBitArray &QBitArray::operator^=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
+}
+
QBitArray &QBitArray::operator^=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar*>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- 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
@@ -606,24 +731,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.
@@ -640,13 +783,16 @@ QBitArray QBitArray::operator~() const
QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp &= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_and<uchar>());
return tmp;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator|(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator|(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator|(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator|(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the OR of the bit arrays \a a1 and \a
a2.
@@ -663,13 +809,16 @@ QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp |= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_or<uchar>());
return tmp;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator^(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator^(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator^(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator^(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the XOR of the bit arrays \a a1 and \a
a2.
@@ -686,8 +835,8 @@ QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp ^= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_xor<uchar>());
return tmp;
}
@@ -703,7 +852,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
@@ -732,7 +881,6 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
Sets the value referenced by the QBitRef to \a v.
*/
-
/*****************************************************************************
QBitArray stream functions
*****************************************************************************/
@@ -748,10 +896,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;
}
@@ -766,19 +922,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();
@@ -788,14 +960,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
@@ -805,7 +976,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 9b0e931aca..b9c36b5320 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,122 +8,160 @@
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 &);
- friend Q_CORE_EXPORT uint qHash(const QBitArray &key, uint seed) noexcept;
+#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; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QBitArray &other) const { return comparesEqual(d, other.d); }
+ inline bool operator!=(const QBitArray &other) const { return !operator==(other); }
+#endif
- inline bool fill(bool val, 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);
+ quint32 toUInt32(QSysInfo::Endian endianness, bool *ok = nullptr) const noexcept;
+
public:
- typedef QByteArray::DataPtr DataPtr;
+ typedef QByteArray::DataPointer DataPtr;
inline DataPtr &data_ptr() { return d.data_ptr(); }
-};
-
-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 const DataPtr &data_ptr() const { return d.data_ptr(); }
-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); }
+private:
+ friend bool comparesEqual(const QBitArray &lhs, const QBitArray &rhs) noexcept
+ {
+ return lhs.d == rhs.d;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QBitArray)
+};
-class Q_CORE_EXPORT QBitRef
+class QT6_ONLY(Q_CORE_EXPORT) QBitRef
{
private:
- QBitArray& a;
- 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 4fcde46fbc..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,151 +12,241 @@ QT_BEGIN_NAMESPACE
template <class Key, class T>
class QCache
{
- struct Node {
- inline Node() : keyPtr(0) {}
- inline Node(T *data, int cost)
- : keyPtr(nullptr), t(data), c(cost), p(nullptr), n(nullptr) {}
- const Key *keyPtr; T *t; int c; Node *p,*n;
+ struct Value
+ {
+ T *t = nullptr;
+ qsizetype cost = 0;
+ Value() noexcept = default;
+ Value(T *tt, qsizetype c) noexcept
+ : t(tt), cost(c)
+ {}
+ Value(Value &&other) noexcept
+ : t(other.t),
+ cost(other.cost)
+ {
+ other.t = nullptr;
+ }
+ Value &operator=(Value &&other) noexcept
+ {
+ qt_ptr_swap(t, other.t);
+ std::swap(cost, other.cost);
+ return *this;
+ }
+ ~Value() { delete t; }
+
+ private:
+ Q_DISABLE_COPY(Value)
};
- Node *f, *l;
- QHash<Key, Node> hash;
- int mx, total;
-
- inline void unlink(Node &n) {
- if (n.p) n.p->n = n.n;
- if (n.n) n.n->p = n.p;
- if (l == &n) l = n.p;
- if (f == &n) f = n.n;
- total -= n.c;
- T *obj = n.t;
- hash.remove(*n.keyPtr);
- delete obj;
- }
- inline T *relink(const Key &key) {
- typename QHash<Key, Node>::iterator i = hash.find(key);
- if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd())
- return nullptr;
- Node &n = *i;
- if (f != &n) {
- if (n.p) n.p->n = n.n;
- if (n.n) n.n->p = n.p;
- if (l == &n) l = n.p;
- n.p = nullptr;
- n.n = f;
- f->p = &n;
- f = &n;
- }
- return n.t;
- }
+ struct Chain
+ {
+ Chain() noexcept : prev(this), next(this) { }
+ Chain *prev;
+ Chain *next;
+ };
- Q_DISABLE_COPY(QCache)
+ struct Node : public Chain
+ {
+ using KeyType = Key;
+ using ValueType = Value;
-public:
- inline explicit QCache(int maxCost = 100) noexcept;
- inline ~QCache() { clear(); }
+ Key key;
+ Value value;
- inline int maxCost() const { return mx; }
- void setMaxCost(int m);
- inline int totalCost() const { return total; }
+ Node(const Key &k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key>)
+ : Chain(),
+ key(k),
+ value(std::move(t))
+ {
+ }
+ Node(Key &&k, Value &&t) noexcept(std::is_nothrow_move_assignable_v<Key>)
+ : Chain(),
+ key(std::move(k)),
+ value(std::move(t))
+ {
+ }
+ static void createInPlace(Node *n, const Key &k, T *o, qsizetype cost)
+ {
+ new (n) Node{ Key(k), Value(o, cost) };
+ }
+ void emplace(T *o, qsizetype cost)
+ {
+ value = Value(o, cost);
+ }
- inline int size() const { return hash.size(); }
- inline int count() const { return hash.size(); }
- inline bool isEmpty() const { return hash.isEmpty(); }
- inline QList<Key> keys() const { return hash.keys(); }
+ Node(Node &&other)
+ : Chain(other),
+ key(std::move(other.key)),
+ value(std::move(other.value))
+ {
+ Q_ASSERT(this->prev);
+ Q_ASSERT(this->next);
+ this->prev->next = this;
+ this->next->prev = this;
+ }
+ private:
+ Q_DISABLE_COPY(Node)
+ };
- void clear();
+ using Data = QHashPrivate::Data<Node>;
+
+ mutable Chain chain;
+ Data d;
+ qsizetype mx = 0;
+ qsizetype total = 0;
+
+ void unlink(Node *n) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ Q_ASSERT(n->prev);
+ Q_ASSERT(n->next);
+ n->prev->next = n->next;
+ n->next->prev = n->prev;
+ total -= n->value.cost;
+ auto it = d.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;
- bool insert(const Key &key, T *object, int cost = 1);
- T *object(const Key &key) const;
- inline bool contains(const Key &key) const { return hash.contains(key); }
- T *operator[](const Key &key) const;
+ if (chain.next != n) {
+ Q_ASSERT(n->prev);
+ Q_ASSERT(n->next);
+ n->prev->next = n->next;
+ n->next->prev = n->prev;
+ n->next = chain.next;
+ chain.next->prev = n;
+ n->prev = &chain;
+ chain.next = n;
+ }
+ return n->value.t;
+ }
- bool remove(const Key &key);
- T *take(const Key &key);
+ void trim(qsizetype m) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ while (chain.prev != &chain && total > m) {
+ Node *n = static_cast<Node *>(chain.prev);
+ unlink(n);
+ }
+ }
-private:
- void trim(int m);
-};
-template <class Key, class T>
-inline QCache<Key, T>::QCache(int amaxCost) noexcept
- : f(nullptr), l(nullptr), mx(amaxCost), total(0) {}
+ Q_DISABLE_COPY(QCache)
-template <class Key, class T>
-inline void QCache<Key,T>::clear()
-{ while (f) { delete f->t; f = f->n; }
- hash.clear(); l = nullptr; total = 0; }
+public:
+ inline explicit QCache(qsizetype maxCost = 100) noexcept
+ : mx(maxCost)
+ {
+ }
+ 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.");
-template <class Key, class T>
-inline void QCache<Key,T>::setMaxCost(int m)
-{ mx = m; trim(mx); }
+ clear();
+ }
-template <class Key, class T>
-inline T *QCache<Key,T>::object(const Key &key) const
-{ return const_cast<QCache<Key,T>*>(this)->relink(key); }
+ inline qsizetype maxCost() const noexcept { return mx; }
+ void setMaxCost(qsizetype m) noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ mx = m;
+ trim(mx);
+ }
+ inline qsizetype totalCost() const noexcept { return total; }
+
+ 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 (size()) {
+ k.reserve(size());
+ for (auto it = d.begin(); it != d.end(); ++it)
+ k << it.node()->key;
+ }
+ Q_ASSERT(k.size() == size());
+ return k;
+ }
-template <class Key, class T>
-inline T *QCache<Key,T>::operator[](const Key &key) const
-{ return object(key); }
+ void clear() noexcept(std::is_nothrow_destructible_v<Node>)
+ {
+ d.clear();
+ total = 0;
+ chain.next = &chain;
+ chain.prev = &chain;
+ }
-template <class Key, class T>
-inline bool QCache<Key,T>::remove(const Key &key)
-{
- typename QHash<Key, Node>::iterator i = hash.find(key);
- if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd()) {
- return false;
- } else {
- unlink(*i);
+ bool insert(const Key &key, T *object, qsizetype cost = 1)
+ {
+ if (cost > mx) {
+ remove(key);
+ delete object;
+ return false;
+ }
+ trim(mx - cost);
+ auto result = d.findOrInsert(key);
+ Node *n = result.it.node();
+ if (result.initialized) {
+ 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;
return true;
}
-}
+ T *object(const Key &key) const noexcept
+ {
+ return relink(key);
+ }
+ T *operator[](const Key &key) const noexcept
+ {
+ return relink(key);
+ }
+ inline bool contains(const Key &key) const noexcept
+ {
+ return !isEmpty() && d.findNode(key) != nullptr;
+ }
-template <class Key, class T>
-inline T *QCache<Key,T>::take(const Key &key)
-{
- typename QHash<Key, Node>::iterator i = hash.find(key);
- if (i == hash.end())
- return nullptr;
+ 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;
+ } else {
+ unlink(n);
+ return true;
+ }
+ }
- Node &n = *i;
- T *t = n.t;
- n.t = nullptr;
- unlink(n);
- return t;
-}
+ 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;
-template <class Key, class T>
-bool QCache<Key,T>::insert(const Key &akey, T *aobject, int acost)
-{
- remove(akey);
- if (acost > mx) {
- delete aobject;
- return false;
+ T *t = n->value.t;
+ n->value.t = nullptr;
+ unlink(n);
+ return t;
}
- trim(mx - acost);
- Node sn(aobject, acost);
- typename QHash<Key, Node>::iterator i = hash.insert(akey, sn);
- total += acost;
- Node *n = &i.value();
- n->keyPtr = &i.key();
- if (f) f->p = n;
- n->n = f;
- f = n;
- if (!l) l = f;
- return true;
-}
-template <class Key, class T>
-void QCache<Key,T>::trim(int m)
-{
- Node *n = l;
- while (n && total > m) {
- Node *u = n;
- n = n->p;
- unlink(*u);
- }
-}
+};
QT_END_NAMESPACE
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 aff684fad2..6b990cecf1 100644
--- a/src/corelib/tools/qcommandlineoption.cpp
+++ b/src/corelib/tools/qcommandlineoption.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** 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"
@@ -151,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
@@ -187,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
@@ -260,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;
@@ -285,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;
}
@@ -391,36 +353,6 @@ QStringList QCommandLineOption::defaultValues() const
return d->defaultValues;
}
-#if QT_DEPRECATED_SINCE(5, 8)
-/*!
- Sets whether to hide this option in the user-visible help output.
-
- All options are visible by default. Setting \a hide to true for
- a particular option makes it internal, i.e. not listed in the help output.
-
- \since 5.6
- \obsolete Use setFlags(QCommandLineOption::HiddenFromHelp), QCommandLineOption::HiddenFromHelp
- \sa isHidden
- */
-void QCommandLineOption::setHidden(bool hide)
-{
- d->flags.setFlag(HiddenFromHelp, hide);
-}
-
-/*!
- Returns true if this option is omitted from the help output,
- false if the option is listed.
-
- \since 5.6
- \obsolete Use flags() & QCommandLineOption::HiddenFromHelp
- \sa setHidden(), QCommandLineOption::HiddenFromHelp
- */
-bool QCommandLineOption::isHidden() const
-{
- return d->flags & HiddenFromHelp;
-}
-#endif
-
/*!
Returns a set of flags that affect this command-line option.
diff --git a/src/corelib/tools/qcommandlineoption.h b/src/corelib/tools/qcommandlineoption.h
index e2ca64acef..63c90a4005 100644
--- a/src/corelib/tools/qcommandlineoption.h
+++ b/src/corelib/tools/qcommandlineoption.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** 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
@@ -71,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;
@@ -91,14 +56,6 @@ public:
Flags flags() const;
void setFlags(Flags aflags);
-#if QT_DEPRECATED_SINCE(5, 8)
- QT_DEPRECATED_X("Use setFlags() with HiddenFromHelp")
- void setHidden(bool hidden);
- QT_DEPRECATED_X("Use flags() and HiddenFromHelp")
- bool isHidden() const;
-#endif
-
-
private:
QSharedDataPointer<QCommandLineOptionPrivate> d;
};
diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp
index 48501f5271..2880eedf77 100644
--- a/src/corelib/tools/qcommandlineparser.cpp
+++ b/src/corelib/tools/qcommandlineparser.cpp
@@ -1,51 +1,16 @@
-/****************************************************************************
-**
-** 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 <qvector.h>
+#include <qvarlengtharray.h>
+#include <qlist.h>
#include <qdebug.h>
-#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
# include <qt_windows.h>
#endif
#include <stdio.h>
@@ -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;
@@ -109,7 +76,7 @@ public:
QString description;
QString syntax;
};
- QVector<PositionalArgumentDefinition> positionalArgumentDefinitions;
+ QList<PositionalArgumentDefinition> positionalArgumentDefinitions;
//! The parsing mode for "-abc"
QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode;
@@ -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,38 +507,33 @@ 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();
}
enum MessageType { UsageMessage, ErrorMessage };
-#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
// Return whether to use a message box. Use handles if a console can be obtained
// 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);
GetStartupInfo(&startupInfo);
return !(startupInfo.dwFlags & STARTF_USESTDHANDLES);
}
-#endif // Q_OS_WIN && !QT_BOOTSTRAPPED && !Q_OS_WIN && !Q_OS_WINRT
+#endif // Q_OS_WIN && !QT_BOOTSTRAPPED
static void showParserMessage(const QString &message, MessageType type)
{
-#if defined(Q_OS_WINRT)
- if (type == UsageMessage)
- qInfo("%ls", qUtf16Printable(message));
- else
- qCritical("%ls", qUtf16Printable(message));
- return;
-#elif defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
+#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
if (displayMessageBox()) {
const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND
| (type == UsageMessage ? MB_ICONINFORMATION : MB_ICONERROR);
@@ -598,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);
}
@@ -665,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) {
@@ -705,7 +674,6 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
needsParsing = false;
bool error = false;
- const QString doubleDashString(QStringLiteral("--"));
const QLatin1Char dashChar('-');
const QLatin1Char assignChar('=');
@@ -729,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()))
@@ -818,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.
@@ -832,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;
}
@@ -844,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.
@@ -852,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()
*/
@@ -873,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.
@@ -889,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;
}
@@ -981,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
@@ -1023,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);
@@ -1063,29 +1037,34 @@ QString QCommandLineParser::helpText() const
return d->helpText(false);
}
-static QString wrapText(const QString &names, int longestOptionNameString, const QString &description)
+static QString wrapText(const QString &names, int optionNameMaxWidth, const QString &description)
{
- const QLatin1Char nl('\n');
- const QLatin1String indentation(" ");
- if (description.isEmpty())
- return indentation + names + nl;
-
- QString text = indentation + names.leftJustified(longestOptionNameString) + QLatin1Char(' ');
- const int indent = text.length();
- int lineStart = 0;
- int lastBreakable = -1;
- const int max = 79 - indent;
+ 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;
+ auto nextNameSection = [&]() {
+ QString section = names.mid(nameIndex, optionNameMaxWidth);
+ nameIndex += section.size();
+ return section;
+ };
+
+ QString text;
+ 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;
@@ -1101,11 +1080,10 @@ static QString wrapText(const QString &names, int longestOptionNameString, const
}
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);
- if (lineStart > 0)
- text += QString(indent, QLatin1Char(' '));
- text += description.midRef(lineStart, numChars) + nl;
+ text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + u' ';
+ text += QStringView{description}.mid(lineStart, numChars) + nl;
x = 0;
lastBreakable = -1;
lineStart = nextLineStart;
@@ -1115,6 +1093,10 @@ static QString wrapText(const QString &names, int longestOptionNameString, const
}
}
+ while (nameIndex < names.size()) {
+ text += indentation + nextNameSection() + nl;
+ }
+
return text;
}
@@ -1123,46 +1105,49 @@ 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, 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, longestOptionNameString, option.description());
+ text += wrapText(*optionNameIterator, optionNameMaxWidth, option.description());
++optionNameIterator;
}
if (!positionalArgumentDefinitions.isEmpty()) {
@@ -1170,7 +1155,7 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
text += nl;
text += QCommandLineParser::tr("Arguments:") + nl;
for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
- text += wrapText(arg.name, longestOptionNameString, arg.description);
+ text += wrapText(arg.name, optionNameMaxWidth, arg.description);
}
return text;
}
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 f6efa99b6a..d5590553fa 100644
--- a/src/corelib/tools/qcontainerfwd.h
+++ b/src/corelib/tools/qcontainerfwd.h
@@ -1,65 +1,63 @@
-/****************************************************************************
-**
-** 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>
-QT_BEGIN_NAMESPACE
+#if 0
+#pragma qt_class(QtContainerFwd)
+#endif
+// std headers can unfortunately not be forward declared
+#include <cstddef> // std::size_t
+#include <utility>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
-template <class Key, class T> class QCache;
-template <class Key, class T> class QHash;
-#ifndef QT_NO_LINKED_LIST
-template <class T> class QLinkedList;
+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>;
#endif
-template <class Key, class T> class QMap;
-template <class Key, class T> class QMultiHash;
-template <class Key, class T> class QMultiMap;
-template <class T1, class T2> struct QPair;
-template <class T> class QQueue;
-template <class T> class QSet;
-template <class T> class QStack;
-template<class T, int Prealloc = 256> class QVarLengthArray;
-template <class T> class QVector;
-template<typename T> using QList = QVector<T>;
+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>;
+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
diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h
index 3a0c4381f1..998bc292d4 100644
--- a/src/corelib/tools/qcontainertools_impl.h
+++ b/src/corelib/tools/qcontainertools_impl.h
@@ -1,42 +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>
-** 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
@@ -47,12 +12,255 @@
#define QCONTAINERTOOLS_IMPL_H
#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) {
+ 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 {
+ 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<
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>::value,
@@ -83,47 +291,177 @@ 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>
+using KeyAndValueTest = decltype(
+ std::declval<Iterator &>().key(),
+ std::declval<Iterator &>().value()
+);
-template <typename Iterator, typename = void_t<>>
-struct AssociativeIteratorHasKeyAndValue : std::false_type
-{
-};
+template <typename Iterator>
+using FirstAndSecondTest = decltype(
+ std::declval<Iterator &>()->first,
+ std::declval<Iterator &>()->second
+);
+
+template <typename Iterator>
+using IfAssociativeIteratorHasKeyAndValue =
+ std::enable_if_t<qxp::is_detected_v<KeyAndValueTest, Iterator>, bool>;
template <typename Iterator>
-struct AssociativeIteratorHasKeyAndValue<
- Iterator,
- void_t<decltype(std::declval<Iterator &>().key()),
- decltype(std::declval<Iterator &>().value())>
- >
- : std::true_type
+using IfAssociativeIteratorHasFirstAndSecond =
+ 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;
+ }
+ }
-template <typename Iterator, typename = void_t<>, typename = void_t<>>
-struct AssociativeIteratorHasFirstAndSecond : std::false_type
+ 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 Iterator>
-struct AssociativeIteratorHasFirstAndSecond<
- Iterator,
- void_t<decltype(std::declval<Iterator &>()->first),
- decltype(std::declval<Iterator &>()->second)>
- >
- : std::true_type
+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 Iterator>
-using IfAssociativeIteratorHasKeyAndValue =
- typename std::enable_if<AssociativeIteratorHasKeyAndValue<Iterator>::value, bool>::type;
+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 Iterator>
-using IfAssociativeIteratorHasFirstAndSecond =
- typename std::enable_if<AssociativeIteratorHasFirstAndSecond<Iterator>::value, bool>::type;
+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
diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp
index 64cbd7df4b..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
@@ -54,9 +20,9 @@ void QContiguousCacheData::dump() const
}
#endif
-QContiguousCacheData *QContiguousCacheData::allocateData(int size, int alignment)
+QContiguousCacheData *QContiguousCacheData::allocateData(qsizetype size, qsizetype alignment)
{
- return static_cast<QContiguousCacheData *>(qMallocAligned(size, alignment));
+ return static_cast<QContiguousCacheData *>(qMallocAligned(size_t(size), size_t(alignment)));
}
void QContiguousCacheData::freeData(QContiguousCacheData *data)
@@ -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 8cae7d1651..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
@@ -52,19 +22,12 @@ QT_BEGIN_NAMESPACE
struct Q_CORE_EXPORT QContiguousCacheData
{
QBasicAtomicInt ref;
- int alloc;
- int count;
- int start;
- int offset;
- uint sharable : 1;
- uint reserved : 31;
-
- // total is 24 bytes (HP-UX aCC: 40 bytes)
- // the next entry is already aligned to 8 bytes
- // there will be an 8 byte gap here if T requires 16-byte alignment
- // (such as long double on 64-bit platforms, __int128, __float128)
-
- static QContiguousCacheData *allocateData(int size, int alignment);
+ qsizetype alloc;
+ qsizetype count;
+ qsizetype start;
+ qsizetype offset;
+
+ static QContiguousCacheData *allocateData(qsizetype size, qsizetype alignment);
static void freeData(QContiguousCacheData *data);
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
@@ -73,18 +36,17 @@ struct Q_CORE_EXPORT QContiguousCacheData
};
template <typename T>
-struct QContiguousCacheTypedData: private QContiguousCacheData
+struct QContiguousCacheTypedData : public QContiguousCacheData
{
- // private inheritance to avoid aliasing warningss
T array[1];
-
- static inline void freeData(QContiguousCacheTypedData *data) { QContiguousCacheData::freeData(data); }
};
template<typename T>
class QContiguousCache {
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
typedef QContiguousCacheTypedData<T> Data;
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; };
+ Data *d;
public:
// STL compatibility
typedef T value_type;
@@ -93,156 +55,160 @@ public:
typedef value_type& reference;
typedef const value_type& const_reference;
typedef qptrdiff difference_type;
- typedef int size_type;
+ typedef qsizetype size_type;
- explicit QContiguousCache(int capacity = 0);
- QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
+ explicit QContiguousCache(qsizetype capacity = 0);
+ QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); }
- inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(p); }
+ inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(d); }
inline void detach() { if (d->ref.loadRelaxed() != 1) detach_helper(); }
inline bool isDetached() const { return d->ref.loadRelaxed() == 1; }
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); }
- bool operator==(const QContiguousCache<T> &other) const;
- inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QContiguousCache)
+ void swap(QContiguousCache &other) noexcept { qt_ptr_swap(d, other.d); }
- inline int capacity() const {return d->alloc; }
- inline int count() const { return d->count; }
- inline int size() const { return d->count; }
+#ifndef Q_QDOC
+ template <typename U = T>
+ QTypeTraits::compare_eq_result<U> operator==(const QContiguousCache<T> &other) const
+ {
+ if (other.d == d)
+ return true;
+ if (other.d->start != d->start
+ || other.d->count != d->count
+ || other.d->offset != d->offset
+ || other.d->alloc != d->alloc)
+ return false;
+ for (qsizetype i = firstIndex(); i <= lastIndex(); ++i)
+ if (!(at(i) == other.at(i)))
+ return false;
+ return true;
+ }
+ 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; }
+ inline qsizetype size() const { return d->count; }
inline bool isEmpty() const { return d->count == 0; }
inline bool isFull() const { return d->count == d->alloc; }
- inline int available() const { return d->alloc - d->count; }
+ inline qsizetype available() const { return d->alloc - d->count; }
void clear();
- void setCapacity(int size);
+ void setCapacity(qsizetype size);
- const T &at(int pos) const;
- T &operator[](int i);
- const T &operator[](int i) const;
+ const T &at(qsizetype pos) const;
+ T &operator[](qsizetype i);
+ const T &operator[](qsizetype i) const;
+ void append(T &&value);
void append(const T &value);
+ void prepend(T &&value);
void prepend(const T &value);
- void insert(int pos, const T &value);
+ void insert(qsizetype pos, T &&value);
+ void insert(qsizetype pos, const T &value);
- inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; }
- inline int firstIndex() const { return d->offset; }
- inline int lastIndex() const { return d->offset + d->count - 1; }
- inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; }
- inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; }
- inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; }
- inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; }
+ inline bool containsIndex(qsizetype pos) const { return pos >= d->offset && pos - d->offset < d->count; }
+ inline qsizetype firstIndex() const { return d->offset; }
+ inline qsizetype lastIndex() const { return d->offset + d->count - 1; }
+
+ inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; }
+ inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; }
+ inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; }
+ inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; }
void removeFirst();
T takeFirst();
void removeLast();
T takeLast();
+ // Use extra parentheses around max to avoid expanding it if it is a macro.
inline bool areIndexesValid() const
- { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; }
+ { return d->offset >= 0 && d->offset < (std::numeric_limits<qsizetype>::max)() - d->count && (d->offset % d->alloc) == d->start; }
inline void normalizeIndexes() { d->offset = d->start; }
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
- void dump() const { p->dump(); }
+ void dump() const { d->dump(); }
#endif
private:
void detach_helper();
- QContiguousCacheData *allocateData(int aalloc);
+ Data *allocateData(qsizetype aalloc);
void freeData(Data *x);
- int sizeOfTypedData() {
- // this is more or less the same as sizeof(Data), except that it doesn't
- // count the padding at the end
- return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this);
- }
- int alignOfTypedData() const
- {
- return qMax<int>(sizeof(void*), alignof(Data));
- }
};
template <typename T>
void QContiguousCache<T>::detach_helper()
{
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
-
- x.d = allocateData(d->alloc);
- x.d->ref.storeRelaxed(1);
- x.d->count = d->count;
- x.d->start = d->start;
- x.d->offset = d->offset;
- x.d->alloc = d->alloc;
- x.d->sharable = true;
- x.d->reserved = 0;
-
- T *dest = x.p->array + x.d->start;
- T *src = p->array + d->start;
- int oldcount = x.d->count;
+ Data *x = allocateData(d->alloc);
+ x->ref.storeRelaxed(1);
+ x->count = d->count;
+ x->start = d->start;
+ x->offset = d->offset;
+ x->alloc = d->alloc;
+
+ T *dest = x->array + x->start;
+ T *src = d->array + d->start;
+ qsizetype oldcount = x->count;
while (oldcount--) {
- if (QTypeInfo<T>::isComplex) {
- new (dest) T(*src);
- } else {
- *dest = *src;
- }
+ new (dest) T(*src);
dest++;
- if (dest == x.p->array + x.d->alloc)
- dest = x.p->array;
+ if (dest == x->array + x->alloc)
+ dest = x->array;
src++;
- if (src == p->array + d->alloc)
- src = p->array;
+ if (src == d->array + d->alloc)
+ src = d->array;
}
if (!d->ref.deref())
- freeData(p);
- d = x.d;
+ freeData(d);
+ d = x;
}
template <typename T>
-void QContiguousCache<T>::setCapacity(int asize)
+void QContiguousCache<T>::setCapacity(qsizetype asize)
{
Q_ASSERT(asize >= 0);
if (asize == d->alloc)
return;
detach();
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
- x.d = allocateData(asize);
- x.d->ref.storeRelaxed(1);
- x.d->alloc = asize;
- x.d->count = qMin(d->count, asize);
- x.d->offset = d->offset + d->count - x.d->count;
- if(asize)
- x.d->start = x.d->offset % x.d->alloc;
+ Data *x = allocateData(asize);
+ x->ref.storeRelaxed(1);
+ x->alloc = asize;
+ x->count = qMin(d->count, asize);
+ x->offset = d->offset + d->count - x->count;
+ if (asize)
+ x->start = x->offset % x->alloc;
else
- x.d->start = 0;
+ x->start = 0;
- int oldcount = x.d->count;
- if(oldcount)
+ qsizetype oldcount = x->count;
+ if (oldcount)
{
- T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc;
- T *src = p->array + (d->start + d->count-1) % d->alloc;
+ T *dest = x->array + (x->start + x->count-1) % x->alloc;
+ T *src = d->array + (d->start + d->count-1) % d->alloc;
while (oldcount--) {
- if (QTypeInfo<T>::isComplex) {
- new (dest) T(*src);
- } else {
- *dest = *src;
- }
- if (dest == x.p->array)
- dest = x.p->array + x.d->alloc;
+ new (dest) T(*src);
+ if (dest == x->array)
+ dest = x->array + x->alloc;
dest--;
- if (src == p->array)
- src = p->array + d->alloc;
+ if (src == d->array)
+ src = d->array + d->alloc;
src--;
}
}
/* free old */
- freeData(p);
- d = x.d;
+ freeData(d);
+ d = x;
}
template <typename T>
@@ -250,44 +216,42 @@ void QContiguousCache<T>::clear()
{
if (d->ref.loadRelaxed() == 1) {
if (QTypeInfo<T>::isComplex) {
- int oldcount = d->count;
- T * i = p->array + d->start;
- T * e = p->array + d->alloc;
+ qsizetype oldcount = d->count;
+ T * i = d->array + d->start;
+ T * e = d->array + d->alloc;
while (oldcount--) {
i->~T();
i++;
if (i == e)
- i = p->array;
+ i = d->array;
}
}
d->count = d->start = d->offset = 0;
} else {
- union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
- x.d = allocateData(d->alloc);
- x.d->ref.storeRelaxed(1);
- x.d->alloc = d->alloc;
- x.d->count = x.d->start = x.d->offset = 0;
- x.d->sharable = true;
- if (!d->ref.deref()) freeData(p);
- d = x.d;
+ Data *x = allocateData(d->alloc);
+ x->ref.storeRelaxed(1);
+ x->alloc = d->alloc;
+ x->count = x->start = x->offset = 0;
+ if (!d->ref.deref())
+ freeData(d);
+ d = x;
}
}
template <typename T>
-inline QContiguousCacheData *QContiguousCache<T>::allocateData(int aalloc)
+inline typename QContiguousCache<T>::Data *QContiguousCache<T>::allocateData(qsizetype aalloc)
{
- return QContiguousCacheData::allocateData(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData());
+ return static_cast<Data *>(QContiguousCacheData::allocateData(sizeof(Data) + (aalloc - 1) * sizeof(T), alignof(Data)));
}
template <typename T>
-QContiguousCache<T>::QContiguousCache(int cap)
+QContiguousCache<T>::QContiguousCache(qsizetype cap)
{
Q_ASSERT(cap >= 0);
d = allocateData(cap);
d->ref.storeRelaxed(1);
d->alloc = cap;
d->count = d->start = d->offset = 0;
- d->sharable = true;
}
template <typename T>
@@ -295,58 +259,55 @@ QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &o
{
other.d->ref.ref();
if (!d->ref.deref())
- freeData(p);
+ freeData(d);
d = other.d;
- if (!d->sharable)
- detach_helper();
return *this;
}
template <typename T>
-bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const
-{
- if (other.d == d)
- return true;
- if (other.d->start != d->start
- || other.d->count != d->count
- || other.d->offset != d->offset
- || other.d->alloc != d->alloc)
- return false;
- for (int i = firstIndex(); i <= lastIndex(); ++i)
- if (!(at(i) == other.at(i)))
- return false;
- return true;
-}
-
-template <typename T>
void QContiguousCache<T>::freeData(Data *x)
{
if (QTypeInfo<T>::isComplex) {
- int oldcount = d->count;
- T * i = p->array + d->start;
- T * e = p->array + d->alloc;
+ qsizetype oldcount = d->count;
+ T * i = d->array + d->start;
+ T * e = d->array + d->alloc;
while (oldcount--) {
i->~T();
i++;
if (i == e)
- i = p->array;
+ i = d->array;
}
}
- x->freeData(x);
+ Data::freeData(x);
}
template <typename T>
-void QContiguousCache<T>::append(const T &value)
+void QContiguousCache<T>::append(T &&value)
{
if (!d->alloc)
return; // zero capacity
detach();
- if (QTypeInfo<T>::isComplex) {
- if (d->count == d->alloc)
- (p->array + (d->start+d->count) % d->alloc)->~T();
- new (p->array + (d->start+d->count) % d->alloc) T(value);
+ if (d->count == d->alloc)
+ (d->array + (d->start+d->count) % d->alloc)->~T();
+ new (d->array + (d->start+d->count) % d->alloc) T(std::move(value));
+
+ if (d->count == d->alloc) {
+ d->start++;
+ d->start %= d->alloc;
+ d->offset++;
} else {
- p->array[(d->start+d->count) % d->alloc] = value;
+ d->count++;
}
+}
+
+template <typename T>
+void QContiguousCache<T>::append(const T &value)
+{
+ if (!d->alloc)
+ return; // zero capacity
+ detach();
+ if (d->count == d->alloc)
+ (d->array + (d->start+d->count) % d->alloc)->~T();
+ new (d->array + (d->start+d->count) % d->alloc) T(value);
if (d->count == d->alloc) {
d->start++;
@@ -358,7 +319,7 @@ void QContiguousCache<T>::append(const T &value)
}
template<typename T>
-void QContiguousCache<T>::prepend(const T &value)
+void QContiguousCache<T>::prepend(T &&value)
{
if (!d->alloc)
return; // zero capacity
@@ -372,29 +333,40 @@ void QContiguousCache<T>::prepend(const T &value)
if (d->count != d->alloc)
d->count++;
else
- if (d->count == d->alloc)
- (p->array + d->start)->~T();
+ (d->array + d->start)->~T();
- if (QTypeInfo<T>::isComplex)
- new (p->array + d->start) T(value);
+ new (d->array + d->start) T(std::move(value));
+}
+
+template<typename T>
+void QContiguousCache<T>::prepend(const T &value)
+{
+ if (!d->alloc)
+ return; // zero capacity
+ detach();
+ if (d->start)
+ d->start--;
else
- p->array[d->start] = value;
+ d->start = d->alloc-1;
+ d->offset--;
+
+ if (d->count != d->alloc)
+ d->count++;
+ else
+ (d->array + d->start)->~T();
+
+ new (d->array + d->start) T(value);
}
template<typename T>
-void QContiguousCache<T>::insert(int pos, const T &value)
+void QContiguousCache<T>::insert(qsizetype pos, T &&value)
{
- Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range");
+ Q_ASSERT_X(pos >= 0, "QContiguousCache<T>::insert", "index out of range");
if (!d->alloc)
return; // zero capacity
detach();
if (containsIndex(pos)) {
- if (QTypeInfo<T>::isComplex) {
- (p->array + pos % d->alloc)->~T();
- new (p->array + pos % d->alloc) T(value);
- } else {
- p->array[pos % d->alloc] = value;
- }
+ d->array[pos % d->alloc] = std::move(value);
} else if (pos == d->offset-1)
prepend(value);
else if (pos == d->offset+d->count)
@@ -405,27 +377,29 @@ void QContiguousCache<T>::insert(int pos, const T &value)
d->offset = pos;
d->start = pos % d->alloc;
d->count = 1;
- if (QTypeInfo<T>::isComplex)
- new (p->array + d->start) T(value);
- else
- p->array[d->start] = value;
+ new (d->array + d->start) T(std::move(value));
}
}
+template<typename T>
+void QContiguousCache<T>::insert(qsizetype pos, const T &value)
+{
+ return insert(pos, T(value));
+}
template <typename T>
-inline const T &QContiguousCache<T>::at(int pos) const
-{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
+inline const T &QContiguousCache<T>::at(qsizetype pos) const
+{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; }
template <typename T>
-inline const T &QContiguousCache<T>::operator[](int pos) const
-{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
+inline const T &QContiguousCache<T>::operator[](qsizetype pos) const
+{ return at(pos); }
template <typename T>
-inline T &QContiguousCache<T>::operator[](int pos)
+inline T &QContiguousCache<T>::operator[](qsizetype pos)
{
detach();
if (!containsIndex(pos))
insert(pos, T());
- return p->array[pos % d->alloc];
+ return d->array[pos % d->alloc];
}
template <typename T>
@@ -435,7 +409,7 @@ inline void QContiguousCache<T>::removeFirst()
detach();
d->count--;
if (QTypeInfo<T>::isComplex)
- (p->array + d->start)->~T();
+ (d->array + d->start)->~T();
d->start = (d->start + 1) % d->alloc;
d->offset++;
}
@@ -447,16 +421,16 @@ inline void QContiguousCache<T>::removeLast()
detach();
d->count--;
if (QTypeInfo<T>::isComplex)
- (p->array + (d->start + d->count) % d->alloc)->~T();
+ (d->array + (d->start + d->count) % d->alloc)->~T();
}
template <typename T>
inline T QContiguousCache<T>::takeFirst()
-{ T t = first(); removeFirst(); return t; }
+{ T t = std::move(first()); removeFirst(); return t; }
template <typename T>
inline T QContiguousCache<T>::takeLast()
-{ T t = last(); removeLast(); return t; }
+{ T t = std::move(last()); removeLast(); return t; }
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index fa8d21e07a..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,54 +94,301 @@ 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>
+#else
+#include "../../3rdparty/blake2/src/blake2b-ref.c"
+#include "../../3rdparty/blake2/src/blake2s-ref.c"
+#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;
- SHA3Context sha3Context;
#endif
- };
-#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- enum class Sha3Variant
- {
- Sha3,
- Keccak
- };
- void sha3Finish(int bitCount, Sha3Variant sha3Variant);
+ SHA3Context sha3Context;
+
+ enum class Sha3Variant { Sha3, Keccak };
+ void sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant);
+ blake2b_state blake2bContext;
+ blake2s_state blake2sContext;
#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
@@ -220,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;
@@ -232,7 +424,7 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
break;
}
- sha3Final(&copy, reinterpret_cast<BitSequence *>(result.data()));
+ sha3Final(&copy, result.data());
}
#endif
@@ -277,23 +469,42 @@ void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant
\value Keccak_256 Generate a Keccak-256 hash sum. Introduced in Qt 5.9.2
\value Keccak_384 Generate a Keccak-384 hash sum. Introduced in Qt 5.9.2
\value Keccak_512 Generate a Keccak-512 hash sum. Introduced in Qt 5.9.2
+ \value Blake2b_160 Generate a BLAKE2b-160 hash sum. Introduced in Qt 6.0
+ \value Blake2b_256 Generate a BLAKE2b-256 hash sum. Introduced in Qt 6.0
+ \value Blake2b_384 Generate a BLAKE2b-384 hash sum. Introduced in Qt 6.0
+ \value Blake2b_512 Generate a BLAKE2b-512 hash sum. Introduced in Qt 6.0
+ \value Blake2s_128 Generate a BLAKE2s-128 hash sum. Introduced in Qt 6.0
+ \value Blake2s_160 Generate a BLAKE2s-160 hash sum. Introduced in Qt 6.0
+ \value Blake2s_224 Generate a BLAKE2s-224 hash sum. Introduced in Qt 6.0
+ \value Blake2s_256 Generate a BLAKE2s-256 hash sum. Introduced in Qt 6.0
\omitvalue RealSha3_224
\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()
@@ -302,13 +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
+{
+ 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 (d->method) {
- case Sha1:
- sha1InitState(&d->sha1Context);
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ new (&sha1Context) Sha1State;
break;
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
default:
@@ -316,54 +643,106 @@ void QCryptographicHash::reset()
Q_UNREACHABLE();
break;
#else
- case Md4:
- md4_init(&d->md4Context);
- break;
- case Md5:
- MD5Init(&d->md5Context);
+ case QCryptographicHash::Md4:
+ new (&md4Context) md4_context;
break;
- case Sha224:
- SHA224Reset(&d->sha224Context);
+ case QCryptographicHash::Md5:
+ new (&md5Context) MD5Context;
break;
- case Sha256:
- SHA256Reset(&d->sha256Context);
+ case QCryptographicHash::Sha224:
+ new (&sha224Context) SHA224Context;
break;
- case Sha384:
- SHA384Reset(&d->sha384Context);
+ case QCryptographicHash::Sha256:
+ new (&sha256Context) SHA256Context;
break;
- case Sha512:
- SHA512Reset(&d->sha512Context);
+ case QCryptographicHash::Sha384:
+ new (&sha384Context) SHA384Context;
break;
- case RealSha3_224:
- case Keccak_224:
- sha3Init(&d->sha3Context, 224);
+ case QCryptographicHash::Sha512:
+ new (&sha512Context) SHA512Context;
break;
- case RealSha3_256:
- case Keccak_256:
- sha3Init(&d->sha3Context, 256);
+ 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 RealSha3_384:
- case Keccak_384:
- sha3Init(&d->sha3Context, 384);
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ new (&blake2bContext) blake2b_state;
break;
- case RealSha3_512:
- case Keccak_512:
- sha3Init(&d->sha3Context, 512);
+ 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();
}
- d->result.clear();
+ reset(method);
}
-/*!
- Adds the first \a length chars of \a data to the cryptographic
- hash.
-*/
-void QCryptographicHash::addData(const char *data, int length)
+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
{
- switch (d->method) {
- case Sha1:
- sha1Update(&d->sha1Context, (const unsigned char *)data, length);
+ if (!initializationFailed) {
+ Q_ASSERT(context);
+ Q_ASSERT(algorithm);
+ // everything already set up - just reset the context
+ EVP_MD_CTX_reset(context.get());
+ initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr);
+ }
+ // if initializationFailed first time around, it will not succeed this time, either
+}
+
+#else // USING_OPENSSL30
+
+void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept
+{
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ sha1InitState(&sha1Context);
break;
#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
default:
@@ -371,59 +750,200 @@ void QCryptographicHash::addData(const char *data, int 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);
+ case QCryptographicHash::Md4:
+ md4_init(&md4Context);
break;
- case Sha224:
- SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Md5:
+ MD5Init(&md5Context);
break;
- case Sha256:
- SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Sha224:
+ SHA224Reset(&sha224Context);
break;
- case Sha384:
- SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Sha256:
+ SHA256Reset(&sha256Context);
break;
- case Sha512:
- SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length);
+ case QCryptographicHash::Sha384:
+ SHA384Reset(&sha384Context);
break;
- case RealSha3_224:
- case Keccak_224:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ case QCryptographicHash::Sha512:
+ SHA512Reset(&sha512Context);
break;
- case RealSha3_256:
- case Keccak_256:
- 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:
+ sha3Init(&sha3Context, hashLengthInternal(method) * 8);
break;
- case RealSha3_384:
- case Keccak_384:
- 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_init(&blake2bContext, hashLengthInternal(method));
break;
- case RealSha3_512:
- case Keccak_512:
- sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8);
+ 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();
}
- d->result.clear();
}
+#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
+
/*!
- \overload addData()
+ 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(const QByteArray &data)
+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
{
- addData(data.constData(), data.length());
+ 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)
+ for (auto remaining = length; remaining; remaining -= length, data += length) {
+ length = qMin(qsizetype(std::numeric_limits<uint>::max()), remaining);
+#else
+ {
+#endif
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ sha1Update(&sha1Context, (const unsigned char *)data, length);
+ break;
+#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ default:
+ Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
+ Q_UNREACHABLE();
+ break;
+#else
+ case QCryptographicHash::Md4:
+ md4_update(&md4Context, (const unsigned char *)data, length);
+ break;
+ case QCryptographicHash::Md5:
+ MD5Update(&md5Context, (const unsigned char *)data, length);
+ break;
+ case QCryptographicHash::Sha224:
+ SHA224Input(&sha224Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case QCryptographicHash::Sha256:
+ SHA256Input(&sha256Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case QCryptographicHash::Sha384:
+ SHA384Input(&sha384Context, reinterpret_cast<const unsigned char *>(data), length);
+ break;
+ case QCryptographicHash::Sha512:
+ SHA512Input(&sha512Context, reinterpret_cast<const unsigned char *>(data), length);
+ 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:
+ sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
+ break;
+ 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 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();
+ }
+ }
}
+#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;
@@ -432,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();
}
@@ -444,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
@@ -465,87 +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());
- break;
- }
- case Md5: {
- MD5Context copy = d->md5Context;
- d->result.resize(16);
- MD5Final(&copy, (unsigned char *)d->result.data());
+ case QCryptographicHash::Md4: {
+ md4_context copy = md4Context;
+ result.resizeForOverwrite(MD4_RESULTLEN);
+ md4_final(&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::Md5: {
+ MD5Context copy = md5Context;
+ result.resizeForOverwrite(16);
+ MD5Final(&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::Sha224: {
+ SHA224Context copy = sha224Context;
+ result.resizeForOverwrite(SHA224HashSize);
+ SHA224Result(&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::Sha256: {
+ SHA256Context copy = sha256Context;
+ result.resizeForOverwrite(SHA256HashSize);
+ SHA256Result(&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::Sha384: {
+ SHA384Context copy = sha384Context;
+ result.resizeForOverwrite(SHA384HashSize);
+ SHA384Result(&copy, result.data());
break;
}
- case RealSha3_224: {
- d->sha3Finish(224, QCryptographicHashPrivate::Sha3Variant::Sha3);
+ case QCryptographicHash::Sha512: {
+ SHA512Context copy = sha512Context;
+ result.resizeForOverwrite(SHA512HashSize);
+ SHA512Result(&copy, result.data());
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);
+ 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_256: {
- d->sha3Finish(256, 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 Keccak_384: {
- d->sha3Finish(384, QCryptographicHashPrivate::Sha3Variant::Keccak);
+ 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 Keccak_512: {
- d->sha3Finish(512, QCryptographicHashPrivate::Sha3Variant::Keccak);
+ 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();
}
/*!
@@ -555,39 +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::RealSha3_224:
case QCryptographicHash::Keccak_224:
- return 224 / 8;
case QCryptographicHash::RealSha3_256:
case QCryptographicHash::Keccak_256:
- return 256 / 8;
case QCryptographicHash::RealSha3_384:
case QCryptographicHash::Keccak_384:
- return 384 / 8;
case QCryptographicHash::RealSha3_512:
case QCryptographicHash::Keccak_512:
- return 512 / 8;
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+#endif
+ return true;
+ case QCryptographicHash::NumAlgorithms: ;
+ };
+ return false;
+#endif // !USING_OPENSSL3
+}
+
+static constexpr int qt_hash_block_size(QCryptographicHash::Algorithm method)
+{
+ switch (method) {
+ case QCryptographicHash::Sha1:
+ return SHA1_Message_Block_Size;
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ case QCryptographicHash::Md4:
+ return 64;
+ case QCryptographicHash::Md5:
+ return 64;
+ case QCryptographicHash::Sha224:
+ return SHA224_Message_Block_Size;
+ case QCryptographicHash::Sha256:
+ return SHA256_Message_Block_Size;
+ case QCryptographicHash::Sha384:
+ return SHA384_Message_Block_Size;
+ case QCryptographicHash::Sha512:
+ return SHA512_Message_Block_Size;
+ case QCryptographicHash::RealSha3_224:
+ case QCryptographicHash::Keccak_224:
+ return 144;
+ case QCryptographicHash::RealSha3_256:
+ case QCryptographicHash::Keccak_256:
+ return 136;
+ case QCryptographicHash::RealSha3_384:
+ case QCryptographicHash::Keccak_384:
+ return 104;
+ case QCryptographicHash::RealSha3_512:
+ case QCryptographicHash::Keccak_512:
+ return 72;
+ case QCryptographicHash::Blake2b_160:
+ case QCryptographicHash::Blake2b_256:
+ case QCryptographicHash::Blake2b_384:
+ case QCryptographicHash::Blake2b_512:
+ return BLAKE2B_BLOCKBYTES;
+ case QCryptographicHash::Blake2s_128:
+ case QCryptographicHash::Blake2s_160:
+ case QCryptographicHash::Blake2s_224:
+ case QCryptographicHash::Blake2s_256:
+ return BLAKE2S_BLOCKBYTES;
+#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ case QCryptographicHash::NumAlgorithms:
+#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 900
+ // GCC 8 has trouble with Q_UNREACHABLE() in constexpr functions
+ Q_UNREACHABLE();
#endif
+ break;
}
return 0;
}
+constexpr int maxHashBlockSize()
+{
+ int result = 0;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms ; ++i)
+ result = std::max(result, qt_hash_block_size(A(i)));
+ return result;
+}
+
+[[maybe_unused]]
+constexpr int minHashBlockSize()
+{
+ int result = INT_MAX;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms ; ++i)
+ result = std::min(result, qt_hash_block_size(A(i)));
+ return result;
+}
+
+[[maybe_unused]]
+constexpr int gcdHashBlockSize()
+{
+ int result = 0;
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms ; ++i)
+ result = std::gcd(result, qt_hash_block_size(A(i)));
+ return result;
+}
+
+using HashBlock = QSmallByteArray<maxHashBlockSize()>;
+
+static HashBlock xored(const HashBlock &block, quint8 val) noexcept
+{
+ // some hints for the optimizer:
+ Q_ASSERT(block.size() >= minHashBlockSize());
+ Q_ASSERT(block.size() <= maxHashBlockSize());
+ Q_ASSERT(block.size() % gcdHashBlockSize() == 0);
+ HashBlock result;
+ result.resizeForOverwrite(block.size());
+ for (qsizetype i = 0; i < block.size(); ++i)
+ result[i] = block[i] ^ val;
+ return result;
+}
+
+class QMessageAuthenticationCodePrivate
+{
+public:
+ QMessageAuthenticationCodePrivate(QCryptographicHash::Algorithm m)
+ : messageHash(m)
+ {
+ }
+
+ HashBlock key;
+ QCryptographicHashPrivate messageHash;
+
+ void setKey(QByteArrayView k) noexcept;
+ void initMessageHash() noexcept;
+ void finalize();
+
+ // when not called from the static hash() function, this function needs to be
+ // called with messageHash.finalizeMutex held:
+ void finalizeUnchecked() noexcept;
+ // END functions that need to be called with finalizeMutex held
+};
+
+/*!
+ \internal
+
+ Transforms key \a newKey into a block-sized format and stores it in member
+ \c key.
+
+ This function assumes it can use messageHash (i.e. it's in its initial
+ state (reset() has been called)).
+*/
+void QMessageAuthenticationCodePrivate::setKey(QByteArrayView newKey) noexcept
+{
+ const int blockSize = qt_hash_block_size(messageHash.method);
+
+ if (newKey.size() > blockSize) {
+ messageHash.addData(newKey);
+ messageHash.finalizeUnchecked();
+ static_assert([] {
+ using A = QCryptographicHash::Algorithm;
+ for (int i = 0; i < A::NumAlgorithms; ++i) {
+ if (hashLengthInternal(A(i)) > qt_hash_block_size(A(i)))
+ return false;
+ }
+ return true;
+ }(), "this code assumes that a hash's result always fits into that hash's block size");
+ key = messageHash.result;
+ messageHash.reset();
+ } else {
+ key.assign(newKey);
+ }
+
+ if (key.size() < blockSize)
+ key.resize(blockSize, '\0');
+
+ initMessageHash();
+}
+
+/*!
+ \internal
+
+ Seeds messageHash from \c key.
+
+ This function assumes that messageHash is in its initial state (reset() has
+ been called).
+*/
+void QMessageAuthenticationCodePrivate::initMessageHash() noexcept
+{
+ messageHash.addData(xored(key, 0x36));
+}
+
+/*!
+ \class QMessageAuthenticationCode
+ \inmodule QtCore
+
+ \brief The QMessageAuthenticationCode class provides a way to generate
+ hash-based message authentication codes.
+
+ \since 5.1
+
+ \ingroup tools
+ \reentrant
+
+ Use the QMessageAuthenticationCode class to generate hash-based message
+ authentication codes (HMACs). The class supports all cryptographic
+ hash algorithms from \l QCryptographicHash (see also
+ \l{QCryptographicHash::Algorithm}).
+
+ To generate a message authentication code, pass a suitable hash
+ algorithm and secret key to the constructor. Then process the message
+ data by calling \l addData() one or more times. After the full
+ message has been processed, get the final authentication code
+ via the \l result() function:
+
+ \snippet qmessageauthenticationcode/main.cpp 0
+ \dots
+ \snippet qmessageauthenticationcode/main.cpp 1
+
+ For simple cases like above, you can also use the static
+ \l hash() function:
+
+ \snippet qmessageauthenticationcode/main.cpp 2
+
+
+ \note The cryptographic strength of the HMAC depends upon the
+ size of the secret key, and the security of the
+ underlying hash function.
+
+ \sa QCryptographicHash, QCryptographicHash::Algorithm
+*/
+
+/*!
+ Constructs an object that can be used to create a cryptographic hash from data
+ using method \a method and key \a key.
+
+//! [qba-to-qbav-6.6]
+ \note In Qt versions prior to 6.6, this function took its arguments as
+ QByteArray, not QByteArrayView. If you experience compile errors, it's
+ because your code is passing objects that are implicitly convertible to
+ QByteArray, but not QByteArrayView. Wrap the corresponding argument in
+ \c{QByteArray{~~~}} to make the cast explicit. This is backwards-compatible
+ with old Qt versions.
+//! [qba-to-qbav-6.6]
+*/
+QMessageAuthenticationCode::QMessageAuthenticationCode(QCryptographicHash::Algorithm method,
+ QByteArrayView key)
+ : d(new QMessageAuthenticationCodePrivate(method))
+{
+ d->setKey(key);
+}
+
+/*!
+ Destroys the object.
+*/
+QMessageAuthenticationCode::~QMessageAuthenticationCode()
+{
+ delete d;
+}
+
+/*!
+ \fn QMessageAuthenticationCode::QMessageAuthenticationCode(QMessageAuthenticationCode &&other)
+
+ Move-constructs a new QMessageAuthenticationCode from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new object.
+
+ \since 6.6
+*/
+
+/*!
+ \fn QMessageAuthenticationCode &QMessageAuthenticationCode::operator=(QMessageAuthenticationCode &&other)
+
+ Move-assigns \a other to this QMessageAuthenticationCode instance.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new object.
+
+ \since 6.6
+*/
+
+/*!
+ \fn void QMessageAuthenticationCode::swap(QMessageAuthenticationCode &other)
+
+ Swaps message authentication code \a other with this message authentication
+ code. This operation is very fast and never fails.
+
+ \since 6.6
+*/
+
+/*!
+ Resets message data. Calling this function doesn't affect the key.
+*/
+void QMessageAuthenticationCode::reset() noexcept
+{
+ d->messageHash.reset();
+ d->initMessageHash();
+}
+
+/*!
+ Sets secret \a key. Calling this function automatically resets the object state.
+
+ For optimal performance, call this function only to \e change the active key,
+ not to set an \e initial key, as in
+
+ \code
+ QMessageAuthenticationCode mac(method);
+ mac.setKey(key); // does extra work
+ use(mac);
+ \endcode
+
+ Prefer to pass initial keys as the constructor argument:
+
+ \code
+ QMessageAuthenticationCode mac(method, key); // OK, optimal
+ use(mac);
+ \endcode
+
+ You can use std::optional to delay construction of a
+ QMessageAuthenticationCode until you know the key:
+
+ \code
+ std::optional<QMessageAuthenticationCode> mac;
+ ~~~
+ key = ~~~;
+ mac.emplace(method, key);
+ use(*mac);
+ \endcode
+
+ \include qcryptographichash.cpp {qba-to-qbav-6.6}
+*/
+void QMessageAuthenticationCode::setKey(QByteArrayView key) noexcept
+{
+ d->messageHash.reset();
+ d->setKey(key);
+}
+
+/*!
+ \overload
+ Adds the first \a length chars of \a data to the message.
+*/
+void QMessageAuthenticationCode::addData(const char *data, qsizetype length)
+{
+ d->messageHash.addData({data, length});
+}
+
+/*!
+ Adds \a data to the message.
+
+ \include qcryptographichash.cpp {qba-to-qbav-6.6}
+
+ \sa resultView(), result()
+*/
+void QMessageAuthenticationCode::addData(QByteArrayView data) noexcept
+{
+ d->messageHash.addData(data);
+}
+
+/*!
+ Reads the data from the open QIODevice \a device until it ends
+ and adds it to message. Returns \c true if reading was successful.
+
+ \note \a device must be already opened.
+ */
+bool QMessageAuthenticationCode::addData(QIODevice *device)
+{
+ return d->messageHash.addData(device);
+}
+
+/*!
+ \since 6.6
+
+ Returns the final hash value.
+
+ Note that the returned view remains valid only as long as the
+ QMessageAuthenticationCode object is not modified by other means.
+
+ \sa result()
+*/
+QByteArrayView QMessageAuthenticationCode::resultView() const noexcept
+{
+ d->finalize();
+ return d->messageHash.resultView();
+}
+
+/*!
+ Returns the final authentication code.
+
+ \sa resultView(), QByteArray::toHex()
+*/
+QByteArray QMessageAuthenticationCode::result() const
+{
+ return resultView().toByteArray();
+}
+
+void QMessageAuthenticationCodePrivate::finalize()
+{
+ const auto lock = qt_scoped_lock(messageHash.finalizeMutex);
+ if (!messageHash.result.isEmpty())
+ return;
+ finalizeUnchecked();
+}
+
+void QMessageAuthenticationCodePrivate::finalizeUnchecked() noexcept
+{
+ messageHash.finalizeUnchecked();
+ const HashResult hashedMessage = messageHash.result;
+
+ messageHash.reset();
+ messageHash.addData(xored(key, 0x5c));
+ messageHash.addData(hashedMessage);
+ messageHash.finalizeUnchecked();
+}
+
+/*!
+ Returns the authentication code for the message \a message using
+ the key \a key and the method \a method.
+
+ \include qcryptographichash.cpp {qba-to-qbav-6.6}
+*/
+QByteArray QMessageAuthenticationCode::hash(QByteArrayView message, QByteArrayView key,
+ QCryptographicHash::Algorithm method)
+{
+ QMessageAuthenticationCodePrivate mac(method);
+ mac.setKey(key);
+ mac.messageHash.addData(message);
+ mac.finalizeUnchecked();
+ return mac.messageHash.resultView().toByteArray();
+}
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h
index ad1de7c756..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
@@ -78,30 +43,56 @@ public:
Sha3_224 = RealSha3_224,
Sha3_256 = RealSha3_256,
Sha3_384 = RealSha3_384,
- Sha3_512 = RealSha3_512
+ Sha3_512 = RealSha3_512,
# else
Sha3_224 = Keccak_224,
Sha3_256 = Keccak_256,
Sha3_384 = Keccak_384,
- Sha3_512 = Keccak_512
+ Sha3_512 = Keccak_512,
# endif
+
+ Blake2b_160 = 15,
+ Blake2b_256,
+ Blake2b_384,
+ Blake2b_512,
+ Blake2s_128,
+ Blake2s_160,
+ 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;
- void addData(const char *data, int length);
+#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
new file mode 100644
index 0000000000..23465ecffe
--- /dev/null
+++ b/src/corelib/tools/qduplicatetracker_p.h
@@ -0,0 +1,124 @@
+// 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
+
+//
+// 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 <private/qglobal_p.h>
+
+#ifdef __cpp_lib_memory_resource
+# include <unordered_set>
+# include <memory_resource>
+# include <qhash.h> // for the hashing helpers
+#else
+# include <qset.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+template <typename T, size_t Prealloc = 32>
+class QDuplicateTracker {
+#ifdef __cpp_lib_memory_resource
+ 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, QHasher<T>> set{Prealloc, &res};
+#else
+ 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;
+ explicit QDuplicateTracker(qsizetype n)
+#ifdef __cpp_lib_memory_resource
+ : set{size_t(n), &res}
+#else
+ : set{n}
+#endif
+ {}
+ 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;
+ }
+ [[nodiscard]] bool hasSeen(T &&s)
+ {
+ return !set.insert(std::move(s)).second;
+ }
+
+ template <typename C>
+ void appendTo(C &c) const &
+ {
+ for (const auto &e : set)
+ c.push_back(e);
+ }
+
+ template <typename C>
+ void appendTo(C &c) &&
+ {
+ 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();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif /* QDUPLICATETRACKER_P_H */
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index d7f69d3e0a..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
/*
@@ -308,7 +272,7 @@
#endif
#include <QtCore/qpoint.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
@@ -320,7 +284,8 @@ static bool isConfigFunction(QEasingCurve::Type type)
type == QEasingCurve::TCBSpline;
}
-struct TCBPoint {
+struct TCBPoint
+{
QPointF _point;
qreal _t;
qreal _c;
@@ -357,7 +322,7 @@ QDataStream &operator>>(QDataStream &stream, TCBPoint &point)
return stream;
}
-typedef QVector<TCBPoint> TCBPoints;
+typedef QList<TCBPoint> TCBPoints;
class QEasingCurveFunction
{
@@ -375,7 +340,7 @@ public:
qreal _p;
qreal _a;
qreal _o;
- QVector<QPointF> _bezierCurves;
+ QList<QPointF> _bezierCurves;
TCBPoints _tcbPoints;
};
@@ -443,12 +408,12 @@ class QEasingCurvePrivate
public:
QEasingCurvePrivate()
: type(QEasingCurve::Linear),
- config(0),
+ config(nullptr),
func(&easeNone)
{ }
QEasingCurvePrivate(const QEasingCurvePrivate &other)
: type(other.type),
- config(other.config ? other.config->copy() : 0),
+ config(other.config ? other.config->copy() : nullptr),
func(other.func)
{ }
~QEasingCurvePrivate() { delete config; }
@@ -468,8 +433,8 @@ struct BezierEase : public QEasingCurveFunction
qreal p3x, p3y;
};
- QVector<SingleCubicBezier> _curves;
- QVector<qreal> _intervals;
+ QList<SingleCubicBezier> _curves;
+ QList<qreal> _intervals;
int _curveCount;
bool _init;
bool _valid;
@@ -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;
@@ -590,7 +555,7 @@ struct BezierEase : public QEasingCurveFunction
if (!(x < 1))
return 1;
- SingleCubicBezier *singleCubicBezier = 0;
+ SingleCubicBezier *singleCubicBezier = nullptr;
getBezierSegment(singleCubicBezier, x);
return evaluateSegmentForY(*singleCubicBezier, findTForX(*singleCubicBezier, 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:
@@ -1087,7 +1052,7 @@ static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
return &easeInOutCirc;
case QEasingCurve::OutInCirc:
return &easeOutInCirc;
- // Internal for, compatibility with QTimeLine only ??
+ // Internal - needed for QTimeLine backward-compatibility:
case QEasingCurve::InCurve:
return &easeInCurve;
case QEasingCurve::OutCurve:
@@ -1097,13 +1062,13 @@ static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
case QEasingCurve::CosineCurve:
return &easeCosineCurve;
default:
- return 0;
+ return nullptr;
};
}
static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
{
- switch(type) {
+ switch (type) {
case QEasingCurve::InElastic:
case QEasingCurve::OutElastic:
case QEasingCurve::InOutElastic:
@@ -1127,7 +1092,7 @@ static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
return new QEasingCurveFunction(type, qreal(0.3), qreal(1.0), qreal(1.70158));
}
- return 0;
+ return nullptr;
}
/*!
@@ -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);
}
/*!
@@ -1307,10 +1272,10 @@ void QEasingCurve::addCubicBezierSegment(const QPointF & c1, const QPointF & c2,
d_ptr->config->_bezierCurves << c1 << c2 << endPoint;
}
-QVector<QPointF> static inline tcbToBezier(const TCBPoints &tcbPoints)
+QList<QPointF> static inline tcbToBezier(const TCBPoints &tcbPoints)
{
- const int count = tcbPoints.count();
- QVector<QPointF> bezierPoints;
+ const int count = tcbPoints.size();
+ QList<QPointF> bezierPoints;
bezierPoints.reserve(3 * (count - 1));
for (int i = 1; i < count; i++) {
@@ -1356,7 +1321,7 @@ QVector<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);
@@ -1388,9 +1353,9 @@ void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qre
If the easing curve does not have a custom bezier easing curve the list
is empty.
*/
-QVector<QPointF> QEasingCurve::toCubicSpline() const
+QList<QPointF> QEasingCurve::toCubicSpline() const
{
- return d_ptr->config ? d_ptr->config->_bezierCurves : QVector<QPointF>();
+ return d_ptr->config ? d_ptr->config->_bezierCurves : QList<QPointF>();
}
/*!
@@ -1406,8 +1371,8 @@ void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType)
qreal amp = -1.0;
qreal period = -1.0;
qreal overshoot = -1.0;
- QVector<QPointF> bezierCurves;
- QVector<TCBPoint> tcbPoints;
+ QList<QPointF> bezierCurves;
+ QList<TCBPoint> tcbPoints;
if (config) {
amp = config->_a;
@@ -1417,7 +1382,7 @@ void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType)
tcbPoints = std::move(config->_tcbPoints);
delete config;
- config = 0;
+ config = nullptr;
}
if (isConfigFunction(newType) || (amp != -1.0) || (period != -1.0) || (overshoot != -1.0) ||
@@ -1431,11 +1396,11 @@ void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType)
config->_o = overshoot;
config->_bezierCurves = std::move(bezierCurves);
config->_tcbPoints = std::move(tcbPoints);
- func = 0;
+ func = nullptr;
} else if (newType != QEasingCurve::Custom) {
func = curveToFunc(newType);
}
- Q_ASSERT((func == 0) == (config != 0));
+ Q_ASSERT((func == nullptr) == (config != nullptr));
type = newType;
}
@@ -1482,7 +1447,7 @@ void QEasingCurve::setCustomType(EasingFunction func)
*/
QEasingCurve::EasingFunction QEasingCurve::customType() const
{
- return d_ptr->type == Custom ? d_ptr->func : 0;
+ return d_ptr->type == Custom ? d_ptr->func : nullptr;
}
/*!
@@ -1507,7 +1472,7 @@ QDebug operator<<(QDebug debug, const QEasingCurve &item)
{
QDebugStateSaver saver(debug);
debug << "type:" << item.d_ptr->type
- << "func:" << item.d_ptr->func;
+ << "func:" << reinterpret_cast<const void *>(item.d_ptr->func);
if (item.d_ptr->config) {
debug << QString::fromLatin1("period:%1").arg(item.d_ptr->config->_p, 0, 'f', 20)
<< QString::fromLatin1("amp:%1").arg(item.d_ptr->config->_a, 0, 'f', 20)
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index 81833a758f..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
@@ -44,12 +8,11 @@
QT_REQUIRE_CONFIG(easingcurve);
+#include <QtCore/qlist.h>
#include <QtCore/qobjectdefs.h>
-#include <QtCore/qvector.h>
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,9 +60,9 @@ 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);
- QVector<QPointF> toCubicSpline() const;
+ QList<QPointF> toCubicSpline() const;
Type type() const;
void setType(Type type);
@@ -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
new file mode 100644
index 0000000000..d2c0d45b79
--- /dev/null
+++ b/src/corelib/tools/qflatmap_p.h
@@ -0,0 +1,1109 @@
+// 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
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qlist.h"
+#include "private/qglobal_p.h"
+
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <numeric>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QFlatMap provides an associative container backed by sorted sequential
+ containers. By default, QList is used.
+
+ Keys and values are stored in two separate containers. This provides improved
+ cache locality for key iteration and makes keys() and values() fast
+ operations.
+
+ One can customize the underlying container type by passing the KeyContainer
+ and MappedContainer template arguments:
+ QFlatMap<float, int, std::less<float>, std::vector<float>, std::vector<int>>
+*/
+
+// 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 {};
+constexpr OrderedUniqueRange_t OrderedUniqueRange = {};
+
+} // namespace Qt
+
+template <class Key, class T, class Compare>
+class QFlatMapValueCompare : protected Compare
+{
+public:
+ QFlatMapValueCompare() = default;
+ QFlatMapValueCompare(const Compare &key_compare)
+ : Compare(key_compare)
+ {
+ }
+
+ using value_type = std::pair<const Key, T>;
+ static constexpr bool is_comparator_noexcept = noexcept(
+ std::declval<Compare>()(std::declval<const Key &>(), std::declval<const Key &>()));
+
+ bool operator()(const value_type &lhs, const value_type &rhs) const
+ noexcept(is_comparator_noexcept)
+ {
+ return Compare::operator()(lhs.first, rhs.first);
+ }
+};
+
+namespace qflatmap {
+namespace detail {
+template <class T>
+class QFlatMapMockPointer
+{
+ T ref;
+public:
+ QFlatMapMockPointer(T r)
+ : ref(r)
+ {
+ }
+
+ T *operator->()
+ {
+ return &ref;
+ }
+};
+} // namespace detail
+} // namespace qflatmap
+
+template<class Key, class T, class Compare = std::less<Key>, class KeyContainer = QList<Key>,
+ class MappedContainer = QList<T>>
+class QFlatMap : private QFlatMapValueCompare<Key, T, Compare>
+{
+ static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
+
+ template<class U>
+ using mock_pointer = qflatmap::detail::QFlatMapMockPointer<U>;
+
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using value_compare = QFlatMapValueCompare<Key, T, Compare>;
+ using value_type = typename value_compare::value_type;
+ using key_container_type = KeyContainer;
+ using mapped_container_type = MappedContainer;
+ using size_type = typename key_container_type::size_type;
+ using key_compare = Compare;
+
+ struct containers
+ {
+ key_container_type keys;
+ mapped_container_type values;
+ };
+
+ class iterator
+ {
+ public:
+ using difference_type = ptrdiff_t;
+ using value_type = std::pair<const Key, T>;
+ using reference = std::pair<const Key &, T &>;
+ using pointer = mock_pointer<reference>;
+ using iterator_category = std::random_access_iterator_tag;
+
+ iterator() = default;
+
+ iterator(containers *ac, size_type ai)
+ : c(ac), i(ai)
+ {
+ }
+
+ reference operator*() const
+ {
+ return { c->keys[i], c->values[i] };
+ }
+
+ pointer operator->() const
+ {
+ return { operator*() };
+ }
+
+ bool operator==(const iterator &o) const
+ {
+ return c == o.c && i == o.i;
+ }
+
+ bool operator!=(const iterator &o) const
+ {
+ return !operator==(o);
+ }
+
+ iterator &operator++()
+ {
+ ++i;
+ return *this;
+ }
+
+ iterator operator++(int)
+ {
+
+ iterator r = *this;
+ ++*this;
+ return r;
+ }
+
+ iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+
+ iterator operator--(int)
+ {
+ iterator r = *this;
+ --*this;
+ return r;
+ }
+
+ iterator &operator+=(size_type n)
+ {
+ i += n;
+ return *this;
+ }
+
+ friend iterator operator+(size_type n, const iterator a)
+ {
+ iterator ret = a;
+ return ret += n;
+ }
+
+ friend iterator operator+(const iterator a, size_type n)
+ {
+ return n + a;
+ }
+
+ iterator &operator-=(size_type n)
+ {
+ i -= n;
+ return *this;
+ }
+
+ friend iterator operator-(const iterator a, size_type n)
+ {
+ iterator ret = a;
+ return ret -= n;
+ }
+
+ friend difference_type operator-(const iterator b, const iterator a)
+ {
+ return b.i - a.i;
+ }
+
+ reference operator[](size_type n) const
+ {
+ size_type k = i + n;
+ return { c->keys[k], c->values[k] };
+ }
+
+ bool operator<(const iterator &other) const
+ {
+ return i < other.i;
+ }
+
+ bool operator>(const iterator &other) const
+ {
+ return i > other.i;
+ }
+
+ bool operator<=(const iterator &other) const
+ {
+ return i <= other.i;
+ }
+
+ bool operator>=(const iterator &other) const
+ {
+ return i >= other.i;
+ }
+
+ const Key &key() const { return c->keys[i]; }
+ T &value() const { return c->values[i]; }
+
+ private:
+ containers *c = nullptr;
+ size_type i = 0;
+ friend QFlatMap;
+ };
+
+ class const_iterator
+ {
+ public:
+ using difference_type = ptrdiff_t;
+ using value_type = std::pair<const Key, const T>;
+ using reference = std::pair<const Key &, const T &>;
+ using pointer = mock_pointer<reference>;
+ using iterator_category = std::random_access_iterator_tag;
+
+ const_iterator() = default;
+
+ const_iterator(const containers *ac, size_type ai)
+ : c(ac), i(ai)
+ {
+ }
+
+ const_iterator(iterator o)
+ : c(o.c), i(o.i)
+ {
+ }
+
+ reference operator*() const
+ {
+ return { c->keys[i], c->values[i] };
+ }
+
+ pointer operator->() const
+ {
+ return { operator*() };
+ }
+
+ bool operator==(const const_iterator &o) const
+ {
+ return c == o.c && i == o.i;
+ }
+
+ bool operator!=(const const_iterator &o) const
+ {
+ return !operator==(o);
+ }
+
+ const_iterator &operator++()
+ {
+ ++i;
+ return *this;
+ }
+
+ const_iterator operator++(int)
+ {
+
+ const_iterator r = *this;
+ ++*this;
+ return r;
+ }
+
+ const_iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+
+ const_iterator operator--(int)
+ {
+ const_iterator r = *this;
+ --*this;
+ return r;
+ }
+
+ const_iterator &operator+=(size_type n)
+ {
+ i += n;
+ return *this;
+ }
+
+ friend const_iterator operator+(size_type n, const const_iterator a)
+ {
+ const_iterator ret = a;
+ return ret += n;
+ }
+
+ friend const_iterator operator+(const const_iterator a, size_type n)
+ {
+ return n + a;
+ }
+
+ const_iterator &operator-=(size_type n)
+ {
+ i -= n;
+ return *this;
+ }
+
+ friend const_iterator operator-(const const_iterator a, size_type n)
+ {
+ const_iterator ret = a;
+ return ret -= n;
+ }
+
+ friend difference_type operator-(const const_iterator b, const const_iterator a)
+ {
+ return b.i - a.i;
+ }
+
+ reference operator[](size_type n) const
+ {
+ size_type k = i + n;
+ return { c->keys[k], c->values[k] };
+ }
+
+ bool operator<(const const_iterator &other) const
+ {
+ return i < other.i;
+ }
+
+ bool operator>(const const_iterator &other) const
+ {
+ return i > other.i;
+ }
+
+ bool operator<=(const const_iterator &other) const
+ {
+ return i <= other.i;
+ }
+
+ bool operator>=(const const_iterator &other) const
+ {
+ return i >= other.i;
+ }
+
+ const Key &key() const { return c->keys[i]; }
+ const T &value() const { return c->values[i]; }
+
+ private:
+ const containers *c = nullptr;
+ size_type i = 0;
+ friend QFlatMap;
+ };
+
+private:
+ template <class, class = void>
+ struct is_marked_transparent_type : std::false_type { };
+
+ template <class X>
+ 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<
+ is_marked_transparent_type<X>::value>::type *;
+
+ template <typename It>
+ using is_compatible_iterator = typename std::enable_if<
+ std::is_same<value_type, typename std::iterator_traits<It>::value_type>::value>::type *;
+
+public:
+ QFlatMap() = default;
+
+#ifdef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
+ explicit QFlatMap(const key_container_type &keys, const mapped_container_type &values)
+ : c{keys, values}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, const mapped_container_type &values)
+ : c{std::move(keys), values}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(const key_container_type &keys, mapped_container_type &&values)
+ : c{keys, std::move(values)}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, mapped_container_type &&values)
+ : c{std::move(keys), std::move(values)}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(std::initializer_list<value_type> lst)
+ : QFlatMap(lst.begin(), lst.end())
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(InputIt first, InputIt last)
+ {
+ initWithRange(first, last);
+ ensureOrderedUnique();
+ }
+#endif
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ const mapped_container_type &values)
+ : c{keys, values}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ const mapped_container_type &values)
+ : c{std::move(keys), values}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ mapped_container_type &&values)
+ : c{keys, std::move(values)}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ mapped_container_type &&values)
+ : c{std::move(keys), std::move(values)}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, std::initializer_list<value_type> lst)
+ : QFlatMap(Qt::OrderedUniqueRange, lst.begin(), lst.end())
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, InputIt first, InputIt last)
+ {
+ initWithRange(first, last);
+ }
+
+ explicit QFlatMap(const Compare &compare)
+ : value_compare(compare)
+ {
+ }
+
+#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}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, const mapped_container_type &values,
+ const Compare &compare)
+ : value_compare(compare), c{std::move(keys), values}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(const key_container_type &keys, mapped_container_type &&values,
+ const Compare &compare)
+ : value_compare(compare), c{keys, std::move(values)}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(key_container_type &&keys, mapped_container_type &&values,
+ const Compare &compare)
+ : value_compare(compare), c{std::move(keys), std::move(values)}
+ {
+ ensureOrderedUnique();
+ }
+
+ explicit QFlatMap(std::initializer_list<value_type> lst, const Compare &compare)
+ : QFlatMap(lst.begin(), lst.end(), compare)
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(InputIt first, InputIt last, const Compare &compare)
+ : value_compare(compare)
+ {
+ initWithRange(first, last);
+ ensureOrderedUnique();
+ }
+#endif
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ const mapped_container_type &values, const Compare &compare)
+ : value_compare(compare), c{keys, values}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ const mapped_container_type &values, const Compare &compare)
+ : value_compare(compare), c{std::move(keys), values}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, const key_container_type &keys,
+ mapped_container_type &&values, const Compare &compare)
+ : value_compare(compare), c{keys, std::move(values)}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, key_container_type &&keys,
+ mapped_container_type &&values, const Compare &compare)
+ : value_compare(compare), c{std::move(keys), std::move(values)}
+ {
+ }
+
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, std::initializer_list<value_type> lst,
+ const Compare &compare)
+ : QFlatMap(Qt::OrderedUniqueRange, lst.begin(), lst.end(), compare)
+ {
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ explicit QFlatMap(Qt::OrderedUniqueRange_t, InputIt first, InputIt last, const Compare &compare)
+ : value_compare(compare)
+ {
+ initWithRange(first, last);
+ }
+
+ size_type count() const noexcept { return c.keys.size(); }
+ size_type size() const noexcept { return c.keys.size(); }
+ size_type capacity() const noexcept { return c.keys.capacity(); }
+ bool isEmpty() const noexcept { return c.keys.empty(); }
+ bool empty() const noexcept { return c.keys.empty(); }
+ containers extract() && { return std::move(c); }
+ const key_container_type &keys() const noexcept { return c.keys; }
+ const mapped_container_type &values() const noexcept { return c.values; }
+
+ void reserve(size_type s)
+ {
+ c.keys.reserve(s);
+ c.values.reserve(s);
+ }
+
+ void clear()
+ {
+ c.keys.clear();
+ c.values.clear();
+ }
+
+ bool remove(const Key &key)
+ {
+ 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)
+ {
+ c.values.erase(toValuesIterator(it));
+ return fromKeysIterator(c.keys.erase(toKeysIterator(it)));
+ }
+
+ T take(const Key &key)
+ {
+ 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 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 = 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 = 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)
+ {
+ return try_emplace(key).first.value();
+ }
+
+ T &operator[](Key &&key)
+ {
+ return try_emplace(std::move(key)).first.value();
+ }
+
+ T operator[](const Key &key) const
+ {
+ return value(key);
+ }
+
+#ifdef QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
+ std::pair<iterator, bool> insert(const Key &key, const T &value)
+ {
+ return try_emplace(key, value);
+ }
+
+ std::pair<iterator, bool> insert(Key &&key, const T &value)
+ {
+ 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.emplace(toValuesIterator(it), std::forward<Args>(args)...);
+ return { fromKeysIterator(c.keys.insert(toKeysIterator(it), key)), true };
+ } else {
+ return {it, false};
+ }
+ }
+
+ 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.emplace(toValuesIterator(it), std::forward<Args>(args)...);
+ return { fromKeysIterator(c.keys.insert(toKeysIterator(it), std::move(key))), true };
+ } else {
+ 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)
+ {
+ insertRange(first, last);
+ }
+
+ // ### Merge with the templated version above
+ // once we can use std::disjunction in is_compatible_iterator.
+ void insert(const value_type *first, const value_type *last)
+ {
+ insertRange(first, last);
+ }
+
+ template <class InputIt, is_compatible_iterator<InputIt> = nullptr>
+ void insert(Qt::OrderedUniqueRange_t, InputIt first, InputIt last)
+ {
+ insertOrderedUniqueRange(first, last);
+ }
+
+ // ### Merge with the templated version above
+ // once we can use std::disjunction in is_compatible_iterator.
+ void insert(Qt::OrderedUniqueRange_t, const value_type *first, const value_type *last)
+ {
+ insertOrderedUniqueRange(first, last);
+ }
+#endif
+
+ iterator begin() { return { &c, 0 }; }
+ const_iterator begin() const { return { &c, 0 }; }
+ const_iterator cbegin() const { return begin(); }
+ const_iterator constBegin() const { return cbegin(); }
+ iterator end() { return { &c, c.keys.size() }; }
+ const_iterator end() const { return { &c, c.keys.size() }; }
+ const_iterator cend() const { return end(); }
+ const_iterator constEnd() const { return cend(); }
+ std::reverse_iterator<iterator> rbegin() { return std::reverse_iterator<iterator>(end()); }
+ std::reverse_iterator<const_iterator> rbegin() const
+ {
+ return std::reverse_iterator<const_iterator>(end());
+ }
+ std::reverse_iterator<const_iterator> crbegin() const { return rbegin(); }
+ std::reverse_iterator<iterator> rend() {
+ return std::reverse_iterator<iterator>(begin());
+ }
+ std::reverse_iterator<const_iterator> rend() const
+ {
+ return std::reverse_iterator<const_iterator>(begin());
+ }
+ std::reverse_iterator<const_iterator> crend() const { return rend(); }
+
+ iterator lower_bound(const Key &key)
+ {
+ auto cit = 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 = std::as_const(*this).lower_bound(key);
+ return { &c, cit.i };
+ }
+
+ const_iterator lower_bound(const Key &key) const
+ {
+ return fromKeysIterator(std::lower_bound(c.keys.begin(), c.keys.end(), key, key_comp()));
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ const_iterator lower_bound(const X &key) const
+ {
+ return fromKeysIterator(std::lower_bound(c.keys.begin(), c.keys.end(), key, key_comp()));
+ }
+
+ iterator find(const Key &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
+ {
+ auto it = lower_bound(key);
+ if (it != end()) {
+ if (!key_compare::operator()(key, it.key()))
+ return it;
+ it = end();
+ }
+ return it;
+ }
+
+ template <class X, class Y = Compare, is_marked_transparent<Y> = nullptr>
+ const_iterator find(const X &key) const
+ {
+ 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
+ {
+ return static_cast<key_compare>(*this);
+ }
+
+ value_compare value_comp() const noexcept
+ {
+ return static_cast<value_compare>(*this);
+ }
+
+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)
+ {
+ QtPrivate::reserveIfForwardIterator(this, first, last);
+ while (first != last) {
+ c.keys.push_back(first->first);
+ c.values.push_back(first->second);
+ ++first;
+ }
+ }
+
+ iterator fromKeysIterator(typename key_container_type::iterator kit)
+ {
+ return { &c, static_cast<size_type>(std::distance(c.keys.begin(), kit)) };
+ }
+
+ const_iterator fromKeysIterator(typename key_container_type::const_iterator kit) const
+ {
+ return { &c, static_cast<size_type>(std::distance(c.keys.begin(), kit)) };
+ }
+
+ typename key_container_type::iterator toKeysIterator(iterator it)
+ {
+ return c.keys.begin() + it.i;
+ }
+
+ typename mapped_container_type::iterator toValuesIterator(iterator it)
+ {
+ return c.values.begin() + it.i;
+ }
+
+ template <class InputIt>
+ void insertRange(InputIt first, InputIt last)
+ {
+ size_type i = c.keys.size();
+ c.keys.resize(i + std::distance(first, last));
+ c.values.resize(c.keys.size());
+ for (; first != last; ++first, ++i) {
+ c.keys[i] = first->first;
+ c.values[i] = first->second;
+ }
+ ensureOrderedUnique();
+ }
+
+ class IndexedKeyComparator
+ {
+ public:
+ IndexedKeyComparator(const QFlatMap *am)
+ : m(am)
+ {
+ }
+
+ bool operator()(size_type i, size_type k) const
+ {
+ return m->key_comp()(m->c.keys[i], m->c.keys[k]);
+ }
+
+ private:
+ const QFlatMap *m;
+ };
+
+ template <class InputIt>
+ void insertOrderedUniqueRange(InputIt first, InputIt last)
+ {
+ const size_type s = c.keys.size();
+ c.keys.resize(s + std::distance(first, last));
+ c.values.resize(c.keys.size());
+ for (size_type i = s; first != last; ++first, ++i) {
+ c.keys[i] = first->first;
+ c.values[i] = first->second;
+ }
+
+ std::vector<size_type> p(size_t(c.keys.size()));
+ std::iota(p.begin(), p.end(), 0);
+ std::inplace_merge(p.begin(), p.begin() + s, p.end(), IndexedKeyComparator(this));
+ applyPermutation(p);
+ makeUnique();
+ }
+
+ void ensureOrderedUnique()
+ {
+ std::vector<size_type> p(size_t(c.keys.size()));
+ std::iota(p.begin(), p.end(), 0);
+ std::stable_sort(p.begin(), p.end(), IndexedKeyComparator(this));
+ applyPermutation(p);
+ makeUnique();
+ }
+
+ void applyPermutation(const std::vector<size_type> &p)
+ {
+ const size_type s = c.keys.size();
+ std::vector<bool> done(s);
+ for (size_type i = 0; i < s; ++i) {
+ if (done[i])
+ continue;
+ done[i] = true;
+ size_type j = i;
+ size_type k = p[i];
+ while (i != k) {
+ qSwap(c.keys[j], c.keys[k]);
+ qSwap(c.values[j], c.values[k]);
+ done[k] = true;
+ j = k;
+ k = p[j];
+ }
+ }
+ }
+
+ void makeUnique()
+ {
+ // 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;
+
+ // 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.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 5ba23b344b..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
@@ -190,7 +152,7 @@ class QFreeList
Q_DISABLE_COPY_MOVE(QFreeList)
public:
- Q_DECL_CONSTEXPR inline QFreeList();
+ constexpr inline QFreeList();
inline ~QFreeList();
// returns the payload for the given index \a x
@@ -206,11 +168,9 @@ public:
};
template <typename T, typename ConstantsType>
-Q_DECL_CONSTEXPR inline QFreeList<T, ConstantsType>::QFreeList()
+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 a53d6db997..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
@@ -45,6 +9,7 @@
#define _CRT_RAND_S
#endif
#include <stdlib.h>
+#include <stdint.h>
#include "qhash.h"
@@ -59,292 +24,1254 @@
#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
-/*
- The Java's hashing algorithm for strings is a variation of D. J. Bernstein
- hashing algorithm appeared here http://cr.yp.to/cdb/cdb.txt
- and informally known as DJB33XX - DJB's 33 Times Xor.
- Java uses DJB31XA, that is, 31 Times Add.
-
- The original algorithm was a loop around
- (h << 5) + h ^ c
- (which is indeed h*33 ^ c); it was then changed to
- (h << 5) - h ^ c
- (so h*31^c: DJB31XX), and the XOR changed to a sum:
- (h << 5) - h + c
- (DJB31XA), which can save some assembly instructions.
-
- Still, we can avoid writing the multiplication as "(h << 5) - h"
- -- the compiler will turn it into a shift and an addition anyway
- (for instance, gcc 4.4 does that even at -O0).
-*/
-
-#if QT_COMPILER_SUPPORTS_HERE(SSE4_2)
-static inline bool hasFastCrc32()
+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
{
- return qCpuHasFeature(SSE4_2);
-}
+ 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;
+ };
-template <typename Char>
-QT_FUNCTION_TARGET(SSE4_2)
-static uint crc32(const Char *ptr, size_t len, uint h)
+ 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
{
- // The CRC32 instructions from Nehalem calculate a 32-bit CRC32 checksum
- const uchar *p = reinterpret_cast<const uchar *>(ptr);
- const uchar *const e = p + (len * sizeof(Char));
-# ifdef Q_PROCESSOR_X86_64
- // The 64-bit instruction still calculates only 32-bit, but without this
- // variable GCC 4.9 still tries to clear the high bits on every loop
- qulonglong h2 = h;
-
- p += 8;
- for ( ; p <= e; p += 8)
- h2 = _mm_crc32_u64(h2, qFromUnaligned<qlonglong>(p - 8));
- h = h2;
- p -= 8;
-
- len = e - p;
- if (len & 4) {
- h = _mm_crc32_u32(h, qFromUnaligned<uint>(p));
- p += 4;
+ 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;
+ }
}
-# else
- p += 4;
- for ( ; p <= e; p += 4)
- h = _mm_crc32_u32(h, qFromUnaligned<uint>(p - 4));
- p -= 4;
- len = e - p;
-# endif
- if (len & 2) {
- h = _mm_crc32_u16(h, qFromUnaligned<ushort>(p));
- p += 2;
+
+ // 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];
}
- if (sizeof(Char) == 1 && len & 1)
- h = _mm_crc32_u8(h, *p);
- return h;
+ result.state = JustInitialized;
+ return result;
+#endif
}
-#elif defined(__ARM_FEATURE_CRC32)
-static inline bool hasFastCrc32()
+
+inline HashSeedStorage::StateResult HashSeedStorage::state(int which)
{
- return qCpuHasFeature(CRC32);
+ 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
-template <typename Char>
-#if defined(Q_PROCESSOR_ARM_64)
-QT_FUNCTION_TARGET(CRC32)
+/*
+ The QHash seed itself.
+*/
+#ifdef Q_DECL_INIT_PRIORITY
+Q_DECL_INIT_PRIORITY(05)
+#else
+Q_CONSTINIT
#endif
-static uint crc32(const Char *ptr, size_t len, uint h)
+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
{
- // The crc32[whbd] instructions on Aarch64/Aarch32 calculate a 32-bit CRC32 checksum
- const uchar *p = reinterpret_cast<const uchar *>(ptr);
- const uchar *const e = p + (len * sizeof(Char));
-
-#ifndef __ARM_FEATURE_UNALIGNED
- if (Q_UNLIKELY(reinterpret_cast<quintptr>(p) & 7)) {
- if ((sizeof(Char) == 1) && (reinterpret_cast<quintptr>(p) & 1) && (e - p > 0)) {
- h = __crc32b(h, *p);
- ++p;
- }
- if ((reinterpret_cast<quintptr>(p) & 2) && (e >= p + 2)) {
- h = __crc32h(h, *reinterpret_cast<const uint16_t *>(p));
- p += 2;
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+
+ unsigned int h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
+ const unsigned char *end = data + (len & ~3);
+
+ while (data != end) {
+ size_t k;
+ memcpy(&k, data, sizeof(uint));
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ }
+
+ // Handle the last few bytes of the input array
+ len &= 3;
+ if (len) {
+ unsigned int k = 0;
+ end += len;
+
+ while (data != end) {
+ k <<= 8;
+ k |= *data;
+ ++data;
}
- if ((reinterpret_cast<quintptr>(p) & 4) && (e >= p + 4)) {
- h = __crc32w(h, *reinterpret_cast<const uint32_t *>(p));
- p += 4;
+ h ^= k;
+ h *= m;
+ }
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+#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;
+ const int r = 47;
+
+ uint64_t h = seed ^ (len * m);
+
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
+ const unsigned char *end = data + (len & ~7ul);
+
+ while (data != end) {
+ uint64_t k;
+ memcpy(&k, data, sizeof(uint64_t));
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h ^= k;
+ h *= m;
+
+ data += 8;
+ }
+
+ len &= 7;
+ if (len) {
+ // handle the last few bytes of input
+ size_t k = 0;
+ end += len;
+
+ while (data != end) {
+ k <<= 8;
+ k |= *data;
+ ++data;
}
+ h ^= k;
+ h *= m;
}
+
+ h ^= h >> r;
+ h *= m;
+ h ^= h >> r;
+
+ return h;
+}
+
#endif
- for ( ; p + 8 <= e; p += 8)
- h = __crc32d(h, *reinterpret_cast<const uint64_t *>(p));
+namespace {
+// This is an inlined version of the SipHash implementation that is
+// trying to avoid some memcpy's from uint64 to uint8[] and back.
+
+#define ROTL(x, b) (((x) << (b)) | ((x) >> (sizeof(x) * 8 - (b))))
+
+#define SIPROUND \
+ do { \
+ v0 += v1; \
+ v1 = ROTL(v1, 13); \
+ v1 ^= v0; \
+ v0 = ROTL(v0, 32); \
+ v2 += v3; \
+ v3 = ROTL(v3, 16); \
+ v3 ^= v2; \
+ v0 += v3; \
+ v3 = ROTL(v3, 21); \
+ v3 ^= v0; \
+ v2 += v1; \
+ v1 = ROTL(v1, 17); \
+ v1 ^= v2; \
+ v2 = ROTL(v2, 32); \
+ } while (0)
+
+template <int cROUNDS = 2, int dROUNDS = 4> struct SipHash64
+{
+ /* "somepseudorandomlygeneratedbytes" */
+ uint64_t v0 = 0x736f6d6570736575ULL;
+ uint64_t v1 = 0x646f72616e646f6dULL;
+ uint64_t v2 = 0x6c7967656e657261ULL;
+ uint64_t v3 = 0x7465646279746573ULL;
+ uint64_t b;
+ 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;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
- len = e - p;
- if (len == 0)
- return h;
- if (len & 4) {
- h = __crc32w(h, *reinterpret_cast<const uint32_t *>(p));
- p += 4;
+ v0 ^= m;
}
- if (len & 2) {
- h = __crc32h(h, *reinterpret_cast<const uint16_t *>(p));
- p += 2;
+}
+
+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;
+ case 0:
+ break;
}
- if (sizeof(Char) == 1 && len & 1)
- h = __crc32b(h, *p);
- return h;
+
+ v3 ^= b;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
+
+ v0 ^= b;
+
+ v2 ^= 0xff;
+
+ for (i = 0; i < dROUNDS; ++i)
+ SIPROUND;
+
+ b = v0 ^ v1 ^ v2 ^ v3;
+ return b;
}
-#else
-static inline bool hasFastCrc32()
+#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.
+//
+// To make this work, we also need to change the constants for the mixing
+// rotations in ROTL. We're simply using half of the 64bit constants, rounded up
+// for odd numbers.
+//
+// For the v0-v4 constants, simply use the first four bytes of the 64 bit versions.
+//
+
+#define SIPROUND \
+ do { \
+ v0 += v1; \
+ v1 = ROTL(v1, 7); \
+ v1 ^= v0; \
+ v0 = ROTL(v0, 16); \
+ v2 += v3; \
+ v3 = ROTL(v3, 8); \
+ v3 ^= v2; \
+ v0 += v3; \
+ v3 = ROTL(v3, 11); \
+ v3 ^= v0; \
+ v2 += v1; \
+ v1 = ROTL(v1, 9); \
+ v1 ^= v2; \
+ v2 = ROTL(v2, 16); \
+ } while (0)
+
+template <int cROUNDS = 2, int dROUNDS = 4> struct SipHash32
+{
+ /* "somepseudorandomlygeneratedbytes" */
+ uint v0 = 0x736f6d65U;
+ uint v1 = 0x646f7261U;
+ 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)
{
- return false;
+ uint k0 = seed;
+ uint k1 = seed2;
+ b = inlen << 24;
+ v3 ^= k1;
+ v2 ^= k0;
+ v1 ^= k1;
+ v0 ^= k0;
}
-static uint crc32(...)
+template <int cROUNDS, int dROUNDS> inline Q_DECL_HOT_FUNCTION void
+SipHash32<cROUNDS, dROUNDS>::addBlock(const uint8_t *in, size_t inlen)
{
- Q_UNREACHABLE();
- return 0;
+ 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;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
+
+ v0 ^= m;
+ }
}
+
+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;
+ case 0:
+ break;
+ }
+
+ v3 ^= b;
+
+ for (i = 0; i < cROUNDS; ++i)
+ SIPROUND;
+
+ v0 ^= b;
+
+ v2 ^= 0xff;
+
+ for (i = 0; i < dROUNDS; ++i)
+ SIPROUND;
+
+ b = v0 ^ v1 ^ v2 ^ v3;
+ return b;
+}
+#undef SIPROUND
+#undef ROTL
+
+// Use SipHash-1-2, which has similar performance characteristics as
+// stablehash() above, instead of the SipHash-2-4 default
+template <int cROUNDS = 1, int dROUNDS = 2>
+using SipHash = std::conditional_t<sizeof(void *) == 8,
+ SipHash64<cROUNDS, dROUNDS>, SipHash32<cROUNDS, dROUNDS>>;
+} // unnamed namespace
+
+Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
+static size_t siphash(const uint8_t *in, size_t inlen, size_t seed, size_t seed2)
+{
+ constexpr size_t TailSizeMask = sizeof(void *) - 1;
+ SipHash<> hasher(inlen, seed, seed2);
+ hasher.addBlock(in, inlen & ~TailSizeMask);
+ return hasher.finalize(in + (inlen & ~TailSizeMask), inlen & TailSizeMask);
+}
+
+enum ZeroExtension {
+ None = 0,
+ ByteToWord = 1,
+};
+
+template <ZeroExtension = None> static size_t
+qHashBits_fallback(const uchar *p, size_t size, size_t seed, size_t seed2) noexcept;
+template <> size_t qHashBits_fallback<None>(const uchar *p, size_t size, size_t seed, size_t seed2) noexcept
+{
+ if (size <= QT_POINTER_SIZE)
+ return murmurhash(p, size, seed);
+
+ return siphash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
+}
+
+template <> size_t qHashBits_fallback<ByteToWord>(const uchar *data, size_t size, size_t seed, size_t seed2) noexcept
+{
+ auto quick_from_latin1 = [](char16_t *dest, const uchar *data, size_t size) {
+ // Quick, "inlined" version for very short blocks
+ std::copy_n(data, size, dest);
+ };
+ if (size <= QT_POINTER_SIZE / 2) {
+ std::array<char16_t, QT_POINTER_SIZE / 2> buf;
+ quick_from_latin1(buf.data(), data, size);
+ return murmurhash(buf.data(), size * 2, seed);
+ }
+
+ constexpr size_t TailSizeMask = sizeof(void *) / 2 - 1;
+ std::array<char16_t, 256> buf;
+ SipHash<> siphash(size * 2, seed, seed2);
+ ptrdiff_t offset = 0;
+ for ( ; offset + buf.size() < size; offset += buf.size()) {
+ qt_from_latin1(buf.data(), reinterpret_cast<const char *>(data) + offset, buf.size());
+ siphash.addBlock(reinterpret_cast<uint8_t *>(buf.data()), sizeof(buf));
+ }
+ if (size_t n = size - offset; n > TailSizeMask) {
+ n &= ~TailSizeMask;
+ qt_from_latin1(buf.data(), reinterpret_cast<const char *>(data) + offset, n);
+ siphash.addBlock(reinterpret_cast<uint8_t *>(buf.data()), n * 2);
+ offset += n;
+ }
+
+ quick_from_latin1(buf.data(), data + offset, size - offset);
+ return siphash.finalize(reinterpret_cast<uint8_t *>(buf.data()), (size - offset) * 2);
+}
+
+#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__) // GCC
+# define QHASH_AES_SANITIZER_BUILD
+#elif __has_feature(address_sanitizer) || __has_feature(thread_sanitizer) // Clang
+# define QHASH_AES_SANITIZER_BUILD
#endif
-static inline uint hash(const uchar *p, size_t len, uint seed) noexcept
+// 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/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
+ // cryptographically secure. We're simply using the instruction that performs
+ // 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")
+ 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)
{
- uint h = seed;
+ __m128i mseed = mm_cvtsz_si128(seed);
+ mseed2 = mm_set1_epz(seed2);
- if (seed && hasFastCrc32())
- return crc32(p, len, h);
+ // 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);
- for (size_t i = 0; i < len; ++i)
- h = 31 * h + p[i];
+ // merge with the process-global seed
+ __m128i key = _mm_xor_si128(mseed, mseed2);
- return h;
+ // scramble the key
+ __m128i state0 = _mm_aesenc_si128(key, key);
+ this->state0 = state0;
}
-uint qHashBits(const void *p, size_t len, uint seed) noexcept
+Q_ALWAYS_INLINE __m128i AESHashSeed::state1() const
{
- return hash(static_cast<const uchar*>(p), int(len), seed);
+ {
+ // unlike the Go code, we don't have more per-process seed
+ __m128i state1 = _mm_aesenc_si128(state0, mseed2);
+ return state1;
+ }
}
-static inline uint hash(const QChar *p, size_t len, uint seed) noexcept
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+aeshash128_16to32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
{
- uint h = seed;
+ {
+ 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);
+ }
- if (seed && hasFastCrc32())
- return crc32(p, len, h);
+ // combine results:
+ state0 = _mm_xor_si128(state0, state1);
+ }
- for (size_t i = 0; i < len; ++i)
- h = 31 * h + p[i].unicode();
+ return mm_cvtsi128_sz(state0);
+}
- return h;
+// 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);
}
-uint qHash(const QByteArray &key, uint seed) noexcept
+# 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)
{
- return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed);
+ // VPMOVZXBW xmm, ymm
+ __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ return _mm256_cvtepu8_epi16(data);
}
-#if QT_STRINGVIEW_LEVEL < 2
-uint qHash(const QString &key, uint seed) noexcept
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(VAES_AVX512) QT_VECTORCALL
+aeshash256_lt32_avx256(__m256i state0, const uchar *p, size_t len)
{
- return hash(key.unicode(), size_t(key.size()), seed);
+ __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);
}
-uint qHash(const QStringRef &key, uint seed) noexcept
+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)
{
- return hash(key.unicode(), size_t(key.size()), seed);
+ 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)
+ goto lt32;
+
+ // rounds of 32 bytes
+ {
+ // Make state1 = ~state0:
+ 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 *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 = veorq_u8(state0, state1);
+ }
+ len &= 0x1f;
+
+ // do we still have 16 or more bytes?
+ if (len & 0x10) {
+lt32:
+ uint8x16_t data = vld1q_u8(p);
+ hash16bytes(state0, data);
+ 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 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
+
+ uint8x8_t data8;
+
+ if (Q_LIKELY(quintptr(p + 8) & 0xff8)) {
+ // same page, we definitely can't fault:
+ // 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,
+ 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 8 bytes ending at the data end, then shuffle them to the beginning
+ static const qint8 shufflecontrol[] = {
+ 1, 2, 3, 4, 5, 6, 7,
+ -1, -1, -1, -1, -1, -1, -1,
+ };
+ 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 vgetq_lane_u64(vreinterpretq_u64_u8(state0), 0);
+# else
+ return vgetq_lane_u32(vreinterpretq_u32_u8(state0), 0);
+# endif
}
#endif
-uint qHash(QStringView key, uint seed) noexcept
+size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
+{
+#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
+ // 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(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
+
+ return qHashBits_fallback<>(data, size, seed, seed2);
+}
+
+size_t qHash(QByteArrayView key, size_t seed) noexcept
+{
+ return qHashBits(key.constData(), size_t(key.size()), seed);
+}
+
+size_t qHash(QStringView key, size_t seed) noexcept
{
- return hash(key.data(), key.size(), seed);
+ return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
}
-uint qHash(const QBitArray &bitArray, uint seed) noexcept
+#ifndef QT_BOOTSTRAPPED
+size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
{
- int m = bitArray.d.size() - 1;
- uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()),
- size_t(qMax(0, m)), seed);
+ 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
-uint qHash(QLatin1String key, uint seed) noexcept
+size_t qHash(QLatin1StringView key, size_t seed) noexcept
{
- return hash(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.
- Creates the QHash random seed from various sources.
- In order of decreasing precedence:
- - under Unix, it attemps to read from /dev/urandom;
- - under Unix, it attemps to read from /dev/random;
- - under Windows, it attempts to use rand_s;
- - as a general fallback, the application's PID, a timestamp and the
- address of a stack-local variable are used.
+ 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.
+ */
- return seed;
+/*!
+ \fn QHashSeed::operator size_t() const
+
+ Converts the returned hash seed into a \c size_t.
+ */
+
+/*!
+ \threadsafe
+
+ 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.
@@ -364,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
@@ -413,354 +1337,59 @@ uint qt_hash(QStringView key, uint chained) noexcept
return h;
}
-/*
- The prime_deltas array contains the difference between a power
- of two and the next prime number:
-
- prime_deltas[i] = nextprime(2^i) - 2^i
-
- Basically, it's sequence A092131 from OEIS, assuming:
- - nextprime(1) = 1
- - nextprime(2) = 2
- and
- - left-extending it for the offset 0 (A092131 starts at i=1)
- - stopping the sequence at i = 28 (the table is big enough...)
-*/
-
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 17, 27, 3,
- 1, 29, 3, 21, 7, 17, 15, 9, 43, 35, 15, 0, 0, 0, 0, 0
-};
-
-/*
- The primeForNumBits() function returns the prime associated to a
- power of two. For example, primeForNumBits(8) returns 257.
-*/
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-/*
- Returns the smallest integer n such that
- primeForNumBits(n) >= hint.
-*/
-static int countBits(int hint)
-{
- int numBits = 0;
- int bits = hint;
-
- while (bits > 1) {
- bits >>= 1;
- numBits++;
- }
+/*!
+ \fn template <typename T1, typename T2> size_t qHash(const std::pair<T1, T2> &key, size_t seed = 0)
+ \since 5.7
+ \relates QHash
- if (numBits >= (int)sizeof(prime_deltas)) {
- numBits = sizeof(prime_deltas) - 1;
- } else if (primeForNumBits(numBits) < hint) {
- ++numBits;
- }
- return numBits;
-}
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
-/*
- A QHash has initially around pow(2, MinNumBits) buckets. For
- example, if MinNumBits is 4, it has 17 buckets.
+ Types \c T1 and \c T2 must be supported by qHash().
*/
-const int MinNumBits = 4;
-
-const QHashData QHashData::shared_null = {
- nullptr, nullptr, Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, MinNumBits, 0, 0, 0, true, false, 0
-};
-
-void *QHashData::allocateNode(int nodeAlign)
-{
- void *ptr = strictAlignment ? qMallocAligned(nodeSize, nodeAlign) : malloc(nodeSize);
- Q_CHECK_PTR(ptr);
- return ptr;
-}
-
-void QHashData::freeNode(void *node)
-{
- if (strictAlignment)
- qFreeAligned(node);
- else
- free(node);
-}
-QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *),
- void (*node_delete)(Node *),
- int nodeSize,
- int nodeAlign)
-{
- union {
- QHashData *d;
- Node *e;
- };
- if (this == &shared_null)
- qt_initialize_qhash_seed(); // may throw
- d = new QHashData;
- d->fakeNext = nullptr;
- d->buckets = nullptr;
- d->ref.initializeOwned();
- d->size = size;
- d->nodeSize = nodeSize;
- d->userNumBits = userNumBits;
- d->numBits = numBits;
- d->numBuckets = numBuckets;
- d->seed = (this == &shared_null) ? uint(qt_qhash_seed.loadRelaxed()) : seed;
- d->sharable = true;
- d->strictAlignment = nodeAlign > 8;
- d->reserved = 0;
-
- if (numBuckets) {
- QT_TRY {
- d->buckets = new Node *[numBuckets];
- } QT_CATCH(...) {
- // restore a consistent state for d
- d->numBuckets = 0;
- // roll back
- d->free_helper(node_delete);
- QT_RETHROW;
- }
-
- Node *this_e = reinterpret_cast<Node *>(this);
- for (int i = 0; i < numBuckets; ++i) {
- Node **nextNode = &d->buckets[i];
- Node *oldNode = buckets[i];
- while (oldNode != this_e) {
- QT_TRY {
- Node *dup = static_cast<Node *>(allocateNode(nodeAlign));
-
- QT_TRY {
- node_duplicate(oldNode, dup);
- } QT_CATCH(...) {
- freeNode( dup );
- QT_RETHROW;
- }
-
- *nextNode = dup;
- nextNode = &dup->next;
- oldNode = oldNode->next;
- } QT_CATCH(...) {
- // restore a consistent state for d
- *nextNode = e;
- d->numBuckets = i+1;
- // roll back
- d->free_helper(node_delete);
- QT_RETHROW;
- }
- }
- *nextNode = e;
- }
- }
- return d;
-}
-
-void QHashData::free_helper(void (*node_delete)(Node *))
-{
- if (node_delete) {
- Node *this_e = reinterpret_cast<Node *>(this);
- Node **bucket = reinterpret_cast<Node **>(this->buckets);
-
- int n = numBuckets;
- while (n--) {
- Node *cur = *bucket++;
- while (cur != this_e) {
- Node *next = cur->next;
- node_delete(cur);
- freeNode(cur);
- cur = next;
- }
- }
- }
- delete [] buckets;
- delete this;
-}
+/*!
+ \fn template <typename... T> size_t qHashMulti(size_t seed, const T &...args)
+ \relates QHash
+ \since 6.0
-QHashData::Node *QHashData::nextNode(Node *node)
-{
- union {
- Node *next;
- Node *e;
- QHashData *d;
- };
- next = node->next;
- Q_ASSERT_X(next, "QHash", "Iterating beyond end()");
- if (next->next)
- return next;
-
- int start = (node->h % d->numBuckets) + 1;
- Node **bucket = d->buckets + start;
- int n = d->numBuckets - start;
- while (n--) {
- if (*bucket != e)
- return *bucket;
- ++bucket;
- }
- return e;
-}
+ Returns the hash value for the \a{args}, using \a seed to seed
+ the calculation, by successively applying qHash() to each
+ element and combining the hash values into a single one.
-QHashData::Node *QHashData::previousNode(Node *node)
-{
- union {
- Node *e;
- QHashData *d;
- };
+ Note that the order of the arguments is significant. If order does
+ not matter, use qHashMultiCommutative() instead. If you are hashing raw
+ memory, use qHashBits(); if you are hashing a range, use qHashRange().
- e = node;
- while (e->next)
- e = e->next;
-
- int start;
- if (node == e)
- start = d->numBuckets - 1;
- else
- start = node->h % d->numBuckets;
-
- Node *sentinel = node;
- Node **bucket = d->buckets + start;
- while (start >= 0) {
- if (*bucket != sentinel) {
- Node *prev = *bucket;
- while (prev->next != sentinel)
- prev = prev->next;
- return prev;
- }
+ This function is provided as a convenience to implement qHash() for
+ your own custom types. For example, here's how you could implement
+ a qHash() overload for a class \c{Employee}:
- sentinel = e;
- --bucket;
- --start;
- }
- Q_ASSERT_X(start >= 0, "QHash", "Iterating backward beyond begin()");
- return e;
-}
+ \snippet code/src_corelib_tools_qhash.cpp 13
-/*
- If hint is negative, -hint gives the approximate number of
- buckets that should be used for the hash table. If hint is
- nonnegative, (1 << hint) gives the approximate number
- of buckets that should be used.
+ \sa qHashMultiCommutative, qHashRange
*/
-void QHashData::rehash(int hint)
-{
- if (hint < 0) {
- hint = countBits(-hint);
- if (hint < MinNumBits)
- hint = MinNumBits;
- userNumBits = hint;
- while (primeForNumBits(hint) < (size >> 1))
- ++hint;
- } else if (hint < MinNumBits) {
- hint = MinNumBits;
- }
-
- if (numBits != hint) {
- Node *e = reinterpret_cast<Node *>(this);
- Node **oldBuckets = buckets;
- int oldNumBuckets = numBuckets;
-
- int nb = primeForNumBits(hint);
- buckets = new Node *[nb];
- numBits = hint;
- numBuckets = nb;
- for (int i = 0; i < numBuckets; ++i)
- buckets[i] = e;
-
- for (int i = 0; i < oldNumBuckets; ++i) {
- Node *firstNode = oldBuckets[i];
- while (firstNode != e) {
- uint h = firstNode->h;
- Node *lastNode = firstNode;
- while (lastNode->next != e && lastNode->next->h == h)
- lastNode = lastNode->next;
-
- Node *afterLastNode = lastNode->next;
- Node **beforeFirstNode = &buckets[h % numBuckets];
- while (*beforeFirstNode != e)
- beforeFirstNode = &(*beforeFirstNode)->next;
- lastNode->next = *beforeFirstNode;
- *beforeFirstNode = firstNode;
- firstNode = afterLastNode;
- }
- }
- delete [] oldBuckets;
- }
-}
-
-#ifdef QT_QHASH_DEBUG
-
-void QHashData::dump()
-{
- qDebug("Hash data (ref = %d, size = %d, nodeSize = %d, userNumBits = %d, numBits = %d, numBuckets = %d)",
- int(ref), size, nodeSize, userNumBits, numBits,
- numBuckets);
- qDebug(" %p (fakeNode = %p)", this, fakeNext);
- for (int i = 0; i < numBuckets; ++i) {
- Node *n = buckets[i];
- if (n != reinterpret_cast<Node *>(this)) {
- QString line = QString::asprintf("%d:", i);
- while (n != reinterpret_cast<Node *>(this)) {
- line += QString::asprintf(" -> [%p]", n);
- if (!n) {
- line += " (CORRUPT)";
- break;
- }
- n = n->next;
- }
- qDebug("%ls", qUtf16Printable(line));
- }
- }
-}
-
-void QHashData::checkSanity()
-{
- if (Q_UNLIKELY(fakeNext))
- qFatal("Fake next isn't 0");
-
- for (int i = 0; i < numBuckets; ++i) {
- Node *n = buckets[i];
- Node *p = n;
- if (Q_UNLIKELY(!n))
- qFatal("%d: Bucket entry is 0", i);
- if (n != reinterpret_cast<Node *>(this)) {
- while (n != reinterpret_cast<Node *>(this)) {
- if (Q_UNLIKELY(!n->next))
- qFatal("%d: Next of %p is 0, should be %p", i, n, this);
- n = n->next;
- }
- }
- }
-}
-#endif
/*!
- \fn template <typename T1, typename T2> uint qHash(const QPair<T1, T2> &key, uint seed = 0)
- \since 5.0
+ \fn template <typename... T> size_t qHashMultiCommutative(size_t seed, const T &...args)
\relates QHash
+ \since 6.0
- 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> uint qHash(const std::pair<T1, T2> &key, uint seed = 0)
- \since 5.7
- \relates QHash
+ Returns the hash value for the \a{args}, using \a seed to seed
+ the calculation, by successively applying qHash() to each
+ element and combining the hash values into a single one.
- Returns the hash value for the \a key, using \a seed to seed the calculation.
+ The order of the arguments is insignificant. If order does
+ matter, use qHashMulti() instead, as it may produce better quality
+ hashing. If you are hashing raw memory, use qHashBits(); if you are
+ hashing a range, use qHashRange().
- Types \c T1 and \c T2 must be supported by qHash().
+ This function is provided as a convenience to implement qHash() for
+ your own custom types.
- \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.
+ \sa qHashMulti, qHashRange
*/
-/*! \fn template <typename InputIterator> uint qHashRange(InputIterator first, InputIterator last, uint seed = 0)
+/*! \fn template <typename InputIterator> size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
\relates QHash
\since 5.5
@@ -795,7 +1424,7 @@ void QHashData::checkSanity()
\sa qHashBits(), qHashRangeCommutative()
*/
-/*! \fn template <typename InputIterator> uint qHashRangeCommutative(InputIterator first, InputIterator last, uint seed = 0)
+/*! \fn template <typename InputIterator> size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
\relates QHash
\since 5.5
@@ -831,7 +1460,7 @@ void QHashData::checkSanity()
\sa qHashBits(), qHashRange()
*/
-/*! \fn uint qHashBits(const void *p, size_t len, uint seed = 0)
+/*! \fn size_t qHashBits(const void *p, size_t len, size_t seed = 0)
\relates QHash
\since 5.4
@@ -856,171 +1485,252 @@ void QHashData::checkSanity()
\sa qHashRange(), qHashRangeCommutative()
*/
-/*! \fn uint qHash(char key, uint seed = 0)
+/*! \fn size_t qHash(char key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(uchar key, uint seed = 0)
+/*! \fn size_t qHash(uchar key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(signed char key, uint seed = 0)
+/*! \fn size_t qHash(signed char key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(ushort key, uint seed = 0)
+/*! \fn size_t qHash(ushort key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(short key, uint seed = 0)
+/*! \fn size_t qHash(short key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(uint key, uint seed = 0)
+/*! \fn size_t qHash(uint key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(int key, uint seed = 0)
+/*! \fn size_t qHash(int key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(ulong key, uint seed = 0)
+/*! \fn size_t qHash(ulong key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(long key, uint seed = 0)
+/*! \fn size_t qHash(long key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(quint64 key, uint seed = 0)
+/*! \fn size_t qHash(quint64 key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(qint64 key, uint seed = 0)
+/*! \fn size_t qHash(qint64 key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \relates QHash
+/*! \fn size_t qHash(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
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+
+/*! \fn size_t qHash(char16_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 size_t qHash(char32_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 size_t qHash(wchar_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 size_t qHash(float key, size_t seed = 0) noexcept
+ \relates QHash
\since 5.3
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(float key, uint seed) noexcept
-{
- return key != 0.0f ? hash(reinterpret_cast<const uchar *>(&key), sizeof(key), seed) : seed ;
-}
/*! \relates QHash
\since 5.3
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(double key, uint seed) noexcept
+size_t qHash(double key, size_t seed) noexcept
{
- return key != 0.0 ? hash(reinterpret_cast<const uchar *>(&key), sizeof(key), seed) : seed ;
+ // ensure -0 gets mapped to 0
+ key += 0.0;
+ if constexpr (sizeof(double) == sizeof(size_t)) {
+ size_t k;
+ memcpy(&k, &key, sizeof(double));
+ return QHashPrivate::hash(k, seed);
+ } else {
+ return murmurhash(&key, sizeof(key), seed);
+ }
}
-#if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
/*! \relates QHash
\since 5.3
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-uint qHash(long double key, uint seed) noexcept
+size_t qHash(long double key, size_t seed) noexcept
{
- return key != 0.0L ? hash(reinterpret_cast<const uchar *>(&key), sizeof(key), seed) : seed ;
+ // ensure -0 gets mapped to 0
+ key += static_cast<long double>(0.0);
+ if constexpr (sizeof(long double) == sizeof(size_t)) {
+ size_t k;
+ memcpy(&k, &key, sizeof(long double));
+ return QHashPrivate::hash(k, seed);
+ } else {
+ return murmurhash(&key, sizeof(key), seed);
+ }
}
-#endif
-/*! \fn uint qHash(const QChar key, uint seed = 0)
+/*! \fn size_t qHash(const QChar key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QByteArray &key, uint seed = 0)
+/*! \fn size_t qHash(const QByteArray &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QBitArray &key, uint seed = 0)
+/*! \fn size_t qHash(const QByteArrayView &key, size_t seed = 0)
\relates QHash
- \since 5.0
+ \since 6.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QString &key, uint seed = 0)
+/*! \fn size_t qHash(const QBitArray &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(const QStringRef &key, uint seed = 0)
+/*! \fn size_t qHash(const QString &key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(QStringView key, uint seed = 0)
+/*! \fn size_t qHash(QStringView key, size_t seed = 0)
\relates QStringView
\since 5.10
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn uint qHash(QLatin1String key, uint seed = 0)
+/*! \fn size_t qHash(QLatin1StringView key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn template <class T> uint qHash(const T *key, uint seed = 0)
+/*! \fn template <class T> size_t qHash(const T *key, size_t seed = 0)
\relates QHash
\since 5.0
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
+/*! \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
@@ -1091,13 +1801,16 @@ uint qHash(long double key, uint seed) noexcept
in the code above.
Internally, QHash uses a hash table to perform lookups. This
- hash table automatically grows and shrinks to
+ hash table automatically grows to
provide fast lookups without wasting too much memory. You can
still control the size of the hash table by calling reserve() if
you already know approximately how many items the QHash will
contain, but this isn't necessary to obtain good performance. You
can also call capacity() to retrieve the hash table's size.
+ QHash will not shrink automatically if items are removed from the
+ table. To minimize the memory used by the hash, call squeeze().
+
If you want to navigate through all the (key, value) pairs stored
in a QHash, you can use an iterator. QHash provides both
\l{Java-style iterators} (QHashIterator and QMutableHashIterator)
@@ -1114,29 +1827,17 @@ uint qHash(long double key, uint seed) noexcept
QHash is unordered, so an iterator's sequence cannot be assumed
to be predictable. If ordering by key is required, use a QMap.
- Normally, a QHash allows only one value per key. If you call
+ A QHash allows only one value per key. If you call
insert() with a key that already exists in the QHash, the
previous value is erased. For example:
\snippet code/src_corelib_tools_qhash.cpp 9
- However, you can store multiple values per key by using
- insertMulti() instead of insert() (or using the convenience
- subclass QMultiHash). 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_qhash.cpp 10
-
- The items that share the same key are available from most
- recently to least recently inserted. A more efficient approach is
- to call find() to get the iterator for the first item with a key
- and iterate from there:
-
- \snippet code/src_corelib_tools_qhash.cpp 11
+ If you need to store multiple entries for the same key in the
+ hash table, use \l{QMultiHash}.
If you only need to extract the values from a hash (not the keys),
- you can also use \l{foreach}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qhash.cpp 12
@@ -1150,31 +1851,54 @@ uint qHash(long double key, uint 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,
@@ -1184,15 +1908,18 @@ uint qHash(long double key, uint 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.
+ 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
- In the example above, we've relied on Qt's global qHash(const
- QString &, uint) to give us a hash value for the employee's name, and
- XOR'ed this with the day they were born to help produce unique
- hashes for people with the same name.
+ In the example above, we've relied on Qt's own implementation of
+ qHash() for QString and QDate to give us a hash value for the
+ employee's name and date of birth respectively.
Note that the implementation of the qHash() overloads offered by Qt
may change at any time. You \b{must not} rely on the fact that qHash()
@@ -1220,7 +1947,7 @@ uint qHash(long double key, uint 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
*/
@@ -1246,9 +1973,6 @@ uint qHash(long double key, uint seed) noexcept
Constructs a hash with a copy of each of the elements in the
initializer list \a list.
-
- This function is only available if the program is being
- compiled in C++11 mode.
*/
/*! \fn template <class Key, class T> template <class InputIterator> QHash<Key, T>::QHash(InputIterator begin, InputIterator end)
@@ -1256,8 +1980,8 @@ uint qHash(long double key, uint 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.
*/
@@ -1333,7 +2057,7 @@ uint qHash(long double key, uint 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.
@@ -1348,7 +2072,7 @@ uint qHash(long double key, uint 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.
@@ -1360,24 +2084,45 @@ uint qHash(long double key, uint seed) noexcept
\sa reserve(), squeeze()
*/
-/*! \fn template <class Key, class T> void QHash<Key, T>::reserve(int size)
+/*! \fn template <class Key, class T> float QHash<Key, T>::load_factor() const noexcept
+
+ Returns the current load factor of the QHash's internal hash table.
+ This is the same as capacity()/size(). The implementation used
+ will aim to keep the load factor between 0.25 and 0.5. This avoids
+ having too many hash table collisions that would degrade performance.
+
+ Even with a low load factor, the implementation of the hash table has a
+ very low memory overhead.
+
+ This method purely exists for diagnostic purposes and you should rarely
+ need to call it yourself.
+
+ \sa reserve(), squeeze()
+*/
+
+
+/*! \fn template <class Key, class T> void QHash<Key, T>::reserve(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.
- Ensures that the QHash's internal hash table consists of at least
- \a size buckets.
+ This implies that the hash table will contain at least 2 * \a size buckets
+ to ensure good performance
This function is useful for code that needs to build a huge hash
and wants to avoid repeated reallocation. For example:
\snippet code/src_corelib_tools_qhash.cpp 14
- Ideally, \a size should be slightly more than the maximum number
- of items expected in the hash. \a size doesn't have to be prime,
- because QHash will use a prime number internally anyway. If \a size
+ Ideally, \a size should be the maximum number of items expected
+ in the hash. QHash will then choose the smallest possible
+ number of buckets that will allow storing \a size items in the table
+ without having to grow the internal hash table. If \a size
is an underestimate, the worst that will happen is that the QHash
will be a bit slower.
In general, you will rarely ever need to call this function.
- QHash's internal hash table automatically shrinks or grows to
+ QHash's internal hash table automatically grows to
provide good performance without wasting too much memory.
\sa squeeze(), capacity()
@@ -1415,31 +2160,42 @@ uint qHash(long double key, uint seed) noexcept
\sa detach()
*/
-/*! \fn template <class Key, class T> void QHash<Key, T>::setSharable(bool sharable)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> bool QHash<Key, T>::isSharedWith(const QHash &other) const
\internal
+
+ Returns true if the internal hash table of this QHash is shared with \a other, otherwise false.
*/
/*! \fn template <class Key, class T> void QHash<Key, T>::clear()
- Removes all items from the hash.
+ Removes all items from the hash and frees up all memory used by it.
\sa remove()
*/
-/*! \fn template <class Key, class T> int QHash<Key, T>::remove(const Key &key)
+/*! \fn template <class Key, class T> bool QHash<Key, T>::remove(const Key &key)
- Removes all the items that have the \a key from the hash.
- Returns the number of items removed which is usually 1 but will
- be 0 if the key isn't in the hash, or greater than 1 if
- insertMulti() has been used with the \a key.
+ Removes the item that has the \a key from the hash.
+ Returns true if the key exists in the hash and the item has been removed,
+ and false otherwise.
- \sa clear(), take(), QMultiHash::remove()
+ \sa clear(), take()
+*/
+
+/*! \fn template <class Key, class T> 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)
@@ -1448,9 +2204,7 @@ uint qHash(long double key, uint seed) noexcept
the value associated with it.
If the item does not exist in the hash, the function simply
- returns a \l{default-constructed value}. If there are multiple
- items for \a key in the hash, only the most recently inserted one
- is removed.
+ returns a \l{default-constructed value}.
If you don't use the return value, remove() is more efficient.
@@ -1462,26 +2216,18 @@ uint qHash(long double key, uint 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> const T QHash<Key, T>::value(const Key &key) const
+/*! \fn template <class Key, class T> T QHash<Key, T>::value(const Key &key) const
+ \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 \l{default-constructed value}. If there are multiple
- items for the \a key in the hash, the value of the most recently
- inserted one is returned.
-
- \sa key(), values(), contains(), operator[]()
-*/
-
-/*! \fn template <class Key, class T> const T QHash<Key, T>::value(const Key &key, const T &defaultValue) const
- \overload
-
- If the hash contains no item with the given \a key, the function returns
- \a defaultValue.
+ returns \a defaultValue, 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)
@@ -1491,9 +2237,13 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains no item with the \a key, the function inserts
a \l{default-constructed value} into the hash with the \a key, and
- returns a reference to it. If the hash contains multiple items
- with the \a key, this function returns a reference to the most
- recently inserted value.
+ returns a reference to it.
+
+//! [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()
*/
@@ -1505,29 +2255,18 @@ uint qHash(long double key, uint seed) noexcept
Same as value().
*/
-/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::uniqueKeys() const
- \since 4.2
-
- Returns a list containing all the keys in the map. Keys that occur multiple
- times in the map (because items were inserted with insertMulti(), or
- unite() was used) occur only once in the returned list.
-
- \sa keys(), values()
-*/
-
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::keys() const
Returns a list containing all the keys in the hash, in an
- arbitrary order. Keys that occur multiple times in the hash
- (because items were inserted with insertMulti(), or unite() was
- used) also occur multiple times in the list.
-
- To obtain a list of unique keys, where each key from the map only
- occurs once, use uniqueKeys().
+ arbitrary order.
The order is guaranteed to be the same as that used by values().
- \sa uniqueKeys(), values(), key()
+ This function creates a new list, in \l {linear time}. The time and memory
+ use that entails can be avoided by iterating from \l keyBegin() to
+ \l keyEnd().
+
+ \sa values(), key()
*/
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::keys(const T &value) const
@@ -1545,60 +2284,39 @@ uint qHash(long double key, uint seed) noexcept
/*! \fn template <class Key, class T> QList<T> QHash<Key, T>::values() const
Returns a list containing all the values in the hash, in an
- arbitrary order. If a key is associated with multiple values, all of
- its values will be in the list, and not just the most recently
- inserted one.
+ arbitrary order.
The order is guaranteed to be the same as that used by keys().
- \sa keys(), value()
-*/
-
-/*! \fn template <class Key, class T> QList<T> QHash<Key, T>::values(const Key &key) const
-
- \overload
+ 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
+ \l keyValueEnd().
- Returns a list of all the values associated with the \a key,
- from the most recently inserted to the least recently inserted.
-
- \sa count(), insertMulti()
-*/
-
-/*! \fn template <class Key, class T> Key QHash<Key, T>::key(const T &value) const
-
- Returns the first key mapped to \a value.
-
- If the hash contains no item with the \a value, the function
- returns a \l{default-constructed value}{default-constructed key}.
-
- This function can be slow (\l{linear time}), because QHash's
- internal data structure is optimized for fast lookup by key, not
- by value.
-
- \sa value(), keys()
+ \sa keys(), value()
*/
/*!
+ \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
- \overload
- 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(), insertMulti()
+ \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
@@ -1610,12 +2328,16 @@ uint qHash(long double key, uint 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
@@ -1624,6 +2346,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1632,6 +2356,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1641,6 +2367,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1649,12 +2377,16 @@ uint qHash(long double key, uint 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
@@ -1662,6 +2394,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1671,6 +2405,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1680,6 +2416,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1689,6 +2427,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1698,6 +2438,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1707,6 +2449,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1716,6 +2460,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1725,6 +2471,8 @@ uint qHash(long double key, uint 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()
*/
@@ -1734,9 +2482,32 @@ uint qHash(long double key, uint 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
@@ -1744,18 +2515,16 @@ uint qHash(long double key, uint seed) noexcept
from the hash, and returns an iterator to the next item in the
hash.
- Unlike remove() and take(), this function never causes QHash to
+ This function never causes QHash to
rehash its internal data structure. This means that it can safely
be called while iterating, and won't affect the order of items in
the hash. For example:
\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)
@@ -1774,12 +2543,16 @@ uint qHash(long double key, uint seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 16
- \sa value(), values(), QMultiHash::find()
+ \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
@@ -1791,7 +2564,9 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains no item with the \a key, the function
returns constEnd().
- \sa find(), QMultiHash::constFind()
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa find()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::insert(const Key &key, const T &value)
@@ -1801,31 +2576,32 @@ uint qHash(long double key, uint seed) noexcept
If there is already an item with the \a key, that item's value
is replaced with \a value.
- If there are multiple items with the \a key, the most
- recently inserted item's value is replaced with \a value.
+ Returns an iterator pointing to the new/updated element.
- \sa insertMulti()
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &key, const T &value)
+/*!
+ \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 item with the \a key and a value of \a value.
+ Inserts a new element into the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
- If there is already an item with the same key in the hash, this
- function will simply create a new one. (This behavior is
- different from insert(), which overwrites the value of an
- existing item.)
+ Returns an iterator pointing to the new element.
- \sa insert(), values()
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
-/*! \fn template <class Key, class T> QHash &QHash<Key, T>::unite(const QHash &other)
- Inserts all the items in the \a other hash into this hash. If a
- key is common to both hashes, the resulting hash will contain the
- key multiple times.
+/*! \fn template <class Key, class T> void QHash<Key, T>::insert(const QHash &other)
+ \since 5.15
+
+ Inserts all the items in the \a other hash into this hash.
- \sa insertMulti()
+ If a key is common to both hashes, its value will be replaced with the
+ value stored in \a other.
*/
/*! \fn template <class Key, class T> bool QHash<Key, T>::empty() const
@@ -1835,17 +2611,21 @@ uint qHash(long double key, uint seed) noexcept
returns \c false.
*/
-/*! \fn template <class Key, class T> QPair<iterator, iterator> QHash<Key, T>::equal_range(const Key &key)
+/*! \fn template <class Key, class T> 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> QHash<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
@@ -1940,16 +2720,10 @@ uint qHash(long double key, uint seed) noexcept
/*! \class QHash::iterator
\inmodule QtCore
- \brief The QHash::iterator class provides an STL-style non-const iterator for QHash and QMultiHash.
-
- 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.
+ \brief The QHash::iterator class provides an STL-style non-const iterator for QHash.
- QHash\<Key, T\>::iterator allows you to iterate over a QHash (or
- QMultiHash) and to modify the value (but not the key) associated
+ QHash\<Key, T\>::iterator allows you to iterate over a QHash
+ and to modify the value (but not the key) associated
with a particular key. If you want to iterate over a const QHash,
you should use QHash::const_iterator. It is generally good
practice to use QHash::const_iterator on a non-const QHash as
@@ -1966,44 +2740,28 @@ uint qHash(long double key, uint seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 17
Unlike QMap, which orders its items by key, QHash stores its
- items in an arbitrary order. The only guarantee is that items that
- share the same key (because they were inserted using
- QHash::insertMulti()) will appear consecutively, from the most
- recently to the least recently inserted value.
+ 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:
+ To remove elements from a QHash you can use erase_if(QHash\<Key, T\> &map, Predicate pred):
- \snippet code/src_corelib_tools_qhash.cpp 20
+ \snippet code/src_corelib_tools_qhash.cpp 21
- It might be tempting to write code like this:
+ 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.
- \snippet code/src_corelib_tools_qhash.cpp 21
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink its internal hash table.
+ Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
- Multiple iterators can be used on the same hash. However, be
- aware that any modification performed directly on the QHash has
- the potential of dramatically changing the order in which the
- items are stored in the hash, as they might cause QHash to rehash
- its internal data structure. There is one notable exception:
- QHash::erase(). This function can safely be called while
- iterating, and won't affect the order of items in the hash. If you
- need to keep iterators over a long period of time, we recommend
+ If you need to keep iterators over a long period of time, we recommend
that you use QMap rather than QHash.
\warning Iterators on implicitly shared containers do not work
@@ -2011,7 +2769,7 @@ uint qHash(long double key, uint 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()
@@ -2025,18 +2783,13 @@ uint qHash(long double key, uint seed) noexcept
\sa QHash::begin(), QHash::end()
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator::iterator(void *node)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> const Key &QHash<Key, T>::iterator::key() const
Returns the current item's key as a const reference.
There is no direct way of changing an item's key through an
iterator, although it can be done by calling QHash::erase()
- followed by QHash::insert() or QHash::insertMulti().
+ followed by QHash::insert().
\sa value()
*/
@@ -2097,8 +2850,6 @@ uint qHash(long double key, uint seed) noexcept
item.
Calling this function on QHash::end() leads to undefined results.
-
- \sa operator--()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator++(int)
@@ -2110,77 +2861,12 @@ uint qHash(long double key, uint seed) noexcept
current item.
*/
-/*!
- \fn template <class Key, class T> QHash<Key, T>::iterator &QHash<Key, T>::iterator::operator--()
-
- The prefix -- operator (\c{--i}) makes the preceding item
- current and returns an iterator pointing to the new current item.
-
- Calling this function on QHash::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*!
- \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{i--}) makes the preceding item
- current and returns an iterator pointing to the previously
- current item.
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::iterator::operator-(int j) const
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator &QHash<Key, T>::iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::iterator &QHash<Key, T>::iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
-*/
-
/*! \class QHash::const_iterator
\inmodule QtCore
- \brief The QHash::const_iterator class provides an STL-style const iterator for QHash and QMultiHash.
-
- 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.
+ \brief The QHash::const_iterator class provides an STL-style const iterator for QHash.
QHash\<Key, T\>::const_iterator allows you to iterate over a
- QHash (or a QMultiHash). If you want to modify the QHash as you
+ QHash. If you want to modify the QHash as you
iterate over it, you must use QHash::iterator instead. It is
generally good practice to use QHash::const_iterator on a
non-const QHash as well, unless you need to change the QHash
@@ -2189,8 +2875,8 @@ uint qHash(long double key, uint 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
@@ -2198,22 +2884,29 @@ uint qHash(long double key, uint seed) noexcept
Unlike QMap, which orders its items by key, QHash stores its
items in an arbitrary order. The only guarantee is that items that
share the same key (because they were inserted using
- QHash::insertMulti()) will appear consecutively, from the most
+ a QMultiHash) will appear consecutively, from the most
recently to the least recently inserted value.
Multiple iterators can be used on the same hash. However, be aware
- that any modification performed directly on the QHash has the
- potential of dramatically changing the order in which the items
- are stored in the hash, as they might cause QHash to rehash its
- internal data structure. If you need to keep iterators over a long
- period of time, we recommend that you use QMap rather than QHash.
+ that any modification performed directly on the QHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink its internal hash table.
+ Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
+
+ 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()
@@ -2227,11 +2920,6 @@ uint qHash(long double key, uint seed) noexcept
\sa QHash::constBegin(), QHash::constEnd()
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator::const_iterator(void *node)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator::const_iterator(const iterator &other)
Constructs a copy of \a other.
@@ -2291,8 +2979,6 @@ uint qHash(long double key, uint seed) noexcept
item.
Calling this function on QHash::end() leads to undefined results.
-
- \sa operator--()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator++(int)
@@ -2304,70 +2990,10 @@ uint qHash(long double key, uint seed) noexcept
current item.
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator &QHash<Key, T>::const_iterator::operator--()
-
- The prefix -- operator (\c{--i}) makes the preceding item
- current and returns an iterator pointing to the new current item.
-
- Calling this function on QHash::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{i--}) makes the preceding item
- current and returns an iterator pointing to the previously
- current item.
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::const_iterator::operator-(int j) const
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator &QHash<Key, T>::const_iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator &QHash<Key, T>::const_iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
-*/
-
/*! \class QHash::key_iterator
\inmodule QtCore
\since 5.6
- \brief The QHash::key_iterator class provides an STL-style const iterator for QHash and QMultiHash keys.
+ \brief The QHash::key_iterator class provides an STL-style const iterator for QHash keys.
QHash::key_iterator is essentially the same as QHash::const_iterator
with the difference that operator*() and operator->() return a key
@@ -2436,7 +3062,6 @@ uint qHash(long double key, uint 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)
@@ -2448,26 +3073,6 @@ uint qHash(long double key, uint seed) noexcept
item.
*/
-/*! \fn template <class Key, class T> QHash<Key, T>::key_iterator &QHash<Key, T>::key_iterator::operator--()
-
- The prefix -- operator (\c{--i}) makes the preceding item
- current and returns an iterator pointing to the new current item.
-
- Calling this function on QHash::keyBegin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class Key, class T> QHash<Key, T>::key_iterator QHash<Key, T>::key_iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{i--}) makes the preceding item
- current and returns an iterator pointing to the previous
- item.
-*/
-
/*! \fn template <class Key, class T> const_iterator QHash<Key, T>::key_iterator::base() const
Returns the underlying const_iterator this key_iterator is based on.
*/
@@ -2475,7 +3080,7 @@ uint qHash(long double key, uint seed) noexcept
/*! \typedef QHash::const_key_value_iterator
\inmodule QtCore
\since 5.10
- \brief The QMap::const_key_value_iterator typedef provides an STL-style const iterator for QHash and QMultiHash.
+ \brief The QHash::const_key_value_iterator typedef provides an STL-style const iterator for QHash.
QHash::const_key_value_iterator is essentially the same as QHash::const_iterator
with the difference that operator*() returns a key/value pair instead of a
@@ -2487,7 +3092,7 @@ uint qHash(long double key, uint seed) noexcept
/*! \typedef QHash::key_value_iterator
\inmodule QtCore
\since 5.10
- \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QHash and QMultiHash.
+ \brief The QHash::key_value_iterator typedef provides an STL-style iterator for QHash.
QHash::key_value_iterator is essentially the same as QHash::iterator
with the difference that operator*() returns a key/value pair instead of a
@@ -2531,18 +3136,21 @@ uint qHash(long double key, uint seed) noexcept
It inherits QHash and extends it with a few convenience functions
that make it more suitable than QHash for storing multi-valued
hashes. A multi-valued hash is a hash that allows multiple values
- with the same key; QHash normally doesn't allow that, unless you
- call QHash::insertMulti().
+ 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 in
- addition, it provides an insert() function that corresponds to
- QHash::insertMulti(), and a replace() function that corresponds to
+ QHash's iterator classes (for example, QHashIterator). But opposed to
+ 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+=().
+ Unlike QMultiMap, QMultiHash does not provide and ordering of the
+ inserted items. The only guarantee is that items that
+ share the same key will appear consecutively, from the most
+ recently to the least recently inserted value.
+
Example:
\snippet code/src_corelib_tools_qhash.cpp 24
@@ -2584,26 +3192,21 @@ uint qHash(long double key, uint 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::QMultiHash(InputIterator begin, InputIterator end)
+/*! \fn template <class Key, class T> template <class InputIterator> QMultiHash<Key, T>::QMultiHash(InputIterator begin, InputIterator end)
\since 5.14
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.
*/
@@ -2618,6 +3221,10 @@ uint qHash(long double key, uint 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()
*/
@@ -2630,10 +3237,64 @@ uint qHash(long double key, uint 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 <class Key, class T> QMultiHash &QMultiHash<Key, T>::operator+=(const QMultiHash &other)
+/*!
+ \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
+ construction.
+
+ If there is already an item with the same key in the hash, this
+ function will simply create a new one. (This behavior is
+ different from replace(), which overwrites the value of an
+ existing item.)
+
+ Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa insert
+*/
+
+/*!
+ \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
+ construction.
+
+ If there is already an item with the same key in the hash, that item's
+ value is replaced with a value constructed from \a args.
+
+ Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa replace, emplace
+*/
+
+
+/*! \fn template <class Key, class T> QMultiHash &QMultiHash<Key, T>::unite(const QMultiHash &other)
+ \since 5.13
+
+ 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> 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.
@@ -2641,6 +3302,62 @@ uint qHash(long double key, uint seed) noexcept
\sa insert()
*/
+/*! \fn template <class Key, class T> QList<Key> QMultiHash<Key, T>::uniqueKeys() const
+ \since 5.13
+
+ Returns a list containing all the keys in the map. Keys that occur multiple
+ times in the map occur only once in the returned list.
+
+ \sa keys(), values()
+*/
+
+/*! \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, 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
+ inserted one is returned.
+*/
+
+/*! \fn template <class Key, class T> QList<T> QMultiHash<Key, T>::values(const Key &key) const
+ \overload
+
+ Returns a list of all the values associated with the \a key,
+ from the most recently inserted to the least recently inserted.
+
+ \sa count(), insert()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiHash<Key, T>::operator[](const Key &key)
+
+ Returns the value associated with the \a key as a modifiable reference.
+
+ If the hash contains no item with the \a key, the function inserts
+ a \l{default-constructed value} into the hash with the \a key, and
+ returns a reference to it.
+
+ If the hash contains multiple items with the \a key, this function returns
+ a reference to the most recently inserted value.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa insert(), value()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash &QMultiHash<Key, T>::operator+=(const QMultiHash &other)
+
+ Inserts all the items in the \a other hash into this hash
+ and returns a reference to this hash.
+
+ \sa unite(), insert()
+*/
+
/*! \fn template <class Key, class T> QMultiHash QMultiHash<Key, T>::operator+(const QMultiHash &other) const
Returns a hash that contains all the items in this hash in
@@ -2657,30 +3374,124 @@ uint qHash(long double key, uint seed) noexcept
Returns \c true if the hash contains an item with the \a key and
\a value; otherwise returns \c false.
- \sa QHash::contains()
+ \sa contains()
*/
/*!
- \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
value from the hash. Returns the number of items removed.
- \sa QHash::remove()
+ \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
+ the value associated with it.
+
+ If the item does not exist in the hash, the function simply
+ returns a \l{default-constructed value}. If there are multiple
+ items for \a key in the hash, only the most recently inserted one
+ is removed.
+
+ If you don't use the return value, remove() is more efficient.
+
+ \sa remove()
+*/
+
+/*! \fn template <class Key, class T> QList<Key> QMultiHash<Key, T>::keys() const
+
+ Returns a list containing all the keys in the hash, in an
+ arbitrary order. Keys that occur multiple times in the hash
+ also occur multiple times in the list.
+
+ The order is guaranteed to be the same as that used by values().
+
+ This function creates a new list, in \l {linear time}. The time and memory
+ use that entails can be avoided by iterating from \l keyBegin() to
+ \l keyEnd().
+
+ \sa values(), key()
+*/
+
+/*! \fn template <class Key, class T> QList<T> QMultiHash<Key, T>::values() const
+
+ Returns a list containing all the values in the hash, in an
+ arbitrary order. If a key is associated with multiple values, all of
+ its values will be in the list, and not just the most recently
+ inserted one.
+
+ The order is guaranteed to be the same as that used by keys().
+
+ 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
+ \l keyValueEnd().
+
+ \sa keys(), value()
+*/
+
+/*!
+ \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. 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
+ by value.
*/
/*!
- \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.
- \sa QHash::count()
+ \sa count()
*/
/*!
- \fn template <class Key, class T> typename QHash<Key, T>::iterator QMultiHash<Key, T>::find(const Key &key, const T &value)
+ \fn template <class Key, class T> typename QMultiHash<Key, T>::iterator QMultiHash<Key, T>::find(const Key &key, const T &value)
\since 4.3
Returns an iterator pointing to the item with the \a key and \a value.
@@ -2689,17 +3500,19 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains multiple items with the \a key and \a value, the
iterator returned points to the most recently inserted item.
- \sa QHash::find()
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
- \fn template <class Key, class T> typename QHash<Key, T>::const_iterator QMultiHash<Key, T>::find(const Key &key, const T &value) const
+ \fn template <class Key, class T> typename QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::find(const Key &key, const T &value) const
\since 4.3
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
- \fn template <class Key, class T> typename QHash<Key, T>::const_iterator QMultiHash<Key, T>::constFind(const Key &key, const T &value) const
+ \fn template <class Key, class T> typename QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::constFind(const Key &key, const T &value) const
\since 4.3
Returns an iterator pointing to the item with the \a key and the
@@ -2708,11 +3521,597 @@ uint qHash(long double key, uint seed) noexcept
If the hash contains no such item, the function returns
constEnd().
- \sa QHash::constFind()
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::begin()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
+ the hash.
+
+ \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
+ \since 5.0
+
+ 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()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::constBegin() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
+ in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::keyBegin() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
+ in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::end()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
+ after the last item in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::end() const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::constEnd() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the hash.
+
+ \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>::cend() const
+ \since 5.0
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa cbegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::keyEnd() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last key in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_value_iterator QMultiHash<Key, T>::keyValueBegin()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_value_iterator QMultiHash<Key, T>::keyValueEnd()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::keyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::constKeyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::keyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_key_value_iterator QMultiHash<Key, T>::constKeyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the hash.
+
+ \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\<Key, T\>::iterator allows you to iterate over a QMultiHash
+ and to modify the value (but not the key) associated
+ with a particular key. If you want to iterate over a const QMultiHash,
+ you should use QMultiHash::const_iterator. It is generally good
+ practice to use QMultiHash::const_iterator on a non-const QMultiHash as
+ well, unless you need to change the QMultiHash through the iterator.
+ Const iterators are slightly faster, and can improve code
+ readability.
+
+ The default QMultiHash::iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QMultiHash function like
+ QMultiHash::begin(), QMultiHash::end(), or QMultiHash::find() before you can
+ start iterating. Here's a typical loop that prints all the (key,
+ value) pairs stored in a hash:
+
+ \snippet code/src_corelib_tools_qhash.cpp 17
+
+ Unlike QMap, which orders its items by key, QMultiHash stores its
+ items in an arbitrary order.
+
+ Here's an example that increments every value stored in the QMultiHash
+ by 2:
+
+ \snippet code/src_corelib_tools_qhash.cpp 18
+
+ 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
+
+ Multiple iterators can be used on the same hash. However, be aware
+ that any modification performed directly on the QHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ Inserting items into the hash or calling methods such as QHash::reserve()
+ or QHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ to grow/shrink its internal hash table.
+ Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
+
+ If you need to keep iterators over a long period of time, we recommend
+ that you use QMultiMap rather than QHash.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiHash::const_iterator, QMultiHash::key_iterator, QMultiHash::key_value_iterator
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator::iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QMultiHash::begin(), QMultiHash::end()
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiHash<Key, T>::iterator::key() const
+
+ Returns the current item's key as a const reference.
+
+ There is no direct way of changing an item's key through an
+ iterator, although it can be done by calling QMultiHash::erase()
+ followed by QMultiHash::insert().
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiHash<Key, T>::iterator::value() const
+
+ Returns a modifiable reference to the current item's value.
+
+ You can change the value of an item by using value() on
+ the left side of an assignment, for example:
+
+ \snippet code/src_corelib_tools_qhash.cpp 22
+
+ \sa key(), operator*()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiHash<Key, T>::iterator::operator*() const
+
+ Returns a modifiable reference to the current item's value.
+
+ Same as value().
+
+ \sa key()
+*/
+
+/*! \fn template <class Key, class T> T *QMultiHash<Key, T>::iterator::operator->() const
+
+ Returns a pointer to the current item's value.
+
+ \sa value()
+*/
+
+/*!
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator==(const iterator &other) const
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator==(const const_iterator &other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator!=(const iterator &other) const
+ \fn template <class Key, class T> bool QMultiHash<Key, T>::iterator::operator!=(const const_iterator &other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiHash<Key, T>::iterator &QMultiHash<Key, T>::iterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the hash and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiHash::end() leads to undefined results.
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the hash and returns an iterator to the previously
+ current item.
+*/
+
+/*! \class QMultiHash::const_iterator
+ \inmodule QtCore
+ \brief The QMultiHash::const_iterator class provides an STL-style const iterator for QMultiHash.
+
+ QMultiHash\<Key, T\>::const_iterator allows you to iterate over a
+ QMultiHash. If you want to modify the QMultiHash as you
+ iterate over it, you must use QMultiHash::iterator instead. It is
+ generally good practice to use QMultiHash::const_iterator on a
+ non-const QMultiHash as well, unless you need to change the QMultiHash
+ through the iterator. Const iterators are slightly faster, and
+ can improve code readability.
+
+ The default QMultiHash::const_iterator constructor creates an
+ uninitialized iterator. You must initialize it using a QMultiHash
+ function like QMultiHash::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
+
+ Unlike QMap, which orders its items by key, QMultiHash stores its
+ items in an arbitrary order. The only guarantee is that items that
+ share the same key (because they were inserted using
+ a QMultiHash) will appear consecutively, from the most
+ recently to the least recently inserted value.
+
+ Multiple iterators can be used on the same hash. However, be aware
+ that any modification performed directly on the QMultiHash (inserting and
+ removing items) can cause the iterators to become invalid.
+
+ 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.
+
+ If you need to keep iterators over a long period of time, we recommend
+ 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, QMultiHash::key_iterator, QMultiHash::const_key_value_iterator
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QMultiHash::constBegin(), QMultiHash::constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator(const iterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiHash<Key, T>::const_iterator::key() const
+
+ Returns the current item's key.
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiHash<Key, T>::const_iterator::value() const
+
+ Returns the current item's value.
+
+ \sa key(), operator*()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiHash<Key, T>::const_iterator::operator*() const
+
+ Returns the current item's value.
+
+ Same as value().
+
+ \sa key()
+*/
+
+/*! \fn template <class Key, class T> const T *QMultiHash<Key, T>::const_iterator::operator->() const
+
+ Returns a pointer to the current item's value.
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::const_iterator::operator==(const const_iterator &other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::const_iterator::operator!=(const const_iterator &other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator &QMultiHash<Key, T>::const_iterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the hash and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiHash::end() leads to undefined results.
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::const_iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the hash and returns an iterator to the previously
+ current item.
+*/
+
+/*! \class QMultiHash::key_iterator
+ \inmodule QtCore
+ \since 5.6
+ \brief The QMultiHash::key_iterator class provides an STL-style const iterator for QMultiHash keys.
+
+ QMultiHash::key_iterator is essentially the same as QMultiHash::const_iterator
+ with the difference that operator*() and operator->() return a key
+ instead of a value.
+
+ For most uses QMultiHash::iterator and QMultiHash::const_iterator should be used,
+ you can easily access the key by calling QMultiHash::iterator::key():
+
+ \snippet code/src_corelib_tools_qhash.cpp 27
+
+ However, to have interoperability between QMultiHash's keys and STL-style
+ algorithms we need an iterator that dereferences to a key instead
+ of a value. With QMultiHash::key_iterator we can apply an algorithm to a
+ range of keys without having to call QMultiHash::keys(), which is inefficient
+ as it costs one QMultiHash iteration and memory allocation to create a temporary
+ QList.
+
+ \snippet code/src_corelib_tools_qhash.cpp 28
+
+ QMultiHash::key_iterator is const, it's not possible to modify the key.
+
+ The default QMultiHash::key_iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QMultiHash function like
+ QMultiHash::keyBegin() or QMultiHash::keyEnd().
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiHash::const_iterator, QMultiHash::iterator
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiHash<Key, T>::key_iterator::operator*() const
+
+ Returns the current item's key.
+*/
+
+/*! \fn template <class Key, class T> const T *QMultiHash<Key, T>::key_iterator::operator->() const
+
+ Returns a pointer to the current item's key.
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::key_iterator::operator==(key_iterator other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiHash<Key, T>::key_iterator::operator!=(key_iterator other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
*/
/*!
- \fn template <class Key, class T> uint qHash(const QHash<Key, T> &key, uint seed = 0)
+ \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator &QMultiHash<Key, T>::key_iterator::operator++()
+
+ The prefix ++ operator (\c{++i}) advances the iterator to the
+ next item in the hash and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiHash::keyEnd() leads to undefined results.
+*/
+
+/*! \fn template <class Key, class T> QMultiHash<Key, T>::key_iterator QMultiHash<Key, T>::key_iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator (\c{i++}) advances the iterator to the
+ next item in the hash and returns an iterator to the previous
+ item.
+*/
+
+/*! \fn template <class Key, class T> const_iterator QMultiHash<Key, T>::key_iterator::base() const
+ Returns the underlying const_iterator this key_iterator is based on.
+*/
+
+/*! \typedef QMultiHash::const_key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMap::const_key_value_iterator typedef provides an STL-style const iterator for QMultiHash and QMultiHash.
+
+ QMultiHash::const_key_value_iterator is essentially the same as QMultiHash::const_iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
+/*! \typedef QMultiHash::key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QMultiHash and QMultiHash.
+
+ QMultiHash::key_value_iterator is essentially the same as QMultiHash::iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
+/*! \fn template <class Key, class T> QDataStream &operator<<(QDataStream &out, const QMultiHash<Key, T>& hash)
+ \relates QMultiHash
+
+ Writes the hash \a hash to stream \a out.
+
+ This function requires the key and value types to implement \c
+ operator<<().
+
+ \sa {Serializing Qt Data Types}
+*/
+
+/*! \fn template <class Key, class T> QDataStream &operator>>(QDataStream &in, QMultiHash<Key, T> &hash)
+ \relates QMultiHash
+
+ Reads a hash from stream \a in into \a hash.
+
+ This function requires the key and value types to implement \c
+ operator>>().
+
+ \sa {Serializing Qt Data Types}
+*/
+
+/*!
+ \fn template <class Key, class T> size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
\since 5.8
\relates QHash
@@ -2722,7 +4121,7 @@ uint qHash(long double key, uint seed) noexcept
*/
/*!
- \fn template <class Key, class T> uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
+ \fn template <class Key, class T> size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
\since 5.8
\relates QMultiHash
@@ -2731,4 +4130,64 @@ uint qHash(long double key, uint 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 9fd96686f5..e7cd4123fb 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -1,258 +1,880 @@
-/****************************************************************************
-**
-** 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) 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/qchar.h>
+#include <QtCore/qalgorithms.h>
+#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qlist.h>
#include <QtCore/qrefcount.h>
-#include <QtCore/qhashfunctions.h>
-#include <QtCore/qcontainertools_impl.h>
-#include <algorithm>
#include <initializer_list>
+#include <functional> // for std::hash
-#if defined(Q_CC_MSVC)
-#pragma warning( push )
-#pragma warning( disable : 4311 ) // disable pointer truncation warning
-#pragma warning( disable : 4127 ) // conditional expression is constant
-#endif
+class tst_QHash; // for befriending
QT_BEGIN_NAMESPACE
-struct Q_CORE_EXPORT QHashData
+struct QHashDummyValue
{
- struct Node {
- Node *next;
- uint h;
- };
+ bool operator==(const QHashDummyValue &) const noexcept { return true; }
+};
- Node *fakeNext;
- Node **buckets;
- QtPrivate::RefCount ref;
- int size;
- int nodeSize;
- short userNumBits;
- short numBits;
- int numBuckets;
- uint seed;
- uint sharable : 1;
- uint strictAlignment : 1;
- uint reserved : 30;
-
- void *allocateNode(int nodeAlign);
- void freeNode(void *node);
- QHashData *detach_helper(void (*node_duplicate)(Node *, void *), void (*node_delete)(Node *),
- int nodeSize, int nodeAlign);
- bool willGrow();
- void hasShrunk();
- void rehash(int hint);
- void free_helper(void (*node_delete)(Node *));
- Node *firstNode();
-#ifdef QT_QHASH_DEBUG
- void dump();
- void checkSanity();
-#endif
- static Node *nextNode(Node *node);
- static Node *previousNode(Node *node);
+namespace QHashPrivate {
- static const QHashData shared_null;
-};
+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;
-inline bool QHashData::willGrow()
+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)
{
- if (size >= numBuckets) {
- rehash(numBits + 1);
- return true;
+ 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 {
- return false;
+ static_assert(sizeof(T) == 0, "The key type must have a qHash overload or a std::hash specialization");
+ return 0;
}
}
-inline void QHashData::hasShrunk()
+template <typename Key, typename T>
+struct Node
{
- if (size <= (numBuckets >> 3) && numBits > userNumBits) {
- QT_TRY {
- rehash(qMax(int(numBits) - 2, int(userNumBits)));
- } QT_CATCH(const std::bad_alloc &) {
- // ignore bad allocs - shrinking shouldn't throw. rehash is exception safe.
- }
+ using KeyType = Key;
+ using ValueType = T;
+
+ Key key;
+ T value;
+ template<typename ...Args>
+ static void createInPlace(Node *n, Key &&k, Args &&... args)
+ { new (n) Node{ std::move(k), T(std::forward<Args>(args)...) }; }
+ template<typename ...Args>
+ static void createInPlace(Node *n, const Key &k, Args &&... args)
+ { new (n) Node{ Key(k), T(std::forward<Args>(args)...) }; }
+ template<typename ...Args>
+ void emplaceValue(Args &&... args)
+ {
+ value = T(std::forward<Args>(args)...);
}
-}
+ T &&takeValue() noexcept(std::is_nothrow_move_assignable_v<T>)
+ {
+ return std::move(value);
+ }
+ bool valuesEqual(const Node *other) const { return value == other->value; }
+};
-inline QHashData::Node *QHashData::firstNode()
-{
- Node *e = reinterpret_cast<Node *>(this);
- Node **bucket = buckets;
- int n = numBuckets;
- while (n--) {
- if (*bucket != e)
- return *bucket;
- ++bucket;
+template <typename Key>
+struct Node<Key, QHashDummyValue> {
+ using KeyType = Key;
+ using ValueType = QHashDummyValue;
+
+ Key key;
+ template<typename ...Args>
+ static void createInPlace(Node *n, Key &&k, Args &&...)
+ { new (n) Node{ std::move(k) }; }
+ template<typename ...Args>
+ static void createInPlace(Node *n, const Key &k, Args &&...)
+ { new (n) Node{ k }; }
+ template<typename ...Args>
+ void emplaceValue(Args &&...)
+ {
}
- return e;
-}
+ ValueType takeValue() { return QHashDummyValue(); }
+ bool valuesEqual(const Node *) const { return true; }
+};
-struct QHashDummyValue
+template <typename T>
+struct MultiNodeChain
{
+ T value;
+ MultiNodeChain *next = nullptr;
+ ~MultiNodeChain()
+ {
+ }
+ qsizetype free() noexcept(std::is_nothrow_destructible_v<T>)
+ {
+ qsizetype nEntries = 0;
+ MultiNodeChain *e = this;
+ while (e) {
+ MultiNodeChain *n = e->next;
+ ++nEntries;
+ delete e;
+ e = n;
+ }
+ return nEntries;
+ }
+ bool contains(const T &val) const noexcept
+ {
+ const MultiNodeChain *e = this;
+ while (e) {
+ if (e->value == val)
+ return true;
+ e = e->next;
+ }
+ return false;
+ }
};
-constexpr bool operator==(const QHashDummyValue &, const QHashDummyValue &) noexcept
+template <typename Key, typename T>
+struct MultiNode
{
- return true;
-}
+ using KeyType = Key;
+ using ValueType = T;
+ using Chain = MultiNodeChain<T>;
+
+ Key key;
+ Chain *value;
+
+ template<typename ...Args>
+ static void createInPlace(MultiNode *n, Key &&k, Args &&... args)
+ { new (n) MultiNode(std::move(k), new Chain{ T(std::forward<Args>(args)...), nullptr }); }
+ template<typename ...Args>
+ static void createInPlace(MultiNode *n, const Key &k, Args &&... args)
+ { new (n) MultiNode(k, new Chain{ T(std::forward<Args>(args)...), nullptr }); }
+
+ MultiNode(const Key &k, Chain *c)
+ : key(k),
+ value(c)
+ {}
+ MultiNode(Key &&k, Chain *c) noexcept(std::is_nothrow_move_assignable_v<Key>)
+ : key(std::move(k)),
+ value(c)
+ {}
+
+ MultiNode(MultiNode &&other)
+ : key(other.key),
+ value(std::exchange(other.value, nullptr))
+ {
+ }
-Q_DECLARE_TYPEINFO(QHashDummyValue, Q_MOVABLE_TYPE | Q_DUMMY_TYPE);
+ MultiNode(const MultiNode &other)
+ : key(other.key)
+ {
+ Chain *c = other.value;
+ Chain **e = &value;
+ while (c) {
+ Chain *chain = new Chain{ c->value, nullptr };
+ *e = chain;
+ e = &chain->next;
+ c = c->next;
+ }
+ }
+ ~MultiNode()
+ {
+ if (value)
+ value->free();
+ }
+ static qsizetype freeChain(MultiNode *n) noexcept(std::is_nothrow_destructible_v<T>)
+ {
+ qsizetype size = n->value->free();
+ n->value = nullptr;
+ return size;
+ }
+ template<typename ...Args>
+ void insertMulti(Args &&... args)
+ {
+ Chain *e = new Chain{ T(std::forward<Args>(args)...), nullptr };
+ e->next = std::exchange(value, e);
+ }
+ template<typename ...Args>
+ void emplaceValue(Args &&... args)
+ {
+ value->value = T(std::forward<Args>(args)...);
+ }
+};
-template <class Key, class T>
-struct QHashNode
+template<typename Node>
+constexpr bool isRelocatable()
{
- QHashNode *next;
- const uint h;
- const Key key;
- T value;
+ return QTypeInfo<typename Node::KeyType>::isRelocatable && QTypeInfo<typename Node::ValueType>::isRelocatable;
+}
- inline QHashNode(const Key &key0, const T &value0, uint hash, QHashNode *n)
- : next(n), h(hash), key(key0), value(value0) {}
- inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; }
+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;
-private:
- Q_DISABLE_COPY(QHashNode)
+ static_assert ((NEntries & LocalBucketMask) == 0, "NEntries must be a power of two.");
};
-// Specialize for QHashDummyValue in order to save some memory
-template <class Key>
-struct QHashNode<Key, QHashDummyValue>
-{
- union {
- QHashNode *next;
- QHashDummyValue value;
+// Regular hash tables consist of a list of buckets that can store Nodes. But simply allocating one large array of buckets
+// would waste a lot of memory. To avoid this, we split the vector of buckets up into a vector of Spans. Each Span represents
+// NEntries buckets. To quickly find the correct Span that holds a bucket, NEntries must be a power of two.
+//
+// Inside each Span, there is an offset array that represents the actual buckets. offsets contains either an index into the
+// actual storage space for the Nodes (the 'entries' member) or 0xff (UnusedEntry) to flag that the bucket is empty.
+// As we have only 128 entries per Span, the offset array can be represented using an unsigned char. This trick makes the hash
+// table have a very small memory overhead compared to many other implementations.
+template<typename Node>
+struct Span {
+ // Entry is a slot available for storing a Node. The Span holds a pointer to
+ // an array of Entries. Upon construction of the array, those entries are
+ // unused, and nextFree() is being used to set up a singly linked list
+ // of free entries.
+ // When a node gets inserted, the first free entry is being picked, removed
+ // from the singly linked list and the Node gets constructed in place.
+ struct Entry {
+ 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); }
};
- const uint h;
- const Key key;
- inline QHashNode(const Key &key0, const QHashDummyValue &, uint hash, QHashNode *n)
- : next(n), h(hash), key(key0) {}
- inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; }
+ unsigned char offsets[SpanConstants::NEntries];
+ Entry *entries = nullptr;
+ unsigned char allocated = 0;
+ unsigned char nextFree = 0;
+ Span() noexcept
+ {
+ memset(offsets, SpanConstants::UnusedEntry, sizeof(offsets));
+ }
+ ~Span()
+ {
+ freeData();
+ }
+ void freeData() noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (entries) {
+ if constexpr (!std::is_trivially_destructible<Node>::value) {
+ for (auto o : offsets) {
+ if (o != SpanConstants::UnusedEntry)
+ entries[o].node().~Node();
+ }
+ }
+ delete[] entries;
+ entries = nullptr;
+ }
+ }
+ Node *insert(size_t i)
+ {
+ Q_ASSERT(i < SpanConstants::NEntries);
+ Q_ASSERT(offsets[i] == SpanConstants::UnusedEntry);
+ if (nextFree == allocated)
+ addStorage();
+ unsigned char entry = nextFree;
+ Q_ASSERT(entry < allocated);
+ nextFree = entries[entry].nextFree();
+ offsets[i] = entry;
+ return &entries[entry].node();
+ }
+ void erase(size_t bucket) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ Q_ASSERT(bucket < SpanConstants::NEntries);
+ Q_ASSERT(offsets[bucket] != SpanConstants::UnusedEntry);
+
+ unsigned char entry = offsets[bucket];
+ offsets[bucket] = SpanConstants::UnusedEntry;
-private:
- Q_DISABLE_COPY(QHashNode)
+ entries[entry].node().~Node();
+ entries[entry].nextFree() = nextFree;
+ nextFree = entry;
+ }
+ size_t offset(size_t i) const noexcept
+ {
+ return offsets[i];
+ }
+ bool hasNode(size_t i) const noexcept
+ {
+ return (offsets[i] != SpanConstants::UnusedEntry);
+ }
+ Node &at(size_t i) noexcept
+ {
+ 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 < SpanConstants::NEntries);
+ Q_ASSERT(offsets[i] != SpanConstants::UnusedEntry);
+
+ return entries[offsets[i]].node();
+ }
+ Node &atOffset(size_t o) noexcept
+ {
+ Q_ASSERT(o < allocated);
+
+ return entries[o].node();
+ }
+ const Node &atOffset(size_t o) const noexcept
+ {
+ Q_ASSERT(o < allocated);
+
+ return entries[o].node();
+ }
+ void moveLocal(size_t from, size_t to) noexcept
+ {
+ Q_ASSERT(offsets[from] != SpanConstants::UnusedEntry);
+ Q_ASSERT(offsets[to] == SpanConstants::UnusedEntry);
+ offsets[to] = offsets[from];
+ 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 < 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);
+ offsets[to] = nextFree;
+ Entry &toEntry = entries[nextFree];
+ nextFree = toEntry.nextFree();
+
+ size_t fromOffset = fromSpan.offsets[fromIndex];
+ fromSpan.offsets[fromIndex] = SpanConstants::UnusedEntry;
+ Entry &fromEntry = fromSpan.entries[fromOffset];
+
+ if constexpr (isRelocatable<Node>()) {
+ memcpy(&toEntry, &fromEntry, sizeof(Entry));
+ } else {
+ new (&toEntry.node()) Node(std::move(fromEntry.node()));
+ fromEntry.node().~Node();
+ }
+ fromEntry.nextFree() = fromSpan.nextFree;
+ fromSpan.nextFree = static_cast<unsigned char>(fromOffset);
+ }
+
+ void addStorage()
+ {
+ Q_ASSERT(allocated < 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. 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));
+ } 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 < alloc; ++i) {
+ newEntries[i].nextFree() = uchar(i + 1);
+ }
+ 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
-#if 0
-// ###
-// The introduction of the QHash random seed breaks this optimization, as it
-// relies on qHash(int i) = i. If the hash value is salted, then the hash
-// table becomes corrupted.
-//
-// A bit more research about whether it makes sense or not to salt integer
-// keys (and in general keys whose hash value is easy to invert)
-// is needed, or about how keep this optimization and the seed (f.i. by
-// specializing QHash for integer values, and re-apply the seed during lookup).
-//
-// Be aware that such changes can easily be binary incompatible, and therefore
-// cannot be made during the Qt 5 lifetime.
-#define Q_HASH_DECLARE_INT_NODES(key_type) \
- template <class T> \
- struct QHashDummyNode<key_type, T> { \
- QHashDummyNode *next; \
- union { uint h; key_type key; }; \
-\
- inline QHashDummyNode(key_type /* key0 */) {} \
- }; \
-\
- template <class T> \
- struct QHashNode<key_type, T> { \
- QHashNode *next; \
- union { uint h; key_type key; }; \
- T value; \
-\
- inline QHashNode(key_type /* key0 */) {} \
- inline QHashNode(key_type /* key0 */, const T &value0) : value(value0) {} \
- inline bool same_key(uint h0, key_type) const { return h0 == h; } \
- }
-
-#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-Q_HASH_DECLARE_INT_NODES(short);
-Q_HASH_DECLARE_INT_NODES(ushort);
-#endif
-Q_HASH_DECLARE_INT_NODES(int);
-Q_HASH_DECLARE_INT_NODES(uint);
-#undef Q_HASH_DECLARE_INT_NODES
-#endif // #if 0
+template <typename Node>
+struct iterator;
-template <class Key, class T>
-class QHash
+template <typename Node>
+struct Data
{
- typedef QHashNode<Key, T> Node;
+ using Key = typename Node::KeyType;
+ using T = typename Node::ValueType;
+ using Span = QHashPrivate::Span<Node>;
+ using iterator = QHashPrivate::iterator<Node>;
+
+ QtPrivate::RefCount ref = {{1}};
+ size_t size = 0;
+ size_t numBuckets = 0;
+ size_t seed = 0;
+ Span *spans = nullptr;
+
+ static constexpr size_t maxNumBuckets() noexcept
+ {
+ return (std::numeric_limits<ptrdiff_t>::max)() / sizeof(Span);
+ }
+
+ 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);
+ }
- union {
- QHashData *d;
- QHashNode<Key, T> *e;
+ 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 inline Node *concrete(QHashData::Node *node) {
- return reinterpret_cast<Node *>(node);
+ 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);
+ spans = allocateSpans(numBuckets).spans;
+ seed = QHashSeed::globalSeed();
+ }
+
+ 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 < SpanConstants::NEntries; ++index) {
+ if (!span.hasNode(index))
+ continue;
+ const Node &n = span.at(index);
+ auto it = resized ? findBucket(n.key) : Bucket { spans + s, index };
+ Q_ASSERT(it.isUnused());
+ Node *newNode = it.insert();
+ new (newNode) Node(n);
+ }
+ }
+ }
+
+ 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);
+ Data *dd = new Data(*d, size);
+ if (!d->ref.deref())
+ delete d;
+ return dd;
+ }
+
+ void clear()
+ {
+ delete[] spans;
+ spans = nullptr;
+ size = 0;
+ numBuckets = 0;
+ }
+
+ iterator detachedIterator(iterator other) const noexcept
+ {
+ return iterator{this, other.bucket};
+ }
+
+ iterator begin() const noexcept
+ {
+ iterator it{ this, 0 };
+ if (it.isUnused())
+ ++it;
+ return it;
+ }
+
+ constexpr iterator end() const noexcept
+ {
+ return iterator();
}
- static inline int alignOfNode() { return qMax<int>(sizeof(void*), alignof(Node)); }
+ void rehash(size_t sizeHint = 0)
+ {
+ if (sizeHint == 0)
+ sizeHint = size;
+ size_t newBucketCount = GrowthPolicy::bucketsForCapacity(sizeHint);
+
+ Span *oldSpans = spans;
+ size_t oldBucketCount = numBuckets;
+ spans = allocateSpans(newBucketCount).spans;
+ numBuckets = newBucketCount;
+ size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
+
+ for (size_t s = 0; s < oldNSpans; ++s) {
+ Span &span = oldSpans[s];
+ for (size_t index = 0; index < SpanConstants::NEntries; ++index) {
+ if (!span.hasNode(index))
+ continue;
+ Node &n = span.at(index);
+ auto it = findBucket(n.key);
+ Q_ASSERT(it.isUnused());
+ Node *newNode = it.insert();
+ new (newNode) Node(std::move(n));
+ }
+ span.freeData();
+ }
+ delete[] oldSpans;
+ }
+
+ size_t nextBucket(size_t bucket) const noexcept
+ {
+ ++bucket;
+ if (bucket == numBuckets)
+ bucket = 0;
+ return bucket;
+ }
+
+ float loadFactor() const noexcept
+ {
+ return float(size)/numBuckets;
+ }
+ bool shouldGrow() const noexcept
+ {
+ return size >= (numBuckets >> 1);
+ }
+
+ template <typename K> Bucket findBucket(const K &key) const noexcept
+ {
+ static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
+ QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
+ Q_ASSERT(numBuckets > 0);
+ size_t hash = QHashPrivate::calculateHash(key, seed);
+ 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) {
+ size_t offset = bucket.offset();
+ if (offset == SpanConstants::UnusedEntry) {
+ return bucket;
+ } else {
+ Node &n = bucket.nodeAtOffset(offset);
+ if (qHashEquals(n.key, key))
+ return bucket;
+ }
+ bucket.advanceWrapped(this);
+ }
+ }
+
+ template <typename K> Node *findNode(const K &key) const noexcept
+ {
+ auto bucket = findBucket(key);
+ if (bucket.isUnused())
+ return nullptr;
+ return bucket.node();
+ }
+
+ struct InsertionResult
+ {
+ iterator it;
+ bool initialized;
+ };
+
+ template <typename K> InsertionResult findOrInsert(const K &key) noexcept
+ {
+ 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);
+ it = findBucket(key); // need to get a new iterator after rehashing
+ }
+ Q_ASSERT(it.span != nullptr);
+ Q_ASSERT(it.isUnused());
+ it.insert();
+ ++size;
+ return { it.toIterator(this), false };
+ }
+
+ void erase(Bucket bucket) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ Q_ASSERT(bucket.span->hasNode(bucket.index));
+ bucket.span->erase(bucket.index);
+ --size;
+
+ // re-insert the following entries to avoid holes
+ Bucket next = bucket;
+ while (true) {
+ 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 == 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
+ bucket.span->moveFromSpan(*next.span, next.index, bucket.index);
+ }
+ bucket = next;
+ break;
+ }
+ newBucket.advanceWrapped(this);
+ }
+ }
+ }
+
+ ~Data()
+ {
+ delete [] spans;
+ }
+};
+
+template <typename Node>
+struct iterator {
+ using Span = QHashPrivate::Span<Node>;
+
+ const Data<Node> *d = nullptr;
+ size_t bucket = 0;
+
+ 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
+ {
+ Q_ASSERT(!isUnused());
+ return &d->spans[span()].at(index());
+ }
+ bool atEnd() const noexcept { return !d; }
+
+ iterator operator++() noexcept
+ {
+ while (true) {
+ ++bucket;
+ if (bucket == d->numBuckets) {
+ d = nullptr;
+ bucket = 0;
+ break;
+ }
+ if (!isUnused())
+ break;
+ }
+ return *this;
+ }
+ bool operator==(iterator other) const noexcept
+ { return d == other.d && bucket == other.bucket; }
+ bool operator!=(iterator other) const noexcept
+ { return !(*this == other); }
+};
+
+
+
+} // namespace QHashPrivate
+
+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;
public:
- inline QHash() noexcept : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
+ using key_type = Key;
+ using mapped_type = T;
+ using value_type = T;
+ using size_type = qsizetype;
+ using difference_type = qsizetype;
+ using reference = T &;
+ using const_reference = const T &;
+
+ inline QHash() noexcept = default;
inline QHash(std::initializer_list<std::pair<Key,T> > list)
- : d(const_cast<QHashData *>(&QHashData::shared_null))
+ : d(new Data(list.size()))
{
- reserve(int(list.size()));
for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
insert(it->first, it->second);
}
- QHash(const QHash &other) : d(other.d) { d->ref.ref(); if (!d->sharable) detach(); }
- ~QHash() { if (!d->ref.deref()) freeData(d); }
+ QHash(const QHash &other) noexcept
+ : d(other.d)
+ {
+ if (d)
+ d->ref.ref();
+ }
+ ~QHash()
+ {
+ 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;
+ }
- QHash &operator=(const QHash &other);
- QHash(QHash &&other) noexcept : d(other.d) { other.d = const_cast<QHashData *>(&QHashData::shared_null); }
- QHash &operator=(QHash &&other) noexcept
- { QHash moved(std::move(other)); swap(moved); return *this; }
+ QHash &operator=(const QHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d != other.d) {
+ Data *o = other.d;
+ if (o)
+ o->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = o;
+ }
+ return *this;
+ }
+
+ QHash(QHash &&other) noexcept
+ : d(std::exchange(other.d, nullptr))
+ {
+ }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QHash)
#ifdef Q_QDOC
template <typename InputIterator>
QHash(InputIterator f, InputIterator l);
@@ -275,150 +897,287 @@ public:
insert(f->first, f->second);
}
#endif
- void swap(QHash &other) noexcept { qSwap(d, other.d); }
+ void swap(QHash &other) noexcept { qt_ptr_swap(d, other.d); }
+
+#ifndef Q_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;
+ if (size() != other.size())
+ return false;
+ for (const_iterator it = other.begin(); it != other.end(); ++it) {
+ const_iterator i = find(it.key());
+ if (i == end() || !i.i.node()->valuesEqual(it.i.node()))
+ return false;
+ }
+ // all values must be the same as size is the same
+ return true;
+ }
+ 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 { return !(*this == other); }
+ 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; }
- inline int size() const { return d->size; }
+ 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()
+ {
+ 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(); }
+ bool isSharedWith(const QHash &other) const noexcept { return d == other.d; }
+
+ void clear() noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = nullptr;
+ }
+
+ 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
- inline bool isEmpty() const { return d->size == 0; }
+ if (it.isUnused())
+ return false;
+ d->erase(it);
+ return true;
+ }
- inline int capacity() const { return d->numBuckets; }
- void reserve(int size);
- inline void squeeze() { reserve(1); }
+public:
+ template <typename Predicate>
+ qsizetype removeIf(Predicate pred)
+ {
+ return QtPrivate::associative_erase_if(*this, pred);
+ }
- inline void detach() { if (d->ref.isShared()) detach_helper(); }
- inline bool isDetached() const { return !d->ref.isShared(); }
- bool isSharedWith(const QHash &other) const { return d == other.d; }
+ 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
- void clear();
+ if (it.isUnused())
+ return T();
+ T value = it.node()->takeValue();
+ d->erase(it);
+ return value;
+ }
- int remove(const Key &key);
- T take(const Key &key);
+public:
+ bool contains(const Key &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
+ }
+ qsizetype count(const Key &key) const noexcept
+ {
+ return contains(key) ? 1 : 0;
+ }
- bool contains(const Key &key) const;
- const Key key(const T &value) const;
- const Key key(const T &value, const Key &defaultKey) const;
- const T value(const Key &key) const;
- const T value(const Key &key, const T &defaultValue) const;
- T &operator[](const Key &key);
- const T operator[](const Key &key) const;
+private:
+ template <typename Fn> Key keyImpl(const T &value, Fn &&defaultFn) const noexcept
+ {
+ if (d) {
+ const_iterator i = begin();
+ while (i != end()) {
+ if (i.value() == value)
+ return i.key();
+ ++i;
+ }
+ }
- QList<Key> uniqueKeys() const;
- QList<Key> keys() const;
- QList<Key> keys(const T &value) const;
- QList<T> values() const;
- QList<T> values(const Key &key) const;
- int count(const Key &key) const;
+ return defaultFn();
+ }
+
+public:
+ Key key(const T &value) const noexcept
+ {
+ return keyImpl(value, [] { return Key(); });
+ }
+ Key key(const T &value, const Key &defaultKey) const noexcept
+ {
+ return keyImpl(value, [&] { return defaultKey; });
+ }
+
+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();
+ }
+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(key), T());
+ return result.it.node()->value;
+ }
+
+public:
+ const T operator[](const Key &key) const noexcept
+ {
+ return value(key);
+ }
+
+ QList<Key> keys() const { return QList<Key>(keyBegin(), keyEnd()); }
+ QList<Key> keys(const T &value) const
+ {
+ QList<Key> res;
+ const_iterator i = begin();
+ while (i != end()) {
+ if (i.value() == value)
+ res.append(i.key());
+ ++i;
+ }
+ return res;
+ }
+ QList<T> values() const { return QList<T>(begin(), end()); }
class const_iterator;
class iterator
{
+ using piter = typename QHashPrivate::iterator<Node>;
friend class const_iterator;
friend class QHash<Key, T>;
friend class QSet<Key>;
- QHashData::Node *i;
+ piter i;
+ explicit inline iterator(piter it) noexcept : i(it) { }
public:
- typedef std::bidirectional_iterator_tag iterator_category;
+ typedef std::forward_iterator_tag iterator_category;
typedef qptrdiff difference_type;
typedef T value_type;
typedef T *pointer;
typedef T &reference;
- inline iterator() : i(nullptr) { }
- explicit inline iterator(void *node) : i(reinterpret_cast<QHashData::Node *>(node)) { }
+ constexpr iterator() noexcept = default;
- inline const Key &key() const { return concrete(i)->key; }
- inline T &value() const { return concrete(i)->value; }
- inline T &operator*() const { return concrete(i)->value; }
- inline T *operator->() const { return &concrete(i)->value; }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline T &value() const noexcept { return i.node()->value; }
+ inline T &operator*() const noexcept { return i.node()->value; }
+ inline T *operator->() const noexcept { return &i.node()->value; }
+ inline bool operator==(const iterator &o) const noexcept { return i == o.i; }
+ inline bool operator!=(const iterator &o) const noexcept { return i != o.i; }
- inline iterator &operator++() {
- i = QHashData::nextNode(i);
- return *this;
- }
- inline iterator operator++(int) {
- iterator r = *this;
- i = QHashData::nextNode(i);
- return r;
- }
- inline iterator &operator--() {
- i = QHashData::previousNode(i);
+ inline iterator &operator++() noexcept
+ {
+ ++i;
return *this;
}
- inline iterator operator--(int) {
+ inline iterator operator++(int) noexcept
+ {
iterator r = *this;
- i = QHashData::previousNode(i);
+ ++i;
return r;
}
- inline iterator operator+(int j) const
- { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline iterator operator-(int j) const { return operator+(-j); }
- inline iterator &operator+=(int j) { return *this = *this + j; }
- inline iterator &operator-=(int j) { return *this = *this - j; }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
-
- inline bool operator==(const const_iterator &o) const { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const { return i != o.i; }
+
+ inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
};
friend class iterator;
class const_iterator
{
+ using piter = typename QHashPrivate::iterator<Node>;
friend class iterator;
friend class QHash<Key, T>;
friend class QSet<Key>;
- QHashData::Node *i;
+ piter i;
+ explicit inline const_iterator(piter it) : i(it) { }
public:
- typedef std::bidirectional_iterator_tag iterator_category;
+ typedef std::forward_iterator_tag iterator_category;
typedef qptrdiff difference_type;
typedef T value_type;
typedef const T *pointer;
typedef const T &reference;
- Q_DECL_CONSTEXPR inline const_iterator() : i(nullptr) { }
- explicit inline const_iterator(void *node)
- : i(reinterpret_cast<QHashData::Node *>(node)) { }
- inline const_iterator(const iterator &o)
- { i = o.i; }
-
- inline const Key &key() const { return concrete(i)->key; }
- inline const T &value() const { return concrete(i)->value; }
- inline const T &operator*() const { return concrete(i)->value; }
- inline const T *operator->() const { return &concrete(i)->value; }
- Q_DECL_CONSTEXPR inline bool operator==(const const_iterator &o) const { return i == o.i; }
- Q_DECL_CONSTEXPR inline bool operator!=(const const_iterator &o) const { return i != o.i; }
-
- inline const_iterator &operator++() {
- i = QHashData::nextNode(i);
- return *this;
- }
- inline const_iterator operator++(int) {
- const_iterator r = *this;
- i = QHashData::nextNode(i);
- return r;
- }
- inline const_iterator &operator--() {
- i = QHashData::previousNode(i);
+ constexpr const_iterator() noexcept = default;
+ inline const_iterator(const iterator &o) noexcept : i(o.i) { }
+
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline const T &value() const noexcept { return i.node()->value; }
+ inline const T &operator*() const noexcept { return i.node()->value; }
+ inline const T *operator->() const noexcept { return &i.node()->value; }
+ inline bool operator==(const const_iterator &o) const noexcept { return i == o.i; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return i != o.i; }
+
+ inline const_iterator &operator++() noexcept
+ {
+ ++i;
return *this;
}
- inline const_iterator operator--(int) {
+ inline const_iterator operator++(int) noexcept
+ {
const_iterator r = *this;
- i = QHashData::previousNode(i);
+ ++i;
return r;
}
- inline const_iterator operator+(int j) const
- { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline const_iterator operator-(int j) const { return operator+(-j); }
- inline const_iterator &operator+=(int j) { return *this = *this + j; }
- inline const_iterator &operator-=(int j) { return *this = *this - j; }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
};
friend class const_iterator;
@@ -428,653 +1187,1024 @@ public:
public:
typedef typename const_iterator::iterator_category iterator_category;
- typedef typename const_iterator::difference_type difference_type;
+ typedef qptrdiff difference_type;
typedef Key value_type;
typedef const Key *pointer;
typedef const Key &reference;
- key_iterator() = default;
- explicit key_iterator(const_iterator o) : i(o) { }
+ key_iterator() noexcept = default;
+ explicit key_iterator(const_iterator o) noexcept : i(o) { }
- const Key &operator*() const { return i.key(); }
- const Key *operator->() const { return &i.key(); }
- bool operator==(key_iterator o) const { return i == o.i; }
- bool operator!=(key_iterator o) const { return i != o.i; }
+ const Key &operator*() const noexcept { return i.key(); }
+ const Key *operator->() const noexcept { return &i.key(); }
+ bool operator==(key_iterator o) const noexcept { return i == o.i; }
+ bool operator!=(key_iterator o) const noexcept { return i != o.i; }
- inline key_iterator &operator++() { ++i; return *this; }
- inline key_iterator operator++(int) { return key_iterator(i++);}
- inline key_iterator &operator--() { --i; return *this; }
- inline key_iterator operator--(int) { return key_iterator(i--); }
- const_iterator base() const { return i; }
+ inline key_iterator &operator++() noexcept { ++i; return *this; }
+ inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
+ const_iterator base() const noexcept { return i; }
};
typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
// STL style
- inline iterator begin() { detach(); return iterator(d->firstNode()); }
- inline const_iterator begin() const { return const_iterator(d->firstNode()); }
- inline const_iterator cbegin() const { return const_iterator(d->firstNode()); }
- inline const_iterator constBegin() const { return const_iterator(d->firstNode()); }
- inline iterator end() { detach(); return iterator(e); }
- inline const_iterator end() const { return const_iterator(e); }
- inline const_iterator cend() const { return const_iterator(e); }
- inline const_iterator constEnd() const { return const_iterator(e); }
- inline key_iterator keyBegin() const { return key_iterator(begin()); }
- inline key_iterator keyEnd() const { return key_iterator(end()); }
+ inline iterator begin() { detach(); return iterator(d->begin()); }
+ inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline iterator end() noexcept { return iterator(); }
+ inline const_iterator end() const noexcept { return const_iterator(); }
+ inline const_iterator cend() const noexcept { return const_iterator(); }
+ inline const_iterator constEnd() const noexcept { return const_iterator(); }
+ inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
+ inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
- inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
- inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
- inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
- inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ 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)
+ {
+ Q_ASSERT(it != constEnd());
+ detach();
+ // ensure a valid iterator across the detach:
+ iterator i = iterator{d->detachedIterator(it.i)};
+ typename Data::Bucket bucket(i.i);
- QPair<iterator, iterator> equal_range(const Key &key);
- QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept;
- iterator erase(iterator it) { return erase(const_iterator(it.i)); }
- iterator erase(const_iterator it);
+ d->erase(bucket);
+ if (bucket.toBucketIndex(d) == d->numBuckets - 1 || bucket.isUnused())
+ ++i;
+ return i;
+ }
- // more Qt
+ std::pair<iterator, iterator> equal_range(const Key &key)
+ {
+ return equal_range_impl(*this, key);
+ }
+ 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 = self.find(key);
+ auto second = first;
+ if (second != decltype(first){})
+ ++second;
+ return std::make_pair(first, second);
+ }
+
+ 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();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
+ if (it.isUnused())
+ return end();
+ return iterator(it.toIterator(d));
+ }
+ template <typename K> const_iterator constFindImpl(const K &key) const noexcept
+ {
+ if (isEmpty())
+ return end();
+ auto it = d->findBucket(key);
+ if (it.isUnused())
+ return end();
+ return const_iterator({d, it.toBucketIndex(d)});
+ }
+
+public:
typedef iterator Iterator;
typedef const_iterator ConstIterator;
- inline int count() const { return d->size; }
- iterator find(const Key &key);
- const_iterator find(const Key &key) const;
- const_iterator constFind(const Key &key) const;
- iterator insert(const Key &key, const T &value);
- iterator insertMulti(const Key &key, const T &value);
- QHash &unite(const QHash &other);
-
- // STL compatibility
- typedef T mapped_type;
- typedef Key key_type;
- typedef qptrdiff difference_type;
- typedef int size_type;
-
- inline bool empty() const { return isEmpty(); }
-
-#ifdef QT_QHASH_DEBUG
- inline void dump() const { d->dump(); }
- inline void checkSanity() const { d->checkSanity(); }
-#endif
+ 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
+ {
+ return find(key);
+ }
+ iterator insert(const Key &key, const T &value)
+ {
+ return emplace(key, value);
+ }
-private:
- void detach_helper();
- void freeData(QHashData *d);
- Node **findNode(const Key &key, uint *hp = nullptr) const;
- Node **findNode(const Key &key, uint h) const;
- Node *createNode(uint h, const Key &key, const T &value, Node **nextNode);
- void deleteNode(Node *node);
- static void deleteNode2(QHashData::Node *node);
-
- static void duplicateNode(QHashData::Node *originalNode, void *newNode);
-
- bool isValidIterator(const iterator &it) const noexcept
- { return isValidNode(it.i); }
- bool isValidIterator(const const_iterator &it) const noexcept
- { return isValidNode(it.i); }
- bool isValidNode(QHashData::Node *node) const noexcept
- {
-#if defined(QT_DEBUG) && !defined(Q_HASH_NO_ITERATOR_DEBUG)
- while (node->next)
- node = node->next;
- return (static_cast<void *>(node) == d);
-#else
- Q_UNUSED(node);
- return true;
-#endif
+ void insert(const QHash &hash)
+ {
+ if (d == hash.d || !hash.d)
+ return;
+ if (!d) {
+ *this = hash;
+ return;
+ }
+
+ detach();
+
+ for (auto it = hash.begin(); it != hash.end(); ++it)
+ emplace(it.key(), it.value());
}
- friend class QSet<Key>;
-};
+ template <typename ...Args>
+ iterator emplace(const Key &key, Args &&... args)
+ {
+ Key copy = key; // Needs to be explicit for MSVC 2019
+ return emplace(std::move(copy), std::forward<Args>(args)...);
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(Node *node)
-{
- deleteNode2(reinterpret_cast<QHashData::Node*>(node));
- d->freeNode(node);
-}
+ 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)...);
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode2(QHashData::Node *node)
-{
-#ifdef Q_CC_BOR
- concrete(node)->~QHashNode<Key, T>();
-#else
- concrete(node)->~Node();
-#endif
-}
+ float load_factor() const noexcept { return d ? d->loadFactor() : 0; }
+ static float max_load_factor() noexcept { return 0.5; }
+ size_t bucket_count() const noexcept { return d ? d->numBuckets : 0; }
+ static size_t max_bucket_count() noexcept { return Data::maxNumBuckets(); }
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::duplicateNode(QHashData::Node *node, void *newNode)
-{
- Node *concreteNode = concrete(node);
- new (newNode) Node(concreteNode->key, concreteNode->value, concreteNode->h, nullptr);
-}
+ inline bool empty() const noexcept { return isEmpty(); }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::Node *
-QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode)
-{
- Node *node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, *anextNode);
- *anextNode = node;
- ++d->size;
- return node;
-}
+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)...);
+ else
+ result.it.node()->emplaceValue(std::forward<Args>(args)...);
+ return iterator(result.it);
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash &other)
-{
- if (d == &QHashData::shared_null) {
- *this = other;
- } else {
- QHash copy(other);
- const_iterator it = copy.constEnd();
- while (it != copy.constBegin()) {
- --it;
- insertMulti(it.key(), it.value());
- }
+public:
+#ifdef __cpp_concepts
+ bool remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
}
- return *this;
-}
+ 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>
-Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x)
-{
- x->free_helper(deleteNode2);
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::clear()
+template <typename Key, typename T>
+class QMultiHash
{
- *this = QHash();
-}
+ using Node = QHashPrivate::MultiNode<Key, T>;
+ using Data = QHashPrivate::Data<Node>;
+ using Chain = QHashPrivate::MultiNodeChain<T>;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
-{
- QHashData *x = d->detach_helper(duplicateNode, deleteNode2, sizeof(Node), alignOfNode());
- if (!d->ref.deref())
- freeData(d);
- d = x;
-}
+ Data *d = nullptr;
+ qsizetype m_size = 0;
-template <class Key, class T>
-Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::operator=(const QHash &other)
-{
- if (d != other.d) {
- QHashData *o = other.d;
- o->ref.ref();
- if (!d->ref.deref())
- freeData(d);
- d = o;
- if (!d->sharable)
- detach_helper();
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using value_type = T;
+ using size_type = qsizetype;
+ using difference_type = qsizetype;
+ using reference = T &;
+ using const_reference = const T &;
+
+ QMultiHash() noexcept = default;
+ inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
+ : d(new Data(list.size()))
+ {
+ for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
+ insert(it->first, it->second);
+ }
+#ifdef Q_QDOC
+ template <typename InputIterator>
+ QMultiHash(InputIterator f, InputIterator l);
+#else
+ template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
+ QMultiHash(InputIterator f, InputIterator l)
+ {
+ QtPrivate::reserveIfForwardIterator(this, f, l);
+ for (; f != l; ++f)
+ insert(f.key(), f.value());
}
- return *this;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey) const
-{
- Node *node;
- if (d->size == 0 || (node = *findNode(akey)) == e) {
- return T();
- } else {
- return node->value;
+ template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
+ QMultiHash(InputIterator f, InputIterator l)
+ {
+ QtPrivate::reserveIfForwardIterator(this, f, l);
+ for (; f != l; ++f)
+ insert(f->first, f->second);
}
-}
+#endif
+ QMultiHash(const QMultiHash &other) noexcept
+ : d(other.d), m_size(other.m_size)
+ {
+ if (d)
+ d->ref.ref();
+ }
+ ~QMultiHash()
+ {
+ 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.");
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey, const T &adefaultValue) const
-{
- Node *node;
- if (d->size == 0 || (node = *findNode(akey)) == e) {
- return adefaultValue;
- } else {
- return node->value;
+ if (d && !d->ref.deref())
+ delete d;
}
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::uniqueKeys() const
-{
- QList<Key> res;
- res.reserve(size()); // May be too much, but assume short lifetime
- const_iterator i = begin();
- if (i != end()) {
- for (;;) {
- const Key &aKey = i.key();
- res.append(aKey);
- do {
- if (++i == end())
- goto break_out_of_outer_loop;
- } while (aKey == i.key());
+ QMultiHash &operator=(const QMultiHash &other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d != other.d) {
+ Data *o = other.d;
+ if (o)
+ o->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = o;
+ m_size = other.m_size;
}
+ return *this;
+ }
+ QMultiHash(QMultiHash &&other) noexcept
+ : d(std::exchange(other.d, nullptr)),
+ m_size(std::exchange(other.m_size, 0))
+ {
+ }
+ QMultiHash &operator=(QMultiHash &&other) noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ QMultiHash moved(std::move(other));
+ swap(moved);
+ return *this;
}
-break_out_of_outer_loop:
- return res;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys() const
-{
- QList<Key> res;
- res.reserve(size());
- const_iterator i = begin();
- while (i != end()) {
- res.append(i.key());
- ++i;
- }
- return res;
-}
+ explicit QMultiHash(const QHash<Key, T> &other)
+ : QMultiHash(other.begin(), other.end())
+ {}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::keys(const T &avalue) const
-{
- QList<Key> res;
- const_iterator i = begin();
- while (i != end()) {
- if (i.value() == avalue)
- res.append(i.key());
- ++i;
- }
- return res;
-}
+ explicit QMultiHash(QHash<Key, T> &&other)
+ {
+ unite(std::move(other));
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue) const
-{
- return key(avalue, Key());
-}
+ void swap(QMultiHash &other) noexcept
+ {
+ qt_ptr_swap(d, other.d);
+ std::swap(m_size, other.m_size);
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE const Key QHash<Key, T>::key(const T &avalue, const Key &defaultValue) const
-{
- const_iterator i = begin();
- while (i != end()) {
- if (i.value() == avalue)
- return i.key();
- ++i;
+#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 (m_size != other.m_size)
+ return false;
+ 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 *n = d->findNode(it.node()->key);
+ if (!n)
+ return false;
+ Chain *e = it.node()->value;
+ while (e) {
+ Chain *oe = n->value;
+ while (oe) {
+ if (oe->value == e->value)
+ break;
+ oe = oe->next;
+ }
+ if (!oe)
+ return false;
+ e = e->next;
+ }
+ }
+ // all values must be the same as size is the same
+ return true;
}
+ 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
- return defaultValue;
-}
+ inline qsizetype size() const noexcept { return m_size; }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values() const
-{
- QList<T> res;
- res.reserve(size());
- const_iterator i = begin();
- while (i != end()) {
- res.append(i.value());
- ++i;
- }
- return res;
-}
+ inline bool isEmpty() const noexcept { return !m_size; }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values(const Key &akey) const
-{
- QList<T> res;
- Node *node = *findNode(akey);
- if (node != e) {
- do {
- res.append(node->value);
- } while ((node = node->next) != e && node->key == akey);
- }
- return res;
-}
+ 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); }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::count(const Key &akey) const
-{
- int cnt = 0;
- Node *node = *findNode(akey);
- if (node != e) {
- do {
- ++cnt;
- } while ((node = node->next) != e && node->key == akey);
- }
- return cnt;
-}
+ inline void detach() { if (!d || d->ref.isShared()) d = Data::detached(d); }
+ inline bool isDetached() const noexcept { return d && !d->ref.isShared(); }
+ bool isSharedWith(const QMultiHash &other) const noexcept { return d == other.d; }
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const
-{
- return value(akey);
-}
+ void clear() noexcept(std::is_nothrow_destructible<Node>::value)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = nullptr;
+ m_size = 0;
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE T &QHash<Key, T>::operator[](const Key &akey)
-{
- detach();
+ 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
+
+ if (it.isUnused())
+ return 0;
+ qsizetype n = Node::freeChain(it.node());
+ m_size -= n;
+ Q_ASSERT(m_size >= 0);
+ d->erase(it);
+ return n;
+ }
- uint h;
- Node **node = findNode(akey, &h);
- if (*node == e) {
- if (d->willGrow())
- node = findNode(akey, h);
- return createNode(h, akey, T(), node)->value;
+public:
+ template <typename Predicate>
+ qsizetype removeIf(Predicate pred)
+ {
+ return QtPrivate::associative_erase_if(*this, pred);
}
- return (*node)->value;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insert(const Key &akey,
- const T &avalue)
-{
- detach();
+ 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
+
+ if (it.isUnused())
+ return T();
+ Chain *e = it.node()->value;
+ Q_ASSERT(e);
+ T t = std::move(e->value);
+ if (e->next) {
+ it.node()->value = e->next;
+ delete e;
+ } else {
+ // erase() deletes the values.
+ d->erase(it);
+ }
+ --m_size;
+ Q_ASSERT(m_size >= 0);
+ return t;
+ }
- uint h;
- Node **node = findNode(akey, &h);
- if (*node == e) {
- if (d->willGrow())
- node = findNode(akey, h);
- return iterator(createNode(h, akey, avalue, node));
+public:
+ bool contains(const Key &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
}
- if (!std::is_same<T, QHashDummyValue>::value)
- (*node)->value = avalue;
- return iterator(*node);
-}
+private:
+ template <typename Fn> Key keyImpl(const T &value, Fn &&defaultValue) const noexcept
+ {
+ if (d) {
+ auto i = d->begin();
+ while (i != d->end()) {
+ Chain *e = i.node()->value;
+ if (e->contains(value))
+ return i.node()->key;
+ ++i;
+ }
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &akey,
- const T &avalue)
-{
- detach();
- d->willGrow();
+ return defaultValue();
+ }
+public:
+ Key key(const T &value) const noexcept
+ {
+ return keyImpl(value, [] { return Key(); });
+ }
+ Key key(const T &value, const Key &defaultKey) const noexcept
+ {
+ return keyImpl(value, [&] { return defaultKey; });
+ }
- uint h;
- Node **nextNode = findNode(akey, &h);
- return iterator(createNode(h, akey, avalue, nextNode));
-}
+private:
+ template <typename K, typename Fn> T valueImpl(const K &key, Fn &&defaultValue) const noexcept
+ {
+ if (d) {
+ Node *n = d->findNode(key);
+ if (n) {
+ Q_ASSERT(n->value);
+ return n->value->value;
+ }
+ }
+ 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; });
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::remove(const Key &akey)
-{
- if (isEmpty()) // prevents detaching shared null
- return 0;
- detach();
-
- int oldSize = d->size;
- Node **node = findNode(akey);
- if (*node != e) {
- bool deleteNext = true;
- do {
- Node *next = (*node)->next;
- deleteNext = (next != e && next->key == (*node)->key);
- deleteNode(*node);
- *node = next;
- --d->size;
- } while (deleteNext);
- d->hasShrunk();
- }
- return oldSize - d->size;
-}
+ 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(key), T());
+ ++m_size;
+ }
+ return result.it.node()->value->value;
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE T QHash<Key, T>::take(const Key &akey)
-{
- if (isEmpty()) // prevents detaching shared null
- return T();
- detach();
-
- Node **node = findNode(akey);
- if (*node != e) {
- T t = std::move((*node)->value);
- Node *next = (*node)->next;
- deleteNode(*node);
- *node = next;
- --d->size;
- d->hasShrunk();
- return t;
+public:
+ const T operator[](const Key &key) const noexcept
+ {
+ return value(key);
}
- return T();
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::erase(const_iterator it)
-{
- Q_ASSERT_X(isValidIterator(it), "QHash::erase", "The specified iterator argument 'it' is invalid");
-
- if (it == const_iterator(e))
- return iterator(it.i);
-
- if (d->ref.isShared()) {
- // save 'it' across the detach:
- int bucketNum = (it.i->h % d->numBuckets);
- const_iterator bucketIterator(*(d->buckets + bucketNum));
- int stepsFromBucketStartToIte = 0;
- while (bucketIterator != it) {
- ++stepsFromBucketStartToIte;
- ++bucketIterator;
+ QList<Key> uniqueKeys() const
+ {
+ QList<Key> res;
+ if (d) {
+ auto i = d->begin();
+ while (i != d->end()) {
+ res.append(i.node()->key);
+ ++i;
+ }
}
- detach();
- it = const_iterator(*(d->buckets + bucketNum));
- while (stepsFromBucketStartToIte > 0) {
- --stepsFromBucketStartToIte;
- ++it;
+ return res;
+ }
+
+ QList<Key> keys() const { return QList<Key>(keyBegin(), keyEnd()); }
+ QList<Key> keys(const T &value) const
+ {
+ QList<Key> res;
+ const_iterator i = begin();
+ while (i != end()) {
+ if (i.value() == value)
+ res.append(i.key());
+ ++i;
}
+ return res;
}
- iterator ret(it.i);
- ++ret;
+ 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);
+ if (n) {
+ Chain *e = n->value;
+ while (e) {
+ values.append(e->value);
+ e = e->next;
+ }
+ }
+ }
+ return values;
+ }
- Node *node = concrete(it.i);
- Node **node_ptr = reinterpret_cast<Node **>(&d->buckets[node->h % d->numBuckets]);
- while (*node_ptr != node)
- node_ptr = &(*node_ptr)->next;
- *node_ptr = node->next;
- deleteNode(node);
- --d->size;
- return ret;
-}
+public:
+ class const_iterator;
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QHash<Key, T>::reserve(int asize)
-{
- detach();
- d->rehash(-qMax(asize, 1));
-}
+ class iterator
+ {
+ using piter = typename QHashPrivate::iterator<Node>;
+ friend class const_iterator;
+ friend class QMultiHash<Key, T>;
+ piter i;
+ Chain **e = nullptr;
+ explicit inline iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
+ {
+ if (!it.atEnd() && !e) {
+ e = &it.node()->value;
+ Q_ASSERT(e && *e);
+ }
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &akey) const
-{
- return const_iterator(*findNode(akey));
-}
+ public:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef qptrdiff difference_type;
+ typedef T value_type;
+ typedef T *pointer;
+ typedef T &reference;
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::const_iterator QHash<Key, T>::constFind(const Key &akey) const
-{
- return const_iterator(*findNode(akey));
-}
+ constexpr iterator() noexcept = default;
+
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline T &value() const noexcept { return (*e)->value; }
+ inline T &operator*() const noexcept { return (*e)->value; }
+ inline T *operator->() const noexcept { return &(*e)->value; }
+ inline bool operator==(const iterator &o) const noexcept { return e == o.e; }
+ inline bool operator!=(const iterator &o) const noexcept { return e != o.e; }
+
+ inline iterator &operator++() noexcept {
+ Q_ASSERT(e && *e);
+ e = &(*e)->next;
+ Q_ASSERT(e);
+ if (!*e) {
+ ++i;
+ e = i.atEnd() ? nullptr : &i.node()->value;
+ }
+ return *this;
+ }
+ inline iterator operator++(int) noexcept {
+ iterator r = *this;
+ ++(*this);
+ return r;
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::find(const Key &akey)
-{
- detach();
- return iterator(*findNode(akey));
-}
+ inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
+ };
+ friend class iterator;
-template <class Key, class T>
-Q_INLINE_TEMPLATE bool QHash<Key, T>::contains(const Key &akey) const
-{
- return *findNode(akey) != e;
-}
+ class const_iterator
+ {
+ using piter = typename QHashPrivate::iterator<Node>;
+ friend class iterator;
+ friend class QMultiHash<Key, T>;
+ piter i;
+ Chain **e = nullptr;
+ explicit inline const_iterator(piter it, Chain **entry = nullptr) noexcept : i(it), e(entry)
+ {
+ if (!it.atEnd() && !e) {
+ e = &it.node()->value;
+ Q_ASSERT(e && *e);
+ }
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(const Key &akey, uint h) const
-{
- Node **node;
+ public:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef qptrdiff difference_type;
+ typedef T value_type;
+ typedef const T *pointer;
+ typedef const T &reference;
- if (d->numBuckets) {
- node = reinterpret_cast<Node **>(&d->buckets[h % d->numBuckets]);
- Q_ASSERT(*node == e || (*node)->next);
- while (*node != e && !(*node)->same_key(h, akey))
- node = &(*node)->next;
- } else {
- node = const_cast<Node **>(reinterpret_cast<const Node * const *>(&e));
- }
- return node;
-}
+ constexpr const_iterator() noexcept = default;
+ inline const_iterator(const iterator &o) noexcept : i(o.i), e(o.e) { }
+
+ inline const Key &key() const noexcept { return i.node()->key; }
+ inline T &value() const noexcept { return (*e)->value; }
+ inline T &operator*() const noexcept { return (*e)->value; }
+ inline T *operator->() const noexcept { return &(*e)->value; }
+ inline bool operator==(const const_iterator &o) const noexcept { return e == o.e; }
+ inline bool operator!=(const const_iterator &o) const noexcept { return e != o.e; }
+
+ inline const_iterator &operator++() noexcept {
+ Q_ASSERT(e && *e);
+ e = &(*e)->next;
+ Q_ASSERT(e);
+ if (!*e) {
+ ++i;
+ e = i.atEnd() ? nullptr : &i.node()->value;
+ }
+ return *this;
+ }
+ inline const_iterator operator++(int) noexcept
+ {
+ const_iterator r = *this;
+ ++(*this);
+ return r;
+ }
+ };
+ friend class const_iterator;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::Node **QHash<Key, T>::findNode(const Key &akey,
- uint *ahp) const
-{
- uint h = 0;
+ class key_iterator
+ {
+ const_iterator i;
- if (d->numBuckets || ahp) {
- h = qHash(akey, d->seed);
- if (ahp)
- *ahp = h;
- }
- return findNode(akey, h);
-}
+ public:
+ typedef typename const_iterator::iterator_category iterator_category;
+ typedef qptrdiff difference_type;
+ typedef Key value_type;
+ typedef const Key *pointer;
+ typedef const Key &reference;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash &other) const
-{
- if (d == other.d)
- return true;
- if (size() != other.size())
- return false;
+ key_iterator() noexcept = default;
+ explicit key_iterator(const_iterator o) noexcept : i(o) { }
- const_iterator it = begin();
+ const Key &operator*() const noexcept { return i.key(); }
+ const Key *operator->() const noexcept { return &i.key(); }
+ bool operator==(key_iterator o) const noexcept { return i == o.i; }
+ bool operator!=(key_iterator o) const noexcept { return i != o.i; }
- while (it != end()) {
- // Build two equal ranges for i.key(); one for *this and one for other.
- // For *this we can avoid a lookup via equal_range, as we know the beginning of the range.
- auto thisEqualRangeStart = it;
- const Key &thisEqualRangeKey = it.key();
- size_type n = 0;
- do {
- ++it;
- ++n;
- } while (it != end() && it.key() == thisEqualRangeKey);
+ inline key_iterator &operator++() noexcept { ++i; return *this; }
+ inline key_iterator operator++(int) noexcept { return key_iterator(i++);}
+ const_iterator base() const noexcept { return i; }
+ };
- const auto otherEqualRange = other.equal_range(thisEqualRangeKey);
+ typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
+ typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
- if (n != std::distance(otherEqualRange.first, otherEqualRange.second))
- return false;
+ // STL style
+ inline iterator begin() { detach(); return iterator(d->begin()); }
+ inline const_iterator begin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator cbegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline const_iterator constBegin() const noexcept { return d ? const_iterator(d->begin()): const_iterator(); }
+ inline iterator end() noexcept { return iterator(); }
+ inline const_iterator end() const noexcept { return const_iterator(); }
+ inline const_iterator cend() const noexcept { return const_iterator(); }
+ inline const_iterator constEnd() const noexcept { return const_iterator(); }
+ inline key_iterator keyBegin() const noexcept { return key_iterator(begin()); }
+ inline key_iterator keyEnd() const noexcept { return key_iterator(end()); }
+ inline key_value_iterator keyValueBegin() noexcept { return key_value_iterator(begin()); }
+ inline key_value_iterator keyValueEnd() noexcept { return key_value_iterator(end()); }
+ inline const_key_value_iterator keyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator constKeyValueBegin() const noexcept { return const_key_value_iterator(begin()); }
+ inline const_key_value_iterator keyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ inline const_key_value_iterator constKeyValueEnd() const noexcept { return const_key_value_iterator(end()); }
+ 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)
+ {
+ auto i = it.i;
+ Chain **e = it.e;
+ if (d->ref.isShared()) {
+ // need to store iterator position before detaching
+ qsizetype n = 0;
+ Chain *entry = i.node()->value;
+ while (entry != *it.e) {
+ ++n;
+ entry = entry->next;
+ }
+ Q_ASSERT(entry);
+ detach_helper();
- // Keys in the ranges are equal by construction; this checks only the values.
- if (!qt_is_permutation(thisEqualRangeStart, it, otherEqualRange.first, otherEqualRange.second))
- return false;
+ i = d->detachedIterator(i);
+ e = &i.node()->value;
+ while (n) {
+ e = &(*e)->next;
+ --n;
+ }
+ Q_ASSERT(e && *e);
+ }
+ return iterator(i, e);
}
- return true;
-}
-
-template <class Key, class T>
-QPair<typename QHash<Key, T>::iterator, typename QHash<Key, T>::iterator> QHash<Key, T>::equal_range(const Key &akey)
-{
- detach();
- auto pair = qAsConst(*this).equal_range(akey);
- return qMakePair(iterator(pair.first.i), iterator(pair.second.i));
-}
+ iterator erase(const_iterator it)
+ {
+ Q_ASSERT(d);
+ iterator iter = detach(it);
+ iterator i = iter;
+ Chain *e = *i.e;
+ Chain *next = e->next;
+ *i.e = next;
+ delete e;
+ if (!next) {
+ if (i.e == &i.i.node()->value) {
+ // last remaining entry, erase
+ 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(++iter.i);
+ }
+ }
+ --m_size;
+ Q_ASSERT(m_size >= 0);
+ return i;
+ }
-template <class Key, class T>
-QPair<typename QHash<Key, T>::const_iterator, typename QHash<Key, T>::const_iterator> QHash<Key, T>::equal_range(const Key &akey) const noexcept
-{
- Node *node = *findNode(akey);
- const_iterator firstIt = const_iterator(node);
+ // more Qt
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ inline qsizetype count() const noexcept { return size(); }
- if (node != e) {
- // equal keys must hash to the same value and so they all
- // end up in the same bucket. So we can use node->next,
- // which only works within a bucket, instead of (out-of-line)
- // QHashData::nextNode()
- while (node->next != e && node->next->key == akey)
- node = node->next;
+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();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
- // 'node' may be the last node in the bucket. To produce the end iterator, we'd
- // need to enter the next bucket in this case, so we need to use
- // QHashData::nextNode() here, which, unlike node->next above, can move between
- // buckets.
- node = concrete(QHashData::nextNode(reinterpret_cast<QHashData::Node *>(node)));
+ if (it.isUnused())
+ return end();
+ return iterator(it.toIterator(d));
+ }
+ template <typename K> const_iterator constFindImpl(const K &key) const noexcept
+ {
+ if (isEmpty())
+ return end();
+ auto it = d->findBucket(key);
+ if (it.isUnused())
+ return constEnd();
+ return const_iterator(it.toIterator(d));
}
-
- return qMakePair(firstIt, const_iterator(node));
-}
-
-template <class Key, class T>
-class QMultiHash : public QHash<Key, T>
-{
public:
- QMultiHash() noexcept {}
- inline QMultiHash(std::initializer_list<std::pair<Key,T> > list)
+ iterator find(const Key &key)
{
- this->reserve(int(list.size()));
- for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
- insert(it->first, it->second);
+ return findImpl(key);
}
-#ifdef Q_QDOC
- template <typename InputIterator>
- QMultiHash(InputIterator f, InputIterator l);
-#else
- template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasKeyAndValue<InputIterator> = true>
- QMultiHash(InputIterator f, InputIterator l)
+ const_iterator constFind(const Key &key) const noexcept
{
- QtPrivate::reserveIfForwardIterator(this, f, l);
- for (; f != l; ++f)
- insert(f.key(), f.value());
+ return constFindImpl(key);
+ }
+ const_iterator find(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
}
- template <typename InputIterator, QtPrivate::IfAssociativeIteratorHasFirstAndSecond<InputIterator> = true>
- QMultiHash(InputIterator f, InputIterator l)
+ iterator insert(const Key &key, const T &value)
{
- QtPrivate::reserveIfForwardIterator(this, f, l);
- for (; f != l; ++f)
- insert(f->first, f->second);
+ return emplace(key, value);
+ }
+
+ template <typename ...Args>
+ iterator emplace(const Key &key, Args &&... args)
+ {
+ return emplace(Key(key), std::forward<Args>(args)...);
+ }
+
+ 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)...);
}
-#endif
- // compiler-generated copy/move ctors/assignment operators are fine!
- // compiler-generated destructor is fine!
- QMultiHash(const QHash<Key, T> &other) : QHash<Key, T>(other) {}
- QMultiHash(QHash<Key, T> &&other) noexcept : QHash<Key, T>(std::move(other)) {}
- void swap(QMultiHash &other) noexcept { QHash<Key, T>::swap(other); } // prevent QMultiHash<->QHash swaps
- inline typename QHash<Key, T>::iterator replace(const Key &key, const T &value)
- { return QHash<Key, T>::insert(key, value); }
+ 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(); }
+
+ inline iterator replace(const Key &key, const T &value)
+ {
+ return emplaceReplace(key, value);
+ }
+
+ template <typename ...Args>
+ iterator emplaceReplace(const Key &key, Args &&... args)
+ {
+ return emplaceReplace(Key(key), std::forward<Args>(args)...);
+ }
- inline typename QHash<Key, T>::iterator insert(const Key &key, const T &value)
- { return QHash<Key, T>::insertMulti(key, value); }
+ template <typename ...Args>
+ iterator emplaceReplace(Key &&key, 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)...);
+ }
+ // 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)
{ this->unite(other); return *this; }
inline QMultiHash operator+(const QMultiHash &other) const
{ QMultiHash result = *this; result += other; return result; }
- using QHash<Key, T>::contains;
- using QHash<Key, T>::remove;
- using QHash<Key, T>::count;
- using QHash<Key, T>::find;
- using QHash<Key, T>::constFind;
+ 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);
+ if (n == nullptr)
+ return false;
+ return n->value->contains(value);
+ }
- bool contains(const Key &key, const T &value) const;
+public:
+ qsizetype remove(const Key &key, const T &value)
+ {
+ return removeImpl(key, value);
+ }
+private:
+ template <typename K> qsizetype removeImpl(const K &key, const T &value)
+ {
+ if (isEmpty()) // prevents detaching shared null
+ return 0;
+ auto it = d->findBucket(key);
+ size_t bucket = it.toBucketIndex(d);
+ detach();
+ it = typename Data::Bucket(d, bucket); // reattach in case of detach
+
+ if (it.isUnused())
+ return 0;
+ qsizetype n = 0;
+ Chain **e = &it.node()->value;
+ while (*e) {
+ Chain *entry = *e;
+ if (entry->value == value) {
+ *e = entry->next;
+ delete entry;
+ ++n;
+ } else {
+ e = &entry->next;
+ }
+ }
+ if (!it.node()->value)
+ d->erase(it);
+ m_size -= n;
+ Q_ASSERT(m_size >= 0);
+ return n;
+ }
- int remove(const Key &key, const T &value);
+public:
+ qsizetype count(const Key &key) const noexcept
+ {
+ return countImpl(key);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key) const noexcept
+ {
+ if (!d)
+ return 0;
+ auto it = d->findBucket(key);
+ if (it.isUnused())
+ return 0;
+ qsizetype n = 0;
+ Chain *e = it.node()->value;
+ while (e) {
+ ++n;
+ e = e->next;
+ }
- int count(const Key &key, const T &value) const;
+ return n;
+ }
- typename QHash<Key, T>::iterator find(const Key &key, const T &value) {
- typename QHash<Key, T>::iterator i(find(key));
- typename QHash<Key, T>::iterator end(this->end());
- while (i != end && i.key() == key) {
- if (i.value() == value)
- return i;
- ++i;
+public:
+ qsizetype count(const Key &key, const T &value) const noexcept
+ {
+ return countImpl(key, value);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key, const T &value) const noexcept
+ {
+ if (!d)
+ return 0;
+ auto it = d->findBucket(key);
+ if (it.isUnused())
+ return 0;
+ qsizetype n = 0;
+ Chain *e = it.node()->value;
+ while (e) {
+ if (e->value == value)
+ ++n;
+ e = e->next;
}
- return end;
+
+ return n;
}
- typename QHash<Key, T>::const_iterator find(const Key &key, const T &value) const {
- typename QHash<Key, T>::const_iterator i(constFind(key));
- typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
+
+ 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);
+ }
+ template <typename K> const_iterator constFindImpl(const K &key, const T &value) const noexcept
+ {
+ const_iterator i(constFind(key));
+ const_iterator end(constEnd());
while (i != end && i.key() == key) {
if (i.value() == value)
return i;
@@ -1082,78 +2212,261 @@ public:
}
return end;
}
- typename QHash<Key, T>::const_iterator constFind(const Key &key, const T &value) const
- { return find(key, value); }
+
+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()) {
+ *this = other;
+ } else if (other.isEmpty()) {
+ ;
+ } else {
+ QMultiHash copy(other);
+ detach();
+ for (auto cit = copy.cbegin(); cit != copy.cend(); ++cit)
+ insert(cit.key(), *cit);
+ }
+ return *this;
+ }
+
+ 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:
- T &operator[](const Key &key);
- const T operator[](const Key &key) const;
-};
+ 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 = std::as_const(*this).equal_range(key);
+ return {iterator(pair.first.i), iterator(pair.second.i)};
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE bool QMultiHash<Key, T>::contains(const Key &key, const T &value) const
-{
- return constFind(key, value) != QHash<Key, T>::constEnd();
-}
+public:
+ std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ {
+ return equal_range_impl(key);
+ }
+private:
+ template <typename K> std::pair<const_iterator, const_iterator> equal_range_impl(const K &key) const noexcept
+ {
+ if (!d)
+ return {end(), end()};
+
+ auto bucket = d->findBucket(key);
+ if (bucket.isUnused())
+ return {end(), end()};
+ auto it = bucket.toIterator(d);
+ auto end = it;
+ ++end;
+ return {const_iterator(it), const_iterator(end)};
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiHash<Key, T>::remove(const Key &key, const T &value)
-{
- int n = 0;
- typename QHash<Key, T>::iterator i(find(key));
- typename QHash<Key, T>::iterator end(QHash<Key, T>::end());
- while (i != end && i.key() == key) {
- if (i.value() == value) {
- i = this->erase(i);
- ++n;
+ void detach_helper()
+ {
+ if (!d) {
+ d = new Data;
+ return;
+ }
+ Data *dd = new Data(*d);
+ if (!d->ref.deref())
+ delete d;
+ d = dd;
+ }
+
+ template<typename... Args>
+ iterator emplace_helper(Key &&key, Args &&...args)
+ {
+ auto result = d->findOrInsert(key);
+ if (!result.initialized)
+ Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
+ else
+ result.it.node()->insertMulti(std::forward<Args>(args)...);
+ ++m_size;
+ return iterator(result.it);
+ }
+
+ template<typename... Args>
+ iterator emplaceReplace_helper(Key &&key, Args &&...args)
+ {
+ auto result = d->findOrInsert(key);
+ if (!result.initialized) {
+ Node::createInPlace(result.it.node(), std::move(key), std::forward<Args>(args)...);
+ ++m_size;
} else {
- ++i;
+ result.it.node()->emplaceValue(std::forward<Args>(args)...);
}
+ return iterator(result.it);
}
- return n;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &key, const T &value) const
-{
- int n = 0;
- typename QHash<Key, T>::const_iterator i(constFind(key));
- typename QHash<Key, T>::const_iterator end(QHash<Key, T>::constEnd());
- while (i != end && i.key() == key) {
- if (i.value() == value)
- ++n;
- ++i;
+public:
+#ifdef __cpp_concepts
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
}
- return n;
-}
+ T take(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return takeImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
+ }
+ T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return operatorIndexImpl(key);
+ }
+ const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return value(key);
+ }
+ QList<T> values(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return valuesImpl(key);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return containsImpl(key, value);
+ }
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
+ {
+ return removeImpl(key, value);
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return countImpl(key);
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return countImpl(key, value);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
+ {
+ return findImpl(key, value);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return constFindImpl(key, value);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return constFind(key, value);
+ }
+ std::pair<iterator, iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return equal_range_impl(key);
+ }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return equal_range_impl(key);
+ }
+#endif // __cpp_concepts
+};
-Q_DECLARE_ASSOCIATIVE_ITERATOR(Hash)
-Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Hash)
+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>
-uint qHash(const QHash<Key, T> &key, uint seed = 0)
+size_t qHash(const QHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
- QtPrivate::QHashCombineCommutative hash;
+ 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 uint qHash(const QMultiHash<Key, T> &key, uint seed = 0)
+inline size_t qHash(const QMultiHash<Key, T> &key, size_t seed = 0)
noexcept(noexcept(qHash(std::declval<Key&>())) && noexcept(qHash(std::declval<T&>())))
{
- const QHash<Key, T> &key2 = key;
- 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;
}
-QT_END_NAMESPACE
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QHash<Key, T> &hash, Predicate pred)
+{
+ return QtPrivate::associative_erase_if(hash, pred);
+}
-#if defined(Q_CC_MSVC)
-#pragma warning( pop )
-#endif
+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
#endif // QHASH_H
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index 2ff3464912..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,117 +30,342 @@
QT_BEGIN_NAMESPACE
class QBitArray;
-class QByteArray;
-class QString;
-class QStringRef;
-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 {
+
+Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
+{
+ key ^= seed;
+ if constexpr (sizeof(size_t) == 4) {
+ key ^= key >> 16;
+ key *= UINT32_C(0x45d9f3b);
+ key ^= key >> 16;
+ key *= UINT32_C(0x45d9f3b);
+ key ^= key >> 16;
+ return key;
+ } else {
+ quint64 key64 = key;
+ key64 ^= key64 >> 32;
+ key64 *= UINT64_C(0xd6e8feb86659fd93);
+ key64 ^= key64 >> 32;
+ key64 *= UINT64_C(0xd6e8feb86659fd93);
+ key64 ^= key64 >> 32;
+ return size_t(key64);
+ }
+}
+
+template <typename T1, typename T2> static constexpr bool noexceptPairHash();
+}
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHashBits(const void *p, size_t size, uint seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHashBits(const void *p, size_t size, size_t seed = 0) noexcept;
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(char key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uchar key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(signed char key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ushort key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(short key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uint key, uint seed = 0) noexcept { return key ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(int key, uint seed = 0) noexcept { return uint(key) ^ seed; }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ulong key, uint seed = 0) noexcept
+// 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); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(uchar key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(signed char key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(ushort key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(short key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(uint key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(int key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(ulong key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(long key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(quint64 key, size_t seed = 0) noexcept
+{
+ if constexpr (sizeof(quint64) > sizeof(size_t))
+ 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
+{
+ 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
{
- return (sizeof(ulong) > sizeof(uint))
- ? (uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U)) ^ seed)
- : (uint(key & (~0U)) ^ seed);
+ // 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);
}
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(long key, uint seed = 0) noexcept { return qHash(ulong(key), seed); }
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(quint64 key, uint seed = 0) noexcept
+#endif // QT_SUPPORTS_INT128
+Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
{
- return uint(((key >> (8 * sizeof(uint) - 1)) ^ key) & (~0U)) ^ seed;
+ // ensure -0 gets mapped to 0
+ key += 0.0f;
+ uint k;
+ memcpy(&k, &key, sizeof(float));
+ return QHashPrivate::hash(k, seed);
}
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(qint64 key, uint seed = 0) noexcept { return qHash(quint64(key), seed); }
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(float key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(double key, uint seed = 0) noexcept;
-#if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(long double key, uint seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(double key, size_t seed = 0) noexcept;
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(long double key, size_t seed = 0) noexcept;
+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
+{ return QHashPrivate::hash(size_t(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char32_t key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
+#ifdef __cpp_char8_t
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char8_t key, size_t seed = 0) noexcept
+{ return QHashPrivate::hash(size_t(key), seed); }
#endif
-Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(const QChar key, uint seed = 0) noexcept { return qHash(key.unicode(), seed); }
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QByteArray &key, uint seed = 0) noexcept;
-#if QT_STRINGVIEW_LEVEL < 2
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QString &key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QStringRef &key, uint seed = 0) noexcept;
+template <class T> inline size_t qHash(const T *key, size_t seed = 0) noexcept
+{
+ return qHash(reinterpret_cast<quintptr>(key), seed);
+}
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed = 0) noexcept
+{
+ 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 uint qHash(QStringView key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QBitArray &key, uint seed = 0) noexcept;
-Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QLatin1String key, uint seed = 0) noexcept;
+
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept;
+inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept
+{ return qHash(QStringView{key}, seed); }
+#ifndef QT_BOOTSTRAPPED
+Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &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;
-Q_DECL_CONST_FUNCTION inline uint qHash(std::nullptr_t, uint seed = 0) noexcept
+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 qHash(reinterpret_cast<quintptr>(nullptr), seed);
+ return a == b;
}
-template <class T> inline uint qHash(const T *key, uint seed = 0) noexcept
+template <typename T1, typename T2>
+std::enable_if_t<QHashPrivate::HeterogeneouslySearchableWith<T1, T2>, bool>
+qHashEquals(const T1 &a, const T2 &b)
{
- return qHash(reinterpret_cast<quintptr>(key), seed);
+ return a == b;
}
-template<typename T> inline uint qHash(const T &t, uint seed)
- noexcept(noexcept(qHash(t)))
-{ return qHash(t) ^ seed; }
namespace QtPrivate {
-struct QHashCombine {
- typedef uint result_type;
+struct QHashCombine
+{
+ typedef size_t result_type;
template <typename T>
- Q_DECL_CONSTEXPR result_type operator()(uint seed, const T &t) const noexcept(noexcept(qHash(t)))
+ constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
// combiner taken from N3876 / boost::hash_combine
{ return seed ^ (qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2)) ; }
};
-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
// {1,3,0}. Except when it isn't (e.g. for QSet and
// QHash). Therefore, provide a commutative combiner, too.
- typedef uint result_type;
+ typedef size_t result_type;
template <typename T>
- Q_DECL_CONSTEXPR result_type operator()(uint seed, const T &t) const noexcept(noexcept(qHash(t)))
+ constexpr result_type operator()(size_t seed, const T &t) const noexcept(noexcept(qHash(t)))
{ return seed + qHash(t); } // don't use xor!
};
+template <typename... T>
+using QHashMultiReturnType = decltype(
+ std::declval< std::enable_if_t<(sizeof...(T) > 0)> >(),
+ (qHash(std::declval<const T &>()), ...),
+ size_t{}
+);
+
+// workaround for a MSVC ICE,
+// https://developercommunity.visualstudio.com/content/problem/996540/internal-compiler-error-on-msvc-1924-when-doing-sf.html
+template <typename T>
+inline constexpr bool QNothrowHashableHelper_v = noexcept(qHash(std::declval<const T &>()));
+
+template <typename T, typename Enable = void>
+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>
+constexpr
+#ifdef Q_QDOC
+size_t
+#else
+QtPrivate::QHashMultiReturnType<T...>
+#endif
+qHashMulti(size_t seed, const T &... args)
+ noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
+{
+ QtPrivate::QHashCombine hash;
+ return ((seed = hash(seed, args)), ...), seed;
+}
+
+template <typename... T>
+constexpr
+#ifdef Q_QDOC
+size_t
+#else
+QtPrivate::QHashMultiReturnType<T...>
+#endif
+qHashMultiCommutative(size_t seed, const T &... args)
+ noexcept(std::conjunction_v<QtPrivate::QNothrowHashable<T>...>)
+{
+ QtPrivate::QHashCombineCommutative hash;
+ return ((seed = hash(seed, args)), ...), seed;
+}
+
template <typename InputIterator>
-inline uint qHashRange(InputIterator first, InputIterator last, uint seed = 0)
+inline size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QtPrivate::QHashCombine());
}
template <typename InputIterator>
-inline uint qHashRangeCommutative(InputIterator first, InputIterator last, uint seed = 0)
+inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative());
}
-template <typename T1, typename T2> inline uint qHash(const QPair<T1, T2> &key, uint seed = 0)
- noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
+namespace QHashPrivate {
+template <typename T1, typename T2> static constexpr bool noexceptPairHash()
{
- uint h1 = qHash(key.first, seed);
- uint h2 = qHash(key.second, seed);
- return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed;
+ size_t seed = 0;
+ return noexcept(qHash(std::declval<T1>(), seed)) && noexcept(qHash(std::declval<T2>(), seed));
}
+} // QHashPrivate
-template <typename T1, typename T2> inline uint qHash(const std::pair<T1, T2> &key, uint seed = 0)
- noexcept(noexcept(qHash(key.first, seed)) && noexcept(qHash(key.second, seed)))
+template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2> &key, size_t seed)
+ noexcept(QHashPrivate::noexceptPairHash<T1, T2>())
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, key.first);
- seed = hash(seed, key.second);
- return seed;
+ return qHashMulti(seed, key.first, key.second);
}
#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, Arguments) \
@@ -181,15 +376,15 @@ template <typename T1, typename T2> inline uint qHash(const std::pair<T1, T2> &k
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))); \
} \
}; \
} \
@@ -202,11 +397,13 @@ template <typename T1, typename T2> inline uint qHash(const std::pair<T1, T2> &k
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH(Class, argument_type)
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QString)
-QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QStringRef)
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 84a0e116ca..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>
@@ -195,17 +244,22 @@ public:
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::difference_type difference_type;
typedef std::pair<Key, T> value_type;
- typedef const value_type *pointer;
typedef const value_type &reference;
QKeyValueIterator() = default;
- Q_DECL_CONSTEXPR explicit QKeyValueIterator(Iterator o) noexcept(std::is_nothrow_move_constructible<Iterator>::value)
+ constexpr explicit QKeyValueIterator(Iterator o) noexcept(std::is_nothrow_move_constructible<Iterator>::value)
: i(std::move(o)) {}
std::pair<Key, T> operator*() const {
return std::pair<Key, T>(i.key(), i.value());
}
+ using pointer = QtPrivate::ArrowProxy<value_type>;
+
+ pointer operator->() const {
+ return pointer{std::pair<Key, T>(i.key(), i.value())};
+ }
+
friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i == rhs.i; }
friend bool operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i != rhs.i; }
@@ -219,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 b4d332b7b1..041fb0701d 100644
--- a/src/corelib/tools/qiterator.qdoc
+++ b/src/corelib/tools/qiterator.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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! \class QKeyValueIterator
\inmodule QtCore
@@ -57,7 +33,7 @@
\internal
*/
-/*! \typedef QKeyValueIterator::pointer
+/*! \struct QKeyValueIterator::pointer
\internal
*/
@@ -75,13 +51,21 @@
Constructs a QKeyValueIterator on top of \a o.
*/
-/*! \fn template<typename Key, typename T, class Iterator> const T &QKeyValueIterator<Key, T, Iterator>::operator*() const
+/*! \fn template<typename Key, typename T, class Iterator> std::pair<Key, T> QKeyValueIterator<Key, T, Iterator>::operator*() const
Returns the current entry as a pair.
*/
-/*! \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> pointer QKeyValueIterator<Key, T, Iterator>::operator->() const
+
+ Returns the current entry as a pointer-like object to the pair.
+
+ \since 5.15
+
+ \sa operator*()
+*/
+
+/*! \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.
@@ -89,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.
@@ -101,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
@@ -114,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
@@ -123,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
@@ -136,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
@@ -154,18 +137,17 @@
\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,
making it possible to access, modify, and remove items without
using iterators.
- QListIterator\<T\> allows you to iterate over a QList\<T\> (or a
- QQueue\<T\>). If you want to modify the list as you iterate over
- it, use QMutableListIterator\<T\> instead.
+ QListIterator\<T\> allows you to iterate over a QList\<T\>,
+ a QQueue\<T\> or a QStack\<T\>. If you want to modify the list
+ as you iterate over it, use QMutableListIterator\<T\> instead.
The QListIterator constructor takes a QList as argument. After
construction, the iterator is located at the very beginning of
@@ -201,114 +183,13 @@
*/
/*!
- \class QLinkedListIterator
- \inmodule QtCore
-
- \brief The QLinkedListIterator class provides a Java-style const iterator for QLinkedList.
-
- QLinkedList has both \l{Java-style iterators} and
- \l{STL-style iterators}. The Java-style iterators are more
- high-level and easier to use than the STL-style iterators; on the
- other hand, they are slightly less efficient.
-
- QLinkedListIterator\<T\> allows you to iterate over a
- QLinkedList\<T\>. If you want to modify the list as you iterate
- over it, use QMutableLinkedListIterator\<T\> instead.
-
- The QLinkedListIterator constructor takes a QLinkedList as
- argument. After construction, the iterator is located at the very
- beginning of the list (before the first item). Here's how to
- iterate over all the elements sequentially:
-
- \snippet code/doc_src_qiterator.cpp 2
-
- The next() function returns the next item in the list and
- advances the iterator. Unlike STL-style iterators, Java-style
- iterators point \e between items rather than directly \e at
- items. The first call to next() advances the iterator to the
- position between the first and second item, and returns the first
- item; the second call to next() advances the iterator to the
- position between the second and third item, and returns the second
- item; and so on.
-
- \image javaiterators1.png
-
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 3
-
- If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
-
- Multiple iterators can be used on the same list. If the list is
- modified while a QLinkedListIterator is active, the
- QLinkedListIterator will continue iterating over the original
- list, ignoring the modified copy.
-
- \sa QMutableLinkedListIterator, QLinkedList::const_iterator
-*/
-
-/*!
- \class QVectorIterator
- \inmodule QtCore
- \brief The QVectorIterator class provides a Java-style const iterator for QVector and QStack.
-
- QVector 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.
-
- An alternative to using iterators is to use index positions. Most
- QVector member functions take an index as their first parameter,
- making it possible to access, insert, and remove items without
- using iterators.
-
- QVectorIterator\<T\> allows you to iterate over a QVector\<T\>
- (or a QStack\<T\>). If you want to modify the vector as you
- iterate over it, use QMutableVectorIterator\<T\> instead.
-
- The QVectorIterator constructor takes a QVector as argument.
- After construction, the iterator is located at the very beginning
- of the vector (before the first item). Here's how to iterate over
- all the elements sequentially:
-
- \snippet code/doc_src_qiterator.cpp 4
-
- The next() function returns the next item in the vector and
- advances the iterator. Unlike STL-style iterators, Java-style
- iterators point \e between items rather than directly \e at
- items. The first call to next() advances the iterator to the
- position between the first and second item, and returns the first
- item; the second call to next() advances the iterator to the
- position between the second and third item, returning the second
- item; and so on.
-
- \image javaiterators1.png
-
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 5
-
- If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
-
- Multiple iterators can be used on the same vector. If the vector
- is modified while a QVectorIterator is active, the QVectorIterator
- will continue iterating over the original vector, ignoring the
- modified copy.
-
- \sa QMutableVectorIterator, QVector::const_iterator
-*/
-
-/*!
\class QSetIterator
\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
@@ -332,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
@@ -351,12 +228,11 @@
\class QMutableListIterator
\inmodule QtCore
- \brief The QMutableListIterator class provides a Java-style non-const iterator for QList and QQueue.
+ \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,
@@ -414,133 +290,6 @@
*/
/*!
- \class QMutableLinkedListIterator
- \inmodule QtCore
-
- \brief The QMutableLinkedListIterator class provides a Java-style non-const iterator for QLinkedList.
-
- QLinkedList has both \l{Java-style iterators} and
- \l{STL-style iterators}. The Java-style iterators are more
- high-level and easier to use than the STL-style iterators; on the
- other hand, they are slightly less efficient.
-
- QMutableLinkedListIterator\<T\> allows you to iterate over a
- QLinkedList\<T\> and modify the list. If you don't want to modify
- the list (or have a const QLinkedList), use the slightly faster
- QLinkedListIterator\<T\> instead.
-
- The QMutableLinkedListIterator constructor takes a QLinkedList as
- argument. After construction, the iterator is located at the very
- beginning of the list (before the first item). Here's how to
- iterate over all the elements sequentially:
-
- \snippet code/doc_src_qiterator.cpp 11
-
- The next() function returns the next item in the list and
- advances the iterator. Unlike STL-style iterators, Java-style
- iterators point \e between items rather than directly \e at
- items. The first call to next() advances the iterator to the
- position between the first and second item, and returns the first
- item; the second call to next() advances the iterator to the
- position between the second and third item, returning the second
- item; and so on.
-
- \image javaiterators1.png
-
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 12
-
- If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
-
- If you want to remove items as you iterate over the list, use
- remove(). If you want to modify the value of an item, use
- setValue(). If you want to insert a new item in the list, use
- insert().
-
- Example:
- \snippet code/doc_src_qiterator.cpp 13
-
- The example traverses a list, replacing negative numbers with
- their absolute values, and eliminating zeroes.
-
- Only one mutable iterator can be active on a given list at any
- time. Furthermore, no changes should be done directly to the list
- while the iterator is active (as opposed to through the
- iterator), since this could invalidate the iterator and lead to
- undefined behavior.
-
- \sa QLinkedListIterator, QLinkedList::iterator
-*/
-
-/*!
- \class QMutableVectorIterator
- \inmodule QtCore
-
- \brief The QMutableVectorIterator class provides a Java-style non-const iterator for QVector and QStack.
-
- QVector 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.
-
- An alternative to using iterators is to use index positions. Most
- QVector member functions take an index as their first parameter,
- making it possible to access, insert, and remove items without
- using iterators.
-
- QMutableVectorIterator\<T\> allows you to iterate over a
- QVector\<T\> and modify the vector. If you don't want to modify
- the vector (or have a const QVector), use the slightly faster
- QVectorIterator\<T\> instead.
-
- The QMutableVectorIterator constructor takes a QVector as
- argument. After construction, the iterator is located at the very
- beginning of the list (before the first item). Here's how to
- iterate over all the elements sequentially:
-
- \snippet code/doc_src_qiterator.cpp 14
-
- The next() function returns the next item in the vector and
- advances the iterator. Unlike STL-style iterators, Java-style
- iterators point \e between items rather than directly \e at
- items. The first call to next() advances the iterator to the
- position between the first and second item, and returns the first
- item; the second call to next() advances the iterator to the
- position between the second and third item, returning the second
- item; and so on.
-
- \image javaiterators1.png
-
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 15
-
- If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
-
- If you want to remove items as you iterate over the vector, use
- remove(). If you want to modify the value of an item, use
- setValue(). If you want to insert a new item in the vector, use
- insert().
-
- Example:
- \snippet code/doc_src_qiterator.cpp 16
-
- The example traverses a vector, replacing negative numbers with
- their absolute values, and eliminating zeroes.
-
- Only one mutable iterator can be active on a given vector at any
- time. Furthermore, no changes should be done directly to the
- vector while the iterator is active (as opposed to through the
- iterator), since this could invalidate the iterator and lead to
- undefined behavior.
-
- \sa QVectorIterator, QVector::iterator
-*/
-
-/*!
\class QMutableSetIterator
\inmodule QtCore
\since 4.2
@@ -548,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
@@ -575,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().
@@ -593,9 +337,7 @@
/*!
\fn template <class T> QListIterator<T>::QListIterator(const QList<T> &list)
- \fn template <class T> QLinkedListIterator<T>::QLinkedListIterator(const QLinkedList<T> &list)
\fn template <class T> QMutableListIterator<T>::QMutableListIterator(QList<T> &list)
- \fn template <class T> QMutableLinkedListIterator<T>::QMutableLinkedListIterator(QLinkedList<T> &list)
Constructs an iterator for traversing \a list. The iterator is
set to be at the front of the list (before the first item).
@@ -604,16 +346,6 @@
*/
/*!
- \fn template <class T> QVectorIterator<T>::QVectorIterator(const QVector<T> &vector)
- \fn template <class T> QMutableVectorIterator<T>::QMutableVectorIterator(QVector<T> &vector)
-
- Constructs an iterator for traversing \a vector. The iterator is
- set to be at the front of the vector (before the first item).
-
- \sa operator=()
-*/
-
-/*!
\fn template <class T> QSetIterator<T>::QSetIterator(const QSet<T> &set)
\fn template <class T> QMutableSetIterator<T>::QMutableSetIterator(QSet<T> &set)
@@ -624,9 +356,7 @@
*/
/*! \fn template <class T> QMutableListIterator &QMutableListIterator<T>::operator=(QList<T> &list)
- \fn template <class T> QMutableLinkedListIterator &QMutableLinkedListIterator<T>::operator=(QLinkedList<T> &list)
\fn template <class T> QListIterator &QListIterator<T>::operator=(const QList<T> &list)
- \fn template <class T> QLinkedListIterator &QLinkedListIterator<T>::operator=(const QLinkedList<T> &list)
Makes the iterator operate on \a list. The iterator is set to be
at the front of the list (before the first item).
@@ -634,15 +364,6 @@
\sa toFront(), toBack()
*/
-/*! \fn template <class T> QVectorIterator &QVectorIterator<T>::operator=(const QVector<T> &vector)
- \fn template <class T> QMutableVectorIterator &QMutableVectorIterator<T>::operator=(QVector<T> &vector)
-
- Makes the iterator operate on \a vector. The iterator is set to be
- at the front of the vector (before the first item).
-
- \sa toFront(), toBack()
-*/
-
/*! \fn template <class T> QSetIterator &QSetIterator<T>::operator=(const QSet<T> &set)
\fn template <class T> QMutableSetIterator &QMutableSetIterator<T>::operator=(QSet<T> &set)
@@ -653,12 +374,8 @@
*/
/*! \fn template <class T> void QListIterator<T>::toFront()
- \fn template <class T> void QLinkedListIterator<T>::toFront()
- \fn template <class T> void QVectorIterator<T>::toFront()
\fn template <class T> void QSetIterator<T>::toFront()
\fn template <class T> void QMutableListIterator<T>::toFront()
- \fn template <class T> void QMutableLinkedListIterator<T>::toFront()
- \fn template <class T> void QMutableVectorIterator<T>::toFront()
\fn template <class T> void QMutableSetIterator<T>::toFront()
Moves the iterator to the front of the container (before the
@@ -668,53 +385,93 @@
*/
/*! \fn template <class T> void QListIterator<T>::toBack()
- \fn template <class T> void QLinkedListIterator<T>::toBack()
- \fn template <class T> void QVectorIterator<T>::toBack()
- \fn template <class T> void QSetIterator<T>::toBack()
\fn template <class T> void QMutableListIterator<T>::toBack()
- \fn template <class T> void QMutableLinkedListIterator<T>::toBack()
- \fn template <class T> void QMutableVectorIterator<T>::toBack()
- \fn template <class T> void QMutableSetIterator<T>::toBack()
+//! [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 QLinkedListIterator<T>::hasNext() const
- \fn template <class T> bool QVectorIterator<T>::hasNext() const
- \fn template <class T> bool QSetIterator<T>::hasNext() const
\fn template <class T> bool QMutableListIterator<T>::hasNext() const
- \fn template <class T> bool QMutableLinkedListIterator<T>::hasNext() const
- \fn template <class T> bool QMutableVectorIterator<T>::hasNext() const
- \fn template <class T> bool QMutableSetIterator<T>::hasNext() const
+//! [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 &QLinkedListIterator<T>::next()
- \fn template <class T> const T &QVectorIterator<T>::next()
- \fn template <class T> const T &QSetIterator<T>::next()
- \fn template <class T> const T &QMutableSetIterator<T>::next()
+//! [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()
- \fn template <class T> T &QMutableLinkedListIterator<T>::next()
- \fn template <class T> T &QMutableVectorIterator<T>::next()
Returns a reference to the next item, and advances the iterator
by one position.
@@ -726,9 +483,24 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekNext() const
- \fn template <class T> const T &QLinkedListIterator<T>::peekNext() const
- \fn template <class T> const T &QVectorIterator<T>::peekNext() const
+
+//! [peekNext]
+ Returns the next item without moving the iterator.
+
+ Calling this function on an iterator located at the back of the
+ container leads to undefined results.
+//! [peekNext]
+
+ \sa hasNext(), next(), peekPrevious()
+*/
+
+/*!
\fn template <class T> const T &QSetIterator<T>::peekNext() const
+ \include qiterator.qdoc peekNext
+ \sa hasNext(), next()
+*/
+
+/*!
\fn template <class T> const T &QMutableSetIterator<T>::peekNext() const
Returns the next item without moving the iterator.
@@ -736,12 +508,10 @@
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> T &QMutableListIterator<T>::peekNext() const
- \fn template <class T> T &QMutableLinkedListIterator<T>::peekNext() const
- \fn template <class T> T &QMutableVectorIterator<T>::peekNext() const
Returns a reference to the next item, without moving the iterator.
@@ -752,13 +522,7 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasPrevious() const
- \fn template <class T> bool QLinkedListIterator<T>::hasPrevious() const
- \fn template <class T> bool QVectorIterator<T>::hasPrevious() const
- \fn template <class T> bool QSetIterator<T>::hasPrevious() const
\fn template <class T> bool QMutableListIterator<T>::hasPrevious() const
- \fn template <class T> bool QMutableLinkedListIterator<T>::hasPrevious() const
- \fn template <class T> bool QMutableVectorIterator<T>::hasPrevious() const
- \fn template <class T> bool QMutableSetIterator<T>::hasPrevious() 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;
@@ -768,10 +532,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::previous()
- \fn template <class T> const T &QLinkedListIterator<T>::previous()
- \fn template <class T> const T &QVectorIterator<T>::previous()
- \fn template <class T> const T &QSetIterator<T>::previous()
- \fn template <class T> const T &QMutableSetIterator<T>::previous()
Returns the previous item and moves the iterator back by one
position.
@@ -783,8 +543,6 @@
*/
/*! \fn template <class T> T &QMutableListIterator<T>::previous()
- \fn template <class T> T &QMutableLinkedListIterator<T>::previous()
- \fn template <class T> T &QMutableVectorIterator<T>::previous()
Returns a reference to the previous item and moves the iterator
back by one position.
@@ -796,10 +554,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekPrevious() const
- \fn template <class T> const T &QLinkedListIterator<T>::peekPrevious() const
- \fn template <class T> const T &QVectorIterator<T>::peekPrevious() const
- \fn template <class T> const T &QSetIterator<T>::peekPrevious() const
- \fn template <class T> const T &QMutableSetIterator<T>::peekPrevious() const
Returns the previous item without moving the iterator.
@@ -810,8 +564,6 @@
*/
/*! \fn template <class T> T &QMutableListIterator<T>::peekPrevious() const
- \fn template <class T> T &QMutableLinkedListIterator<T>::peekPrevious() const
- \fn template <class T> T &QMutableVectorIterator<T>::peekPrevious() const
Returns a reference to the previous item, without moving the iterator.
@@ -821,33 +573,38 @@
\sa hasPrevious(), previous(), peekNext()
*/
+/*!
+ \fn template <class T> bool QMutableSetIterator<T>::findNext(const T &value)
+
+ 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.
+*/
+
/*! \fn template <class T> bool QListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QLinkedListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QVectorIterator<T>::findNext(const T &value)
- \fn template <class T> bool QSetIterator<T>::findNext(const T &value)
\fn template <class T> bool QMutableListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QMutableLinkedListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QMutableVectorIterator<T>::findNext(const T &value)
- \fn template <class T> bool QMutableSetIterator<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 QLinkedListIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QVectorIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QSetIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QMutableListIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QMutableLinkedListIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QMutableVectorIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QMutableSetIterator<T>::findPrevious(const T &value)
Searches for \a value starting from the current iterator position
backward. Returns \c true if \a value is found; otherwise returns
@@ -871,32 +628,10 @@
\sa insert(), setValue()
*/
-/*! \fn template <class T> void QMutableLinkedListIterator<T>::remove()
-
- Removes the last item that was jumped over using one of the
- traversal functions (next(), previous(), findNext(), findPrevious()).
-
- Example:
- \snippet code/doc_src_qiterator.cpp 20
-
- \sa insert(), setValue()
-*/
-
-/*! \fn template <class T> void QMutableVectorIterator<T>::remove()
-
- Removes the last item that was jumped over using one of the
- traversal functions (next(), previous(), findNext(), findPrevious()).
-
- Example:
- \snippet code/doc_src_qiterator.cpp 21
-
- \sa insert(), setValue()
-*/
-
/*! \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
@@ -918,38 +653,7 @@
\sa value(), remove(), insert()
*/
-/*! \fn template <class T> void QMutableLinkedListIterator<T>::setValue(const T &value) const
-
- Replaces the value of the last item that was jumped over using
- one of the traversal functions with \a value.
-
- The traversal functions are next(), previous(), findNext(), and
- findPrevious().
-
- Example:
- \snippet code/doc_src_qiterator.cpp 24
-
- \sa value(), remove(), insert()
-*/
-
-/*! \fn template <class T> void QMutableVectorIterator<T>::setValue(const T &value) const
-
- Replaces the value of the last item that was jumped over using
- one of the traversal functions with \a value.
-
- The traversal functions are next(), previous(), findNext(), and
- findPrevious().
-
- Example:
- \snippet code/doc_src_qiterator.cpp 25
-
- \sa value(), remove(), insert()
-*/
-
/*! \fn template <class T> const T &QMutableListIterator<T>::value() const
- \fn template <class T> const T &QMutableLinkedListIterator<T>::value() const
- \fn template <class T> const T &QMutableVectorIterator<T>::value() const
- \fn template <class T> const T &QMutableSetIterator<T>::value() const
Returns the value of the last item that was jumped over using one
of the traversal functions (next(), previous(), findNext(),
@@ -960,10 +664,14 @@
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()
- \fn template <class T> T &QMutableLinkedListIterator<T>::value()
- \fn template <class T> T &QMutableVectorIterator<T>::value()
\overload
Returns a non-const reference to the value of the last item that
@@ -971,8 +679,6 @@
*/
/*! \fn template <class T> void QMutableListIterator<T>::insert(const T &value)
- \fn template <class T> void QMutableLinkedListIterator<T>::insert(const T &value)
- \fn template <class T> void QMutableVectorIterator<T>::insert(const T &value)
Inserts \a value at the current iterator position. After the
call, the iterator is located just after the inserted item.
@@ -984,15 +690,14 @@
\class QMapIterator
\inmodule QtCore
- \brief The QMapIterator class provides a Java-style const iterator for QMap and QMultiMap.
+ \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 (or a
- QMultiMap). If you want to modify the map as you iterate over
+ QMapIterator\<Key, T\> allows you to iterate over a QMap.
+ If you want to modify the map as you iterate over
it, use QMutableMapIterator instead.
The QMapIterator constructor takes a QMap as argument. After
@@ -1033,15 +738,64 @@
*/
/*!
+ \class QMultiMapIterator
+ \inmodule QtCore
+
+ \brief The QMultiMapIterator class provides a Java-style const iterator for QMultiMap.
+ QMultiMap has both \l{Java-style iterators} and \l{STL-style
+ 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
+ it, use QMutableMultiMapIterator instead.
+
+ The QMultiMapIterator constructor takes a QMultiMap as argument. After
+ construction, the iterator is located at the very beginning of
+ the map (before the first item). Here's how to iterate over all
+ the elements sequentially:
+
+ \snippet code/doc_src_qiterator.cpp 26multi
+
+ The next() function returns the next item in the map and
+ advances the iterator. The key() and value() functions return the
+ key and value of the last item that was jumped over.
+
+ Unlike STL-style iterators, Java-style iterators point \e between
+ items rather than directly \e at items. The first call to next()
+ advances the iterator to the position between the first and
+ second item, and returns the first item; the second call to
+ next() advances the iterator to the position between the second
+ and third item; and so on.
+
+ \image javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet code/doc_src_qiterator.cpp 27multi
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop. For example:
+
+ \snippet code/doc_src_qiterator.cpp 28multi
+
+ Multiple iterators can be used on the same map. If the map is
+ modified while a QMultiMapIterator is active, the QMultiMapIterator will
+ continue iterating over the original map, ignoring the modified
+ copy.
+
+ \sa QMutableMultiMapIterator
+*/
+
+/*!
\class QHashIterator
\inmodule QtCore
\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
@@ -1067,12 +821,8 @@
\image javaiterators1.png
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 30
-
If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop. For example:
+ findNext() in a loop. For example:
\snippet code/doc_src_qiterator.cpp 31
@@ -1088,15 +838,14 @@
\class QMutableMapIterator
\inmodule QtCore
- \brief The QMutableMapIterator class provides a Java-style non-const iterator for QMap and QMultiMap.
+ \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
- (or a QMultiMap) and modify the map. If you don't want to modify
+ and modify the map. If you don't want to modify
the map (or have a const QMap), use the slightly faster
QMapIterator instead.
@@ -1150,20 +899,82 @@
*/
/*!
+ \class QMutableMultiMapIterator
+ \inmodule QtCore
+
+ \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}. 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
+ the map (or have a const QMultiMap), use the slightly faster
+ QMultiMapIterator instead.
+
+ The QMutableMultiMapIterator constructor takes a QMultiMap as argument.
+ After construction, the iterator is located at the very beginning
+ of the map (before the first item). Here's how to iterate over
+ all the elements sequentially:
+
+ \snippet code/doc_src_qiterator.cpp 32multi
+
+ The next() function returns the next item in the map and
+ advances the iterator. The key() and value() functions return the
+ key and value of the last item that was jumped over.
+
+ Unlike STL-style iterators, Java-style iterators point \e between
+ items rather than directly \e at items. The first call to next()
+ advances the iterator to the position between the first and
+ second item, and returns the first item; the second call to
+ next() advances the iterator to the position between the second
+ and third item; and so on.
+
+ \image javaiterators1.png
+
+ Here's how to iterate over the elements in reverse order:
+
+ \snippet code/doc_src_qiterator.cpp 33multi
+
+ If you want to find all occurrences of a particular value, use
+ findNext() or findPrevious() in a loop. For example:
+
+ \snippet code/doc_src_qiterator.cpp 34multi
+
+ If you want to remove items as you iterate over the map, use
+ remove(). If you want to modify the value of an item, use
+ setValue().
+
+ Example:
+
+ \snippet code/doc_src_qiterator.cpp 35multi
+
+ The example removes all (key, value) pairs where the key and the
+ value are the same.
+
+ Only one mutable iterator can be active on a given map at any
+ time. Furthermore, no changes should be done directly to the map
+ while the iterator is active (as opposed to through the
+ iterator), since this could invalidate the iterator and lead to
+ undefined behavior.
+
+ \sa QMultiMapIterator, QMultiMap::iterator
+*/
+
+/*!
\class QMutableHashIterator
\inmodule QtCore
\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
@@ -1185,12 +996,8 @@
\image javaiterators1.png
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 37
-
If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop. For example:
+ findNext() in a loop. For example:
\snippet code/doc_src_qiterator.cpp 38
@@ -1216,6 +1023,8 @@
/*! \fn template <class Key, class T> QMapIterator<Key, T>::QMapIterator(const QMap<Key, T> &map)
\fn template <class Key, class T> QMutableMapIterator<Key, T>::QMutableMapIterator(QMap<Key, T> &map)
+ \fn template <class Key, class T> QMultiMapIterator<Key, T>::QMultiMapIterator(const QMultiMap<Key, T> &map)
+ \fn template <class Key, class T> QMutableMultiMapIterator<Key, T>::QMutableMultiMapIterator(QMultiMap<Key, T> &map)
Constructs an iterator for traversing \a map. The iterator is set
to be at the front of the map (before the first item).
@@ -1234,6 +1043,8 @@
/*! \fn template <class Key, class T> QMapIterator &QMapIterator<Key, T>::operator=(const QMap<Key, T> &map)
\fn template <class Key, class T> QMutableMapIterator &QMutableMapIterator<Key, T>::operator=(QMap<Key, T> &map)
+ \fn template <class Key, class T> QMultiMapIterator &QMultiMapIterator<Key, T>::operator=(const QMultiMap<Key, T> &map)
+ \fn template <class Key, class T> QMutableMultiMapIterator &QMutableMultiMapIterator<Key, T>::operator=(QMultiMap<Key, T> &map)
Makes the iterator operate on \a map. The iterator is set to be
at the front of the map (before the first item).
@@ -1251,8 +1062,10 @@
*/
/*! \fn template <class Key, class T> void QMapIterator<Key, T>::toFront()
+ \fn template <class Key, class T> void QMultiMapIterator<Key, T>::toFront()
\fn template <class Key, class T> void QHashIterator<Key, T>::toFront()
\fn template <class Key, class T> void QMutableMapIterator<Key, T>::toFront()
+ \fn template <class Key, class T> void QMutableMultiMapIterator<Key, T>::toFront()
\fn template <class Key, class T> void QMutableHashIterator<Key, T>::toFront()
Moves the iterator to the front of the container (before the
@@ -1262,9 +1075,9 @@
*/
/*! \fn template <class Key, class T> void QMapIterator<Key, T>::toBack()
- \fn template <class Key, class T> void QHashIterator<Key, T>::toBack()
+ \fn template <class Key, class T> void QMultiMapIterator<Key, T>::toBack()
\fn template <class Key, class T> void QMutableMapIterator<Key, T>::toBack()
- \fn template <class Key, class T> void QMutableHashIterator<Key, T>::toBack()
+ \fn template <class Key, class T> void QMutableMultiMapIterator<Key, T>::toBack()
Moves the iterator to the back of the container (after the last
item).
@@ -1272,10 +1085,20 @@
\sa toFront(), previous()
*/
+/*!
+ \fn template <class Key, class T> void QHashIterator<Key, T>::toBack()
+ \fn template <class Key, class T> void QMutableHashIterator<Key, T>::toBack()
+
+ Moves the iterator to the back of the container (after the last
+ item).
+
+ \sa toFront()
+*/
+
/*! \fn template <class Key, class T> bool QMapIterator<Key, T>::hasNext() const
- \fn template <class Key, class T> bool QHashIterator<Key, T>::hasNext() const
+ \fn template <class Key, class T> bool QMultiMapIterator<Key, T>::hasNext() const
\fn template <class Key, class T> bool QMutableMapIterator<Key, T>::hasNext() const
- \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::hasNext() const
+ \fn template <class Key, class T> bool QMutableMultiMapIterator<Key, 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;
@@ -1284,8 +1107,19 @@
\sa hasPrevious(), next()
*/
+/*!
+ \fn template <class Key, class T> bool QHashIterator<Key, T>::hasNext() const
+ \fn template <class Key, class T> bool QMutableHashIterator<Key, 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 Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::next()
- \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::next()
+ \fn template <class Key, class T> QMultiMapIterator<Key, T>::Item QMultiMapIterator<Key, T>::next()
Returns the next item and advances the iterator by one position.
@@ -1295,11 +1129,11 @@
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()
- \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::next()
+ \fn template <class Key, class T> QMutableMultiMapIterator<Key, T>::Item QMutableMultiMapIterator<Key, T>::next()
Returns the next item and advances the iterator by one position.
@@ -1312,8 +1146,36 @@
\sa hasNext(), peekNext(), previous()
*/
+/*!
+ \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::next()
+
+ Returns the next item and advances the iterator 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 back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext()
+*/
+
+/*!
+ \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::next()
+
+ Returns the next item and advances the iterator 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 back of the
+ container leads to undefined results.
+
+ \sa hasNext(), peekNext()
+*/
+
/*! \fn template <class Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::peekNext() const
- \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::peekNext() const
+ \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekNext() const
Returns the next item without moving the iterator.
@@ -1327,7 +1189,7 @@
*/
/*! \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekNext() const
- \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::peekNext() const
+ \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.
@@ -1340,52 +1202,53 @@
\sa hasNext(), next(), peekPrevious()
*/
-/*! \fn template <class Key, class T> bool QMapIterator<Key, T>::hasPrevious() const
- \fn template <class Key, class T> bool QHashIterator<Key, T>::hasPrevious() const
- \fn template <class Key, class T> bool QMutableMapIterator<Key, T>::hasPrevious() const
- \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::hasPrevious() 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.
-
- \sa hasNext(), previous()
-*/
-
-/*! \fn template <class Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::previous()
- \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::previous()
+/*!
+ \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::peekNext() const
- Returns the previous item and moves the iterator back by one
- position.
+ Returns the next 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
+ Calling this function on an iterator located at the back of the
container leads to undefined results.
- \sa hasPrevious(), peekPrevious(), next()
+ \sa hasNext(), next()
*/
-/*! \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::previous()
- \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::previous()
+/*!
+ \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::peekNext() const
- Returns the previous item and moves the iterator back by one
- position.
+ Returns a reference to the next 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
+ Calling this function on an iterator located at the back of the
container leads to undefined results.
- \sa hasPrevious(), peekPrevious(), next()
+ \sa hasNext(), next()
*/
-/*! \fn template <class Key, class T> QMapIterator<Key, T>::Item QMapIterator<Key, T>::peekPrevious() const
- \fn template <class Key, class T> QHashIterator<Key, T>::Item QHashIterator<Key, T>::peekPrevious() const
+/*! \fn template <class Key, class T> bool QMapIterator<Key, T>::hasPrevious() const
+ \fn template <class Key, class T> bool QMultiMapIterator<Key, T>::hasPrevious() const
+ \fn template <class Key, class T> bool QMutableMapIterator<Key, T>::hasPrevious() const
+ \fn template <class Key, class T> bool QMutableMultiMapIterator<Key, T>::hasPrevious() const
- Returns the previous item without moving the iterator.
+ 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()
+ \fn template <class Key, class T> QMutableMultiMapIterator<Key, T>::Item QMutableMultiMapIterator<Key, T>::previous()
+
+ 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.
@@ -1393,11 +1256,13 @@
Calling this function on an iterator located at the front of the
container leads to undefined results.
- \sa hasPrevious(), previous(), peekNext()
+ \sa hasPrevious(), peekPrevious(), next()
*/
-/*! \fn template <class Key, class T> QMutableMapIterator<Key, T>::Item QMutableMapIterator<Key, T>::peekPrevious() const
- \fn template <class Key, class T> QMutableHashIterator<Key, T>::Item QMutableHashIterator<Key, T>::peekPrevious() const
+/*! \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
+ \fn template <class Key, class T> QMutableMultiMapIterator<Key, T>::Item QMutableMultiMapIterator<Key, T>::peekPrevious() const
Returns the previous item without moving the iterator.
@@ -1407,11 +1272,11 @@
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
- \fn template <class Key, class T> const T &QHashIterator<Key, T>::value() const
+ \fn template <class Key, class T> const T &QMultiMapIterator<Key, T>::value() const
Returns the value of the last item that was jumped over using one
of the traversal functions (next(), previous(), findNext(),
@@ -1426,7 +1291,7 @@
/*!
\fn template <class Key, class T> const T &QMutableMapIterator<Key, T>::value() const
- \fn template <class Key, class T> const T &QMutableHashIterator<Key, T>::value() const
+ \fn template <class Key, class T> const T &QMutableMultiMapIterator<Key, T>::value() const
Returns the value of the last item that was jumped over using one
of the traversal functions (next(), previous(), findNext(),
@@ -1439,8 +1304,26 @@
\sa key(), setValue()
*/
+/*! \fn template <class Key, class T> const T &QHashIterator<Key, T>::value() const
+
+ Returns the value of the last item that was jumped over using one
+ of the traversal functions (next(), findNext()).
+
+ \sa key()
+*/
+
+/*!
+ \fn template <class Key, class T> const T &QMutableHashIterator<Key, T>::value() const
+
+ Returns the value of the last item that was jumped over using one
+ of the traversal functions (next(), findNext()).
+
+ \sa key(), setValue()
+*/
+
/*!
\fn template <class Key, class T> T &QMutableMapIterator<Key, T>::value()
+ \fn template <class Key, class T> T &QMutableMultiMapIterator<Key, T>::value()
\fn template <class Key, class T> T &QMutableHashIterator<Key, T>::value()
\overload
@@ -1450,9 +1333,9 @@
*/
/*! \fn template <class Key, class T> const Key &QMapIterator<Key, T>::key() const
- \fn template <class Key, class T> const Key &QHashIterator<Key, T>::key() const
\fn template <class Key, class T> const Key &QMutableMapIterator<Key, T>::key() const
- \fn template <class Key, class T> const Key &QMutableHashIterator<Key, T>::key() const
+ \fn template <class Key, class T> const Key &QMultiMapIterator<Key, T>::key() const
+ \fn template <class Key, class T> const Key &QMutableMultiMapIterator<Key, T>::key() const
Returns the key of the last item that was jumped over using one
of the traversal functions (next(), previous(), findNext(),
@@ -1465,10 +1348,19 @@
\sa value()
*/
+/*! \fn template <class Key, class T> const Key &QHashIterator<Key, T>::key() const
+ \fn template <class Key, class T> const Key &QMutableHashIterator<Key, T>::key() const
+
+ Returns the key of the last item that was jumped over using one
+ of the traversal functions (next(), findNext()).
+
+ \sa value()
+*/
+
/*! \fn template <class Key, class T> bool QMapIterator<Key, T>::findNext(const T &value)
- \fn template <class Key, class T> bool QHashIterator<Key, T>::findNext(const T &value)
\fn template <class Key, class T> bool QMutableMapIterator<Key, T>::findNext(const T &value)
- \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::findNext(const T &value)
+ \fn template <class Key, class T> bool QMultiMapIterator<Key, T>::findNext(const T &value)
+ \fn template <class Key, class T> bool QMutableMultiMapIterator<Key, T>::findNext(const T &value)
Searches for \a value starting from the current iterator position
forward. Returns \c true if a (key, value) pair with value \a value
@@ -1481,10 +1373,22 @@
\sa findPrevious()
*/
+/*! \fn template <class Key, class T> bool QHashIterator<Key, T>::findNext(const T &value)
+ \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::findNext(const T &value)
+
+ Searches for \a value starting from the current iterator position
+ forward. 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 after the matching item; otherwise, the iterator is
+ positioned at the back of the container.
+*/
+
/*! \fn template <class Key, class T> bool QMapIterator<Key, T>::findPrevious(const T &value)
- \fn template <class Key, class T> bool QHashIterator<Key, T>::findPrevious(const T &value)
\fn template <class Key, class T> bool QMutableMapIterator<Key, T>::findPrevious(const T &value)
- \fn template <class Key, class T> bool QMutableHashIterator<Key, T>::findPrevious(const T &value)
+ \fn template <class Key, class T> bool QMultiMapIterator<Key, T>::findPrevious(const T &value)
+ \fn template <class Key, class T> bool QMutableMultiMapIterator<Key, T>::findPrevious(const T &value)
Searches for \a value starting from the current iterator position
backward. Returns \c true if a (key, value) pair with value \a value
@@ -1498,7 +1402,7 @@
*/
/*! \fn template <class Key, class T> void QMutableMapIterator<Key, T>::remove()
- \fn template <class Key, class T> void QMutableHashIterator<Key, T>::remove()
+ \fn template <class Key, class T> void QMutableMultiMapIterator<Key, T>::remove()
Removes the last item that was jumped over using one of the
traversal functions (next(), previous(), findNext(), findPrevious()).
@@ -1506,8 +1410,16 @@
\sa setValue()
*/
+/*! \fn template <class Key, class T> void QMutableHashIterator<Key, T>::remove()
+
+ Removes the last item that was jumped over using one of the
+ traversal functions (next(), findNext()).
+
+ \sa setValue()
+*/
+
/*! \fn template <class Key, class T> void QMutableMapIterator<Key, T>::setValue(const T &value)
- \fn template <class Key, class T> void QMutableHashIterator<Key, T>::setValue(const T &value)
+ \fn template <class Key, class T> void QMutableMultiMapIterator<Key, T>::setValue(const T &value)
Replaces the value of the last item that was jumped over using
one of the traversal functions with \a value.
@@ -1517,3 +1429,14 @@
\sa key(), value(), remove()
*/
+
+/*!
+ \fn template <class Key, class T> void QMutableHashIterator<Key, T>::setValue(const T &value)
+
+ Replaces the value of the last item that was jumped over using
+ one of the traversal functions with \a value.
+
+ The traversal functions are next() and findNext().
+
+ \sa key(), value(), remove()
+*/
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index 3afd23d76b..9216b8875b 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** 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 "qline.h"
+
#include "qdebug.h"
#include "qdatastream.h"
#include "qmath.h"
@@ -99,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.
*/
@@ -262,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
@@ -310,11 +284,6 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
#endif // QT_NO_DATASTREAM
-
-#ifndef M_2PI
-#define M_2PI 6.28318530717958647692528676655900576
-#endif
-
/*!
\class QLineF
\inmodule QtCore
@@ -326,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
@@ -369,8 +338,8 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
*/
/*!
- \enum QLineF::IntersectType
- \obsolete Use QLineF::IntersectionType instead
+ \typealias QLineF::IntersectType
+ \deprecated Use QLineF::IntersectionType instead.
*/
/*!
@@ -399,7 +368,7 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
\value BoundedIntersection The two lines intersect with each other
within the start and end points of each line.
- \sa intersect()
+ \sa intersects()
*/
/*!
@@ -427,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()
*/
/*!
@@ -456,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
@@ -514,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()
*/
/*!
@@ -555,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()
*/
@@ -565,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());
}
/*!
@@ -590,7 +560,7 @@ qreal QLineF::angle() const
const qreal dx = pt2.x() - pt1.x();
const qreal dy = pt2.y() - pt1.y();
- const qreal theta = qAtan2(-dy, dx) * 360.0 / M_2PI;
+ const qreal theta = qRadiansToDegrees(qAtan2(-dy, dx));
const qreal theta_normalized = theta < 0 ? theta + 360 : theta;
@@ -614,7 +584,7 @@ qreal QLineF::angle() const
*/
void QLineF::setAngle(qreal angle)
{
- const qreal angleR = angle * M_2PI / 360.0;
+ const qreal angleR = qDegreesToRadians(angle);
const qreal l = length();
const qreal dx = qCos(angleR) * l;
@@ -636,23 +606,24 @@ void QLineF::setAngle(qreal angle)
*/
QLineF QLineF::fromPolar(qreal length, qreal angle)
{
- const qreal angleR = angle * M_2PI / 360.0;
+ const qreal angleR = qDegreesToRadians(angle);
return QLineF(0, 0, qCos(angleR) * length, -qSin(angleR) * length);
}
/*!
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)
@@ -662,25 +633,6 @@ QLineF QLineF::unitVector() const
return f;
}
-#if QT_DEPRECATED_SINCE(5, 14)
-/*!
- \fn QLineF::IntersectType QLineF::intersect(const QLineF &line, QPointF *intersectionPoint) const
- \obsolete Use intersects() instead
-
- Returns a value indicating whether or not \e this line intersects
- with the given \a line.
-
- The actual intersection point is extracted to \a intersectionPoint
- (if the pointer is valid). If the lines are parallel, the
- intersection point is undefined.
-*/
-
-QLineF::IntersectType QLineF::intersect(const QLineF &l, QPointF *intersectionPoint) const
-{
- return intersects(l, intersectionPoint);
-}
-#endif
-
/*!
\fn QLineF::IntersectionType QLineF::intersects(const QLineF &line, QPointF *intersectionPoint) const
\since 5.14
@@ -802,15 +754,15 @@ QLineF::IntersectionType QLineF::intersects(const QLineF &l, QPointF *intersecti
Returns the angle (in degrees) from this line to the given \a
line, taking the direction of the lines into account. If the lines
- do not intersect within their range, it is the intersection point of
- the extended lines that serves as origin (see
+ do not \l{intersects()}{intersect} within their range, it is the
+ intersection point of the extended lines that serves as origin (see
QLineF::UnboundedIntersection).
The returned value represents the number of degrees you need to add
to this line to make it have the same angle as the given \a line,
going counter-clockwise.
- \sa intersect()
+ \sa intersects()
*/
qreal QLineF::angleTo(const QLineF &l) const
{
@@ -829,42 +781,6 @@ qreal QLineF::angleTo(const QLineF &l) const
return delta_normalized;
}
-#if QT_DEPRECATED_SINCE(5, 14)
-/*!
- \fn qreal QLineF::angle(const QLineF &line) const
-
- \obsolete
-
- Returns the angle (in degrees) between this line and the given \a
- line, taking the direction of the lines into account. If the lines
- do not intersect within their range, it is the intersection point of
- the extended lines that serves as origin (see
- QLineF::UnboundedIntersection).
-
- \table
- \row
- \li \inlineimage qlinef-angle-identicaldirection.png
- \li \inlineimage qlinef-angle-oppositedirection.png
- \endtable
-
- When the lines are parallel, this function returns 0 if they have
- the same direction; otherwise it returns 180.
-
- \sa intersect()
-*/
-qreal QLineF::angle(const QLineF &l) const
-{
- if (isNull() || l.isNull())
- return 0;
- qreal cos_line = (dx()*l.dx() + dy()*l.dy()) / (length()*l.length());
- qreal rad = 0;
- // only accept cos_line in the range [-1,1], if it is outside, use 0 (we return 0 rather than PI for those cases)
- if (cos_line >= -1.0 && cos_line <= 1.0) rad = qAcos( cos_line );
- return rad * 360 / M_2PI;
-}
-#endif
-
-
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QLineF &p)
{
diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h
index c96d624afd..e23ffbe9d5 100644
--- a/src/corelib/tools/qline.h
+++ b/src/corelib/tools/qline.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 QLINE_H
#define QLINE_H
@@ -44,6 +8,7 @@
QT_BEGIN_NAMESPACE
+class QLineF;
/*******************************************************************************
* class QLine
@@ -52,96 +17,98 @@ QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QLine
{
public:
- Q_DECL_CONSTEXPR inline QLine();
- Q_DECL_CONSTEXPR inline QLine(const QPoint &pt1, const QPoint &pt2);
- Q_DECL_CONSTEXPR inline QLine(int x1, int y1, int x2, int y2);
+ constexpr inline QLine();
+ constexpr inline QLine(const QPoint &pt1, const QPoint &pt2);
+ constexpr inline QLine(int x1, int y1, int x2, int y2);
- Q_DECL_CONSTEXPR inline bool isNull() const;
+ constexpr inline bool isNull() const;
- Q_DECL_CONSTEXPR inline QPoint p1() const;
- Q_DECL_CONSTEXPR inline QPoint p2() const;
+ constexpr inline QPoint p1() const;
+ constexpr inline QPoint p2() const;
- Q_DECL_CONSTEXPR inline int x1() const;
- Q_DECL_CONSTEXPR inline int y1() const;
+ constexpr inline int x1() const;
+ constexpr inline int y1() const;
- Q_DECL_CONSTEXPR inline int x2() const;
- Q_DECL_CONSTEXPR inline int y2() const;
+ constexpr inline int x2() const;
+ constexpr inline int y2() const;
- Q_DECL_CONSTEXPR inline int dx() const;
- Q_DECL_CONSTEXPR inline int dy() const;
+ constexpr inline int dx() const;
+ constexpr inline int dy() const;
inline void translate(const QPoint &p);
inline void translate(int dx, int dy);
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QLine translated(const QPoint &p) const;
- Q_REQUIRED_RESULT Q_DECL_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 Q_DECL_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);
- Q_DECL_CONSTEXPR inline bool operator==(const QLine &d) const;
- Q_DECL_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
*******************************************************************************/
-Q_DECL_CONSTEXPR inline QLine::QLine() { }
+constexpr inline QLine::QLine() { }
-Q_DECL_CONSTEXPR inline QLine::QLine(const QPoint &pt1_, const QPoint &pt2_) : pt1(pt1_), pt2(pt2_) { }
+constexpr inline QLine::QLine(const QPoint &pt1_, const QPoint &pt2_) : pt1(pt1_), pt2(pt2_) { }
-Q_DECL_CONSTEXPR inline QLine::QLine(int x1pos, int y1pos, int x2pos, int y2pos) : pt1(QPoint(x1pos, y1pos)), pt2(QPoint(x2pos, y2pos)) { }
+constexpr inline QLine::QLine(int x1pos, int y1pos, int x2pos, int y2pos) : pt1(QPoint(x1pos, y1pos)), pt2(QPoint(x2pos, y2pos)) { }
-Q_DECL_CONSTEXPR inline bool QLine::isNull() const
+constexpr inline bool QLine::isNull() const
{
return pt1 == pt2;
}
-Q_DECL_CONSTEXPR inline int QLine::x1() const
+constexpr inline int QLine::x1() const
{
return pt1.x();
}
-Q_DECL_CONSTEXPR inline int QLine::y1() const
+constexpr inline int QLine::y1() const
{
return pt1.y();
}
-Q_DECL_CONSTEXPR inline int QLine::x2() const
+constexpr inline int QLine::x2() const
{
return pt2.x();
}
-Q_DECL_CONSTEXPR inline int QLine::y2() const
+constexpr inline int QLine::y2() const
{
return pt2.y();
}
-Q_DECL_CONSTEXPR inline QPoint QLine::p1() const
+constexpr inline QPoint QLine::p1() const
{
return pt1;
}
-Q_DECL_CONSTEXPR inline QPoint QLine::p2() const
+constexpr inline QPoint QLine::p2() const
{
return pt2;
}
-Q_DECL_CONSTEXPR inline int QLine::dx() const
+constexpr inline int QLine::dx() const
{
return pt2.x() - pt1.x();
}
-Q_DECL_CONSTEXPR inline int QLine::dy() const
+constexpr inline int QLine::dy() const
{
return pt2.y() - pt1.y();
}
@@ -157,17 +124,17 @@ inline void QLine::translate(int adx, int ady)
this->translate(QPoint(adx, ady));
}
-Q_DECL_CONSTEXPR inline QLine QLine::translated(const QPoint &p) const
+constexpr inline QLine QLine::translated(const QPoint &p) const
{
return QLine(pt1 + p, pt2 + p);
}
-Q_DECL_CONSTEXPR inline QLine QLine::translated(int adx, int ady) const
+constexpr inline QLine QLine::translated(int adx, int ady) const
{
return translated(QPoint(adx, ady));
}
-Q_DECL_CONSTEXPR inline QPoint QLine::center() const
+constexpr inline QPoint QLine::center() const
{
return QPoint(int((qint64(pt1.x()) + pt2.x()) / 2), int((qint64(pt1.y()) + pt2.y()) / 2));
}
@@ -194,7 +161,7 @@ inline void QLine::setLine(int aX1, int aY1, int aX2, int aY2)
pt2 = QPoint(aX2, aY2);
}
-Q_DECL_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;
}
@@ -211,32 +178,33 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QLine &);
/*******************************************************************************
* class QLineF
*******************************************************************************/
-class Q_CORE_EXPORT QLineF {
+class Q_CORE_EXPORT QLineF
+{
public:
- enum IntersectType { NoIntersection, BoundedIntersection, UnboundedIntersection };
- using IntersectionType = IntersectType;
+ enum IntersectionType { NoIntersection, BoundedIntersection, UnboundedIntersection };
+ using IntersectType = IntersectionType; // deprecated name
- Q_DECL_CONSTEXPR inline QLineF();
- Q_DECL_CONSTEXPR inline QLineF(const QPointF &pt1, const QPointF &pt2);
- Q_DECL_CONSTEXPR inline QLineF(qreal x1, qreal y1, qreal x2, qreal y2);
- Q_DECL_CONSTEXPR inline QLineF(const QLine &line) : pt1(line.p1()), pt2(line.p2()) { }
+ constexpr inline QLineF();
+ constexpr inline QLineF(const QPointF &pt1, const QPointF &pt2);
+ 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);
- Q_DECL_CONSTEXPR bool isNull() const;
+ constexpr bool isNull() const;
- Q_DECL_CONSTEXPR inline QPointF p1() const;
- Q_DECL_CONSTEXPR inline QPointF p2() const;
+ constexpr inline QPointF p1() const;
+ constexpr inline QPointF p2() const;
- Q_DECL_CONSTEXPR inline qreal x1() const;
- Q_DECL_CONSTEXPR inline qreal y1() const;
+ constexpr inline qreal x1() const;
+ constexpr inline qreal y1() const;
- Q_DECL_CONSTEXPR inline qreal x2() const;
- Q_DECL_CONSTEXPR inline qreal y2() const;
+ constexpr inline qreal x2() const;
+ constexpr inline qreal y2() const;
- Q_DECL_CONSTEXPR inline qreal dx() const;
- Q_DECL_CONSTEXPR inline qreal dy() const;
+ constexpr inline qreal dx() const;
+ constexpr inline qreal dy() const;
qreal length() const;
void setLength(qreal len);
@@ -246,106 +214,99 @@ public:
qreal angleTo(const QLineF &l) const;
- Q_REQUIRED_RESULT QLineF unitVector() const;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QLineF normalVector() const;
+ [[nodiscard]] QLineF unitVector() const;
+ [[nodiscard]] constexpr inline QLineF normalVector() const;
- IntersectionType intersects(const QLineF &l, QPointF *intersectionPoint) const;
+ IntersectionType intersects(const QLineF &l, QPointF *intersectionPoint = nullptr) const;
-#if QT_DEPRECATED_SINCE(5, 14)
- QT_DEPRECATED_VERSION_X(5, 14, "Use intersects() instead")
- IntersectType intersect(const QLineF &l, QPointF *intersectionPoint) const;
- QT_DEPRECATED_X("Use angleTo() instead, take care that the return value is between 0 and 360 degree.")
- qreal angle(const QLineF &l) const;
-#endif
-
- Q_DECL_CONSTEXPR inline QPointF pointAt(qreal t) const;
+ constexpr inline QPointF pointAt(qreal t) const;
inline void translate(const QPointF &p);
inline void translate(qreal dx, qreal dy);
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QLineF translated(const QPointF &p) const;
- Q_REQUIRED_RESULT Q_DECL_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 Q_DECL_CONSTEXPR inline QPointF center() const;
+ [[nodiscard]] constexpr inline QPointF center() const;
inline void setP1(const QPointF &p1);
inline void setP2(const QPointF &p2);
inline void setPoints(const QPointF &p1, const QPointF &p2);
inline void setLine(qreal x1, qreal y1, qreal x2, qreal y2);
- Q_DECL_CONSTEXPR inline bool operator==(const QLineF &d) const;
- Q_DECL_CONSTEXPR inline bool operator!=(const QLineF &d) const { return !(*this == d); }
+ constexpr inline bool operator==(const QLineF &d) const;
+ constexpr inline bool operator!=(const QLineF &d) const { return !(*this == d); }
- Q_DECL_CONSTEXPR QLine toLine() const;
+ constexpr QLine toLine() const;
private:
QPointF pt1, pt2;
};
-Q_DECLARE_TYPEINFO(QLineF, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QLineF, Q_PRIMITIVE_TYPE);
/*******************************************************************************
* class QLineF inline members
*******************************************************************************/
-Q_DECL_CONSTEXPR inline QLineF::QLineF()
+constexpr inline QLineF::QLineF()
{
}
-Q_DECL_CONSTEXPR inline QLineF::QLineF(const QPointF &apt1, const QPointF &apt2)
+constexpr inline QLineF::QLineF(const QPointF &apt1, const QPointF &apt2)
: pt1(apt1), pt2(apt2)
{
}
-Q_DECL_CONSTEXPR inline QLineF::QLineF(qreal x1pos, qreal y1pos, qreal x2pos, qreal y2pos)
+constexpr inline QLineF::QLineF(qreal x1pos, qreal y1pos, qreal x2pos, qreal y2pos)
: pt1(x1pos, y1pos), pt2(x2pos, y2pos)
{
}
-Q_DECL_CONSTEXPR inline qreal QLineF::x1() const
+constexpr inline qreal QLineF::x1() const
{
return pt1.x();
}
-Q_DECL_CONSTEXPR inline qreal QLineF::y1() const
+constexpr inline qreal QLineF::y1() const
{
return pt1.y();
}
-Q_DECL_CONSTEXPR inline qreal QLineF::x2() const
+constexpr inline qreal QLineF::x2() const
{
return pt2.x();
}
-Q_DECL_CONSTEXPR inline qreal QLineF::y2() const
+constexpr inline qreal QLineF::y2() const
{
return pt2.y();
}
-Q_DECL_CONSTEXPR inline bool QLineF::isNull() const
+constexpr inline bool QLineF::isNull() const
{
return qFuzzyCompare(pt1.x(), pt2.x()) && qFuzzyCompare(pt1.y(), pt2.y());
}
-Q_DECL_CONSTEXPR inline QPointF QLineF::p1() const
+constexpr inline QPointF QLineF::p1() const
{
return pt1;
}
-Q_DECL_CONSTEXPR inline QPointF QLineF::p2() const
+constexpr inline QPointF QLineF::p2() const
{
return pt2;
}
-Q_DECL_CONSTEXPR inline qreal QLineF::dx() const
+constexpr inline qreal QLineF::dx() const
{
return pt2.x() - pt1.x();
}
-Q_DECL_CONSTEXPR inline qreal QLineF::dy() const
+constexpr inline qreal QLineF::dy() const
{
return pt2.y() - pt1.y();
}
-Q_DECL_CONSTEXPR inline QLineF QLineF::normalVector() const
+constexpr inline QLineF QLineF::normalVector() const
{
return QLineF(p1(), p1() + QPointF(dy(), -dx()));
}
@@ -361,35 +322,40 @@ inline void QLineF::translate(qreal adx, qreal ady)
this->translate(QPointF(adx, ady));
}
-Q_DECL_CONSTEXPR inline QLineF QLineF::translated(const QPointF &p) const
+constexpr inline QLineF QLineF::translated(const QPointF &p) const
{
return QLineF(pt1 + p, pt2 + p);
}
-Q_DECL_CONSTEXPR inline QLineF QLineF::translated(qreal adx, qreal ady) const
+constexpr inline QLineF QLineF::translated(qreal adx, qreal ady) const
{
return translated(QPointF(adx, ady));
}
-Q_DECL_CONSTEXPR inline QPointF QLineF::center() const
+constexpr inline QPointF QLineF::center() const
{
return QPointF(0.5 * pt1.x() + 0.5 * pt2.x(), 0.5 * pt1.y() + 0.5 * pt2.y());
}
inline void QLineF::setLength(qreal len)
{
- if (isNull())
- return;
- QLineF v = unitVector();
- pt2 = QPointF(pt1.x() + v.dx() * len, pt1.y() + v.dy() * len);
+ 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));
}
-Q_DECL_CONSTEXPR inline QPointF QLineF::pointAt(qreal t) const
+constexpr inline QPointF QLineF::pointAt(qreal t) const
{
return QPointF(pt1.x() + (pt2.x() - pt1.x()) * t, pt1.y() + (pt2.y() - pt1.y()) * t);
}
-Q_DECL_CONSTEXPR inline QLine QLineF::toLine() const
+constexpr inline QLineF QLine::toLineF() const noexcept { return *this; }
+
+constexpr inline QLine QLineF::toLine() const
{
return QLine(pt1.toPoint(), pt2.toPoint());
}
@@ -418,7 +384,7 @@ inline void QLineF::setLine(qreal aX1, qreal aY1, qreal aX2, qreal aY2)
}
-Q_DECL_CONSTEXPR inline bool QLineF::operator==(const QLineF &d) const
+constexpr inline bool QLineF::operator==(const QLineF &d) const
{
return pt1 == d.pt1 && pt2 == d.pt2;
}
diff --git a/src/corelib/tools/qlinkedlist.cpp b/src/corelib/tools/qlinkedlist.cpp
deleted file mode 100644
index 3b1bc8aab1..0000000000
--- a/src/corelib/tools/qlinkedlist.cpp
+++ /dev/null
@@ -1,1224 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifdef QT_NO_LINKED_LIST
-# undef QT_NO_LINKED_LIST
-#endif
-
-#include "qlinkedlist.h"
-
-QT_BEGIN_NAMESPACE
-
-const QLinkedListData QLinkedListData::shared_null = {
- const_cast<QLinkedListData *>(&QLinkedListData::shared_null),
- const_cast<QLinkedListData *>(&QLinkedListData::shared_null),
- Q_REFCOUNT_INITIALIZE_STATIC, 0, true
-};
-
-/*! \class QLinkedList
- \inmodule QtCore
- \brief The QLinkedList class is a template class that provides linked lists.
-
- \ingroup tools
- \ingroup shared
-
- \reentrant
-
- QLinkedList\<T\> is one of Qt's generic \l{container classes}. It
- stores a list of values and provides iterator-based access as
- well as \l{constant time} insertions and removals.
-
- QList\<T\>, QLinkedList\<T\>, and QVector\<T\> provide similar
- functionality. Here's an overview:
-
- \list
- \li For most purposes, QList is the right class to use. Its
- index-based API is more convenient than QLinkedList's
- iterator-based API, and it is usually faster than
- QVector because of the way it stores its items in
- memory (see \l{Algorithmic Complexity} for details).
- It also expands to less code in your executable.
- \li If you need a real linked list, with guarantees of \l{constant
- time} insertions in the middle of the list and iterators to
- items rather than indexes, use QLinkedList.
- \li If you want the items to occupy adjacent memory positions,
- use QVector.
- \endlist
-
- Here's an example of a QLinkedList that stores integers and a
- QLinkedList that stores QTime values:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 0
-
- QLinkedList stores a list of items. The default constructor
- creates an empty list. To insert items into the list, you can use
- operator<<():
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 1
-
- If you want to get the first or last item in a linked list, use
- first() or last(). If you want to remove an item from either end
- of the list, use removeFirst() or removeLast(). If you want to
- remove all occurrences of a given value in the list, use
- removeAll().
-
- A common requirement is to remove the first or last item in the
- list and do something with it. For this, QLinkedList provides
- takeFirst() and takeLast(). Here's a loop that removes the items
- from a list one at a time and calls \c delete on them:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 2
-
- QLinkedList's value type must be an \l {assignable data type}. This
- covers most data types that are commonly used, but the compiler
- won't let you, for example, store a QWidget as a value; instead,
- store a QWidget *. A few functions have additional requirements;
- for example, contains() and removeAll() expect the value type to
- support \c operator==(). These requirements are documented on a
- per-function basis.
-
- If you want to insert, modify, or remove items in the middle of
- the list, you must use an iterator. QLinkedList provides both
- \l{Java-style iterators} (QLinkedListIterator and
- QMutableLinkedListIterator) and \l{STL-style iterators}
- (QLinkedList::const_iterator and QLinkedList::iterator). See the
- documentation for these classes for details.
-
- \sa QLinkedListIterator, QMutableLinkedListIterator, QList, QVector
-*/
-
-/*! \fn template <class T> QLinkedList<T>::QLinkedList()
-
- Constructs an empty list.
-*/
-
-/*!
- \fn template <class T> QLinkedList<T>::QLinkedList(QLinkedList<T> &&other)
-
- Move-constructs a QLinkedList instance, making it point at the same
- object that \a other was pointing to.
-
- \since 5.2
-*/
-
-/*! \fn template <class T> QLinkedList<T>::QLinkedList(const QLinkedList<T> &other)
-
- Constructs a copy of \a other.
-
- This operation occurs in \l{constant time}, because QLinkedList
- is \l{implicitly shared}. This makes returning a QLinkedList from
- a function very fast. If a shared instance is modified, it will
- be copied (copy-on-write), and this takes \l{linear time}.
-
- \sa operator=()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::QLinkedList(std::initializer_list<T> list)
- \since 5.2
-
- Constructs a list from the std::initializer_list specified by \a list.
-
- This constructor is only enabled if the compiler supports C++11
- initializer lists.
-*/
-
-/*! \fn template <class T> template<typename InputIterator> QLinkedList<T>::QLinkedList(InputIterator first, InputIterator last)
- \since 5.14
-
- Constructs a list with the contents in the iterator range [\a first, \a last).
-
- The value type of \c InputIterator must be convertible to \c T.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::~QLinkedList()
-
- Destroys the list. References to the values in the list, and all
- iterators over this list, become invalid.
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator=(const QLinkedList<T> &other)
-
- Assigns \a other to this list and returns a reference to this
- list.
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::swap(QLinkedList<T> &other)
- \since 4.8
-
- Swaps list \a other with this list. This operation is very
- fast and never fails.
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::operator==(const QLinkedList<T> &other) const
-
- Returns \c true if \a other is equal to this list; otherwise returns
- false.
-
- Two lists are considered equal if they contain the same values in
- the same order.
-
- This function requires the value type to implement \c
- operator==().
-
- \sa operator!=()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::operator!=(const QLinkedList<T> &other) const
-
- Returns \c true if \a other is not equal to this list; otherwise
- returns \c false.
-
- Two lists are considered equal if they contain the same values in
- the same order.
-
- This function requires the value type to implement \c
- operator==().
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::size() const
-
- Returns the number of items in the list.
-
- \sa isEmpty(), count()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::detach()
-
- \internal
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::isDetached() const
-
- \internal
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::setSharable(bool sharable)
-
- \internal
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::isSharedWith(const QLinkedList<T> &other) const
-
- \internal
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::isEmpty() const
-
- Returns \c true if the list contains no items; otherwise returns
- false.
-
- \sa size()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::clear()
-
- Removes all the items in the list.
-
- \sa removeAll()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::append(const T &value)
-
- Inserts \a value at the end of the list.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 3
-
- This is the same as list.insert(end(), \a value).
-
- \sa operator<<(), prepend(), insert()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::prepend(const T &value)
-
- Inserts \a value at the beginning of the list.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 4
-
- This is the same as list.insert(begin(), \a value).
-
- \sa append(), insert()
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::removeAll(const T &value)
-
- Removes all occurrences of \a value in the list.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 5
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa insert()
-*/
-
-/*!
- \fn template <class T> bool QLinkedList<T>::removeOne(const T &value)
- \since 4.4
-
- Removes the first occurrences of \a value in the list. Returns \c true on
- success; otherwise returns \c false.
-
- Example:
- \snippet code/src_corelib_tools_qlinkedlist.cpp 6
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa insert()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::contains(const T &value) const
-
- Returns \c true if the list contains an occurrence of \a value;
- otherwise returns \c false.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa QLinkedListIterator::findNext(), QLinkedListIterator::findPrevious()
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::count(const T &value) const
-
- Returns the number of occurrences of \a value in the list.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa contains()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::startsWith(const T &value) const
- \since 4.5
-
- Returns \c true if the list is not empty and its first
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), first()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::endsWith(const T &value) const
- \since 4.5
-
- Returns \c true if the list is not empty and its last
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), last()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::begin()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
- the list.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::begin() const
-
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::cbegin() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
-
- \sa begin(), cend()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::constBegin() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the list.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::end()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
- after the last item in the list.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::end() const
-
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::cend() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
-
- \sa cbegin(), end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::constEnd() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the list.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::reverse_iterator QLinkedList<T>::rbegin()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
-
- \sa begin(), crbegin(), rend()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::rbegin() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::crbegin() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the list, in reverse order.
-
- \sa begin(), rbegin(), rend()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::reverse_iterator QLinkedList<T>::rend()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last item in the list, in reverse order.
-
- \sa end(), crend(), rbegin()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::rend() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_reverse_iterator QLinkedList<T>::crend() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last item in the list, in reverse order.
-
- \sa end(), rend(), rbegin()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::insert(iterator before, const T &value)
-
- Inserts \a value in front of the item pointed to by the iterator
- \a before. Returns an iterator pointing at the inserted item.
-
- \sa erase()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::erase(iterator pos)
-
- Removes the item pointed to by the iterator \a pos from the list,
- and returns an iterator to the next item in the list (which may be
- end()).
-
- \sa insert()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::erase(iterator begin, iterator end)
-
- \overload
-
- Removes all the items from \a begin up to (but not including) \a
- end.
-*/
-
-/*! \typedef QLinkedList::Iterator
-
- Qt-style synonym for QLinkedList::iterator.
-*/
-
-/*! \typedef QLinkedList::ConstIterator
-
- Qt-style synonym for QLinkedList::const_iterator.
-*/
-
-/*! \typedef QLinkedList::reverse_iterator
- \since 5.6
-
- The QLinkedList::reverse_iterator typedef provides an STL-style non-const
- reverse iterator for QLinkedList.
-
- It is simply a typedef for \c{std::reverse_iterator<QLinkedList::iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::rbegin(), QLinkedList::rend(), QLinkedList::const_reverse_iterator, QLinkedList::iterator
-*/
-
-/*! \typedef QLinkedList::const_reverse_iterator
- \since 5.6
-
- The QLinkedList::const_reverse_iterator typedef provides an STL-style const
- reverse iterator for QLinkedList.
-
- It is simply a typedef for \c{std::reverse_iterator<QLinkedList::const_iterator>}.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::rbegin(), QLinkedList::rend(), QLinkedList::reverse_iterator, QLinkedList::const_iterator
-*/
-
-/*!
- \typedef QLinkedList::size_type
-
- Typedef for int. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::value_type
-
- Typedef for T. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::pointer
-
- Typedef for T *. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::const_pointer
-
- Typedef for const T *. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::reference
-
- Typedef for T &. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::const_reference
-
- Typedef for const T &. Provided for STL compatibility.
-*/
-
-/*!
- \typedef QLinkedList::difference_type
-
- Typedef for ptrdiff_t. Provided for STL compatibility.
-*/
-
-/*! \fn template <class T> int QLinkedList<T>::count() const
-
- Same as size().
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::first()
-
- Returns a reference to the first item in the list. This function
- assumes that the list isn't empty.
-
- \sa last(), isEmpty()
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::first() const
-
- \overload
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::last()
-
- Returns a reference to the last item in the list. This function
- assumes that the list isn't empty.
-
- \sa first(), isEmpty()
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::last() const
-
- \overload
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::removeFirst()
-
- Removes the first item in the list.
-
- This is the same as erase(begin()).
-
- \sa removeLast(), erase()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::removeLast()
-
- Removes the last item in the list.
-
- \sa removeFirst(), erase()
-*/
-
-/*! \fn template <class T> T QLinkedList<T>::takeFirst()
-
- Removes the first item in the list and returns it.
-
- If you don't use the return value, removeFirst() is more
- efficient.
-
- \sa takeLast(), removeFirst()
-*/
-
-/*! \fn template <class T> T QLinkedList<T>::takeLast()
-
- Removes the last item in the list and returns it.
-
- If you don't use the return value, removeLast() is more
- efficient.
-
- \sa takeFirst(), removeLast()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::push_back(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to append(\a value).
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::push_front(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to prepend(\a value).
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::front()
-
- This function is provided for STL compatibility. It is equivalent
- to first().
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::front() const
-
- \overload
-*/
-
-/*! \fn template <class T> T& QLinkedList<T>::back()
-
- This function is provided for STL compatibility. It is equivalent
- to last().
-*/
-
-/*! \fn template <class T> const T& QLinkedList<T>::back() const
-
- \overload
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::pop_front()
-
- This function is provided for STL compatibility. It is equivalent
- to removeFirst().
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::pop_back()
-
- This function is provided for STL compatibility. It is equivalent
- to removeLast().
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::empty() const
-
- This function is provided for STL compatibility. It is equivalent
- to isEmpty() and returns \c true if the list is empty.
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator+=(const QLinkedList<T> &other)
-
- Appends the items of the \a other list to this list and returns a
- reference to this list.
-
- \sa operator+(), append()
-*/
-
-/*! \fn template <class T> void QLinkedList<T>::operator+=(const T &value)
-
- \overload
-
- Appends \a value to the list.
-*/
-
-/*! \fn template <class T> QLinkedList<T> QLinkedList<T>::operator+(const QLinkedList<T> &other) const
-
- Returns a list that contains all the items in this list followed
- by all the items in the \a other list.
-
- \sa operator+=()
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator<<(const QLinkedList<T> &other)
-
- Appends the items of the \a other list to this list and returns a
- reference to this list.
-
- \sa operator+=(), append()
-*/
-
-/*! \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator<<(const T &value)
-
- \overload
-
- Appends \a value to the list.
-*/
-
-/*! \class QLinkedList::iterator
- \inmodule QtCore
- \brief The QLinkedList::iterator class provides an STL-style non-const iterator for QLinkedList.
-
- QLinkedList features both \l{STL-style iterators} and
- \l{Java-style iterators}. The STL-style iterators are more
- low-level and more cumbersome to use; on the other hand, they are
- slightly faster and, for developers who already know STL, have
- the advantage of familiarity.
-
- QLinkedList\<T\>::iterator allows you to iterate over a
- QLinkedList\<T\> and to modify the list item associated with the
- iterator. If you want to iterate over a const QLinkedList, use
- QLinkedList::const_iterator instead. It is generally good
- practice to use QLinkedList::const_iterator on a non-const
- QLinkedList as well, unless you need to change the QLinkedList
- through the iterator. Const iterators are slightly faster, and
- can improve code readability.
-
- The default QLinkedList::iterator constructor creates an
- uninitialized iterator. You must initialize it using a
- function like QLinkedList::begin(), QLinkedList::end(), or
- QLinkedList::insert() before you can start iterating. Here's a
- typical loop that prints all the items stored in a list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 7
-
- STL-style iterators can be used as arguments to \l{generic
- algorithms}. For example, here's how to find an item in the list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 8
-
- Let's see a few examples of things we can do with a
- QLinkedList::iterator that we cannot do with a QLinkedList::const_iterator.
- Here's an example that increments every value stored in a
- QLinkedList\<int\> by 2:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 9
-
- Here's an example that removes all the items that start with an
- underscore character in a QLinkedList\<QString\>:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 10
-
- The call to QLinkedList::erase() removes the item pointed to by
- the iterator from the list, and returns an iterator to the next
- item. Here's another way of removing an item while iterating:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 11
-
- It might be tempting to write code like this:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 12
-
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
- Multiple iterators can be used on the same list. If you add items
- to the list, existing iterators will remain valid. If you remove
- items from the list, iterators that point to the removed items
- will become dangling iterators.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::const_iterator, QMutableLinkedListIterator
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator::iterator()
-
- Constructs an uninitialized iterator.
-
- Functions like operator*() and operator++() should not be called
- on an uninitialized iterator. Use operator=() to assign a value
- to it before using it.
-
- \sa QLinkedList::begin(), QLinkedList::end()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator::iterator(Node *node)
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::iterator_category
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::difference_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::value_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::pointer
-
- \internal
-*/
-
-/*! \typedef QLinkedList::iterator::reference
-
- \internal
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator::iterator(const iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator=(const iterator &other)
-
- Assigns \a other to this iterator.
-*/
-
-/*!
- \fn template <class T> QLinkedList<T> &QLinkedList<T>::operator=(QLinkedList<T> &&other)
-
- Move-assigns \a other to this QLinkedList instance.
-
- \since 5.2
-*/
-
-/*! \fn template <class T> T &QLinkedList<T>::iterator::operator*() const
-
- Returns a modifiable reference to the current item.
-
- You can change the value of an item by using operator*() on the
- left side of an assignment, for example:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 13
-
- \sa operator->()
-*/
-
-/*! \fn template <class T> T *QLinkedList<T>::iterator::operator->() const
-
- Returns a pointer to the current item.
-
- \sa operator*()
-*/
-
-/*!
- \fn template <class T> bool QLinkedList<T>::iterator::operator==(const iterator &other) const
- \fn template <class T> bool QLinkedList<T>::iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*!
- \fn template <class T> bool QLinkedList<T>::iterator::operator!=(const iterator &other) const
- \fn template <class T> bool QLinkedList<T>::iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator++()
-
- The prefix ++ operator (\c{++it}) advances the iterator to the
- next item in the list and returns an iterator to the new current
- item.
-
- Calling this function on QLinkedList::end() leads to undefined
- results.
-
- \sa operator--()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator++(int)
-
- \overload
-
- The postfix ++ operator (\c{it++}) advances the iterator to the
- next item in the list and returns an iterator to the previously
- current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator--()
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QLinkedList::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator QLinkedList<T>::iterator::operator-(int j) const
-
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::iterator &QLinkedList<T>::iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
-*/
-
-/*! \class QLinkedList::const_iterator
- \inmodule QtCore
- \brief The QLinkedList::const_iterator class provides an STL-style const iterator for QLinkedList.
-
- QLinkedList features both \l{STL-style iterators} and
- \l{Java-style iterators}. The STL-style iterators are more
- low-level and more cumbersome to use; on the other hand, they are
- slightly faster and, for developers who already know STL, have
- the advantage of familiarity.
-
- QLinkedList\<T\>::const_iterator allows you to iterate over a
- QLinkedList\<T\>. If you want modify the QLinkedList as you iterate
- over it, you must use QLinkedList::iterator instead. It is
- generally good practice to use QLinkedList::const_iterator on a
- non-const QLinkedList as well, unless you need to change the
- QLinkedList through the iterator. Const iterators are slightly
- faster, and can improve code readability.
-
- The default QLinkedList::const_iterator constructor creates an
- uninitialized iterator. You must initialize it using a function
- like QLinkedList::constBegin(), QLinkedList::constEnd(), or
- QLinkedList::insert() before you can start iterating. Here's a
- typical loop that prints all the items stored in a list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 14
-
- STL-style iterators can be used as arguments to \l{generic
- algorithms}. For example, here's how to find an item in the list:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 15
-
- Multiple iterators can be used on the same list. If you add items
- to the list, existing iterators will remain valid. If you remove
- items from the list, iterators that point to the removed items
- will become dangling iterators.
-
- \warning Iterators on implicitly shared containers do not work
- exactly like STL-iterators. You should avoid copying a container
- while iterators are active on that container. For more information,
- read \l{Implicit sharing iterator problem}.
-
- \sa QLinkedList::iterator, QLinkedListIterator
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator()
-
- Constructs an uninitialized iterator.
-
- Functions like operator*() and operator++() should not be called
- on an uninitialized iterator. Use operator=() to assign a value
- to it before using it.
-
- \sa QLinkedList::constBegin(), QLinkedList::constEnd()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator(Node *node)
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::iterator_category
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::difference_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::value_type
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::pointer
-
- \internal
-*/
-
-/*! \typedef QLinkedList::const_iterator::reference
-
- \internal
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator(const const_iterator &other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator::const_iterator(iterator other)
-
- Constructs a copy of \a other.
-*/
-
-/*! \fn template <class T> typename QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator=(const const_iterator &other)
-
- Assigns \a other to this iterator.
-*/
-
-/*! \fn template <class T> const T &QLinkedList<T>::const_iterator::operator*() const
-
- Returns a reference to the current item.
-
- \sa operator->()
-*/
-
-/*! \fn template <class T> const T *QLinkedList<T>::const_iterator::operator->() const
-
- Returns a pointer to the current item.
-
- \sa operator*()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::const_iterator::operator==(const const_iterator &other) const
-
- Returns \c true if \a other points to the same item as this
- iterator; otherwise returns \c false.
-
- \sa operator!=()
-*/
-
-/*! \fn template <class T> bool QLinkedList<T>::const_iterator::operator!=(const const_iterator &other) const
-
- Returns \c true if \a other points to a different item than this
- iterator; otherwise returns \c false.
-
- \sa operator==()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator++()
-
- The prefix ++ operator (\c{++it}) advances the iterator to the
- next item in the list and returns an iterator to the new current
- item.
-
- Calling this function on QLinkedList<T>::constEnd() leads to
- undefined results.
-
- \sa operator--()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator++(int)
-
- \overload
-
- The postfix ++ operator (\c{it++}) advances the iterator to the
- next item in the list and returns an iterator to the previously
- current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator--()
-
- The prefix -- operator (\c{--it}) makes the preceding item
- current and returns an iterator to the new current item.
-
- Calling this function on QLinkedList::begin() leads to undefined
- results.
-
- \sa operator++()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator--(int)
-
- \overload
-
- The postfix -- operator (\c{it--}) makes the preceding item
- current and returns an iterator to the previously current item.
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator QLinkedList<T>::const_iterator::operator-(int j) const
-
- This function returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class T> QLinkedList<T>::const_iterator &QLinkedList<T>::const_iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
-*/
-
-/*! \fn template <class T> QDataStream &operator<<(QDataStream &out, const QLinkedList<T> &list)
- \relates QLinkedList
-
- Writes the linked list \a list to stream \a out.
-
- This function requires the value type to implement \c
- operator<<().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*! \fn template <class T> QDataStream &operator>>(QDataStream &in, QLinkedList<T> &list)
- \relates QLinkedList
-
- Reads a linked list from stream \a in into \a list.
-
- This function requires the value type to implement \c operator>>().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*!
- \since 4.1
- \fn template <class T> QLinkedList<T> QLinkedList<T>::fromStdList(const std::list<T> &list)
-
- Returns a QLinkedList object with the data contained in \a list.
- The order of the elements in the QLinkedList is the same as in \a
- list.
-
- Example:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 16
-
- \sa toStdList()
-*/
-
-/*!
- \since 4.1
- \fn template <class T> std::list<T> QLinkedList<T>::toStdList() const
-
- Returns a std::list object with the data contained in this
- QLinkedList. Example:
-
- \snippet code/src_corelib_tools_qlinkedlist.cpp 17
-
- \sa fromStdList()
-*/
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h
deleted file mode 100644
index e3713d2c1c..0000000000
--- a/src/corelib/tools/qlinkedlist.h
+++ /dev/null
@@ -1,596 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QLINKEDLIST_H
-#define QLINKEDLIST_H
-
-#include <QtCore/qglobal.h>
-
-#ifndef QT_NO_LINKED_LIST
-
-#include <QtCore/qiterator.h>
-#include <QtCore/qrefcount.h>
-#include <QtCore/qcontainertools_impl.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qtypeinfo.h>
-
-#include <algorithm>
-#include <initializer_list>
-#include <iterator>
-#include <list>
-
-QT_BEGIN_NAMESPACE
-
-
-struct Q_CORE_EXPORT QLinkedListData
-{
- QLinkedListData *n, *p;
- QtPrivate::RefCount ref;
- int size;
- uint sharable : 1;
-
- static const QLinkedListData shared_null;
-};
-
-template <typename T>
-struct QLinkedListNode
-{
- inline QLinkedListNode(const T &arg): t(arg) { }
- QLinkedListNode *n, *p;
- T t;
-};
-
-template <class T>
-class QLinkedList
-{
- typedef QLinkedListNode<T> Node;
- union { QLinkedListData *d; QLinkedListNode<T> *e; };
-
-public:
- inline QLinkedList() noexcept : d(const_cast<QLinkedListData *>(&QLinkedListData::shared_null)) { }
- inline QLinkedList(const QLinkedList<T> &l) : d(l.d) { d->ref.ref(); if (!d->sharable) detach(); }
- inline QLinkedList(std::initializer_list<T> list)
- : QLinkedList(list.begin(), list.end()) {}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
- inline QLinkedList(InputIterator first, InputIterator last)
- : QLinkedList()
- {
- std::copy(first, last, std::back_inserter(*this));
- }
- ~QLinkedList();
- QLinkedList<T> &operator=(const QLinkedList<T> &);
- QLinkedList(QLinkedList<T> &&other) noexcept
- : d(other.d) { other.d = const_cast<QLinkedListData *>(&QLinkedListData::shared_null); }
- QLinkedList<T> &operator=(QLinkedList<T> &&other) noexcept
- { QLinkedList moved(std::move(other)); swap(moved); return *this; }
- inline void swap(QLinkedList<T> &other) noexcept { qSwap(d, other.d); }
- bool operator==(const QLinkedList<T> &l) const;
- inline bool operator!=(const QLinkedList<T> &l) const { return !(*this == l); }
-
- inline int size() const { return d->size; }
- inline void detach()
- { if (d->ref.isShared()) detach_helper2(this->e); }
- inline bool isDetached() const { return !d->ref.isShared(); }
- inline bool isSharedWith(const QLinkedList<T> &other) const { return d == other.d; }
-
- inline bool isEmpty() const { return d->size == 0; }
-
- void clear();
-
- void append(const T &);
- void prepend(const T &);
- T takeFirst();
- T takeLast();
- int removeAll(const T &t);
- bool removeOne(const T &t);
- bool contains(const T &t) const;
- int count(const T &t) const;
-
- class const_iterator;
-
- class iterator
- {
- public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
- Node *i;
- inline iterator() : i(nullptr) {}
- inline iterator(Node *n) : i(n) {}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- iterator(const iterator &other) noexcept : i(other.i) {}
- iterator &operator=(const iterator &other) noexcept { i = other.i; return *this; }
- iterator(iterator &&other) noexcept : i(other.i) {}
- iterator &operator=(iterator &&other) noexcept { return *this = other; }
-#endif
- inline T &operator*() const { return i->t; }
- inline T *operator->() const { return &i->t; }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
- inline bool operator==(const const_iterator &o) const
- { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const
- { return i != o.i; }
- inline iterator &operator++() { i = i->n; return *this; }
- inline iterator operator++(int) { Node *n = i; i = i->n; return n; }
- inline iterator &operator--() { i = i->p; return *this; }
- inline iterator operator--(int) { Node *n = i; i = i->p; return n; }
- inline iterator operator+(int j) const
- { Node *n = i; if (j > 0) while (j--) n = n->n; else while (j++) n = n->p; return n; }
- inline iterator operator-(int j) const { return operator+(-j); }
- inline iterator &operator+=(int j) { return *this = *this + j; }
- inline iterator &operator-=(int j) { return *this = *this - j; }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
- };
- friend class iterator;
-
- class const_iterator
- {
- public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef qptrdiff difference_type;
- typedef T value_type;
- typedef const T *pointer;
- typedef const T &reference;
- Node *i;
- inline const_iterator() : i(nullptr) {}
- inline const_iterator(Node *n) : i(n) {}
- inline const_iterator(iterator ci) : i(ci.i){}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- const_iterator(const const_iterator &other) noexcept : i(other.i) {}
- const_iterator &operator=(const const_iterator &other) noexcept { i = other.i; return *this; }
- const_iterator(const_iterator &&other) noexcept : i(other.i) {}
- const_iterator &operator=(const_iterator &&other) noexcept { return *this = other; }
-#endif
- inline const T &operator*() const { return i->t; }
- inline const T *operator->() const { return &i->t; }
- inline bool operator==(const const_iterator &o) const { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const { return i != o.i; }
- inline const_iterator &operator++() { i = i->n; return *this; }
- inline const_iterator operator++(int) { Node *n = i; i = i->n; return n; }
- inline const_iterator &operator--() { i = i->p; return *this; }
- inline const_iterator operator--(int) { Node *n = i; i = i->p; return n; }
- inline const_iterator operator+(int j) const
- { Node *n = i; if (j > 0) while (j--) n = n->n; else while (j++) n = n->p; return n; }
- inline const_iterator operator-(int j) const { return operator+(-j); }
- inline const_iterator &operator+=(int j) { return *this = *this + j; }
- inline const_iterator &operator-=(int j) { return *this = *this - j; }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
- };
- friend class const_iterator;
-
- // stl style
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- inline iterator begin() { detach(); return e->n; }
- inline const_iterator begin() const noexcept { return e->n; }
- inline const_iterator cbegin() const noexcept { return e->n; }
- inline const_iterator constBegin() const noexcept { return e->n; }
- inline iterator end() { detach(); return e; }
- inline const_iterator end() const noexcept { return e; }
- inline const_iterator cend() const noexcept { return e; }
- inline const_iterator constEnd() const noexcept { return e; }
-
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
- const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
-
- iterator insert(iterator before, const T &t);
- iterator erase(iterator pos);
- iterator erase(iterator first, iterator last);
-
- // more Qt
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- inline int count() const { return d->size; }
- inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T& first() const { Q_ASSERT(!isEmpty()); return *begin(); }
- T& last() { Q_ASSERT(!isEmpty()); return *(--end()); }
- const T& last() const { Q_ASSERT(!isEmpty()); return *(--end()); }
- inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(begin()); }
- inline void removeLast() { Q_ASSERT(!isEmpty()); erase(--end()); }
- inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
- inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
-
- // stl compatibility
- inline void push_back(const T &t) { append(t); }
- inline void push_front(const T &t) { prepend(t); }
- inline T& front() { return first(); }
- inline const T& front() const { return first(); }
- inline T& back() { return last(); }
- inline const T& back() const { return last(); }
- inline void pop_front() { removeFirst(); }
- inline void pop_back() { removeLast(); }
- inline bool empty() const { return isEmpty(); }
- typedef int size_type;
- typedef T value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef value_type &reference;
- typedef const value_type &const_reference;
- typedef qptrdiff difference_type;
-
- static inline QLinkedList<T> fromStdList(const std::list<T> &list)
- { QLinkedList<T> tmp; std::copy(list.begin(), list.end(), std::back_inserter(tmp)); return tmp; }
- inline std::list<T> toStdList() const
- { std::list<T> tmp; std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; }
-
- // comfort
- QLinkedList<T> &operator+=(const QLinkedList<T> &l);
- QLinkedList<T> operator+(const QLinkedList<T> &l) const;
- inline QLinkedList<T> &operator+=(const T &t) { append(t); return *this; }
- inline QLinkedList<T> &operator<< (const T &t) { append(t); return *this; }
- inline QLinkedList<T> &operator<<(const QLinkedList<T> &l) { *this += l; return *this; }
-
-private:
- void detach_helper();
- iterator detach_helper2(iterator);
- void freeData(QLinkedListData*);
-};
-template <typename T>
-Q_DECLARE_TYPEINFO_BODY(QLinkedList<T>, Q_MOVABLE_TYPE|Q_RELOCATABLE_TYPE);
-
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
-template <typename InputIterator,
- typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
- QtPrivate::IfIsInputIterator<InputIterator> = true>
-QLinkedList(InputIterator, InputIterator) -> QLinkedList<ValueType>;
-#endif
-
-template <typename T>
-inline QLinkedList<T>::~QLinkedList()
-{
- if (!d->ref.deref())
- freeData(d);
-}
-
-template <typename T>
-void QLinkedList<T>::detach_helper()
-{
- detach_helper2(this->e);
-}
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::detach_helper2(iterator orgite)
-{
- // detach and convert orgite to an iterator in the detached instance
- bool isEndIterator = (orgite.i == this->e);
- union { QLinkedListData *d; Node *e; } x;
- x.d = new QLinkedListData;
- x.d->ref.initializeOwned();
- x.d->size = d->size;
- x.d->sharable = true;
- Node *original = e->n;
- Node *copy = x.e;
- Node *org = orgite.i;
-
- while (original != org) {
- QT_TRY {
- copy->n = new Node(original->t);
- copy->n->p = copy;
- original = original->n;
- copy = copy->n;
- } QT_CATCH(...) {
- copy->n = x.e;
- Q_ASSERT(!x.d->ref.deref()); // Don't trigger assert in free
- freeData(x.d);
- QT_RETHROW;
- }
- }
- iterator r(copy);
- while (original != e) {
- QT_TRY {
- copy->n = new Node(original->t);
- copy->n->p = copy;
- original = original->n;
- copy = copy->n;
- } QT_CATCH(...) {
- copy->n = x.e;
- Q_ASSERT(!x.d->ref.deref()); // Don't trigger assert in free
- freeData(x.d);
- QT_RETHROW;
- }
- }
- copy->n = x.e;
- x.e->p = copy;
- if (!d->ref.deref())
- freeData(d);
- d = x.d;
- if (!isEndIterator)
- ++r; // since we stored the element right before the original node.
- return r;
-}
-
-template <typename T>
-void QLinkedList<T>::freeData(QLinkedListData *x)
-{
- Node *y = reinterpret_cast<Node*>(x);
- Node *i = y->n;
- Q_ASSERT(x->ref.atomic.loadRelaxed() == 0);
- while (i != y) {
- Node *n = i;
- i = i->n;
- delete n;
- }
- delete x;
-}
-
-template <typename T>
-void QLinkedList<T>::clear()
-{
- *this = QLinkedList<T>();
-}
-
-template <typename T>
-QLinkedList<T> &QLinkedList<T>::operator=(const QLinkedList<T> &l)
-{
- if (d != l.d) {
- QLinkedListData *o = l.d;
- o->ref.ref();
- if (!d->ref.deref())
- freeData(d);
- d = o;
- if (!d->sharable)
- detach_helper();
- }
- return *this;
-}
-
-template <typename T>
-bool QLinkedList<T>::operator== (const QLinkedList<T> &l) const
-{
- if (d->size != l.d->size)
- return false;
- if (e == l.e)
- return true;
- Node *i = e->n;
- Node *il = l.e->n;
- while (i != e) {
- if (! (i->t == il->t))
- return false;
- i = i->n;
- il = il->n;
- }
- return true;
-}
-
-template <typename T>
-void QLinkedList<T>::append(const T &t)
-{
- detach();
- Node *i = new Node(t);
- i->n = e;
- i->p = e->p;
- i->p->n = i;
- e->p = i;
- d->size++;
-}
-
-template <typename T>
-void QLinkedList<T>::prepend(const T &t)
-{
- detach();
- Node *i = new Node(t);
- i->n = e->n;
- i->p = e;
- i->n->p = i;
- e->n = i;
- d->size++;
-}
-
-template <typename T>
-int QLinkedList<T>::removeAll(const T &_t)
-{
- detach();
- const T t = _t;
- Node *i = e->n;
- int c = 0;
- while (i != e) {
- if (i->t == t) {
- Node *n = i;
- i->n->p = i->p;
- i->p->n = i->n;
- i = i->n;
- delete n;
- c++;
- } else {
- i = i->n;
- }
- }
- d->size-=c;
- return c;
-}
-
-template <typename T>
-bool QLinkedList<T>::removeOne(const T &_t)
-{
- detach();
- iterator it = std::find(begin(), end(), _t);
- if (it != end()) {
- erase(it);
- return true;
- }
- return false;
-}
-
-template <typename T>
-inline T QLinkedList<T>::takeFirst()
-{
- T t = std::move(first());
- removeFirst();
- return t;
-}
-
-template <typename T>
-inline T QLinkedList<T>::takeLast()
-{
- T t = std::move(last());
- removeLast();
- return t;
-}
-
-template <typename T>
-bool QLinkedList<T>::contains(const T &t) const
-{
- Node *i = e;
- while ((i = i->n) != e)
- if (i->t == t)
- return true;
- return false;
-}
-
-template <typename T>
-int QLinkedList<T>::count(const T &t) const
-{
- Node *i = e;
- int c = 0;
- while ((i = i->n) != e)
- if (i->t == t)
- c++;
- return c;
-}
-
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::insert(iterator before, const T &t)
-{
- if (d->ref.isShared())
- before = detach_helper2(before);
-
- Node *i = before.i;
- Node *m = new Node(t);
- m->n = i;
- m->p = i->p;
- m->p->n = m;
- i->p = m;
- d->size++;
- return m;
-}
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::erase(typename QLinkedList<T>::iterator afirst,
- typename QLinkedList<T>::iterator alast)
-{
- while (afirst != alast)
- erase(afirst++);
- return alast;
-}
-
-
-template <typename T>
-typename QLinkedList<T>::iterator QLinkedList<T>::erase(iterator pos)
-{
- if (d->ref.isShared())
- pos = detach_helper2(pos);
-
- Node *i = pos.i;
- if (i != e) {
- Node *n = i;
- i->n->p = i->p;
- i->p->n = i->n;
- i = i->n;
- delete n;
- d->size--;
- }
- return i;
-}
-
-template <typename T>
-QLinkedList<T> &QLinkedList<T>::operator+=(const QLinkedList<T> &l)
-{
- detach();
- int n = l.d->size;
- d->size += n;
- Node *original = l.e->n;
- while (n--) {
- QT_TRY {
- Node *copy = new Node(original->t);
- original = original->n;
- copy->n = e;
- copy->p = e->p;
- copy->p->n = copy;
- e->p = copy;
- } QT_CATCH(...) {
- // restore the original list
- while (n++<d->size)
- removeLast();
- QT_RETHROW;
- }
- }
- return *this;
-}
-
-template <typename T>
-QLinkedList<T> QLinkedList<T>::operator+(const QLinkedList<T> &l) const
-{
- QLinkedList<T> n = *this;
- n += l;
- return n;
-}
-
-Q_DECLARE_SEQUENTIAL_ITERATOR(LinkedList)
-Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(LinkedList)
-
-#ifndef QT_NO_DATASTREAM
-template <typename T>
-inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
-{
- return QtPrivate::readListBasedContainer(s, l);
-}
-
-template <typename T>
-inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
-{
- return QtPrivate::writeSequentialContainer(s, l);
-}
-#endif
-
-QT_END_NAMESPACE
-
-Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(QLinkedList)
-
-#endif // QT_NO_LINKED_LIST
-
-#endif // QLINKEDLIST_H
diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp
deleted file mode 100644
index 62201fd5d6..0000000000
--- a/src/corelib/tools/qlist.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $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 <new>
-#include "qlist.h"
-#include "qtools_p.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-QT_BEGIN_NAMESPACE
-
-/*
- ### Qt 5:
- ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
- ### Qt exports QPolygon and QPolygonF that inherit QVector<QPoint> and
- ### QVector<QPointF> respectively.
-*/
-
-#if defined(Q_CC_MSVC) && defined(QT_BUILD_CORE_LIB)
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <QtCore/qpoint.h>
-QT_END_INCLUDE_NAMESPACE
-
-template class Q_CORE_EXPORT QVector<QPointF>;
-template class Q_CORE_EXPORT QVector<QPoint>;
-#endif
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 515fba6530..89e0e3f380 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -1,56 +1,1024 @@
-/****************************************************************************
-**
-** 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.
+// 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
-#include <QtCore/qvector.h>
-#include <QtCore/qcontainerfwd.h>
+#include <QtCore/qarraydatapointer.h>
+#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;
-#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+ template <typename V, typename U> qsizetype indexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
+ template <typename V, typename U> qsizetype lastIndexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
+}
+
+template <typename T> struct QListSpecialMethodsBase
+{
+protected:
+ ~QListSpecialMethodsBase() = default;
+
+ using Self = QList<T>;
+ Self *self() { return static_cast<Self *>(this); }
+ const Self *self() const { return static_cast<const Self *>(this); }
+
+public:
+ 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;
+
+ template <typename AT = T>
+ bool contains(const AT &t) const noexcept
+ {
+ 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
+{
+ 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:
+ 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);
+ bool isValidIterator(const_iterator i) const
+ {
+ const std::less<const T*> less = {};
+ return !less(d->end(), i.i) && !less(i.i, d->begin());
+ }
+
+ void verify([[maybe_unused]] qsizetype pos = 0, [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+public:
+ QList(DataPointer dd) noexcept
+ : d(dd)
+ {
+ }
+
+public:
+ QList() = default;
+ explicit QList(qsizetype size)
+ : d(size)
+ {
+ if (size)
+ d->appendInitialize(size);
+ }
+ QList(qsizetype size, parameter_type t)
+ : d(size)
+ {
+ if (size)
+ d->copyAppend(size, t);
+ }
+
+ inline QList(std::initializer_list<T> args)
+ : d(qsizetype(args.size()))
+ {
+ if (args.size())
+ d->copyAppend(args.begin(), args.end());
+ }
+
+ QList<T> &operator=(std::initializer_list<T> args)
+ {
+ return assign(args);
+ }
+
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
+ QList(InputIterator i1, InputIterator i2)
+ {
+ 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
+ template<typename String, typename = std::enable_if_t<std::is_same_v<T, QString> && std::is_convertible_v<String, QString>>>
+ 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 &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 = 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(); }
+ qsizetype length() const noexcept { return size(); }
+
+ inline bool isEmpty() const noexcept { return d->size == 0; }
+
+ void resize(qsizetype size)
+ {
+ resize_internal(size);
+ if (size > this->size())
+ d->appendInitialize(size);
+ }
+ void resize(qsizetype size, parameter_type c)
+ {
+ 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);
+ inline void squeeze();
+
+ void detach() { d.detach(); }
+ bool isDetached() const noexcept { return !d->isShared(); }
+
+ inline bool isSharedWith(const QList<T> &other) const { return d == other.d; }
+
+ pointer data() { detach(); return d->data(); }
+ const_pointer data() const noexcept { return d->data(); }
+ const_pointer constData() const noexcept { return d->data(); }
+ void clear() {
+ if (!size())
+ return;
+ if (d->needsDetach()) {
+ // must allocate memory
+ DataPointer detached(d.allocatedCapacity());
+ d.swap(detached);
+ } else {
+ d->truncate(0);
+ }
+ }
+
+ const_reference at(qsizetype i) const noexcept
+ {
+ Q_ASSERT_X(size_t(i) < size_t(d->size), "QList::at", "index out of range");
+ return data()[i];
+ }
+ reference operator[](qsizetype i)
+ {
+ Q_ASSERT_X(size_t(i) < size_t(d->size), "QList::operator[]", "index out of range");
+ // don't detach() here, we detach in data below:
+ return data()[i];
+ }
+ const_reference operator[](qsizetype i) const noexcept { return at(i); }
+ void append(parameter_type t) { emplaceBack(t); }
+ void append(const_iterator i1, const_iterator i2);
+ 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) {
+ 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>
+ inline reference emplaceFront(Args&&... args);
+
+ iterator insert(qsizetype i, parameter_type t)
+ { return emplace(i, t); }
+ iterator insert(qsizetype i, qsizetype n, parameter_type t);
+ iterator insert(const_iterator before, parameter_type t)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QList::insert", "The specified iterator argument 'before' is invalid");
+ return insert(before, 1, t);
+ }
+ iterator insert(const_iterator before, qsizetype n, parameter_type t)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QList::insert", "The specified iterator argument 'before' is invalid");
+ return insert(std::distance(constBegin(), before), n, t);
+ }
+ iterator insert(const_iterator before, rvalue_ref t)
+ {
+ Q_ASSERT_X(isValidIterator(before), "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) {
+ 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)
+ {
+ Q_ASSERT_X(isValidIterator(before), "QList::emplace", "The specified iterator argument 'before' is invalid");
+ return emplace(std::distance(constBegin(), before), std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ iterator emplace(qsizetype i, Args&&... args);
+#if 0
+ template< class InputIt >
+ iterator insert( const_iterator pos, InputIt first, InputIt last );
+ iterator insert( const_iterator pos, std::initializer_list<T> ilist );
+#endif
+ void replace(qsizetype i, parameter_type t)
+ {
+ Q_ASSERT_X(i >= 0 && i < d->size, "QList<T>::replace", "index out of range");
+ DataPointer oldData;
+ d.detach(&oldData);
+ d.data()[i] = t;
+ }
+ void replace(qsizetype i, rvalue_ref t)
+ {
+ 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() 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);
+
+#ifndef Q_QDOC
+ using QListSpecialMethods<T>::contains;
+ using QListSpecialMethods<T>::indexOf;
+ using QListSpecialMethods<T>::lastIndexOf;
+#else
+ 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
+
+ template <typename AT = T>
+ qsizetype count(const AT &t) const noexcept
+ {
+ return qsizetype(std::count(data(), data() + size(), t));
+ }
+
+ void removeAt(qsizetype i) { remove(i); }
+ 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)
+ {
+ Q_ASSERT_X(from >= 0 && from < size(), "QList::move(qsizetype, qsizetype)", "'from' is out-of-range");
+ Q_ASSERT_X(to >= 0 && to < size(), "QList::move(qsizetype, qsizetype)", "'to' is out-of-range");
+ if (from == to) // don't detach when no-op
+ return;
+ detach();
+ T * const b = d->begin();
+ if (from < to)
+ std::rotate(b + from, b + from + 1, b + to + 1);
+ else
+ std::rotate(b + to, b + from, b + from + 1);
+ }
+
+ // STL-style
+ 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()); }
+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
+
+ iterator erase(const_iterator begin, const_iterator end);
+ inline iterator erase(const_iterator pos) { return erase(pos, pos+1); }
+
+ // more Qt
+ inline T& first() { 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 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
+ { verify(0, n); return QList<T>(begin(), begin() + n); }
+ QList<T> last(qsizetype n) const
+ { verify(0, n); return QList<T>(end() - n, end()); }
+ QList<T> sliced(qsizetype pos) const
+ { verify(pos, 0); return QList<T>(begin() + pos, end()); }
+ QList<T> sliced(qsizetype pos, qsizetype n) const
+ { verify(pos, n); return QList<T>(begin() + pos, begin() + pos + n); }
+
+ T value(qsizetype i) const { return value(i, T()); }
+ T value(qsizetype i, parameter_type defaultValue) const;
+
+ void swapItemsAt(qsizetype i, qsizetype j) {
+ Q_ASSERT_X(i >= 0 && i < size() && j >= 0 && j < size(),
+ "QList<T>::swap", "index out of range");
+ detach();
+ qSwap(d->begin()[i], d->begin()[j]);
+ }
+
+ // STL compatibility
+ 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(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 noexcept
+ { return d->size == 0; }
+ inline reference front() { return first(); }
+ inline const_reference front() const noexcept { return first(); }
+ inline reference back() { return last(); }
+ inline const_reference back() const noexcept { return last(); }
+ void shrink_to_fit() { squeeze(); }
+ static qsizetype max_size() noexcept
+ {
+ return Data::max_size();
+ }
+
+ // comfort
+ QList<T> &operator+=(const QList<T> &l) { append(l); return *this; }
+ QList<T> &operator+=(QList<T> &&l) { append(std::move(l)); return *this; }
+ inline QList<T> operator+(const QList<T> &l) const &
+ { QList n = *this; n += l; return n; }
+ QList<T> operator+(const QList<T> &l) &&
+ { return std::move(*this += l); }
+ inline QList<T> operator+(QList<T> &&l) const &
+ { QList n = *this; n += std::move(l); return n; }
+ QList<T> operator+(QList<T> &&l) &&
+ { return std::move(*this += std::move(l)); }
+ inline QList<T> &operator+=(parameter_type t)
+ { append(t); return *this; }
+ inline QList<T> &operator<< (parameter_type t)
+ { append(t); return *this; }
+ inline QList<T> &operator<<(const QList<T> &l)
+ { *this += l; return *this; }
+ inline QList<T> &operator<<(QList<T> &&l)
+ { *this += std::move(l); return *this; }
+ inline QList<T> &operator+=(rvalue_ref t)
+ { append(std::move(t)); return *this; }
+ inline QList<T> &operator<<(rvalue_ref t)
+ { append(std::move(t)); return *this; }
+
+ // Consider deprecating in 6.4 or later
+ 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) noexcept { return vector; }
+ inline QList<T> toVector() const noexcept { return *this; }
+
+ template<qsizetype N>
+ static QList<T> fromReadOnlyData(const T (&t)[N]) noexcept
+ {
+ return QList<T>({ nullptr, const_cast<T *>(t), N });
+ }
+};
+
+template <typename InputIterator,
+ typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
+ QtPrivate::IfIsInputIterator<InputIterator> = true>
+QList(InputIterator, InputIterator) -> QList<ValueType>;
+
+template <typename T>
+inline void QList<T>::resize_internal(qsizetype newSize)
+{
+ Q_ASSERT(newSize >= 0);
+
+ if (d->needsDetach() || newSize > capacity() - d.freeSpaceAtBegin()) {
+ d.detachAndGrow(QArrayData::GrowsAtEnd, newSize - d.size, nullptr, nullptr);
+ } else if (newSize < size()) {
+ d->truncate(newSize);
+ }
+}
+
+template <typename T>
+void QList<T>::reserve(qsizetype asize)
+{
+ // capacity() == 0 for immutable data, so this will force a detaching below
+ if (asize <= capacity() - d.freeSpaceAtBegin()) {
+ if (d->flags() & Data::CapacityReserved)
+ return; // already reserved, don't shrink
+ if (!d->isShared()) {
+ // accept current allocation, don't shrink
+ d->setFlag(Data::CapacityReserved);
+ return;
+ }
+ }
+
+ 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.isMutable())
+ return;
+ if (d->needsDetach() || size() < capacity()) {
+ // must allocate memory
+ DataPointer detached(size());
+ if (size()) {
+ 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>
+inline void QList<T>::remove(qsizetype i, qsizetype n)
+{
+ Q_ASSERT_X(size_t(i) + size_t(n) <= size_t(d->size), "QList::remove", "index out of range");
+ Q_ASSERT_X(n >= 0, "QList::remove", "invalid count");
+
+ if (n == 0)
+ return;
+
+ d.detach();
+ d->erase(d->begin() + i, n);
+}
+
+template <typename T>
+inline void QList<T>::removeFirst() noexcept
+{
+ Q_ASSERT(!isEmpty());
+ d.detach();
+ d->eraseFirst();
+}
+
+template <typename T>
+inline void QList<T>::removeLast() noexcept
+{
+ Q_ASSERT(!isEmpty());
+ d.detach();
+ d->eraseLast();
+}
+
+
+template<typename T>
+inline T QList<T>::value(qsizetype i, parameter_type defaultValue) const
+{
+ return size_t(i) < size_t(d->size) ? at(i) : defaultValue;
+}
+
+template <typename T>
+inline void QList<T>::append(const_iterator i1, const_iterator 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);
+
+ // 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());
+}
+
template<typename T>
-using QMutableListIterator = QMutableVectorIterator<T>;
+template<typename... Args>
+inline typename QList<T>::reference QList<T>::emplaceFront(Args &&... args)
+{
+ d->emplace(0, std::forward<Args>(args)...);
+ return *d.begin();
+}
+
+
+template <typename T>
+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");
+ Q_ASSERT_X(n >= 0, "QList::insert", "invalid count");
+ if (Q_LIKELY(n))
+ d->insert(i, n, t);
+ return begin() + i;
+}
+
+template <typename T>
+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");
+ d->emplace(i, std::forward<Args>(args)...);
+ return begin() + i;
+}
+
template<typename T>
-using QListIterator = QVectorIterator<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>
+typename QList<T>::iterator QList<T>::erase(const_iterator abegin, const_iterator aend)
+{
+ Q_ASSERT_X(isValidIterator(abegin), "QList::erase", "The specified iterator argument 'abegin' is invalid");
+ Q_ASSERT_X(isValidIterator(aend), "QList::erase", "The specified iterator argument 'aend' is invalid");
+ Q_ASSERT(aend >= abegin);
+
+ qsizetype i = std::distance(constBegin(), abegin);
+ qsizetype n = std::distance(abegin, aend);
+ remove(i, n);
+
+ return begin() + i;
+}
+
+template <typename T>
+inline QList<T> &QList<T>::fill(parameter_type t, qsizetype newSize)
+{
+ if (newSize == -1)
+ newSize = size();
+ if (d->needsDetach() || newSize > capacity()) {
+ // must allocate memory
+ 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()) {
+ d->copyAppend(newSize - size(), copy);
+ } else if (newSize < size()) {
+ d->truncate(newSize);
+ }
+ }
+ return *this;
+}
+
+namespace QtPrivate {
+template <typename T, typename U>
+qsizetype indexOf(const QList<T> &vector, const U &u, qsizetype from) noexcept
+{
+ if (from < 0)
+ from = qMax(from + vector.size(), qsizetype(0));
+ if (from < vector.size()) {
+ auto n = vector.begin() + from - 1;
+ auto e = vector.end();
+ while (++n != e)
+ if (*n == u)
+ return qsizetype(n - vector.begin());
+ }
+ return -1;
+}
+
+template <typename T, typename U>
+qsizetype lastIndexOf(const QList<T> &vector, const U &u, qsizetype from) noexcept
+{
+ if (from < 0)
+ from += vector.d->size;
+ else if (from >= vector.size())
+ from = vector.size() - 1;
+ if (from >= 0) {
+ auto b = vector.begin();
+ auto n = vector.begin() + from + 1;
+ while (n != b) {
+ if (*--n == u)
+ return qsizetype(n - b);
+ }
+ }
+ return -1;
+}
+}
+
+template <typename T>
+template <typename AT>
+qsizetype QListSpecialMethodsBase<T>::indexOf(const AT &t, qsizetype from) const noexcept
+{
+ return QtPrivate::indexOf(*self(), t, from);
+}
+
+template <typename T>
+template <typename AT>
+qsizetype QListSpecialMethodsBase<T>::lastIndexOf(const AT &t, qsizetype from) const noexcept
+{
+ return QtPrivate::lastIndexOf(*self(), t, from);
+}
+
+template <typename T>
+inline QList<T> QList<T>::mid(qsizetype pos, qsizetype len) const
+{
+ qsizetype p = pos;
+ qsizetype l = len;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(d.size, &p, &l)) {
+ case QContainerImplHelper::Null:
+ case QContainerImplHelper::Empty:
+ return QList();
+ case QContainerImplHelper::Full:
+ return *this;
+ case QContainerImplHelper::Subset:
+ break;
+ }
+
+ // Allocate memory
+ DataPointer copied(l);
+ copied->copyAppend(data() + p, data() + p + l);
+ return copied;
+}
+
+Q_DECLARE_SEQUENTIAL_ITERATOR(List)
+Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(List)
+
+template <typename T>
+size_t qHash(const QList<T> &key, size_t seed = 0)
+ noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
+{
+ return qHashRange(key.cbegin(), key.cend(), seed);
+}
+
+template <typename T, typename AT>
+qsizetype erase(QList<T> &list, const AT &t)
+{
+ return QtPrivate::sequential_erase(list, t);
+}
+
+template <typename T, typename Predicate>
+qsizetype erase_if(QList<T> &list, Predicate pred)
+{
+ return QtPrivate::sequential_erase_if(list, pred);
+}
+
+// ### Qt 7 char32_t
+QList<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); }
+
QT_END_NAMESPACE
-#endif
#include <QtCore/qbytearraylist.h>
#include <QtCore/qstringlist.h>
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
new file mode 100644
index 0000000000..e07b74cd53
--- /dev/null
+++ b/src/corelib/tools/qlist.qdoc
@@ -0,0 +1,1629 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \class QVector
+ \inmodule QtCore
+ \brief QVector is an alias for QList.
+
+ Please see the QList documentation for details.
+*/
+
+/*!
+ \class QList
+ \inmodule QtCore
+ \brief The QList class is a template class that provides a dynamic array.
+
+ \ingroup tools
+ \ingroup shared
+
+ \reentrant
+
+ QList\<T\> is one of Qt's generic \l{container classes}. It
+ stores its items in adjacent memory locations and provides fast
+ index-based access. QVector\<T\> used to be a different class in
+ Qt 5, but is now a simple alias to QList.
+
+ QList\<T\> and QVarLengthArray\<T\>
+ provide similar APIs and functionality. They are often interchangeable,
+ but there are performance consequences. Here is an overview of use cases:
+
+ \list
+ \li QList should be your default first choice.
+ \li QVarLengthArray provides an array that reserves space on the stack,
+ but can dynamically grow onto the heap if required. It's good to
+ use for short lived containers that are usually small.
+ \li If you need a real linked list, which guarantees
+ \l{Algorithmic Complexity}{constant time} insertions mid-list and
+ uses iterators to items rather than indexes, use std::list.
+ \endlist
+
+ \note QList and QVarLengthArray both guarantee C-compatible
+ array layout.
+ \note QList in Qt 5 did not always have a C-compatible array layout and
+ we often recommended to use QVector instead for more predictable
+ performance. This is not the case in Qt 6 anymore, where both classes
+ now share an implementation and can be used interchangeably.
+
+ Here's an example of a QList that stores integers and a QList
+ that stores QString values:
+
+ \snippet code/src_corelib_tools_qlist.cpp 0
+
+ QList stores its items in an array of continuous memory. Typically, lists
+ are created with an initial size. For example, the following code
+ constructs a QList with 200 elements:
+
+ \snippet code/src_corelib_tools_qlist.cpp 1
+
+ The elements are automatically initialized with a
+ \l{default-constructed value}. If you want to initialize the
+ list with a different value, pass that value as the second
+ argument to the constructor:
+
+ \snippet code/src_corelib_tools_qlist.cpp 2
+
+ You can also call fill() at any time to fill the list with a
+ value.
+
+ QList uses 0-based indexes, just like C++ arrays. To access the
+ item at a particular index position, you can use operator[](). On
+ non-const lists, operator[]() returns a reference to the item
+ that can be used on the left side of an assignment:
+
+ \snippet code/src_corelib_tools_qlist.cpp 3
+
+ For read-only access, an alternative syntax is to use at():
+
+ \snippet code/src_corelib_tools_qlist.cpp 4
+
+ at() can be faster than operator[](), because it never causes a
+ \l{deep copy} to occur.
+
+ Another way to access the data stored in a QList is to call
+ data(). The function returns a pointer to the first item in the
+ list. You can use the pointer to directly access and modify the
+ elements stored in the list. The pointer is also useful if you
+ need to pass a QList to a function that accepts a plain C++
+ array.
+
+ If you want to find all occurrences of a particular value in a
+ list, use indexOf() or lastIndexOf(). The former searches
+ forward starting from a given index position, the latter searches
+ backward. Both return the index of the matching item if they found
+ one; otherwise, they return -1. For example:
+
+ \snippet code/src_corelib_tools_qlist.cpp 5
+
+ If you simply want to check whether a list contains a
+ particular value, use contains(). If you want to find out how
+ many times a particular value occurs in the list, use count().
+
+ QList provides these basic functions to add, move, and remove
+ items: insert(), replace(), remove(), prepend(), append(). With the
+ exception of append(), prepend() and replace(), these functions can be slow
+ (\l{linear time}) for large lists, because they require moving many items in
+ the list by one position in memory. If you want a container class that
+ provides fast insertion/removal in the middle, use std::list instead.
+
+ Unlike plain C++ arrays, QLists can be resized at any time by
+ calling resize(). If the new size is larger than the old size,
+ QList might need to reallocate the whole list. QList tries
+ to reduce the number of reallocations by preallocating up to twice
+ as much memory as the actual data needs.
+
+ 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, 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
+ won't let you, for example, store a QWidget as a value; instead,
+ store a QWidget *. A few functions have additional requirements;
+ for example, indexOf() and lastIndexOf() expect the value type to
+ support \c operator==(). These requirements are documented on a
+ per-function basis.
+
+ 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.
+
+ \section2 More Information on Using Qt Containers
+
+ For a detailed discussion comparing Qt containers with each other and
+ with STL containers, see \l {Understand the Qt Containers}.
+
+ \section1 Maximum size and out-of-memory conditions
+
+ 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.
+
+ 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.
+
+ Note that the operating system may impose further limits on applications
+ holding a lot of allocated memory, especially large, contiguous blocks.
+ Such considerations, the configuration of such behavior or any mitigation
+ are outside the scope of the Qt API.
+*/
+
+/*!
+ \fn template <typename T> QList<T> QList<T>::mid(qsizetype pos, qsizetype length = -1) const
+
+ Returns a sub-list which contains elements from this list,
+ starting at position \a pos. If \a length is -1 (the default), all
+ elements after \a pos are included; otherwise \a length elements (or
+ all remaining elements if there are less than \a length elements)
+ are included.
+*/
+
+/*!
+ \fn template <typename T> QList<T> QList<T>::first(qsizetype n) const
+ \since 6.0
+
+ Returns a sub-list that contains the first \a n elements
+ of this list.
+
+ \note The behavior is undefined when \a n < 0 or \a n > size().
+
+ \sa last(), sliced()
+*/
+
+/*!
+ \fn template <typename T> QList<T> QList<T>::last(qsizetype n) const
+ \since 6.0
+
+ Returns a sub-list that contains the last \a n elements of this list.
+
+ \note The behavior is undefined when \a n < 0 or \a n > size().
+
+ \sa first(), sliced()
+*/
+
+/*!
+ \fn template <typename T> QList<T> QList<T>::sliced(qsizetype pos, qsizetype n) const
+ \since 6.0
+
+ Returns a sub-list that contains \a n elements of this list,
+ starting at position \a pos.
+
+ \note The behavior is undefined when \a pos < 0, \a n < 0,
+ or \a pos + \a n > size().
+
+ \sa first(), last()
+*/
+
+/*!
+ \fn template <typename T> QList<T> QList<T>::sliced(qsizetype pos) const
+ \since 6.0
+ \overload
+
+ Returns a sub-list that contains the elements of this list starting at
+ position \a pos and extending to its end.
+
+ \note The behavior is undefined when \a pos < 0 or \a pos > size().
+
+ \sa first(), last()
+*/
+
+
+/*! \fn template <typename T> QList<T>::QList()
+
+ Constructs an empty list.
+
+ \sa resize()
+*/
+
+/*!
+ \fn template <typename T> QList<T>::QList(QList<T> &&other)
+
+ Move-constructs a QList instance, making it point at the same
+ object that \a other was pointing to.
+
+ \since 5.2
+*/
+
+/*! \fn template <typename T> QList<T>::QList(qsizetype size)
+
+ Constructs a list with an initial size of \a size elements.
+
+ The elements are initialized with a \l{default-constructed
+ value}.
+
+ \sa resize()
+*/
+
+/*! \fn template <typename T> QList<T>::QList(qsizetype size, Qt::Initialization)
+ \since 6.8
+
+ Constructs a list with an initial size of \a size elements.
+
+ QList will make an attempt at \b{not initializing} the elements.
+
+//! [qlist-uninitialized-strategy]
+ Specifically:
+
+ \list
+
+ \li if \c{T} has a constructor that accepts \c{Qt::Uninitialized},
+ that constructor will be used to initialize the elements;
+
+ \li otherwise, each element is default constructed. For
+ trivially constructible types (such as \c{int}, \c{float}, etc.)
+ this is equivalent to not initializing them.
+
+ \endlist
+//! [qlist-uninitialized-strategy]
+
+ \sa resizeForOverwrite()
+*/
+
+/*! \fn template <typename T> QList<T>::QList(qsizetype size, parameter_type value)
+
+ Constructs a list with an initial size of \a size elements.
+ Each element is initialized with \a value.
+
+ \sa resize(), fill()
+*/
+
+/*! \fn template <typename T> QList<T>::QList(const QList<T> &other)
+
+ Constructs a copy of \a other.
+
+ This operation takes \l{Algorithmic Complexity}{constant time},
+ because QList is \l{implicitly shared}. This makes returning
+ a QList from a function very fast. If a shared instance is
+ modified, it will be copied (copy-on-write), and that takes
+ \l{Algorithmic Complexity}{linear time}.
+
+ \sa operator=()
+*/
+
+/*! \fn template <typename T> QList<T>::QList(std::initializer_list<T> args)
+ \since 4.8
+
+ Constructs a list from the std::initializer_list given by \a args.
+*/
+
+/*! \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.
+*/
+
+/*! \fn template <typename T> QList<T>::~QList()
+
+ Destroys the list.
+*/
+
+/*! \fn template <typename T> QList<T> &QList<T>::operator=(const QList<T> &other)
+
+ Assigns \a other to this list and returns a reference to this
+ list.
+*/
+
+/*!
+ \fn template <typename T> QList<T> &QList<T>::operator=(QList<T> &&other)
+
+ Move-assigns \a other to this QList instance.
+
+ \since 5.2
+*/
+
+/*!
+ \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.
+*/
+
+/*! \fn template <typename T> void QList<T>::swap(QList<T> &other)
+ \since 4.8
+
+ Swaps list \a other with this list. This operation is very fast and
+ never fails.
+*/
+
+/*! \fn template <typename T> void QList<T>::swapItemsAt(qsizetype i, qsizetype j)
+
+ Exchange the item at index position \a i with the item at index
+ position \a j. This function assumes that both \a i and \a j are
+ at least 0 but less than size(). To avoid failure, test that both
+ \a i and \a j are at least 0 and less than size().
+*/
+
+
+/*! \fn template <typename T> bool QList<T>::operator==(const QList<T> &other) const
+
+ Returns \c true if \a other is equal to this list; otherwise
+ returns \c false.
+
+ Two lists are considered equal if they contain the same values
+ in the same order.
+
+ This function requires the value type to have an implementation
+ of \c operator==().
+
+ \sa operator!=()
+*/
+
+/*! \fn template <typename T> bool QList<T>::operator!=(const QList<T> &other) const
+
+ Returns \c true if \a other is not equal to this list; otherwise
+ returns \c false.
+
+ Two lists are considered equal if they contain the same values
+ in the same order.
+
+ This function requires the value type to have an implementation
+ of \c operator==().
+
+ \sa operator==()
+*/
+
+/*! \fn template <typename T> bool QList<T>::operator<(const QList<T> &other) const
+ \since 5.6
+
+ Returns \c true if this list is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {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 QList<T>::operator<=(const QList<T> &other) const
+ \since 5.6
+
+ Returns \c true if this list is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {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 QList<T>::operator>(const QList<T> &other) const
+ \since 5.6
+
+ Returns \c true if this list is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {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 QList<T>::operator>=(const QList<T> &other) const
+ \since 5.6
+
+ Returns \c true if this list is
+ \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
+ {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<().
+*/
+
+/*!
+ \fn template <typename T> size_t qHash(const QList<T> &key, size_t seed = 0)
+ \since 5.6
+ \relates QList
+
+ Returns the hash value for \a key,
+ using \a seed to seed the calculation.
+
+ This function requires qHash() to be overloaded for the value type \c T.
+*/
+
+/*! \fn template <typename T> qsizetype QList<T>::size() const
+
+ Returns the number of items in the list.
+
+ \sa isEmpty(), resize()
+*/
+
+/*! \fn template <typename T> bool QList<T>::isEmpty() const
+
+ Returns \c true if the list has size 0; otherwise returns \c false.
+
+ \sa size(), resize()
+*/
+
+/*! \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 either a \l{default-constructed value} or \a c. If \a size
+ is less than the current size, elements are removed from the end.
+
+ 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
+ list without forcing a reallocation.
+
+ The sole purpose of this function is to provide a means of fine
+ tuning QList's memory usage. In general, you will rarely ever
+ need to call this function. If you want to know how many items are
+ in the list, call size().
+
+ \note a statically allocated list will report a capacity of 0,
+ even if it's not empty.
+
+ \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. If you resize
+ the list often, you are also likely to get better performance.
+
+ 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 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(), resize()
+*/
+
+/*! \fn template <typename T> void QList<T>::squeeze()
+
+ Releases any memory not required to store the items.
+
+ The sole purpose of this function is to provide a means of fine
+ tuning QList's memory usage. In general, you will rarely ever
+ need to call this function.
+
+ \sa reserve(), capacity()
+*/
+
+/*! \fn template <typename T> void QList<T>::detach()
+
+ \internal
+*/
+
+/*! \fn template <typename T> bool QList<T>::isDetached() const
+
+ \internal
+*/
+
+/*! \fn template <typename T> void QList<T>::setSharable(bool sharable)
+
+ \internal
+*/
+
+/*! \fn template <typename T> bool QList<T>::isSharedWith(const QList<T> &other) const
+
+ \internal
+*/
+
+/*! \fn template <typename T> T *QList<T>::data()
+
+ Returns a pointer to the data stored in the list. The pointer
+ can be used to access and modify the items in the list.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 6
+
+ \warning The pointer is invalidated on detachment or when the QList is
+ modified.
+
+ This function is mostly useful to pass a list to a function
+ that accepts a plain C++ array.
+
+ \sa constData(), operator[]()
+*/
+
+/*! \fn template <typename T> const T *QList<T>::data() const
+
+ \overload
+*/
+
+/*! \fn template <typename T> const T *QList<T>::constData() const
+
+ Returns a const pointer to the data stored in the list. The
+ pointer can be used to access the items in the list.
+
+ \warning The pointer is invalidated on detachment or when the QList is
+ modified.
+
+ This function is mostly useful to pass a list to a function
+ that accepts a plain C++ array.
+
+ \sa data(), operator[]()
+*/
+
+/*! \fn template <typename T> void QList<T>::clear()
+
+ Removes all the elements from the list.
+
+ If this list is not shared, the capacity() is preserved. Use squeeze() to
+ shed excess capacity.
+
+ \note In Qt versions prior to 5.7 (for QVector) and 6.0 (for QList), this
+ function released the memory used by the list instead of preserving the
+ capacity.
+
+ \sa resize(), squeeze()
+*/
+
+/*! \fn template <typename T> const T &QList<T>::at(qsizetype i) const
+
+ Returns the item at index position \a i in the list.
+
+ \a i must be a valid index position in the list (i.e., 0 <= \a
+ i < size()).
+
+ \sa value(), operator[]()
+*/
+
+/*! \fn template <typename T> T &QList<T>::operator[](qsizetype i)
+
+ Returns the item at index position \a i as a modifiable reference.
+
+ \a i must be a valid index position in the list (i.e., 0 <= \a i
+ < size()).
+
+ Note that using non-const operators can cause QList to do a deep
+ copy.
+
+ \sa at(), value()
+*/
+
+/*! \fn template <typename T> const T &QList<T>::operator[](qsizetype i) const
+
+ \overload
+
+ Same as at(\a i).
+*/
+
+/*!
+ \fn template <typename T> void QList<T>::append(parameter_type value)
+
+ Inserts \a value at the end of the list.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 7
+
+ This is the same as calling resize(size() + 1) and assigning \a
+ value to the new last element in the list.
+
+ This operation is relatively fast, because QList typically
+ allocates more memory than necessary, so it can grow without
+ reallocating the entire list each time.
+
+ \sa operator<<(), prepend(), insert()
+*/
+
+/*!
+ \fn template <typename T> void QList<T>::append(rvalue_ref value)
+ \since 5.6
+
+ \overload
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp move-append
+*/
+
+/*! \fn template <typename T> void QList<T>::append(const QList<T> &value)
+
+ \overload
+
+ \since 5.5
+
+ Appends the items of the \a value list to this list.
+
+ \sa operator<<(), operator+=()
+*/
+
+/*! \fn template <typename T> void QList<T>::append(QList<T> &&value)
+ \overload
+
+ \since 6.0
+
+ Moves the items of the \a value list to the end of this list.
+
+ \sa operator<<(), operator+=()
+*/
+
+/*!
+ \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.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 8
+
+ This is the same as list.insert(0, \a value).
+
+ 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()
+*/
+
+/*!
+ \fn template <typename T> template <typename ...Args> T &QList<T>::emplaceBack(Args&&... args)
+ \fn template <typename T> template <typename ...Args> T &QList<T>::emplace_back(Args&&... args)
+
+ Adds a new element to the end for the container. This new element
+ is constructed in-place using \a args as the arguments for its
+ construction.
+
+ Returns a reference to the new element.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp emplace-back
+
+ It is also possible to access a newly created object by using
+ returned reference:
+ \snippet code/src_corelib_tools_qlist.cpp emplace-back-ref
+
+ This is the same as list.emplace(list.size(), \a args).
+
+ \sa emplace
+*/
+
+/*! \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
+ value is appended to the list.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 9
+
+ For large lists, this operation can be slow (\l{linear time}),
+ because it requires moving all the items at indexes \a i and
+ above by one position further in memory. If you want a container
+ class that provides a fast insert() function, use std::list
+ instead.
+
+ \sa append(), prepend(), remove()
+*/
+
+/*! \fn template <typename T> void QList<T>::insert(qsizetype i, qsizetype count, parameter_type value)
+
+ \overload
+
+ Inserts \a count copies of \a value at index position \a i in the
+ list.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 10
+*/
+
+/*! \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
+
+ Inserts \a value in front of the item pointed to by the iterator
+ \a before. Returns an iterator pointing at the inserted item.
+*/
+
+/*! \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
+ first of the inserted items.
+*/
+
+/*!
+ \fn template <typename T> template <typename ...Args> QList<T>::iterator QList<T>::emplace(qsizetype i, Args&&... args)
+
+ Extends the container by inserting a new element at position \a i.
+ This new element is constructed in-place using \a args as the
+ arguments for its construction.
+
+ Returns an iterator to the new element.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp emplace
+
+ \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.
+
+ \sa emplaceBack
+*/
+
+
+/*! \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.
+
+ \a i must be a valid index position in the list (i.e., 0 <= \a
+ i < size()).
+
+ \sa operator[](), remove()
+*/
+
+/*! \fn template <typename T> void QList<T>::remove(qsizetype i, qsizetype n = 1)
+
+ Removes \a n elements from the list, starting at index position \a i.
+
+//! [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}, this function only
+ invalidates iterators at or after the specified position.
+//! [iterator-invalidation-erase]
+
+ \sa insert(), replace(), fill()
+*/
+
+/*! \fn template <typename T> void QList<T>::removeAt(qsizetype i)
+ \since 5.2
+
+ Removes the element at index position \a i.
+ Equivalent to
+ \code
+ remove(i);
+ \endcode
+
+ \include qlist.qdoc shrinking-erase
+ \include qlist.qdoc iterator-invalidation-erase
+
+ \sa remove()
+*/
+
+/*! \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.
+
+ \include qlist.qdoc shrinking-erase
+
+ \sa removeOne()
+*/
+
+/*! \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.
+
+ \include qlist.qdoc shrinking-erase
+
+ \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
+ \since 5.2
+
+ Same as size() and count().
+
+ \sa size(), count()
+*/
+
+/*! \fn template <typename T> T QList<T>::takeAt(qsizetype i)
+ \since 5.2
+
+ Removes the element at index position \a i and returns it.
+
+ Equivalent to
+ \code
+ T t = at(i);
+ remove(i);
+ return t;
+ \endcode
+
+ \include qlist.qdoc iterator-invalidation-erase
+
+ \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.
+*/
+
+/*! \fn template <typename T> void QList<T>::removeFirst()
+ \since 5.1
+ Removes the first item in the list. Calling this function is
+ equivalent to calling remove(0). The list must not be empty. If
+ the list can be empty, call isEmpty() before calling this
+ function.
+
+ \include qlist.qdoc shrinking-erase
+
+ \sa remove(), takeFirst(), isEmpty()
+*/
+
+/*! \fn template <typename T> void QList<T>::removeLast()
+ \since 5.1
+ Removes the last item in the list. Calling this function is
+ equivalent to calling remove(size() - 1). The list must not be
+ empty. If the list can be empty, call isEmpty() before calling
+ this function.
+
+ \include qlist.qdoc shrinking-erase
+
+ \sa remove(), takeLast(), removeFirst(), isEmpty()
+*/
+
+/*! \fn template <typename T> T QList<T>::takeFirst()
+ \since 5.1
+
+ Removes the first item in the list and returns it. This function
+ assumes the list is not empty. To avoid failure, call isEmpty()
+ before calling this function.
+
+ \sa takeLast(), removeFirst()
+*/
+
+/*! \fn template <typename T> T QList<T>::takeLast()
+ \since 5.1
+
+ Removes the last item in the list and returns it. This function
+ assumes the list is not empty. To avoid failure, call isEmpty()
+ before calling this function.
+
+ If you don't use the return value, removeLast() is more
+ efficient.
+
+ \sa takeFirst(), removeLast()
+*/
+
+/*!
+ \fn template <typename T> template <typename ...Args> QList<T>::iterator QList<T>::emplace(const_iterator before, Args&&... args)
+
+ \overload
+
+ Creates a new element in front of the item pointed to by the
+ iterator \a before. This new element is constructed in-place
+ using \a args as the arguments for its construction.
+
+ Returns an iterator to the new element.
+*/
+
+/*! \fn template <typename T> 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 \a size beforehand.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 11
+
+ \sa resize()
+*/
+
+/*! \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.
+ Returns -1 if no item matched.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 12
+
+ This function requires the value type to have an implementation of
+ \c operator==().
+
+ \sa lastIndexOf(), contains()
+*/
+
+/*! \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
+ from. If \a from is -1 (the default), the search starts at the
+ last item. Returns -1 if no item matched.
+
+ Example:
+ \snippet code/src_corelib_tools_qlist.cpp 13
+
+ This function requires the value type to have an implementation of
+ \c operator==().
+
+ \sa indexOf()
+*/
+
+/*! \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.
+
+ This function requires the value type to have an implementation of
+ \c operator==().
+
+ \sa indexOf(), count()
+*/
+
+/*! \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
+ item is equal to \a value; otherwise returns \c false.
+
+ \sa isEmpty(), first()
+*/
+
+/*! \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
+ item is equal to \a value; otherwise returns \c false.
+
+ \sa isEmpty(), last()
+*/
+
+
+/*! \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.
+
+ This function requires the value type to have an implementation of
+ \c operator==().
+
+ \sa contains(), indexOf()
+*/
+
+/*! \fn template <typename T> qsizetype QList<T>::count() const
+
+ \overload
+
+ Same as size().
+*/
+
+/*! \fn template <typename T> QList<T>::iterator QList<T>::begin()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the
+ first item in the list.
+
+//! [iterator-invalidation-func-desc]
+ \warning The returned iterator is invalidated on detachment or when the
+ QList is modified.
+//! [iterator-invalidation-func-desc]
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn template <typename T> QList<T>::const_iterator QList<T>::begin() const
+
+ \overload
+*/
+
+/*! \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.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa begin(), cend()
+*/
+
+/*! \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.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <typename T> QList<T>::iterator QList<T>::end()
+
+ 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
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <typename T> QList<T>::const_iterator QList<T>::end() const
+
+ \overload
+*/
+
+/*! \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 just
+ after the last item in the list.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa cbegin(), end()
+*/
+
+/*! \fn template <typename T> QList<T>::const_iterator QList<T>::constEnd() const
+
+ 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
+
+ \sa constBegin(), end()
+*/
+
+/*! \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.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa begin(), crbegin(), rend()
+*/
+
+/*! \fn template <typename T> QList<T>::const_reverse_iterator QList<T>::rbegin() const
+ \since 5.6
+ \overload
+*/
+
+/*! \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.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa begin(), rbegin(), rend()
+*/
+
+/*! \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 just
+ after the last item in the list, in reverse order.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa end(), crend(), rbegin()
+*/
+
+/*! \fn template <typename T> QList<T>::const_reverse_iterator QList<T>::rend() const
+ \since 5.6
+ \overload
+*/
+
+/*! \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
+ just after the last item in the list, in reverse order.
+
+ \include qlist.qdoc iterator-invalidation-func-desc
+
+ \sa end(), rend(), rbegin()
+*/
+
+/*! \fn template <typename T> QList<T>::iterator QList<T>::erase(const_iterator pos)
+
+ Removes the item pointed to by the iterator \a pos from the
+ list, and returns an iterator to the next item in the list
+ (which may be end()).
+
+ \include qlist.qdoc shrinking-erase
+ \include qlist.qdoc iterator-invalidation-erase
+
+ \sa insert(), remove()
+*/
+
+/*! \fn template <typename T> QList<T>::iterator QList<T>::erase(const_iterator begin, const_iterator end)
+
+ \overload
+
+ Removes all the items from \a begin up to (but not including) \a
+ end. Returns an iterator to the same item that \a end referred to
+ before the call.
+
+ \include qlist.qdoc shrinking-erase
+ \include qlist.qdoc iterator-invalidation-erase
+*/
+
+/*! \fn template <typename T> T& QList<T>::first()
+
+ Returns a reference to the first item in the list. This
+ function assumes that the list isn't empty.
+
+ \sa last(), isEmpty(), constFirst()
+*/
+
+/*! \fn template <typename T> const T& QList<T>::first() const
+
+ \overload
+*/
+
+/*! \fn template <typename T> const T& QList<T>::constFirst() const
+ \since 5.6
+
+ Returns a const reference to the first item in the list. This
+ function assumes that the list isn't empty.
+
+ \sa constLast(), isEmpty(), first()
+*/
+
+/*! \fn template <typename T> T& QList<T>::last()
+
+ Returns a reference to the last item in the list. This function
+ assumes that the list isn't empty.
+
+ \sa first(), isEmpty(), constLast()
+*/
+
+/*! \fn template <typename T> const T& QList<T>::last() const
+
+ \overload
+*/
+
+/*! \fn template <typename T> const T& QList<T>::constLast() const
+ \since 5.6
+
+ Returns a const reference to the last item in the list. This function
+ assumes that the list isn't empty.
+
+ \sa constFirst(), isEmpty(), last()
+*/
+
+/*! \fn template <typename T> T QList<T>::value(qsizetype i) const
+
+ Returns the value at index position \a i in the list.
+
+ If the index \a i is out of bounds, the function returns a
+ \l{default-constructed value}. If you are certain that \a i is within
+ bounds, you can use at() instead, which is slightly faster.
+
+ \sa at(), operator[]()
+*/
+
+/*! \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(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(rvalue_ref value)
+ \since 5.6
+ \overload
+*/
+
+/*!
+ \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).
+*/
+
+/*! \fn template <typename T> void QList<T>::pop_front()
+
+ This function is provided for STL compatibility. It is equivalent
+ to removeFirst().
+*/
+
+/*! \fn template <typename T> void QList<T>::pop_back()
+
+ This function is provided for STL compatibility. It is equivalent
+ to removeLast().
+*/
+
+/*! \fn template <typename T> T& QList<T>::front()
+
+ This function is provided for STL compatibility. It is equivalent
+ to first().
+*/
+
+/*! \fn template <typename T> QList<T>::const_reference QList<T>::front() const
+
+ \overload
+*/
+
+/*! \fn template <typename T> QList<T>::reference QList<T>::back()
+
+ This function is provided for STL compatibility. It is equivalent
+ to last().
+*/
+
+/*! \fn template <typename T> QList<T>::const_reference QList<T>::back() const
+
+ \overload
+*/
+
+/*! \fn template <typename T> void QList<T>::shrink_to_fit()
+ \since 5.10
+
+ This function is provided for STL compatibility. It is equivalent
+ to squeeze().
+*/
+
+/*! \fn template <typename T> bool QList<T>::empty() const
+
+ This function is provided for STL compatibility. It is equivalent
+ to isEmpty(), returning \c true if the list is empty; otherwise
+ 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
+ returns a reference to this list.
+
+ \sa operator+(), append()
+*/
+
+/*! \fn template <typename T> QList<T> &QList<T>::operator+=(QList<T> &&other)
+ \since 6.0
+
+ \overload
+
+ \sa operator+(), append()
+*/
+
+/*! \fn template <typename T> void QList<T>::operator+=(parameter_type value)
+
+ \overload
+
+ Appends \a value to the list.
+
+ \sa append(), operator<<()
+*/
+
+/*! \fn template <typename T> void QList<T>::operator+=(rvalue_ref value)
+ \since 5.11
+
+ \overload
+
+ \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) &&
+ \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.
+
+ \sa operator+=()
+*/
+
+/*! \fn template <typename T> QList<T> &QList<T>::operator<<(parameter_type value)
+
+ Appends \a value to the list and returns a reference to this list.
+
+ \sa append(), operator+=()
+*/
+
+/*! \fn template <typename T> QList<T> &QList<T>::operator<<(rvalue_ref value)
+ \since 5.11
+
+ \overload
+
+ \sa append(), operator+=()
+*/
+
+
+/*! \fn template <typename T> QList<T> &QList<T>::operator<<(const QList<T> &other)
+
+ Appends \a other to the list and returns a reference to the list.
+*/
+
+/*! \fn template <typename T> QList<T> &QList<T>::operator<<(QList<T> &&other)
+ \since 6.0
+
+ \overload
+*/
+
+/*! \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}.
+
+//! [iterator-invalidation-class-desc]
+ \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}.
+
+ \warning Iterators are invalidated when QList is modified. Consider that all
+ iterators are invalidated by default. Exceptions to this rule are explicitly
+ documented.
+//! [iterator-invalidation-class-desc]
+
+ \sa QList::begin(), QList::end(), QList::const_iterator, QMutableListIterator
+*/
+
+/*! \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}.
+
+ \include qlist.qdoc iterator-invalidation-class-desc
+
+ \sa QList::constBegin(), QList::constEnd(), QList::iterator, QListIterator
+*/
+
+/*! \typedef QList::reverse_iterator
+ \since 5.6
+
+ The QList::reverse_iterator typedef provides an STL-style non-const
+ reverse iterator for QList.
+
+ \include qlist.qdoc iterator-invalidation-class-desc
+
+ \sa QList::rbegin(), QList::rend(), QList::const_reverse_iterator, QList::iterator
+*/
+
+/*! \typedef QList::const_reverse_iterator
+ \since 5.6
+
+ The QList::const_reverse_iterator typedef provides an STL-style const
+ reverse iterator for QList.
+
+ \include qlist.qdoc iterator-invalidation-class-desc
+
+ \sa QList::rbegin(), QList::rend(), QList::reverse_iterator, QList::const_iterator
+*/
+
+/*! \typedef QList::Iterator
+
+ Qt-style synonym for QList::iterator.
+*/
+
+/*! \typedef QList::ConstIterator
+
+ Qt-style synonym for QList::const_iterator.
+*/
+
+/*! \typedef QList::const_pointer
+
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::const_reference
+
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::difference_type
+
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::pointer
+
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::reference
+
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::size_type
+
+ Provided for STL compatibility.
+*/
+
+/*! \typedef QList::value_type
+
+ 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
+ \deprecated
+
+ A no-op in Qt 6. Provided for backwards compatibility with
+ Qt 5, where QList and QVector where two different types.
+
+ Returns this list.
+*/
+
+/*! \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)
+ \deprecated
+
+ A no-op in Qt 6. Provided for backwards compatibility with
+ Qt 5, where QList and QVector were two different types.
+
+ Returns this list.
+*/
+
+/*! \fn template <typename T> QDataStream &operator<<(QDataStream &out, const QList<T> &list)
+ \relates QList
+
+ Writes the list \a list to stream \a out.
+
+ This function requires the value type to implement \c operator<<().
+
+ \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+*/
+
+/*! \fn template <typename T> QDataStream &operator>>(QDataStream &in, QList<T> &list)
+ \relates QList
+
+ Reads a list from stream \a in into \a list.
+
+ This function requires the value type to implement \c operator>>().
+
+ \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+*/
+
+/*! \fn template <typename T, typename AT> qsizetype erase(QList<T> &list, const AT &t)
+ \relates QList
+ \since 6.1
+
+ Removes all elements that compare equal to \a t from the
+ list \a list. Returns the number of elements removed, if any.
+
+ \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 QList::removeAll(), erase_if
+*/
+
+/*! \fn template <typename T, typename Predicate> qsizetype erase_if(QList<T> &list, Predicate pred)
+ \relates QList
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the list \a list. Returns the number of elements removed, if
+ any.
+
+ \sa erase
+*/
+
+/*! \fn template <typename T> QList<T>& QList<T>::assign(qsizetype n, parameter_type t)
+ \since 6.6
+
+ Replaces the contents of this list with \a n copies of \a t.
+
+ The size of this list will be equal to \a n.
+
+ This function will only allocate memory if \a n exceeds the capacity of the
+ list or this list is shared.
+*/
+
+/*! \fn template <typename T> template <typename InputIterator, QList<T>::if_input_iterator<InputIterator>> QList<T>& QList<T>::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this list with a copy of the elements in the
+ iterator range [\a first, \a last).
+
+ The size of this list will be equal to the number of elements in the
+ range [\a first, \a last).
+
+ This function will only allocate memory if the number of elements in the
+ range exceeds the capacity of this list or this list is shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
+ \note The behavior is undefined if either argument is an iterator into
+ *this.
+*/
+
+/*! \fn template <typename T> QList<T>& QList<T>::assign(std::initializer_list<T> l)
+ \since 6.6
+
+ Replaces the contents of this list with a copy of the elements of
+ \a l.
+
+ The size of this list will be equal to the number of elements in
+ \a l.
+
+ This function only allocates memory if the number of elements in \a l
+ exceeds the capacity of this list or this list is shared.
+*/
diff --git a/src/corelib/tools/qmakearray_p.h b/src/corelib/tools/qmakearray_p.h
index 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 f169ed5e49..7ee0be1e51 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -1,495 +1,569 @@
-/****************************************************************************
-**
-** 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>
#include <QtCore/qpair.h>
-
-#ifdef Q_MAP_DEBUG
-#include <QtCore/qdebug.h>
-#endif
+#include <QtCore/qshareddata.h>
+#include <QtCore/qshareddata_impl.h>
#include <functional>
#include <initializer_list>
#include <map>
-#include <new>
+#include <algorithm>
QT_BEGIN_NAMESPACE
-/*
- QMap uses qMapLessThanKey() to compare keys. The default
- implementation uses operator<(). For pointer types,
- qMapLessThanKey() uses std::less (because operator<() on
- pointers can be used only between pointers in the same array).
-*/
-
-template <class Key> inline bool qMapLessThanKey(const Key &key1, const Key &key2)
+// common code shared between QMap and QMultimap
+template <typename AMap>
+class QMapData : public QSharedData
{
- return key1 < key2;
-}
+public:
+ using Map = AMap;
+ using Key = typename Map::key_type;
+ using T = typename Map::mapped_type;
+ using value_type = typename Map::value_type;
+ using size_type = typename Map::size_type;
+ 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;
+ explicit QMapData(const Map &other)
+ : m(other)
+ {}
+
+ explicit QMapData(Map &&other)
+ : m(std::move(other))
+ {}
+
+ // used in remove(); copies from source all the values not matching key.
+ // returns how many were NOT copied (removed).
+ size_type copyIfNotEquivalentTo(const Map &source, const Key &key)
+ {
+ Q_ASSERT(m.empty());
+
+ size_type result = 0;
+ const auto &keyCompare = source.key_comp();
+ const auto filter = [&result, &key, &keyCompare](const auto &v)
+ {
+ if (!keyCompare(key, v.first) && !keyCompare(v.first, key)) {
+ // keys are equivalent (neither a<b nor b<a) => found it
+ ++result;
+ return true;
+ }
+ return false;
+ };
-template <class Ptr> inline bool qMapLessThanKey(const Ptr *key1, const Ptr *key2)
-{
- return std::less<const Ptr *>()(key1, key2);
-}
+ std::remove_copy_if(source.cbegin(), source.cend(),
+ std::inserter(m, m.end()),
+ filter);
+ return result;
+ }
-struct QMapDataBase;
-template <class Key, class T> struct QMapData;
+ // used in key(T), count(Key, T), find(key, T), etc; returns a
+ // comparator object suitable for algorithms with std::(multi)map
+ // iterators.
+ static auto valueIsEqualTo(const T &value)
+ {
+ return [&value](const auto &v) { return v.second == value; };
+ }
-struct Q_CORE_EXPORT QMapNodeBase
-{
- quintptr p;
- QMapNodeBase *left;
- QMapNodeBase *right;
-
- enum Color { Red = 0, Black = 1 };
- enum { Mask = 3 }; // reserve the second bit as well
-
- const QMapNodeBase *nextNode() const;
- QMapNodeBase *nextNode() { return const_cast<QMapNodeBase *>(const_cast<const QMapNodeBase *>(this)->nextNode()); }
- const QMapNodeBase *previousNode() const;
- QMapNodeBase *previousNode() { return const_cast<QMapNodeBase *>(const_cast<const QMapNodeBase *>(this)->previousNode()); }
-
- Color color() const { return Color(p & 1); }
- void setColor(Color c) { if (c == Black) p |= Black; else p &= ~Black; }
- QMapNodeBase *parent() const { return reinterpret_cast<QMapNodeBase *>(p & ~Mask); }
- void setParent(QMapNodeBase *pp) { p = (p & Mask) | quintptr(pp); }
-
- template <typename T>
- static typename std::enable_if<QTypeInfo<T>::isComplex>::type
- callDestructorIfNecessary(T &t) noexcept { Q_UNUSED(t); t.~T(); } // Q_UNUSED: silence MSVC unused 't' warning
- template <typename T>
- static typename std::enable_if<!QTypeInfo<T>::isComplex>::type
- callDestructorIfNecessary(T &) noexcept {}
-};
+ Key key(const T &value, const Key &defaultKey) const
+ {
+ auto i = std::find_if(m.cbegin(),
+ m.cend(),
+ valueIsEqualTo(value));
+ if (i != m.cend())
+ return i->first;
-template <class Key, class T>
-struct QMapNode : public QMapNodeBase
-{
- Key key;
- T value;
+ return defaultKey;
+ }
- inline QMapNode *leftNode() const { return static_cast<QMapNode *>(left); }
- inline QMapNode *rightNode() const { return static_cast<QMapNode *>(right); }
+ QList<Key> keys() const
+ {
+ QList<Key> result;
+ result.reserve(m.size());
- inline const QMapNode *nextNode() const { return reinterpret_cast<const QMapNode *>(QMapNodeBase::nextNode()); }
- inline const QMapNode *previousNode() const { return static_cast<const QMapNode *>(QMapNodeBase::previousNode()); }
- inline QMapNode *nextNode() { return reinterpret_cast<QMapNode *>(QMapNodeBase::nextNode()); }
- inline QMapNode *previousNode() { return static_cast<QMapNode *>(QMapNodeBase::previousNode()); }
+ const auto extractKey = [](const auto &v) { return v.first; };
- QMapNode<Key, T> *copy(QMapData<Key, T> *d) const;
+ std::transform(m.cbegin(),
+ m.cend(),
+ std::back_inserter(result),
+ extractKey);
+ return result;
+ }
- void destroySubTree()
+ QList<Key> keys(const T &value) const
{
- callDestructorIfNecessary(key);
- callDestructorIfNecessary(value);
- doDestroySubTree(std::integral_constant<bool, QTypeInfo<T>::isComplex || QTypeInfo<Key>::isComplex>());
+ QList<Key> result;
+ result.reserve(m.size());
+ // no std::transform_if...
+ for (const auto &v : m) {
+ if (v.second == value)
+ result.append(v.first);
+ }
+ result.shrink_to_fit();
+ return result;
}
- QMapNode<Key, T> *lowerBound(const Key &key);
- QMapNode<Key, T> *upperBound(const Key &key);
+ QList<T> values() const
+ {
+ QList<T> result;
+ result.reserve(m.size());
-private:
- void doDestroySubTree(std::false_type) {}
- void doDestroySubTree(std::true_type)
+ const auto extractValue = [](const auto &v) { return v.second; };
+
+ std::transform(m.cbegin(),
+ m.cend(),
+ std::back_inserter(result),
+ extractValue);
+ return result;
+ }
+
+ size_type count(const Key &key) const
{
- if (left)
- leftNode()->destroySubTree();
- if (right)
- rightNode()->destroySubTree();
+ return m.count(key);
}
- QMapNode() = delete;
- Q_DISABLE_COPY(QMapNode)
-};
+ // Used in erase. Allocates a new QMapData and copies, from this->m,
+ // the elements not in the [first, last) range. The return contains
+ // the new QMapData and an iterator in its map pointing at the first
+ // element after the erase.
+ struct EraseResult {
+ QMapData *data;
+ iterator it;
+ };
-template <class Key, class T>
-inline QMapNode<Key, T> *QMapNode<Key, T>::lowerBound(const Key &akey)
-{
- QMapNode<Key, T> *n = this;
- QMapNode<Key, T> *lastNode = nullptr;
- while (n) {
- if (!qMapLessThanKey(n->key, akey)) {
- lastNode = n;
- n = n->leftNode();
- } else {
- n = n->rightNode();
+ EraseResult erase(const_iterator first, const_iterator last) const
+ {
+ EraseResult result;
+ result.data = new QMapData;
+ result.it = result.data->m.end();
+ const auto newDataEnd = result.it;
+
+ auto i = m.begin();
+ const auto e = m.end();
+
+ // copy over all the elements before first
+ while (i != first) {
+ result.it = result.data->m.insert(newDataEnd, *i);
+ ++i;
}
+
+ // skip until last
+ while (i != last)
+ ++i;
+
+ // copy from last to the end
+ while (i != e) {
+ result.data->m.insert(newDataEnd, *i);
+ ++i;
+ }
+
+ if (result.it != newDataEnd)
+ ++result.it;
+
+ return result;
}
- return lastNode;
-}
+};
+
+//
+// QMap
+//
template <class Key, class T>
-inline QMapNode<Key, T> *QMapNode<Key, T>::upperBound(const Key &akey)
+class QMap
{
- QMapNode<Key, T> *n = this;
- QMapNode<Key, T> *lastNode = nullptr;
- while (n) {
- if (qMapLessThanKey(akey, n->key)) {
- lastNode = n;
- n = n->leftNode();
- } else {
- n = n->rightNode();
- }
- }
- return lastNode;
-}
+ using Map = std::map<Key, T>;
+ using MapData = QMapData<Map>;
+ QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
+ friend class QMultiMap<Key, T>;
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using difference_type = qptrdiff;
+ using size_type = qsizetype;
-struct Q_CORE_EXPORT QMapDataBase
-{
- QtPrivate::RefCount ref;
- int size;
- QMapNodeBase header;
- QMapNodeBase *mostLeftNode;
+ QMap() = default;
- void rotateLeft(QMapNodeBase *x);
- void rotateRight(QMapNodeBase *x);
- void rebalance(QMapNodeBase *x);
- void freeNodeAndRebalance(QMapNodeBase *z);
- void recalcMostLeftNode();
+ // implicitly generated special member functions are OK!
- QMapNodeBase *createNode(int size, int alignment, QMapNodeBase *parent, bool left);
- void freeTree(QMapNodeBase *root, int alignment);
+ void swap(QMap<Key, T> &other) noexcept
+ {
+ d.swap(other.d);
+ }
- static const QMapDataBase shared_null;
+ QMap(std::initializer_list<std::pair<Key, T>> list)
+ {
+ for (auto &p : list)
+ insert(p.first, p.second);
+ }
- static QMapDataBase *createData();
- static void freeData(QMapDataBase *d);
-};
+ explicit QMap(const std::map<Key, T> &other)
+ : d(other.empty() ? nullptr : new MapData(other))
+ {
+ }
-template <class Key, class T>
-struct QMapData : public QMapDataBase
-{
- typedef QMapNode<Key, T> Node;
-
- Node *root() const { return static_cast<Node *>(header.left); }
-
- // using reinterpret_cast because QMapDataBase::header is not
- // actually a QMapNode.
- const Node *end() const { return reinterpret_cast<const Node *>(&header); }
- Node *end() { return reinterpret_cast<Node *>(&header); }
- const Node *begin() const { if (root()) return static_cast<const Node*>(mostLeftNode); return end(); }
- Node *begin() { if (root()) return static_cast<Node*>(mostLeftNode); return end(); }
-
- void deleteNode(Node *z);
- Node *findNode(const Key &akey) const;
- void nodeRange(const Key &akey, Node **firstNode, Node **lastNode);
-
- Node *createNode(const Key &k, const T &v, Node *parent = nullptr, bool left = false)
- {
- Node *n = static_cast<Node *>(QMapDataBase::createNode(sizeof(Node), alignof(Node),
- parent, left));
- QT_TRY {
- new (&n->key) Key(k);
- QT_TRY {
- new (&n->value) T(v);
- } QT_CATCH(...) {
- n->key.~Key();
- QT_RETHROW;
- }
- } QT_CATCH(...) {
- QMapDataBase::freeNodeAndRebalance(n);
- QT_RETHROW;
- }
- return n;
+ explicit QMap(std::map<Key, T> &&other)
+ : d(other.empty() ? nullptr : new MapData(std::move(other)))
+ {
}
- static QMapData *create() {
- return static_cast<QMapData *>(createData());
+ std::map<Key, T> toStdMap() const &
+ {
+ if (d)
+ return d->m;
+ return {};
}
- void destroy() {
- if (root()) {
- root()->destroySubTree();
- freeTree(header.left, alignof(Node));
+ std::map<Key, T> toStdMap() &&
+ {
+ if (d) {
+ if (d.isShared())
+ return d->m;
+ else
+ return std::move(d->m);
}
- freeData(this);
+
+ return {};
}
-};
-template <class Key, class T>
-QMapNode<Key, T> *QMapNode<Key, T>::copy(QMapData<Key, T> *d) const
-{
- QMapNode<Key, T> *n = d->createNode(key, value);
- n->setColor(color());
- if (left) {
- n->left = leftNode()->copy(d);
- n->left->setParent(n);
- } else {
- n->left = nullptr;
- }
- if (right) {
- n->right = rightNode()->copy(d);
- n->right->setParent(n);
- } else {
- n->right = nullptr;
- }
- return n;
-}
+#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 <class Key, class T>
-void QMapData<Key, T>::deleteNode(QMapNode<Key, T> *z)
-{
- QMapNodeBase::callDestructorIfNecessary(z->key);
- QMapNodeBase::callDestructorIfNecessary(z->value);
- freeNodeAndRebalance(z);
-}
+ 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
-template <class Key, class T>
-QMapNode<Key, T> *QMapData<Key, T>::findNode(const Key &akey) const
-{
- if (Node *r = root()) {
- Node *lb = r->lowerBound(akey);
- if (lb && !qMapLessThanKey(akey, lb->key))
- return lb;
+ size_type size() const { return d ? size_type(d->m.size()) : size_type(0); }
+
+ bool isEmpty() const { return d ? d->m.empty() : true; }
+
+ void detach()
+ {
+ if (d)
+ d.detach();
+ else
+ d.reset(new MapData);
}
- return nullptr;
-}
+ bool isDetached() const noexcept
+ {
+ return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
+ }
-template <class Key, class T>
-void QMapData<Key, T>::nodeRange(const Key &akey, QMapNode<Key, T> **firstNode, QMapNode<Key, T> **lastNode)
-{
- Node *n = root();
- Node *l = end();
- while (n) {
- if (qMapLessThanKey(akey, n->key)) {
- l = n;
- n = n->leftNode();
- } else if (qMapLessThanKey(n->key, akey)) {
- n = n->rightNode();
- } else {
- *firstNode = n->leftNode() ? n->leftNode()->lowerBound(akey) : nullptr;
- if (!*firstNode)
- *firstNode = n;
- *lastNode = n->rightNode() ? n->rightNode()->upperBound(akey) : nullptr;
- if (!*lastNode)
- *lastNode = l;
+ bool isSharedWith(const QMap<Key, T> &other) const noexcept
+ {
+ return d == other.d; // also this makes little sense?
+ }
+
+ void clear()
+ {
+ if (!d)
return;
- }
+
+ if (!d.isShared())
+ d->m.clear();
+ else
+ d.reset();
}
- *firstNode = *lastNode = l;
-}
+ size_type remove(const Key &key)
+ {
+ if (!d)
+ return 0;
+
+ if (!d.isShared())
+ return size_type(d->m.erase(key));
-template <class Key, class T>
-class QMap
-{
- typedef QMapNode<Key, T> Node;
+ MapData *newData = new MapData;
+ size_type result = newData->copyIfNotEquivalentTo(d->m, key);
- QMapData<Key, T> *d;
+ d.reset(newData);
-public:
- inline QMap() noexcept : d(static_cast<QMapData<Key, T> *>(const_cast<QMapDataBase *>(&QMapDataBase::shared_null))) { }
- inline QMap(std::initializer_list<std::pair<Key,T> > list)
- : d(static_cast<QMapData<Key, T> *>(const_cast<QMapDataBase *>(&QMapDataBase::shared_null)))
+ return result;
+ }
+
+ template <typename Predicate>
+ size_type removeIf(Predicate pred)
{
- for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
- insert(it->first, it->second);
+ return QtPrivate::associative_erase_if(*this, pred);
}
- QMap(const QMap<Key, T> &other);
- inline ~QMap() { if (!d->ref.deref()) d->destroy(); }
+ 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();
+
+ auto i = d->m.find(key);
+ if (i != d->m.end()) {
+ T result(std::move(i->second));
+ d->m.erase(i);
+ return result;
+ }
+ return T();
+ }
- QMap<Key, T> &operator=(const QMap<Key, T> &other);
- inline QMap(QMap<Key, T> &&other) noexcept
- : d(other.d)
+ bool contains(const Key &key) const
{
- other.d = static_cast<QMapData<Key, T> *>(
- const_cast<QMapDataBase *>(&QMapDataBase::shared_null));
+ if (!d)
+ return false;
+ auto i = d->m.find(key);
+ return i != d->m.end();
}
- inline QMap<Key, T> &operator=(QMap<Key, T> &&other) noexcept
- { QMap moved(std::move(other)); swap(moved); return *this; }
- inline void swap(QMap<Key, T> &other) noexcept { qSwap(d, other.d); }
- explicit QMap(const typename std::map<Key, T> &other);
- std::map<Key, T> toStdMap() const;
+ Key key(const T &value, const Key &defaultKey = Key()) const
+ {
+ if (!d)
+ return defaultKey;
- bool operator==(const QMap<Key, T> &other) const;
- inline bool operator!=(const QMap<Key, T> &other) const { return !(*this == other); }
+ return d->key(value, defaultKey);
+ }
- inline int size() const { return d->size; }
+ T value(const Key &key, const T &defaultValue = T()) const
+ {
+ if (!d)
+ return defaultValue;
+ const auto i = d->m.find(key);
+ if (i != d->m.cend())
+ return i->second;
+ return defaultValue;
+ }
- inline bool isEmpty() const { return d->size == 0; }
+ 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())
+ i = d->m.insert({key, T()}).first;
+ return i->second;
+ }
- inline void detach() { if (d->ref.isShared()) detach_helper(); }
- inline bool isDetached() const { return !d->ref.isShared(); }
- inline bool isSharedWith(const QMap<Key, T> &other) const { return d == other.d; }
+ // CHANGE: return T, not const T!
+ T operator[](const Key &key) const
+ {
+ return value(key);
+ }
- void clear();
+ QList<Key> keys() const
+ {
+ if (!d)
+ return {};
+ return d->keys();
+ }
- int remove(const Key &key);
- T take(const Key &key);
+ QList<Key> keys(const T &value) const
+ {
+ if (!d)
+ return {};
+ return d->keys(value);
+ }
- bool contains(const Key &key) const;
- const Key key(const T &value, const Key &defaultKey = Key()) const;
- const T value(const Key &key, const T &defaultValue = T()) const;
- T &operator[](const Key &key);
- const T operator[](const Key &key) const;
+ QList<T> values() const
+ {
+ if (!d)
+ return {};
+ return d->values();
+ }
- QList<Key> uniqueKeys() const;
- QList<Key> keys() const;
- QList<Key> keys(const T &value) const;
- QList<T> values() const;
- QList<T> values(const Key &key) const;
- int count(const Key &key) const;
+ size_type count(const Key &key) const
+ {
+ if (!d)
+ return 0;
+ return d->count(key);
+ }
+
+ size_type count() const
+ {
+ return size();
+ }
inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
- inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return (constEnd() - 1).key(); }
+ inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return (--constEnd()).key(); }
inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
- inline T &last() { Q_ASSERT(!isEmpty()); return *(end() - 1); }
- inline const T &last() const { Q_ASSERT(!isEmpty()); return *(constEnd() - 1); }
+ inline T &last() { Q_ASSERT(!isEmpty()); return *(--end()); }
+ inline const T &last() const { Q_ASSERT(!isEmpty()); return *(--constEnd()); }
class const_iterator;
class iterator
{
+ friend class QMap<Key, T>;
friend class const_iterator;
- Node *i;
+ 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;
-
- inline iterator() : i(nullptr) { }
- inline iterator(Node *node) : i(node) { }
-
- inline const Key &key() const { return i->key; }
- inline T &value() const { return i->value; }
- inline T &operator*() const { return i->value; }
- inline T *operator->() const { return &i->value; }
- inline bool operator==(const iterator &o) const { return i == o.i; }
- inline bool operator!=(const iterator &o) const { return i != o.i; }
-
- inline iterator &operator++() {
- i = i->nextNode();
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = qptrdiff;
+ using value_type = T;
+ using pointer = T *;
+ using reference = T &;
+
+ iterator() = default;
+
+ const Key &key() const { return i->first; }
+ T &value() const { return i->second; }
+ T &operator*() const { return i->second; }
+ T *operator->() const { return &i->second; }
+ friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
+ friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
+
+ iterator &operator++()
+ {
+ ++i;
return *this;
}
- inline iterator operator++(int) {
+ iterator operator++(int)
+ {
iterator r = *this;
- i = i->nextNode();
+ ++i;
return r;
}
- inline iterator &operator--() {
- i = i->previousNode();
+ iterator &operator--()
+ {
+ --i;
return *this;
}
- inline iterator operator--(int) {
+ iterator operator--(int)
+ {
iterator r = *this;
- i = i->previousNode();
+ --i;
return r;
}
- inline iterator operator+(int j) const
- { iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline iterator operator-(int j) const { return operator+(-j); }
- inline iterator &operator+=(int j) { return *this = *this + j; }
- inline iterator &operator-=(int j) { return *this = *this - j; }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
-
- inline bool operator==(const const_iterator &o) const { return i == o.i; }
- inline bool operator!=(const const_iterator &o) const { return i != o.i; }
- friend class QMap<Key, T>;
+
+#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
};
- friend class iterator;
class const_iterator
{
- friend class iterator;
- const Node *i;
+ friend class QMap<Key, T>;
+ 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;
-
- Q_DECL_CONSTEXPR inline const_iterator() : i(nullptr) { }
- inline const_iterator(const Node *node) : i(node) { }
- inline const_iterator(const iterator &o) { i = o.i; }
-
- inline const Key &key() const { return i->key; }
- inline const T &value() const { return i->value; }
- inline const T &operator*() const { return i->value; }
- inline const T *operator->() const { return &i->value; }
- Q_DECL_CONSTEXPR inline bool operator==(const const_iterator &o) const { return i == o.i; }
- Q_DECL_CONSTEXPR inline bool operator!=(const const_iterator &o) const { return i != o.i; }
-
- inline const_iterator &operator++() {
- i = i->nextNode();
+ 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;
+ Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
+
+ const Key &key() const { return i->first; }
+ const T &value() const { return i->second; }
+ const T &operator*() const { return i->second; }
+ const T *operator->() const { return &i->second; }
+ friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
+ friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
+
+ const_iterator &operator++()
+ {
+ ++i;
return *this;
}
- inline const_iterator operator++(int) {
+ const_iterator operator++(int)
+ {
const_iterator r = *this;
- i = i->nextNode();
+ ++i;
return r;
}
- inline const_iterator &operator--() {
- i = i->previousNode();
+ const_iterator &operator--()
+ {
+ --i;
return *this;
}
- inline const_iterator operator--(int) {
+ const_iterator operator--(int)
+ {
const_iterator r = *this;
- i = i->previousNode();
+ --i;
return r;
}
- inline const_iterator operator+(int j) const
- { const_iterator r = *this; if (j > 0) while (j--) ++r; else while (j++) --r; return r; }
- inline const_iterator operator-(int j) const { return operator+(-j); }
- inline const_iterator &operator+=(int j) { return *this = *this + j; }
- inline const_iterator &operator-=(int j) { return *this = *this - j; }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
- friend class QMap<Key, T>;
+#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
};
- friend class const_iterator;
class key_iterator
{
@@ -521,740 +595,1011 @@ public:
typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
// STL style
- inline iterator begin() { detach(); return iterator(d->begin()); }
- inline const_iterator begin() const { return const_iterator(d->begin()); }
- inline const_iterator constBegin() const { return const_iterator(d->begin()); }
- inline const_iterator cbegin() const { return const_iterator(d->begin()); }
- inline iterator end() { detach(); return iterator(d->end()); }
- inline const_iterator end() const { return const_iterator(d->end()); }
- inline const_iterator constEnd() const { return const_iterator(d->end()); }
- inline const_iterator cend() const { return const_iterator(d->end()); }
- inline key_iterator keyBegin() const { return key_iterator(begin()); }
- inline key_iterator keyEnd() const { return key_iterator(end()); }
- inline key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
- inline key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
- inline const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
- inline const_key_value_iterator constKeyValueBegin() const { return const_key_value_iterator(begin()); }
- inline const_key_value_iterator keyValueEnd() const { return const_key_value_iterator(end()); }
- inline const_key_value_iterator constKeyValueEnd() const { return const_key_value_iterator(end()); }
- iterator erase(iterator it);
+ iterator begin() { detach(); return iterator(d->m.begin()); }
+ const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
+ const_iterator constBegin() const { return begin(); }
+ const_iterator cbegin() const { return begin(); }
+ iterator end() { detach(); return iterator(d->m.end()); }
+ const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
+ const_iterator constEnd() const { return end(); }
+ const_iterator cend() const { return end(); }
+ key_iterator keyBegin() const { return key_iterator(begin()); }
+ key_iterator keyEnd() const { return key_iterator(end()); }
+ key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
+ key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
+ const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
+ 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)
+ {
+ return erase(it, std::next(it));
+ }
+
+ iterator erase(const_iterator afirst, const_iterator alast)
+ {
+ if (!d)
+ return iterator();
+
+ if (!d.isShared())
+ return iterator(d->m.erase(afirst.i, alast.i));
+
+ auto result = d->erase(afirst.i, alast.i);
+ d.reset(result.data);
+ return iterator(result.it);
+ }
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
- inline int count() const { return d->size; }
- iterator find(const Key &key);
- const_iterator find(const Key &key) const;
- const_iterator constFind(const Key &key) const;
- iterator lowerBound(const Key &key);
- const_iterator lowerBound(const Key &key) const;
- iterator upperBound(const Key &key);
- const_iterator upperBound(const Key &key) const;
- iterator insert(const Key &key, const T &value);
- iterator insert(const_iterator pos, const Key &key, const T &value);
- iterator insertMulti(const Key &key, const T &value);
- iterator insertMulti(const_iterator pos, const Key &akey, const T &avalue);
- QMap<Key, T> &unite(const QMap<Key, T> &other);
- // STL compatibility
- typedef Key key_type;
- typedef T mapped_type;
- typedef qptrdiff difference_type;
- typedef int size_type;
- inline bool empty() const { return isEmpty(); }
- QPair<iterator, iterator> equal_range(const Key &akey);
- QPair<const_iterator, const_iterator> equal_range(const Key &akey) const;
+ 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));
+ }
-#ifdef Q_MAP_DEBUG
- void dump() const;
-#endif
+ const_iterator find(const Key &key) const
+ {
+ if (!d)
+ return const_iterator();
+ return const_iterator(d->m.find(key));
+ }
-private:
- void detach_helper();
- bool isValidIterator(const const_iterator &ci) const
- {
-#if defined(QT_DEBUG) && !defined(Q_MAP_NO_ITERATOR_DEBUG)
- const QMapNodeBase *n = ci.i;
- while (n->parent())
- n = n->parent();
- return n->left == d->root();
+ const_iterator constFind(const Key &key) const
+ {
+ return find(key);
+ }
+
+ 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));
+ }
+
+ const_iterator lowerBound(const Key &key) const
+ {
+ if (!d)
+ return const_iterator();
+ return const_iterator(d->m.lower_bound(key));
+ }
+
+ 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));
+ }
+
+ const_iterator upperBound(const Key &key) const
+ {
+ if (!d)
+ return const_iterator();
+ return const_iterator(d->m.upper_bound(key));
+ }
+
+ 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);
+ }
+
+ iterator insert(const_iterator pos, const Key &key, const T &value)
+ {
+ // TODO: improve. In case of assignment, why copying first?
+ typename Map::const_iterator dpos;
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key`/`value` alive across the detach
+ if (!d || d.isShared()) {
+ auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
+ detach();
+ 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)
+ {
+ // TODO: improve. In case of assignment, why copying first?
+ if (map.isEmpty())
+ return;
+
+ detach();
+
+#ifdef __cpp_lib_node_extract
+ auto copy = map.d->m;
+ copy.merge(std::move(d->m));
+ d->m = std::move(copy);
#else
- Q_UNUSED(ci);
- return true;
+ // this is a std::copy, but we can't use std::inserter (need insert_or_assign...).
+ // copy in reverse order, trying to make effective use of insertionHint.
+ auto insertionHint = d->m.end();
+ auto mapIt = map.d->m.crbegin();
+ auto end = map.d->m.crend();
+ for (; mapIt != end; ++mapIt)
+ insertionHint = d->m.insert_or_assign(insertionHint, mapIt->first, mapIt->second);
#endif
}
-};
-template <class Key, class T>
-inline QMap<Key, T>::QMap(const QMap<Key, T> &other)
-{
- if (other.d->ref.ref()) {
- d = other.d;
- } else {
- d = QMapData<Key, T>::create();
- if (other.d->header.left) {
- d->header.left = static_cast<Node *>(other.d->header.left)->copy(d);
- d->header.left->setParent(&d->header);
- d->recalcMostLeftNode();
+ void insert(QMap<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));
+ *this = std::move(map);
+#else
+ // same as above
+ auto insertionHint = d->m.end();
+ auto mapIt = map.d->m.crbegin();
+ auto end = map.d->m.crend();
+ for (; mapIt != end; ++mapIt)
+ insertionHint = d->m.insert_or_assign(insertionHint, std::move(mapIt->first), std::move(mapIt->second));
+#endif
}
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE QMap<Key, T> &QMap<Key, T>::operator=(const QMap<Key, T> &other)
-{
- if (d != other.d) {
- QMap<Key, T> tmp(other);
- tmp.swap(*this);
+ // STL compatibility
+ inline bool empty() const
+ {
+ return isEmpty();
}
- return *this;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE void QMap<Key, T>::clear()
-{
- *this = QMap<Key, T>();
-}
+ 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)};
+ }
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wreturn-stack-address")
+ 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)};
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QMap<Key, T>::value(const Key &akey, const T &adefaultValue) const
-{
- Node *n = d->findNode(akey);
- return n ? n->value : adefaultValue;
-}
+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
+};
-QT_WARNING_POP
+Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
+Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
-template <class Key, class T>
-Q_INLINE_TEMPLATE const T QMap<Key, T>::operator[](const Key &akey) const
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
{
- return value(akey);
+ return QtPrivate::associative_erase_if(map, pred);
}
-template <class Key, class T>
-Q_INLINE_TEMPLATE T &QMap<Key, T>::operator[](const Key &akey)
-{
- detach();
- Node *n = d->findNode(akey);
- if (!n)
- return *insert(akey, T());
- return n->value;
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMap<Key, T>::count(const Key &akey) const
-{
- Node *firstNode;
- Node *lastNode;
- d->nodeRange(akey, &firstNode, &lastNode);
-
- const_iterator ci_first(firstNode);
- const const_iterator ci_last(lastNode);
- int cnt = 0;
- while (ci_first != ci_last) {
- ++cnt;
- ++ci_first;
- }
- return cnt;
-}
+//
+// QMultiMap
+//
template <class Key, class T>
-Q_INLINE_TEMPLATE bool QMap<Key, T>::contains(const Key &akey) const
+class QMultiMap
{
- return d->findNode(akey) != nullptr;
-}
+ using Map = std::multimap<Key, T>;
+ using MapData = QMapData<Map>;
+ QtPrivate::QExplicitlySharedDataPointerV2<MapData> d;
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insert(const Key &akey, const T &avalue)
-{
- detach();
- Node *n = d->root();
- Node *y = d->end();
- Node *lastNode = nullptr;
- bool left = true;
- while (n) {
- y = n;
- if (!qMapLessThanKey(n->key, akey)) {
- lastNode = n;
- left = true;
- n = n->leftNode();
- } else {
- left = false;
- n = n->rightNode();
- }
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using difference_type = qptrdiff;
+ using size_type = qsizetype;
+
+ QMultiMap() = default;
+
+ // implicitly generated special member functions are OK!
+
+ QMultiMap(std::initializer_list<std::pair<Key,T>> list)
+ {
+ for (auto &p : list)
+ insert(p.first, p.second);
}
- if (lastNode && !qMapLessThanKey(akey, lastNode->key)) {
- lastNode->value = avalue;
- return iterator(lastNode);
+
+ void swap(QMultiMap<Key, T> &other) noexcept
+ {
+ d.swap(other.d);
}
- Node *z = d->createNode(akey, avalue, y, left);
- return iterator(z);
-}
-template <class Key, class T>
-typename QMap<Key, T>::iterator QMap<Key, T>::insert(const_iterator pos, const Key &akey, const T &avalue)
-{
- if (d->ref.isShared())
- return this->insert(akey, avalue);
-
- Q_ASSERT_X(isValidIterator(pos), "QMap::insert", "The specified const_iterator argument 'it' is invalid");
-
- if (pos == constEnd()) {
- // Hint is that the Node is larger than (or equal to) the largest value.
- Node *n = static_cast<Node *>(pos.i->left);
- if (n) {
- while (n->right)
- n = static_cast<Node *>(n->right);
-
- if (!qMapLessThanKey(n->key, akey))
- return this->insert(akey, avalue); // ignore hint
- // This can be optimized by checking equal too.
- // we can overwrite if previous node key is strictly smaller
- // (or there is no previous node)
-
- Node *z = d->createNode(akey, avalue, n, false); // insert right most
- return iterator(z);
+ explicit QMultiMap(const QMap<Key, T> &other)
+ : d(other.isEmpty() ? nullptr : new MapData)
+ {
+ if (d) {
+ Q_ASSERT(other.d);
+ d->m.insert(other.d->m.begin(),
+ other.d->m.end());
}
- return this->insert(akey, avalue);
- } else {
- // Hint indicates that the node should be less (or equal to) the hint given
- // but larger than the previous value.
- Node *next = const_cast<Node*>(pos.i);
- if (qMapLessThanKey(next->key, akey))
- return this->insert(akey, avalue); // ignore hint
-
- if (pos == constBegin()) {
- // There is no previous value
- // Maybe overwrite left most value
- if (!qMapLessThanKey(akey, next->key)) {
- next->value = avalue; // overwrite current iterator
- return iterator(next);
- }
- // insert left most.
- Node *z = d->createNode(akey, avalue, begin().i, true);
- return iterator(z);
- } else {
- Node *prev = const_cast<Node*>(pos.i->previousNode());
- if (!qMapLessThanKey(prev->key, akey)) {
- return this->insert(akey, avalue); // ignore hint
- }
- // Hint is ok
- if (!qMapLessThanKey(akey, next->key)) {
- next->value = avalue; // overwrite current iterator
- return iterator(next);
- }
+ }
- // we need to insert (not overwrite)
- if (prev->right == nullptr) {
- Node *z = d->createNode(akey, avalue, prev, false);
- return iterator(z);
- }
- if (next->left == nullptr) {
- Node *z = d->createNode(akey, avalue, next, true);
- return iterator(z);
+ explicit QMultiMap(QMap<Key, T> &&other)
+ : d(other.isEmpty() ? nullptr : new MapData)
+ {
+ if (d) {
+ Q_ASSERT(other.d);
+ if (other.d.isShared()) {
+ d->m.insert(other.d->m.begin(),
+ other.d->m.end());
+ } else {
+#ifdef __cpp_lib_node_extract
+ d->m.merge(std::move(other.d->m));
+#else
+ d->m.insert(std::make_move_iterator(other.d->m.begin()),
+ std::make_move_iterator(other.d->m.end()));
+#endif
}
- Q_ASSERT(false); // We should have prev->right == nullptr or next->left == nullptr.
- return this->insert(akey, avalue);
}
}
-}
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key &akey,
- const T &avalue)
-{
- detach();
- Node* y = d->end();
- Node* x = static_cast<Node *>(d->root());
- bool left = true;
- while (x != nullptr) {
- left = !qMapLessThanKey(x->key, akey);
- y = x;
- x = left ? x->leftNode() : x->rightNode();
- }
- Node *z = d->createNode(akey, avalue, y, left);
- return iterator(z);
-}
+ explicit QMultiMap(const std::multimap<Key, T> &other)
+ : d(other.empty() ? nullptr : new MapData(other))
+ {
+ }
-template <class Key, class T>
-typename QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const_iterator pos, const Key &akey, const T &avalue)
-{
- if (d->ref.isShared())
- return this->insertMulti(akey, avalue);
-
- Q_ASSERT_X(isValidIterator(pos), "QMap::insertMulti", "The specified const_iterator argument 'pos' is invalid");
-
- if (pos == constEnd()) {
- // Hint is that the Node is larger than (or equal to) the largest value.
- Node *n = static_cast<Node *>(pos.i->left);
- if (n) {
- while (n->right)
- n = static_cast<Node *>(n->right);
-
- if (!qMapLessThanKey(n->key, akey))
- return this->insertMulti(akey, avalue); // ignore hint
- Node *z = d->createNode(akey, avalue, n, false); // insert right most
- return iterator(z);
+ explicit QMultiMap(std::multimap<Key, T> &&other)
+ : d(other.empty() ? nullptr : new MapData(std::move(other)))
+ {
+ }
+
+ // CHANGE: return type
+ Q_DECL_DEPRECATED_X("Use toStdMultiMap instead")
+ std::multimap<Key, T> toStdMap() const
+ {
+ return toStdMultiMap();
+ }
+
+ std::multimap<Key, T> toStdMultiMap() const &
+ {
+ if (d)
+ return d->m;
+ return {};
+ }
+
+ std::multimap<Key, T> toStdMultiMap() &&
+ {
+ if (d) {
+ if (d.isShared())
+ return d->m;
+ else
+ return std::move(d->m);
}
- return this->insertMulti(akey, avalue);
- } else {
- // Hint indicates that the node should be less (or equal to) the hint given
- // but larger than the previous value.
- Node *next = const_cast<Node*>(pos.i);
- if (qMapLessThanKey(next->key, akey))
- return this->insertMulti(akey, avalue); // ignore hint
-
- if (pos == constBegin()) {
- // There is no previous value (insert left most)
- Node *z = d->createNode(akey, avalue, begin().i, true);
- return iterator(z);
- } else {
- Node *prev = const_cast<Node*>(pos.i->previousNode());
- if (!qMapLessThanKey(prev->key, akey))
- return this->insertMulti(akey, avalue); // ignore hint
-
- // Hint is ok - do insert
- if (prev->right == nullptr) {
- Node *z = d->createNode(akey, avalue, prev, false);
- return iterator(z);
- }
- if (next->left == nullptr) {
- Node *z = d->createNode(akey, avalue, next, true);
- return iterator(z);
+
+ return {};
+ }
+
+#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); }
+
+ bool isEmpty() const { return d ? d->m.empty() : true; }
+
+ void detach()
+ {
+ if (d)
+ d.detach();
+ else
+ d.reset(new MapData);
+ }
+
+ bool isDetached() const noexcept
+ {
+ return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior...
+ }
+
+ bool isSharedWith(const QMultiMap<Key, T> &other) const noexcept
+ {
+ return d == other.d; // also this makes little sense?
+ }
+
+ void clear()
+ {
+ if (!d)
+ return;
+
+ if (!d.isShared())
+ d->m.clear();
+ else
+ d.reset();
+ }
+
+ size_type remove(const Key &key)
+ {
+ if (!d)
+ return 0;
+
+ if (!d.isShared())
+ return size_type(d->m.erase(key));
+
+ MapData *newData = new MapData;
+ size_type result = newData->copyIfNotEquivalentTo(d->m, key);
+
+ d.reset(newData);
+
+ return result;
+ }
+
+ size_type remove(const Key &key, const T &value)
+ {
+ if (!d)
+ return 0;
+
+ // key and value may belong to this map. As such, we need to copy
+ // them to ensure they stay valid throughout the iteration below
+ // (which may destroy them)
+ const Key keyCopy = key;
+ const T valueCopy = value;
+
+ // TODO: improve. Copy over only the elements not to be removed.
+ detach();
+
+ size_type result = 0;
+ const auto &keyCompare = d->m.key_comp();
+
+ auto i = d->m.find(keyCopy);
+ const auto e = d->m.end();
+
+ while (i != e && !keyCompare(keyCopy, i->first)) {
+ if (i->second == valueCopy) {
+ i = d->m.erase(i);
+ ++result;
+ } else {
+ ++i;
}
- Q_ASSERT(false); // We should have prev->right == nullptr or next->left == nullptr.
- return this->insertMulti(akey, avalue);
}
+
+ return result;
}
-}
+ template <typename Predicate>
+ size_type removeIf(Predicate pred)
+ {
+ return QtPrivate::associative_erase_if(*this, pred);
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator QMap<Key, T>::constFind(const Key &akey) const
-{
- Node *n = d->findNode(akey);
- return const_iterator(n ? n : d->end());
-}
+ T take(const Key &key)
+ {
+ if (!d)
+ return T();
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator QMap<Key, T>::find(const Key &akey) const
-{
- return constFind(akey);
-}
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::find(const Key &akey)
-{
- detach();
- Node *n = d->findNode(akey);
- return iterator(n ? n : d->end());
-}
+ // TODO: improve. There is no need of copying all the
+ // elements (the one to be removed can be skipped).
+ detach();
-template <class Key, class T>
-Q_INLINE_TEMPLATE QMap<Key, T> &QMap<Key, T>::unite(const QMap<Key, T> &other)
-{
- QMap<Key, T> copy(other);
- const_iterator it = copy.constEnd();
- const const_iterator b = copy.constBegin();
- while (it != b) {
- --it;
- insertMulti(it.key(), it.value());
- }
- return *this;
-}
+ auto i = d->m.find(key);
+ if (i != d->m.end()) {
+ T result(std::move(i->second));
+ d->m.erase(i);
+ return result;
+ }
+ return T();
+ }
-template <class Key, class T>
-QPair<typename QMap<Key, T>::iterator, typename QMap<Key, T>::iterator> QMap<Key, T>::equal_range(const Key &akey)
-{
- detach();
- Node *firstNode, *lastNode;
- d->nodeRange(akey, &firstNode, &lastNode);
- return QPair<iterator, iterator>(iterator(firstNode), iterator(lastNode));
-}
+ bool contains(const Key &key) const
+ {
+ if (!d)
+ return false;
+ auto i = d->m.find(key);
+ return i != d->m.end();
+ }
-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 &akey) const
-{
- Node *firstNode, *lastNode;
- d->nodeRange(akey, &firstNode, &lastNode);
- return qMakePair(const_iterator(firstNode), const_iterator(lastNode));
-}
+ bool contains(const Key &key, const T &value) const
+ {
+ return find(key, value) != end();
+ }
-#ifdef Q_MAP_DEBUG
-template <class Key, class T>
-void QMap<Key, T>::dump() const
-{
- const_iterator it = begin();
- qDebug("map dump:");
- while (it != end()) {
- const QMapNodeBase *n = it.i;
- int depth = 0;
- while (n && n != d->root()) {
- ++depth;
- n = n->parent();
- }
- QByteArray space(4*depth, ' ');
- qDebug() << space << (it.i->color() == Node::Red ? "Red " : "Black") << it.i << it.i->left << it.i->right
- << it.key() << it.value();
- ++it;
+ Key key(const T &value, const Key &defaultKey = Key()) const
+ {
+ if (!d)
+ return defaultKey;
+
+ return d->key(value, defaultKey);
}
- qDebug("---------");
-}
-#endif
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE int QMap<Key, T>::remove(const Key &akey)
-{
- detach();
- int n = 0;
- while (Node *node = d->findNode(akey)) {
- d->deleteNode(node);
- ++n;
+ T value(const Key &key, const T &defaultValue = T()) const
+ {
+ if (!d)
+ return defaultValue;
+ const auto i = d->m.find(key);
+ if (i != d->m.cend())
+ return i->second;
+ return defaultValue;
}
- return n;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE T QMap<Key, T>::take(const Key &akey)
-{
- detach();
+ QList<Key> keys() const
+ {
+ if (!d)
+ return {};
+ return d->keys();
+ }
- Node *node = d->findNode(akey);
- if (node) {
- T t = std::move(node->value);
- d->deleteNode(node);
- return t;
+ QList<Key> keys(const T &value) const
+ {
+ if (!d)
+ return {};
+ return d->keys(value);
}
- return T();
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::erase(iterator it)
-{
- if (it == iterator(d->end()))
- return it;
+ QList<Key> uniqueKeys() const
+ {
+ QList<Key> result;
+ if (!d)
+ return result;
+
+ result.reserve(size());
+
+ std::unique_copy(keyBegin(), keyEnd(),
+ std::back_inserter(result));
+
+ result.shrink_to_fit();
+ return result;
+ }
+
+ QList<T> values() const
+ {
+ if (!d)
+ return {};
+ return d->values();
+ }
+
+ QList<T> values(const Key &key) const
+ {
+ QList<T> result;
+ const auto range = equal_range(key);
+ result.reserve(std::distance(range.first, range.second));
+ std::copy(range.first, range.second, std::back_inserter(result));
+ return result;
+ }
+
+ size_type count(const Key &key) const
+ {
+ if (!d)
+ return 0;
+ return d->count(key);
+ }
- Q_ASSERT_X(isValidIterator(const_iterator(it)), "QMap::erase", "The specified iterator argument 'it' is invalid");
+ size_type count(const Key &key, const T &value) const
+ {
+ if (!d)
+ return 0;
+
+ // TODO: improve; no need of scanning the equal_range twice.
+ auto range = d->m.equal_range(key);
+
+ return size_type(std::count_if(range.first,
+ range.second,
+ MapData::valueIsEqualTo(value)));
+ }
+
+ inline const Key &firstKey() const { Q_ASSERT(!isEmpty()); return constBegin().key(); }
+ inline const Key &lastKey() const { Q_ASSERT(!isEmpty()); return std::next(constEnd(), -1).key(); }
- if (d->ref.isShared()) {
- const_iterator oldBegin = constBegin();
- const_iterator old = const_iterator(it);
- int backStepsWithSameKey = 0;
+ inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
+ inline const T &first() const { Q_ASSERT(!isEmpty()); return *constBegin(); }
+ inline T &last() { Q_ASSERT(!isEmpty()); return *std::next(end(), -1); }
+ inline const T &last() const { Q_ASSERT(!isEmpty()); return *std::next(constEnd(), -1); }
+
+ class const_iterator;
- while (old != oldBegin) {
- --old;
- if (qMapLessThanKey(old.key(), it.key()))
- break;
- ++backStepsWithSameKey;
+ class iterator
+ {
+ friend class QMultiMap<Key, T>;
+ friend class const_iterator;
+
+ typename Map::iterator i;
+ explicit iterator(typename Map::iterator it) : i(it) {}
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = qptrdiff;
+ using value_type = T;
+ using pointer = T *;
+ using reference = T &;
+
+ iterator() = default;
+
+ const Key &key() const { return i->first; }
+ T &value() const { return i->second; }
+ T &operator*() const { return i->second; }
+ T *operator->() const { return &i->second; }
+ friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs.i == rhs.i; }
+ friend bool operator!=(const iterator &lhs, const iterator &rhs) { return lhs.i != rhs.i; }
+
+ iterator &operator++()
+ {
+ ++i;
+ return *this;
+ }
+ iterator operator++(int)
+ {
+ iterator r = *this;
+ ++i;
+ return r;
+ }
+ iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+ iterator operator--(int)
+ {
+ iterator r = *this;
+ --i;
+ return r;
}
- it = find(old.key()); // ensures detach
- Q_ASSERT_X(it != iterator(d->end()), "QMap::erase", "Unable to locate same key in erase after detach.");
+#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; }
- while (backStepsWithSameKey > 0) {
- ++it;
- --backStepsWithSameKey;
+ 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 Map::const_iterator i;
+ explicit const_iterator(typename Map::const_iterator it) : i(it) {}
+
+ public:
+ 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;
+ Q_IMPLICIT const_iterator(const iterator &o) : i(o.i) {}
+
+ const Key &key() const { return i->first; }
+ const T &value() const { return i->second; }
+ const T &operator*() const { return i->second; }
+ const T *operator->() const { return &i->second; }
+ friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i == rhs.i; }
+ friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) { return lhs.i != rhs.i; }
+
+ const_iterator &operator++()
+ {
+ ++i;
+ return *this;
+ }
+ const_iterator operator++(int)
+ {
+ const_iterator r = *this;
+ ++i;
+ return r;
+ }
+ const_iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+ const_iterator operator--(int)
+ {
+ const_iterator r = *this;
+ --i;
+ return r;
}
+
+#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
+ {
+ const_iterator i;
+
+ public:
+ typedef typename const_iterator::iterator_category iterator_category;
+ typedef typename const_iterator::difference_type difference_type;
+ typedef Key value_type;
+ typedef const Key *pointer;
+ typedef const Key &reference;
+
+ key_iterator() = default;
+ explicit key_iterator(const_iterator o) : i(o) { }
+
+ const Key &operator*() const { return i.key(); }
+ const Key *operator->() const { return &i.key(); }
+ bool operator==(key_iterator o) const { return i == o.i; }
+ bool operator!=(key_iterator o) const { return i != o.i; }
+
+ inline key_iterator &operator++() { ++i; return *this; }
+ inline key_iterator operator++(int) { return key_iterator(i++);}
+ inline key_iterator &operator--() { --i; return *this; }
+ inline key_iterator operator--(int) { return key_iterator(i--); }
+ const_iterator base() const { return i; }
+ };
+
+ typedef QKeyValueIterator<const Key&, const T&, const_iterator> const_key_value_iterator;
+ typedef QKeyValueIterator<const Key&, T&, iterator> key_value_iterator;
+
+ // STL style
+ iterator begin() { detach(); return iterator(d->m.begin()); }
+ const_iterator begin() const { if (!d) return const_iterator(); return const_iterator(d->m.cbegin()); }
+ const_iterator constBegin() const { return begin(); }
+ const_iterator cbegin() const { return begin(); }
+ iterator end() { detach(); return iterator(d->m.end()); }
+ const_iterator end() const { if (!d) return const_iterator(); return const_iterator(d->m.end()); }
+ const_iterator constEnd() const { return end(); }
+ const_iterator cend() const { return end(); }
+ key_iterator keyBegin() const { return key_iterator(begin()); }
+ key_iterator keyEnd() const { return key_iterator(end()); }
+ key_value_iterator keyValueBegin() { return key_value_iterator(begin()); }
+ key_value_iterator keyValueEnd() { return key_value_iterator(end()); }
+ const_key_value_iterator keyValueBegin() const { return const_key_value_iterator(begin()); }
+ 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)
+ {
+ return erase(it, std::next(it));
}
- Node *n = it.i;
- ++it;
- d->deleteNode(n);
- return it;
-}
+ iterator erase(const_iterator afirst, const_iterator alast)
+ {
+ if (!d)
+ return iterator();
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE void QMap<Key, T>::detach_helper()
-{
- QMapData<Key, T> *x = QMapData<Key, T>::create();
- if (d->header.left) {
- x->header.left = static_cast<Node *>(d->header.left)->copy(x);
- x->header.left->setParent(&x->header);
- }
- if (!d->ref.deref())
- d->destroy();
- d = x;
- d->recalcMostLeftNode();
-}
+ if (!d.isShared())
+ return iterator(d->m.erase(afirst.i, alast.i));
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::uniqueKeys() const
-{
- QList<Key> res;
- res.reserve(size()); // May be too much, but assume short lifetime
- const_iterator i = begin();
- if (i != end()) {
- for (;;) {
- const Key &aKey = i.key();
- res.append(aKey);
- do {
- if (++i == end())
- goto break_out_of_outer_loop;
- } while (!qMapLessThanKey(aKey, i.key())); // loop while (key == i.key())
- }
+ auto result = d->erase(afirst.i, alast.i);
+ d.reset(result.data);
+ return iterator(result.it);
}
-break_out_of_outer_loop:
- return res;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::keys() const
-{
- QList<Key> res;
- res.reserve(size());
- const_iterator i = begin();
- while (i != end()) {
- res.append(i.key());
- ++i;
- }
- return res;
-}
+ // more Qt
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<Key> QMap<Key, T>::keys(const T &avalue) const
-{
- QList<Key> res;
- const_iterator i = begin();
- while (i != end()) {
- if (i.value() == avalue)
- res.append(i.key());
- ++i;
- }
- return res;
-}
+ size_type count() const
+ {
+ return size();
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE const Key QMap<Key, T>::key(const T &avalue, const Key &defaultKey) const
-{
- const_iterator i = begin();
- while (i != end()) {
- if (i.value() == avalue)
- return i.key();
- ++i;
+ 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));
}
- return defaultKey;
-}
+ const_iterator find(const Key &key) const
+ {
+ if (!d)
+ return const_iterator();
+ return const_iterator(d->m.find(key));
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QMap<Key, T>::values() const
-{
- QList<T> res;
- res.reserve(size());
- const_iterator i = begin();
- while (i != end()) {
- res.append(i.value());
- ++i;
- }
- return res;
-}
+ const_iterator constFind(const Key &key) const
+ {
+ return find(key);
+ }
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QList<T> QMap<Key, T>::values(const Key &akey) const
-{
- QList<T> res;
- Node *n = d->findNode(akey);
- if (n) {
- const_iterator it(n);
- do {
- res.append(*it);
- ++it;
- } while (it != constEnd() && !qMapLessThanKey<Key>(akey, it.key()));
- }
- return res;
-}
+ iterator find(const Key &key, const T &value)
+ {
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator QMap<Key, T>::lowerBound(const Key &akey) const
-{
- Node *lb = d->root() ? d->root()->lowerBound(akey) : nullptr;
- if (!lb)
- lb = d->end();
- return const_iterator(lb);
-}
+ detach();
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::lowerBound(const Key &akey)
-{
- detach();
- Node *lb = d->root() ? d->root()->lowerBound(akey) : nullptr;
- if (!lb)
- lb = d->end();
- return iterator(lb);
-}
+ auto range = d->m.equal_range(key);
+ auto i = std::find_if(range.first, range.second,
+ MapData::valueIsEqualTo(value));
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::const_iterator
-QMap<Key, T>::upperBound(const Key &akey) const
-{
- Node *ub = d->root() ? d->root()->upperBound(akey) : nullptr;
- if (!ub)
- ub = d->end();
- return const_iterator(ub);
-}
+ if (i != range.second)
+ return iterator(i);
+ return iterator(d->m.end());
+ }
-template <class Key, class T>
-Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::upperBound(const Key &akey)
-{
- detach();
- Node *ub = d->root() ? d->root()->upperBound(akey) : nullptr;
- if (!ub)
- ub = d->end();
- return iterator(ub);
-}
+ const_iterator find(const Key &key, const T &value) const
+ {
+ if (!d)
+ return const_iterator();
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE bool QMap<Key, T>::operator==(const QMap<Key, T> &other) const
-{
- if (size() != other.size())
- return false;
- if (d == other.d)
- return true;
+ auto range = d->m.equal_range(key);
+ auto i = std::find_if(range.first, range.second,
+ MapData::valueIsEqualTo(value));
- const_iterator it1 = begin();
- const_iterator it2 = other.begin();
+ if (i != range.second)
+ return const_iterator(i);
+ return const_iterator(d->m.end());
+ }
- while (it1 != end()) {
- if (!(it1.value() == it2.value()) || qMapLessThanKey(it1.key(), it2.key()) || qMapLessThanKey(it2.key(), it1.key()))
- return false;
- ++it2;
- ++it1;
+ const_iterator constFind(const Key &key, const T &value) const
+ {
+ return find(key, value);
}
- return true;
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QMap<Key, T>::QMap(const std::map<Key, T> &other)
-{
- d = QMapData<Key, T>::create();
- typename std::map<Key,T>::const_iterator it = other.end();
- while (it != other.begin()) {
- --it;
- d->createNode((*it).first, (*it).second, d->begin(), true); // insert on most left node.
+ 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));
}
-}
-template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE std::map<Key, T> QMap<Key, T>::toStdMap() const
-{
- std::map<Key, T> map;
- const_iterator it = end();
- while (it != begin()) {
- --it;
- map.insert(map.begin(), std::pair<Key, T>(it.key(), it.value()));
+ const_iterator lowerBound(const Key &key) const
+ {
+ if (!d)
+ return const_iterator();
+ return const_iterator(d->m.lower_bound(key));
}
- return map;
-}
-template <class Key, class T>
-class QMultiMap : public QMap<Key, T>
-{
-public:
- QMultiMap() noexcept {}
- inline QMultiMap(std::initializer_list<std::pair<Key,T> > list)
- {
- for (typename std::initializer_list<std::pair<Key,T> >::const_iterator it = list.begin(); it != list.end(); ++it)
- insert(it->first, it->second);
- }
- QMultiMap(const QMap<Key, T> &other) : QMap<Key, T>(other) {}
- QMultiMap(QMap<Key, T> &&other) noexcept : QMap<Key, T>(std::move(other)) {}
- void swap(QMultiMap<Key, T> &other) noexcept { QMap<Key, T>::swap(other); }
-
- inline typename QMap<Key, T>::iterator replace(const Key &key, const T &value)
- { return QMap<Key, T>::insert(key, value); }
- inline typename QMap<Key, T>::iterator insert(const Key &key, const T &value)
- { return QMap<Key, T>::insertMulti(key, value); }
- inline typename QMap<Key, T>::iterator insert(typename QMap<Key, T>::const_iterator pos, const Key &key, const T &value)
- { return QMap<Key, T>::insertMulti(pos, key, value); }
-
- inline QMultiMap &operator+=(const QMultiMap &other)
- { this->unite(other); return *this; }
- inline QMultiMap operator+(const QMultiMap &other) const
- { QMultiMap result = *this; result += other; return result; }
-
- using QMap<Key, T>::contains;
- using QMap<Key, T>::remove;
- using QMap<Key, T>::count;
- using QMap<Key, T>::find;
- using QMap<Key, T>::constFind;
-
- bool contains(const Key &key, const T &value) const;
-
- int remove(const Key &key, const T &value);
-
- int count(const Key &key, const T &value) const;
-
- typename QMap<Key, T>::iterator find(const Key &key, const T &value) {
- typename QMap<Key, T>::iterator i(find(key));
- typename QMap<Key, T>::iterator end(this->end());
- while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
- if (i.value() == value)
- return i;
- ++i;
+ 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));
+ }
+
+ const_iterator upperBound(const Key &key) const
+ {
+ if (!d)
+ return const_iterator();
+ return const_iterator(d->m.upper_bound(key));
+ }
+
+ 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.
+ auto i = d->m.lower_bound(key);
+ return iterator(d->m.insert(i, {key, value}));
+ }
+
+ iterator insert(const_iterator pos, const Key &key, const T &value)
+ {
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
+ typename Map::const_iterator dpos;
+ if (!d || d.isShared()) {
+ auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
+ detach();
+ dpos = std::next(d->m.cbegin(), posDistance);
+ } else {
+ dpos = pos.i;
}
- return end;
- }
- typename QMap<Key, T>::const_iterator find(const Key &key, const T &value) const {
- typename QMap<Key, T>::const_iterator i(constFind(key));
- typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd());
- while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
- if (i.value() == value)
- return i;
- ++i;
+ return iterator(d->m.insert(dpos, {key, value}));
+ }
+
+#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)
+ {
+ unite(map);
+ }
+
+ QT_DEPRECATED_VERSION_X_6_0("Use unite() instead")
+ void insert(QMultiMap<Key, T> &&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();
+
+ // Similarly, improve here (e.g. lower_bound and hinted insert);
+ // there's no insert_or_assign on multimaps
+ auto i = d->m.find(key);
+ if (i != d->m.end())
+ i->second = value;
+ else
+ i = d->m.insert({key, value});
+
+ return iterator(i);
+ }
+
+ // STL compatibility
+ inline bool empty() const { return isEmpty(); }
+
+ 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)};
+ }
+
+ 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)};
+ }
+
+ QMultiMap &unite(const QMultiMap &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;
}
- return end;
+
+ 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;
}
- typename QMap<Key, T>::const_iterator constFind(const Key &key, const T &value) const
- { return find(key, value); }
-private:
- T &operator[](const Key &key);
- const T operator[](const Key &key) const;
};
-template <class Key, class T>
-Q_INLINE_TEMPLATE bool QMultiMap<Key, T>::contains(const Key &key, const T &value) const
+Q_DECLARE_ASSOCIATIVE_ITERATOR(MultiMap)
+Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(MultiMap)
+
+template <typename Key, typename T>
+QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
{
- return constFind(key, value) != QMap<Key, T>::constEnd();
+ auto result = lhs;
+ result += rhs;
+ return result;
}
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value)
+template <typename Key, typename T>
+QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
{
- int n = 0;
- typename QMap<Key, T>::iterator i(find(key));
- typename QMap<Key, T>::iterator end(QMap<Key, T>::end());
- while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
- if (i.value() == value) {
- i = this->erase(i);
- ++n;
- } else {
- ++i;
- }
- }
- return n;
+ return lhs.unite(rhs);
}
-template <class Key, class T>
-Q_INLINE_TEMPLATE int QMultiMap<Key, T>::count(const Key &key, const T &value) const
+template <typename Key, typename T, typename Predicate>
+qsizetype erase_if(QMultiMap<Key, T> &map, Predicate pred)
{
- int n = 0;
- typename QMap<Key, T>::const_iterator i(constFind(key));
- typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd());
- while (i != end && !qMapLessThanKey<Key>(key, i.key())) {
- if (i.value() == value)
- ++n;
- ++i;
- }
- return n;
+ return QtPrivate::associative_erase_if(map, pred);
}
-Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
-Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Map)
-
QT_END_NAMESPACE
#endif // QMAP_H
diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.qdoc
index a0ec372f9a..0cabf3df38 100644
--- a/src/corelib/tools/qmap.cpp
+++ b/src/corelib/tools/qmap.qdoc
@@ -1,384 +1,11 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qmap.h"
-
-#include <stdlib.h>
-
-#ifdef QT_QMAP_DEBUG
-# include <qstring.h>
-# include <qvector.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-const QMapDataBase QMapDataBase::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, { 0, nullptr, nullptr }, nullptr };
-
-const QMapNodeBase *QMapNodeBase::nextNode() const
-{
- const QMapNodeBase *n = this;
- if (n->right) {
- n = n->right;
- while (n->left)
- n = n->left;
- } else {
- const QMapNodeBase *y = n->parent();
- while (y && n == y->right) {
- n = y;
- y = n->parent();
- }
- n = y;
- }
- return n;
-}
-
-const QMapNodeBase *QMapNodeBase::previousNode() const
-{
- const QMapNodeBase *n = this;
- if (n->left) {
- n = n->left;
- while (n->right)
- n = n->right;
- } else {
- const QMapNodeBase *y = n->parent();
- while (y && n == y->left) {
- n = y;
- y = n->parent();
- }
- n = y;
- }
- return n;
-}
-
-
-void QMapDataBase::rotateLeft(QMapNodeBase *x)
-{
- QMapNodeBase *&root = header.left;
- QMapNodeBase *y = x->right;
- x->right = y->left;
- if (y->left != nullptr)
- y->left->setParent(x);
- y->setParent(x->parent());
- if (x == root)
- root = y;
- else if (x == x->parent()->left)
- x->parent()->left = y;
- else
- x->parent()->right = y;
- y->left = x;
- x->setParent(y);
-}
-
-
-void QMapDataBase::rotateRight(QMapNodeBase *x)
-{
- QMapNodeBase *&root = header.left;
- QMapNodeBase *y = x->left;
- x->left = y->right;
- if (y->right != nullptr)
- y->right->setParent(x);
- y->setParent(x->parent());
- if (x == root)
- root = y;
- else if (x == x->parent()->right)
- x->parent()->right = y;
- else
- x->parent()->left = y;
- y->right = x;
- x->setParent(y);
-}
-
-
-void QMapDataBase::rebalance(QMapNodeBase *x)
-{
- QMapNodeBase *&root = header.left;
- x->setColor(QMapNodeBase::Red);
- while (x != root && x->parent()->color() == QMapNodeBase::Red) {
- if (x->parent() == x->parent()->parent()->left) {
- QMapNodeBase *y = x->parent()->parent()->right;
- if (y && y->color() == QMapNodeBase::Red) {
- x->parent()->setColor(QMapNodeBase::Black);
- y->setColor(QMapNodeBase::Black);
- x->parent()->parent()->setColor(QMapNodeBase::Red);
- x = x->parent()->parent();
- } else {
- if (x == x->parent()->right) {
- x = x->parent();
- rotateLeft(x);
- }
- x->parent()->setColor(QMapNodeBase::Black);
- x->parent()->parent()->setColor(QMapNodeBase::Red);
- rotateRight (x->parent()->parent());
- }
- } else {
- QMapNodeBase *y = x->parent()->parent()->left;
- if (y && y->color() == QMapNodeBase::Red) {
- x->parent()->setColor(QMapNodeBase::Black);
- y->setColor(QMapNodeBase::Black);
- x->parent()->parent()->setColor(QMapNodeBase::Red);
- x = x->parent()->parent();
- } else {
- if (x == x->parent()->left) {
- x = x->parent();
- rotateRight(x);
- }
- x->parent()->setColor(QMapNodeBase::Black);
- x->parent()->parent()->setColor(QMapNodeBase::Red);
- rotateLeft(x->parent()->parent());
- }
- }
- }
- root->setColor(QMapNodeBase::Black);
-}
-
-void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z)
-{
- QMapNodeBase *&root = header.left;
- QMapNodeBase *y = z;
- QMapNodeBase *x;
- QMapNodeBase *x_parent;
- if (y->left == nullptr) {
- x = y->right;
- if (y == mostLeftNode) {
- if (x)
- mostLeftNode = x; // It cannot have (left) children due the red black invariant.
- else
- mostLeftNode = y->parent();
- }
- } else {
- if (y->right == nullptr) {
- x = y->left;
- } else {
- y = y->right;
- while (y->left != nullptr)
- y = y->left;
- x = y->right;
- }
- }
- if (y != z) {
- z->left->setParent(y);
- y->left = z->left;
- if (y != z->right) {
- x_parent = y->parent();
- if (x)
- x->setParent(y->parent());
- y->parent()->left = x;
- y->right = z->right;
- z->right->setParent(y);
- } else {
- x_parent = y;
- }
- if (root == z)
- root = y;
- else if (z->parent()->left == z)
- z->parent()->left = y;
- else
- z->parent()->right = y;
- y->setParent(z->parent());
- // Swap the colors
- QMapNodeBase::Color c = y->color();
- y->setColor(z->color());
- z->setColor(c);
- y = z;
- } else {
- x_parent = y->parent();
- if (x)
- x->setParent(y->parent());
- if (root == z)
- root = x;
- else if (z->parent()->left == z)
- z->parent()->left = x;
- else
- z->parent()->right = x;
- }
- if (y->color() != QMapNodeBase::Red) {
- while (x != root && (x == nullptr || x->color() == QMapNodeBase::Black)) {
- if (x == x_parent->left) {
- QMapNodeBase *w = x_parent->right;
- if (w->color() == QMapNodeBase::Red) {
- w->setColor(QMapNodeBase::Black);
- x_parent->setColor(QMapNodeBase::Red);
- rotateLeft(x_parent);
- w = x_parent->right;
- }
- if ((w->left == nullptr || w->left->color() == QMapNodeBase::Black) &&
- (w->right == nullptr || w->right->color() == QMapNodeBase::Black)) {
- w->setColor(QMapNodeBase::Red);
- x = x_parent;
- x_parent = x_parent->parent();
- } else {
- if (w->right == nullptr || w->right->color() == QMapNodeBase::Black) {
- if (w->left)
- w->left->setColor(QMapNodeBase::Black);
- w->setColor(QMapNodeBase::Red);
- rotateRight(w);
- w = x_parent->right;
- }
- w->setColor(x_parent->color());
- x_parent->setColor(QMapNodeBase::Black);
- if (w->right)
- w->right->setColor(QMapNodeBase::Black);
- rotateLeft(x_parent);
- break;
- }
- } else {
- QMapNodeBase *w = x_parent->left;
- if (w->color() == QMapNodeBase::Red) {
- w->setColor(QMapNodeBase::Black);
- x_parent->setColor(QMapNodeBase::Red);
- rotateRight(x_parent);
- w = x_parent->left;
- }
- if ((w->right == nullptr || w->right->color() == QMapNodeBase::Black) &&
- (w->left == nullptr|| w->left->color() == QMapNodeBase::Black)) {
- w->setColor(QMapNodeBase::Red);
- x = x_parent;
- x_parent = x_parent->parent();
- } else {
- if (w->left == nullptr || w->left->color() == QMapNodeBase::Black) {
- if (w->right)
- w->right->setColor(QMapNodeBase::Black);
- w->setColor(QMapNodeBase::Red);
- rotateLeft(w);
- w = x_parent->left;
- }
- w->setColor(x_parent->color());
- x_parent->setColor(QMapNodeBase::Black);
- if (w->left)
- w->left->setColor(QMapNodeBase::Black);
- rotateRight(x_parent);
- break;
- }
- }
- }
- if (x)
- x->setColor(QMapNodeBase::Black);
- }
- free(y);
- --size;
-}
-
-void QMapDataBase::recalcMostLeftNode()
-{
- mostLeftNode = &header;
- while (mostLeftNode->left)
- mostLeftNode = mostLeftNode->left;
-}
-
-static inline int qMapAlignmentThreshold()
-{
- // malloc on 32-bit platforms should return pointers that are 8-byte
- // aligned or more while on 64-bit platforms they should be 16-byte aligned
- // or more
- return 2 * sizeof(void*);
-}
-
-static inline void *qMapAllocate(int alloc, int alignment)
-{
- return alignment > qMapAlignmentThreshold()
- ? qMallocAligned(alloc, alignment)
- : ::malloc(alloc);
-}
-
-static inline void qMapDeallocate(QMapNodeBase *node, int alignment)
-{
- if (alignment > qMapAlignmentThreshold())
- qFreeAligned(node);
- else
- ::free(node);
-}
-
-QMapNodeBase *QMapDataBase::createNode(int alloc, int alignment, QMapNodeBase *parent, bool left)
-{
- QMapNodeBase *node = static_cast<QMapNodeBase *>(qMapAllocate(alloc, alignment));
- Q_CHECK_PTR(node);
-
- memset(node, 0, alloc);
- ++size;
-
- if (parent) {
- if (left) {
- parent->left = node;
- if (parent == mostLeftNode)
- mostLeftNode = node;
- } else {
- parent->right = node;
- }
- node->setParent(parent);
- rebalance(node);
- }
- return node;
-}
-
-void QMapDataBase::freeTree(QMapNodeBase *root, int alignment)
-{
- if (root->left)
- freeTree(root->left, alignment);
- if (root->right)
- freeTree(root->right, alignment);
- qMapDeallocate(root, alignment);
-}
-
-QMapDataBase *QMapDataBase::createData()
-{
- QMapDataBase *d = new QMapDataBase;
-
- d->ref.initializeOwned();
- d->size = 0;
-
- d->header.p = 0;
- d->header.left = nullptr;
- d->header.right = nullptr;
- d->mostLeftNode = &(d->header);
-
- return d;
-}
-
-void QMapDataBase::freeData(QMapDataBase *d)
-{
- delete d;
-}
+// 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
\inmodule QtCore
- \brief The QMap class is a template class that provides a red-black-tree-based dictionary.
+ \brief The QMap class is a template class that provides an associative array.
\ingroup tools
\ingroup shared
@@ -386,8 +13,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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:
@@ -461,29 +87,17 @@ void QMapDataBase::freeData(QMapDataBase *d)
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
- insertMulti() instead of insert() (or using the convenience
- subclass 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
-
- The items that share the same key are available from most
- recently to least recently inserted. 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
@@ -497,7 +111,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
but the compiler won't let you, for example, store a QWidget as a
value; instead, store a QWidget *. In addition, QMap's key type
must provide operator<(). QMap uses it to keep its items sorted,
- and assumes that two keys \c x and \c y are equal if neither \c{x
+ and assumes that two keys \c x and \c y are equivalent if neither \c{x
< y} nor \c{y < x} is true.
Example:
@@ -516,15 +130,6 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa clear()
*/
-/*!
- \fn template <class Key, class T> QMap<Key, T>::QMap(QMap<Key, T> &&other)
-
- Move-constructs a QMap instance, making it point at the same
- object that \a other was pointing to.
-
- \since 5.2
-*/
-
/*! \fn template <class Key, class T> QMap<Key, T>::QMap(const QMap<Key, T> &other)
Constructs a copy of \a other.
@@ -534,29 +139,28 @@ void QMapDataBase::freeData(QMapDataBase *d)
function very fast. If a shared instance is modified, it will be
copied (copy-on-write), and this takes \l{linear time}.
- \sa operator=()
+ \sa operator=
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::QMap(const typename std::map<Key, T> & other)
+/*!
+ \fn template <class Key, class T> QMap<Key, T>::QMap(QMap<Key, T> &&other)
- Constructs a copy of \a other.
+ Move-constructs a QMap instance.
- \sa toStdMap()
+ \since 5.2
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::QMap(std::initializer_list<std::pair<Key,T> > list)
- \since 5.1
-
- Constructs a map with a copy of each of the elements in the
- initializer list \a list.
+/*! \fn template <class Key, class T> QMap<Key, T> &QMap<Key, T>::operator=(const QMap<Key, T> &other)
- This function is only available if the program is being
- compiled in C++11 mode.
+ Assigns \a other to this map and returns a reference to this map.
*/
-/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() const
+/*!
+ \fn template <class Key, class T> QMap<Key, T> &QMap<Key, T>::operator=(QMap<Key, T> &&other)
+
+ Move-assigns \a other to this QMap instance.
- Returns an STL map equivalent to this QMap.
+ \since 5.2
*/
/*! \fn template <class Key, class T> QMap<Key, T>::~QMap()
@@ -565,62 +169,77 @@ void QMapDataBase::freeData(QMapDataBase *d)
iterators over this map, become invalid.
*/
-/*! \fn template <class Key, class T> QMap<Key, T> &QMap<Key, T>::operator=(const QMap<Key, T> &other)
+/*! \fn template <class Key, class T> void QMap<Key, T>::swap(QMap<Key, T> &other) noexcept
+ \since 4.8
- Assigns \a other to this map and returns a reference to this map.
+ Swaps map \a other with this map. This operation is very
+ fast and never fails.
*/
-/*!
- \fn template <class Key, class T> QMap<Key, T> &QMap<Key, T>::operator=(QMap<Key, T> &&other)
+/*! \fn template <class Key, class T> QMap<Key, T>::QMap(std::initializer_list<std::pair<Key,T> > list)
+ \since 5.1
- Move-assigns \a other to this QMap instance.
+ Constructs a map with a copy of each of the elements in the
+ initializer list \a list.
+*/
- \since 5.2
+/*! \fn template <class Key, class T> QMap<Key, T>::QMap(const std::map<Key, T> & other)
+
+ Constructs a copy of \a other.
+
+ \sa toStdMap()
*/
-/*! \fn template <class Key, class T> void QMap<Key, T>::swap(QMap<Key, T> &other)
- \since 4.8
+/*! \fn template <class Key, class T> QMap<Key, T>::QMap(std::map<Key, T> && other)
- Swaps map \a other with this map. This operation is very
- fast and never fails.
+ Constructs a map by moving from \a other.
+
+ \sa toStdMap()
*/
-/*! \fn template <class Key, class T> void QMultiMap<Key, T>::swap(QMultiMap<Key, T> &other)
- \since 4.8
+/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() const &
- Swaps map \a other with this map. This operation is very
- fast and never fails.
+ Returns an STL map equivalent to this QMap.
+*/
+
+/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() &&
+
+ \overload
+ \since 6.0
+
+ \note Calling this function will leave this QMap in the partially-formed state, in which
+ the only valid operations are destruction or assignment of a new value.
*/
-/*! \fn template <class Key, class T> bool QMap<Key, T>::operator==(const QMap<Key, T> &other) const
+/*! \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 other is equal to this map; otherwise returns
+ Returns \c true if \a lhs is equal to \a rhs; otherwise returns
false.
Two maps are considered equal if they contain the same (key,
value) pairs.
- This function requires the value type to implement \c
+ This function requires the key and the value types to implement \c
operator==().
\sa operator!=()
*/
-/*! \fn template <class Key, class T> bool QMap<Key, T>::operator!=(const QMap<Key, T> &other) const
+/*! \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 other is not equal to this map; otherwise
- returns \c false.
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise returns
+ false.
Two maps are considered equal if they contain the same (key,
value) pairs.
- This function requires the value type to implement \c
+ This function requires the key and the value types to implement \c
operator==().
\sa operator==()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::size() const
+/*! \fn template <class Key, class T> size_type QMap<Key, T>::size() const
Returns the number of (key, value) pairs in the map.
@@ -656,11 +275,6 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa detach()
*/
-/*! \fn template <class Key, class T> void QMap<Key, T>::setSharable(bool sharable)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> bool QMap<Key, T>::isSharedWith(const QMap<Key, T> &other) const
\internal
@@ -673,14 +287,28 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa remove()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::remove(const Key &key)
+/*! \fn template <class Key, class T> size_type QMap<Key, T>::remove(const Key &key)
Removes all the items that have the key \a key from the map.
- Returns the number of items removed which is usually 1 but will be
- 0 if the key isn't in the map, or \> 1 if insertMulti() has been
- used with the \a key.
+ Returns the number of items removed which will be 1 if the key
+ exists in the map, and 0 otherwise.
+
+ \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 &>}.
- \sa clear(), take(), QMultiMap::remove()
+ 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)
@@ -689,9 +317,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
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.
@@ -703,18 +329,33 @@ void QMapDataBase::freeData(QMapDataBase *d)
Returns \c true if the map contains an item with key \a key;
otherwise returns \c false.
- \sa count(), QMultiMap::contains()
+ \sa count()
+*/
+
+/*!
+ \fn template <class Key, class T> Key QMap<Key, T>::key(const T &value, const Key &defaultKey) const
+ \since 4.3
+ \overload
+
+ Returns the first key with value \a value, or \a defaultKey if
+ the map contains no item with value \a value. If no \a defaultKey
+ is provided the function returns a
+ \l{default-constructed value}{default-constructed key}.
+
+ This function can be slow (\l{linear time}), because QMap's
+ internal data structure is optimized for fast lookup by key, not
+ by value.
+
+ \sa value(), keys()
*/
-/*! \fn template <class Key, class T> const T QMap<Key, T>::value(const Key &key, const T &defaultValue) const
+/*! \fn template <class Key, class T> T QMap<Key, T>::value(const Key &key, const T &defaultValue) const
Returns the value associated with the key \a key.
If the map contains no item with key \a key, the function returns
\a defaultValue. If no \a defaultValue is specified, the function
- returns a \l{default-constructed value}. If there are multiple
- items for \a key in the map, the value of the most recently
- inserted one is returned.
+ returns a \l{default-constructed value}.
\sa key(), values(), contains(), operator[]()
*/
@@ -726,44 +367,30 @@ void QMapDataBase::freeData(QMapDataBase *d)
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()
*/
-/*! \fn template <class Key, class T> const T QMap<Key, T>::operator[](const Key &key) const
+/*! \fn template <class Key, class T> T QMap<Key, T>::operator[](const Key &key) const
\overload
Same as value().
*/
-/*! \fn template <class Key, class T> QList<Key> QMap<Key, T>::uniqueKeys() const
- \since 4.2
-
- Returns a list containing all the keys in the map in ascending
- order. Keys that occur multiple times in the map (because items
- were inserted with insertMulti(), or unite() was used) occur only
- once in the returned list.
-
- \sa keys(), values()
-*/
-
/*! \fn template <class Key, class T> QList<Key> QMap<Key, T>::keys() const
Returns a list containing all the keys in the map in ascending
- order. Keys that occur multiple times in the map (because items
- were inserted with insertMulti(), or unite() was used) also
- occur multiple times in the list.
-
- To obtain a list of unique keys, where each key from the map only
- occurs once, use uniqueKeys().
+ order.
The order is guaranteed to be the same as that used by values().
- \sa uniqueKeys(), values(), key()
+ This function creates a new list, in \l {linear time}. The time and memory
+ use that entails can be avoided by iterating from \l keyBegin() to
+ \l keyEnd().
+
+ \sa values(), key()
*/
/*! \fn template <class Key, class T> QList<Key> QMap<Key, T>::keys(const T &value) const
@@ -778,56 +405,86 @@ void QMapDataBase::freeData(QMapDataBase *d)
by value.
*/
-/*!
- \fn template <class Key, class T> Key QMap<Key, T>::key(const T &value, const Key &defaultKey) const
- \since 4.3
- \overload
+/*! \fn template <class Key, class T> QList<T> QMap<Key, T>::values() const
- Returns the first key with value \a value, or \a defaultKey if
- the map contains no item with value \a value. If no \a defaultKey
- is provided the function returns a
- \l{default-constructed value}{default-constructed key}.
+ Returns a list containing all the values in the map, in ascending
+ order of their keys.
- This function can be slow (\l{linear time}), because QMap's
- internal data structure is optimized for fast lookup by key, not
- by value.
+ 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
+ \l keyValueEnd().
- \sa value(), keys()
+ \sa keys(), value()
*/
-/*! \fn template <class Key, class T> QList<T> QMap<Key, T>::values() const
+/*! \fn template <class Key, class T> size_type QMap<Key, T>::count(const Key &key) 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.
+ Returns the number of items associated with key \a key.
- \sa keys(), value()
+ \sa contains()
*/
-/*! \fn template <class Key, class T> QList<T> QMap<Key, T>::values(const Key &key) const
+/*! \fn template <class Key, class T> size_type QMap<Key, T>::count() const
\overload
- Returns a list containing all the values associated with key
- \a key, from the most recently inserted to the least recently
- inserted one.
+ Same as size().
+*/
+
+/*! \fn template <class Key, class T> const Key &QMap<Key, T>::firstKey() const
+ \since 5.2
+
+ Returns a reference to the smallest key in the map.
+ This function assumes that the map is not empty.
- \sa count(), insertMulti()
+ This executes in \l{constant time}.
+
+ \sa lastKey(), first(), keyBegin(), isEmpty()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::count(const Key &key) const
+/*! \fn template <class Key, class T> const Key &QMap<Key, T>::lastKey() const
+ \since 5.2
- Returns the number of items associated with key \a key.
+ Returns a reference to the largest key in the map.
+ This function assumes that the map is not empty.
+
+ This executes in \l{logarithmic time}.
+
+ \sa firstKey(), last(), keyEnd(), isEmpty()
+*/
+
+/*! \fn template <class Key, class T> T &QMap<Key, T>::first()
+ \since 5.2
- \sa contains(), insertMulti(), QMultiMap::count()
+ Returns a reference to the first value in the map, that is the value mapped
+ to the smallest key. This function assumes that the map is not empty.
+
+ When unshared (or const version is called), this executes in \l{constant time}.
+
+ \sa last(), firstKey(), isEmpty()
*/
-/*! \fn template <class Key, class T> int QMap<Key, T>::count() const
+/*! \fn template <class Key, class T> const T &QMap<Key, T>::first() const
+ \since 5.2
\overload
+*/
- Same as size().
+/*! \fn template <class Key, class T> T &QMap<Key, T>::last()
+ \since 5.2
+
+ Returns a reference to the last value in the map, that is the value mapped
+ to the largest key. This function assumes that the map is not empty.
+
+ When unshared (or const version is called), this executes in \l{logarithmic time}.
+
+ \sa first(), lastKey(), isEmpty()
+*/
+
+/*! \fn template <class Key, class T> const T &QMap<Key, T>::last() const
+ \since 5.2
+
+ \overload
*/
/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::begin()
@@ -963,67 +620,44 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa constKeyValueBegin()
*/
-/*! \fn template <class Key, class T> const Key &QMap<Key, T>::firstKey() const
- \since 5.2
-
- Returns a reference to the smallest key in the map.
- This function assumes that the map is not empty.
-
- This executes in \l{constant time}.
-
- \sa lastKey(), first(), keyBegin(), isEmpty()
-*/
+/*! \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
-/*! \fn template <class Key, class T> const Key &QMap<Key, T>::lastKey() const
- \since 5.2
+ 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:
- Returns a reference to the largest key in the map.
- This function assumes that the map is not empty.
+ \snippet code/src_corelib_tools_qmap.cpp 28
- This executes in \l{logarithmic time}.
+ 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 firstKey(), last(), keyEnd(), isEmpty()
+ \sa QKeyValueIterator
*/
-/*! \fn template <class Key, class T> T &QMap<Key, T>::first()
- \since 5.2
-
- Returns a reference to the first value in the map, that is the value mapped
- to the smallest key. This function assumes that the map is not empty.
-
- When unshared (or const version is called), this executes in \l{constant time}.
+/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::erase(const_iterator pos)
- \sa last(), firstKey(), isEmpty()
-*/
+ 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.
-/*! \fn template <class Key, class T> const T &QMap<Key, T>::first() const
- \since 5.2
+ \note The iterator \a pos \e must be valid and dereferenceable.
- \overload
+ \sa remove()
*/
-/*! \fn template <class Key, class T> T &QMap<Key, T>::last()
- \since 5.2
+/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::erase(const_iterator first, const_iterator last)
+ \since 6.0
- Returns a reference to the last value in the map, that is the value mapped
- to the largest key. This function assumes that the map is not empty.
+ Removes the (key, value) pairs pointed to by the iterator range
+ [\a first, \a last) from the map.
+ Returns an iterator to the item in the map following the last removed element.
- When unshared (or const version is called), this executes in \l{logarithmic time}.
-
- \sa first(), lastKey(), isEmpty()
-*/
-
-/*! \fn template <class Key, class T> const T &QMap<Key, T>::last() const
- \since 5.2
-
- \overload
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::erase(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 range \c {[first, last)} \e must be a valid range in \c {*this}.
\sa remove()
*/
@@ -1036,15 +670,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
If the map contains no item with key \a key, the function
returns end().
- If the map contains multiple items with key \a key, this
- function returns an iterator that points to the most recently
- inserted value. The other values are accessible by incrementing
- the iterator. For example, here's some code that iterates over all
- the items with the same key:
-
- \snippet code/src_corelib_tools_qmap.cpp 14
-
- \sa constFind(), value(), values(), lowerBound(), upperBound(), QMultiMap::find()
+ \sa constFind(), value(), values(), lowerBound(), upperBound()
*/
/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::find(const Key &key) const
@@ -1061,7 +687,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
If the map contains no item with key \a key, the function
returns constEnd().
- \sa find(), QMultiMap::constFind()
+ \sa find()
*/
/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::lowerBound(const Key &key)
@@ -1071,17 +697,6 @@ void QMapDataBase::freeData(QMapDataBase *d)
function returns an iterator to the nearest item with a greater
key.
- Example:
- \snippet code/src_corelib_tools_qmap.cpp 15
-
- If the map contains multiple items with key \a key, this
- function returns an iterator that points to the most recently
- inserted value. The other values are accessible by incrementing
- the iterator. For example, here's some code that iterates over all
- the items with the same key:
-
- \snippet code/src_corelib_tools_qmap.cpp 16
-
\sa upperBound(), find()
*/
@@ -1115,10 +730,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
If there is already an item with the key \a key, that item's value
is replaced with \a value.
- If there are multiple items with the key \a key, the most
- recently inserted item's value is replaced with \a value.
-
- \sa insertMulti()
+ 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)
@@ -1135,9 +747,6 @@ void QMapDataBase::freeData(QMapDataBase *d)
If there is already an item with the key \a key, that item's value
is replaced with \a value.
- If there are multiple items with the key \a key, then exactly one of them
- is replaced with \a value.
-
If the hint is correct and the map is unshared, the insert executes in amortized \l{constant time}.
When creating a map from sorted data inserting the largest key first with constBegin()
@@ -1147,58 +756,37 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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 insertMulti()
+ Returns an iterator pointing to the new/updated element.
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key &key, const T &value)
-
- Inserts a new item with the key \a key and a value of \a value.
-
- If there is already an item with the same key in the map, this
- function will simply create a new one. (This behavior is
- different from insert(), which overwrites the value of an
- existing item.)
-
- \sa insert(), values()
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::insertMulti(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
- suggesting where to do the insert.
-
- If constBegin() is used as hint it indicates that the \a key is less than any key in the map
- while constEnd() suggests that the \a key is larger than any key in the map.
- Otherwise the hint should meet the condition (\a pos - 1).key() < \a key <= pos.key().
- If the hint \a pos is wrong it is ignored and a regular insertMulti is done.
+/*! \fn template <class Key, class T> void QMap<Key, T>::insert(const QMap<Key, T> &map)
+ \since 5.15
- If there is already an item with the same key in the map, this function will simply create a new one.
+ Inserts all the items in \a map into this map.
- \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 insert()
+ If a key is common to both maps, its value will be replaced with
+ the value stored in \a map.
*/
+/*! \fn template <class Key, class T> void QMap<Key, T>::insert(QMap<Key, T> &&map)
+ \since 5.15
-/*! \fn template <class Key, class T> QMap<Key, T> &QMap<Key, T>::unite(const QMap<Key, T> &other)
+ Moves all the items from \a map into this map.
- 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.
+ If a key is common to both maps, its value will be replaced with
+ the value stored in \a map.
- \sa insertMulti()
+ 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
@@ -1230,14 +818,14 @@ void QMapDataBase::freeData(QMapDataBase *d)
*/
/*!
- \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
*/
@@ -1245,16 +833,10 @@ void QMapDataBase::freeData(QMapDataBase *d)
/*! \class QMap::iterator
\inmodule QtCore
- \brief The QMap::iterator class provides an STL-style non-const iterator for QMap and QMultiMap.
-
- 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.
+ \brief The QMap::iterator class provides an STL-style non-const iterator for QMap.
- QMap\<Key, T\>::iterator allows you to iterate over a QMap (or
- QMultiMap) and to modify the value (but not the key) stored under
+ 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
should use QMap::const_iterator. It is generally good practice to
use QMap::const_iterator on a non-const QMap as well, unless you
@@ -1270,36 +852,17 @@ void QMapDataBase::freeData(QMapDataBase *d)
\snippet code/src_corelib_tools_qmap.cpp 18
Unlike QHash, which stores its items in an arbitrary order, QMap
- stores its items ordered by key. Items that share the same key
- (because they were inserted using QMap::insertMulti(), or due to a
- unite()) will appear consecutively, from the most recently to the
- least recently inserted value.
+ 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
@@ -1310,7 +873,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
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
@@ -1350,18 +913,13 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa QMap::begin(), QMap::end()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator::iterator(Node *)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> const Key &QMap<Key, T>::iterator::key() const
Returns the current item's key as a const reference.
There is no direct way of changing an item's key through an
iterator, although it can be done by calling QMap::erase()
- followed by QMap::insert() or QMap::insertMulti().
+ followed by QMap::insert().
\sa value()
*/
@@ -1395,28 +953,28 @@ void QMapDataBase::freeData(QMapDataBase *d)
*/
/*!
- \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++()
+/*! \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.
@@ -1429,14 +987,14 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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--()
+/*! \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
@@ -1449,60 +1007,34 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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.
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::iterator::operator-(int j) const
+/*! //! 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)
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
+ //! 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)
- This operation can be slow for large \a j values.
+ \deprecated [6.2] Use \c{std::next}, \c{std::prev} or \c{std::advance} instead.
- \sa operator+()
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::iterator &QMap<Key, T>::iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- \sa operator+=(), operator-()
+ 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 and QMultiMap.
+ \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
- (or a QMultiMap). If you want to modify the QMap as you iterate
+ 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
good practice to use QMap::const_iterator on a non-const QMap as
well, unless you need to change the QMap through the iterator.
@@ -1511,17 +1043,22 @@ void QMapDataBase::freeData(QMapDataBase *d)
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. Items that share the same key
- (because they were inserted using QMap::insertMulti()) will
- appear consecutively, from the most recently to the least
- recently inserted value.
+ stores its items ordered by key.
Multiple iterators can be used on the same map. If you add items
to the map, existing iterators will remain valid. If you remove
@@ -1533,7 +1070,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
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
@@ -1573,11 +1110,6 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa QMap::constBegin(), QMap::constEnd()
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator::const_iterator(const Node *)
-
- \internal
-*/
-
/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator::const_iterator(const iterator &other)
Constructs a copy of \a other.
@@ -1613,25 +1145,9 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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
+/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator++()
- 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.
@@ -1644,14 +1160,14 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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
@@ -1664,55 +1180,32 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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.
*/
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator+(int j) const
-
- Returns an iterator to the item at \a j positions forward from
- this iterator. (If \a j is negative, the iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-()
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator QMap<Key, T>::const_iterator::operator-(int j) const
+/*! //! 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)
- Returns an iterator to the item at \a j positions backward from
- this iterator. (If \a j is negative, the iterator goes forward.)
+ //! 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)
- This operation can be slow for large \a j values.
+ \deprecated [6.2] Use \c{std::next}, \c{std::prev} or \c{std::advance} instead.
- \sa operator+()
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator+=(int j)
-
- Advances the iterator by \a j items. (If \a j is negative, the
- iterator goes backward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator-=(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QMap<Key, T>::const_iterator &QMap<Key, T>::const_iterator::operator-=(int j)
-
- Makes the iterator go back by \a j items. (If \a j is negative,
- the iterator goes forward.)
-
- This operation can be slow for large \a j values.
-
- \sa operator+=(), operator-()
+ 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
- \brief The QMap::key_iterator class provides an STL-style const iterator for QMap and QMultiMap keys.
+ \brief The QMap::key_iterator class provides an STL-style const iterator for QMap keys.
QMap::key_iterator is essentially the same as QMap::const_iterator
with the difference that operator*() and operator->() return a key
@@ -1795,7 +1288,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
/*!
\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.
@@ -1808,14 +1301,14 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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
@@ -1828,7 +1321,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
\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.
*/
@@ -1840,7 +1333,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
/*! \typedef QMap::const_key_value_iterator
\inmodule QtCore
\since 5.10
- \brief The QMap::const_key_value_iterator typedef provides an STL-style iterator for QMap and QMultiMap.
+ \brief The QMap::const_key_value_iterator typedef provides an STL-style iterator for QMap.
QMap::const_key_value_iterator is essentially the same as QMap::const_iterator
with the difference that operator*() returns a key/value pair instead of a
@@ -1852,7 +1345,7 @@ void QMapDataBase::freeData(QMapDataBase *d)
/*! \typedef QMap::key_value_iterator
\inmodule QtCore
\since 5.10
- \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QMap and QMultiMap.
+ \brief The QMap::key_value_iterator typedef provides an STL-style iterator for QMap.
QMap::key_value_iterator is essentially the same as QMap::iterator
with the difference that operator*() returns a key/value pair instead of a
@@ -1883,216 +1376,25 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa{Serializing Qt Data Types}{Format of the QDataStream operators}
*/
-/*! \class QMultiMap
- \inmodule QtCore
- \brief The QMultiMap class is a convenience QMap subclass that provides multi-valued maps.
-
- \ingroup tools
- \ingroup shared
-
- \reentrant
-
- QMultiMap\<Key, T\> is one of Qt's generic \l{container classes}.
- It inherits QMap and extends it with a few convenience functions
- that make it more suitable than QMap for storing multi-valued
- maps. A multi-valued map is a map that allows multiple values
- with the same key; QMap normally doesn't allow that, unless you
- call QMap::insertMulti().
-
- Because QMultiMap inherits QMap, all of QMap's functionality also
- applies to QMultiMap. For example, you can use isEmpty() to test
- whether the map is empty, and you can traverse a QMultiMap using
- QMap's iterator classes (for example, QMapIterator). But in
- addition, it provides an insert() function that corresponds to
- QMap::insertMulti(), and a replace() function that corresponds to
- QMap::insert(). It also provides convenient operator+() and
- operator+=().
-
- Example:
- \snippet code/src_corelib_tools_qmap.cpp 25
-
- Unlike QMap, QMultiMap provides no operator[]. Use value() or
- replace() if you want to access the most recently inserted item
- with a certain key.
-
- 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 26
-
- The items that share the same key are available from most
- recently to least recently inserted.
-
- If you prefer the STL-style iterators, you can call find() to get
- the iterator for the first item with a key and iterate from
- there:
-
- \snippet code/src_corelib_tools_qmap.cpp 27
-
- QMultiMap's key and value data types must be \l{assignable data
- types}. This covers most data types you are likely to encounter,
- but the compiler won't let you, for example, store a QWidget as a
- value; instead, store a QWidget *. In addition, QMultiMap's key type
- must provide operator<(). See the QMap documentation for details.
-
- \sa QMap, QMapIterator, QMutableMapIterator, QMultiHash
-*/
-
-/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap()
-
- Constructs an empty map.
-*/
-
-/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(std::initializer_list<std::pair<Key,T> > list)
- \since 5.1
-
- Constructs a multi-map 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> QMultiMap<Key, T>::QMultiMap(const QMap<Key, T> &other)
-
- Constructs a copy of \a other (which can be a QMap or a
- QMultiMap).
-
- \sa operator=()
-*/
-
-/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::replace(const Key &key, const T &value)
-
- Inserts a new item with the key \a key and a value of \a value.
-
- If there is already an item with the key \a key, that item's value
- is replaced with \a value.
-
- If there are multiple items with the key \a key, the most
- recently inserted item's value is replaced with \a value.
-
- \sa insert()
-*/
-
-/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const Key &key, const T &value)
-
- Inserts a new item with the key \a key and a value of \a value.
-
- If there is already an item with the same key in the map, this
- function will simply create a new one. (This behavior is
- different from replace(), which overwrites the value of an
- existing item.)
-
- \sa replace()
-*/
-
-/*! \fn template <class Key, class T> typename QMap<Key, T>::iterator QMultiMap<Key, T>::insert(typename QMap<Key, T>::const_iterator pos, const Key &key, const T &value)
-
- \since 5.1
- Inserts a new item with the key \a key and value \a value and with hint \a pos
- suggesting where to do the insert.
-
- If constBegin() is used as hint it indicates that the \a key is less than any key in the map
- while constEnd() suggests that the \a key is larger than any key in the map.
- Otherwise the hint should meet the condition (\a pos - 1).key() < \a key <= pos.key().
- If the hint \a pos is wrong it is ignored and a regular insert is done.
-
- If there is already an item with the same key in the map, this function will simply create a new one.
-
- \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.
-*/
-
-/*! \fn template <class Key, class T> QMultiMap &QMultiMap<Key, T>::operator+=(const QMultiMap &other)
-
- Inserts all the items in the \a other map into this map and
- returns a reference to this map.
-
- \sa insert(), operator+()
-*/
-
-/*! \fn template <class Key, class T> QMultiMap QMultiMap<Key, T>::operator+(const QMultiMap &other) const
-
- 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
- maps, the resulting map will contain the key multiple times.
-
- \sa operator+=()
-*/
-
-/*!
- \fn template <class Key, class T> bool QMultiMap<Key, T>::contains(const Key &key, const T &value) const
- \since 4.3
-
- Returns \c true if the map contains an item with key \a key and
- value \a value; otherwise returns \c false.
-
- \sa QMap::contains()
-*/
-
-/*!
- \fn template <class Key, class T> int QMultiMap<Key, T>::remove(const Key &key, const T &value)
- \since 4.3
-
- Removes all the items that have the key \a key and the value \a
- value from the map. Returns the number of items removed.
-
- \sa QMap::remove()
-*/
-
-/*!
- \fn template <class Key, class T> int QMultiMap<Key, T>::count(const Key &key, const T &value) const
- \since 4.3
-
- Returns the number of items with key \a key and value \a value.
-
- \sa QMap::count()
-*/
-
-/*!
- \fn template <class Key, class T> typename QMap<Key, T>::iterator QMultiMap<Key, T>::find(const Key &key, const T &value)
- \since 4.3
-
- Returns an iterator pointing to the item with key \a key and
- value \a value in the map.
-
- If the map contains no such item, the function returns end().
-
- If the map contains multiple items with key \a key, this
- function returns an iterator that points to the most recently
- inserted value.
-
- \sa QMap::find()
-*/
-
-/*!
- \fn template <class Key, class T> typename QMap<Key, T>::const_iterator QMultiMap<Key, T>::find(const Key &key, const T &value) const
- \since 4.3
- \overload
-
- Returns a const iterator pointing to the item with the given \a key and
- \a value in the map.
+/*! \fn template <typename Key, typename T, typename Predicate> qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
+ \relates QMap
+ \since 6.1
- If the map contains no such item, the function returns end().
+ Removes all elements for which the predicate \a pred returns true
+ from the map \a map.
- If the map contains multiple items with the specified \a key, this
- function returns a const iterator that points to the most recently
- inserted value.
+ 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 &>}.
- \sa QMap::find()
+ Returns the number of elements removed, if any.
*/
/*!
- \fn template <class Key, class T> typename QMap<Key, T>::const_iterator QMultiMap<Key, T>::constFind(const Key &key, const T &value) const
- \since 4.3
-
- Returns an iterator pointing to the item with key \a key and the
- value \a value in the map.
+ \fn template <class Key, class T> size_t QMap<Key, T>::qHash(const QMap &key, size_t seed) noexcept
+ \since 6.8
- If the map contains no such item, the function returns
- constEnd().
+ Returns the hash value for \a key, using \a seed to seed the calculation.
- \sa QMap::constFind()
+ Types \c Key and \c T must be supported by qHash().
*/
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qmargins.cpp b/src/corelib/tools/qmargins.cpp
index 74be7bb2ba..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,21 +107,19 @@ 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.
*/
/*!
- \fn const QMargins operator+(const QMargins &m1, const QMargins &m2)
+ \fn QMargins operator+(const QMargins &m1, const QMargins &m2)
\relates QMargins
Returns a QMargins object that is the sum of the given margins, \a m1
@@ -169,7 +131,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator-(const QMargins &m1, const QMargins &m2)
+ \fn QMargins operator-(const QMargins &m1, const QMargins &m2)
\relates QMargins
Returns a QMargins object that is formed by subtracting \a m2 from
@@ -181,7 +143,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator+(const QMargins &lhs, int rhs)
+ \fn QMargins operator+(const QMargins &lhs, int rhs)
\relates QMargins
Returns a QMargins object that is formed by adding \a rhs to
@@ -193,7 +155,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator+(int lhs, const QMargins &rhs)
+ \fn QMargins operator+(int lhs, const QMargins &rhs)
\relates QMargins
Returns a QMargins object that is formed by adding \a lhs to
@@ -205,7 +167,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator-(const QMargins &lhs, int rhs)
+ \fn QMargins operator-(const QMargins &lhs, int rhs)
\relates QMargins
Returns a QMargins object that is formed by subtracting \a rhs from
@@ -217,7 +179,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator*(const QMargins &margins, int factor)
+ \fn QMargins operator*(const QMargins &margins, int factor)
\relates QMargins
Returns a QMargins object that is formed by multiplying each component
@@ -229,7 +191,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator*(int factor, const QMargins &margins)
+ \fn QMargins operator*(int factor, const QMargins &margins)
\relates QMargins
\overload
@@ -242,7 +204,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator*(const QMargins &margins, qreal factor)
+ \fn QMargins operator*(const QMargins &margins, qreal factor)
\relates QMargins
\overload
@@ -255,7 +217,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator*(qreal factor, const QMargins &margins)
+ \fn QMargins operator*(qreal factor, const QMargins &margins)
\relates QMargins
\overload
@@ -268,7 +230,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator/(const QMargins &margins, int divisor)
+ \fn QMargins operator/(const QMargins &margins, int divisor)
\relates QMargins
Returns a QMargins object that is formed by dividing the components of
@@ -280,7 +242,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QMargins operator/(const QMargins &, qreal)
+ \fn QMargins operator/(const QMargins &, qreal)
\relates QMargins
\overload
@@ -311,6 +273,18 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn QMargins operator|(const QMargins &m1, const QMargins &m2)
+ \relates QMargins
+
+ Returns a QMargins object that is formed from the maximum of each
+ component of \a m2 and \a m1.
+
+ \sa QMargins::operator+=(), QMargins::operator-=()
+
+ \since 6.0
+*/
+
+/*!
\fn QMargins &QMargins::operator+=(const QMargins &margins)
Add each component of \a margins to the respective component of this object
@@ -396,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
*****************************************************************************/
@@ -457,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.
*/
@@ -481,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()
*/
@@ -489,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()}
*/
@@ -530,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
*/
/*!
@@ -591,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-=()
*/
@@ -601,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-=()
*/
@@ -611,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-=()
*/
@@ -623,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/=()
*/
@@ -634,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/=()
*/
@@ -647,10 +645,25 @@ 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/=()
*/
/*!
+ \fn QMarginsF operator|(const QMarginsF &m1, const QMarginsF &m2)
+ \relates QMarginsF
+ \overload
+
+ Returns a QMarginsF object that is formed from the maximum of each
+ component of \a m2 and \a m1.
+
+ \sa QMarginsF::operator+=(), QMarginsF::operator-=()
+
+ \since 6.0
+*/
+
+/*!
\fn QMarginsF operator+(const QMarginsF &margins)
\relates QMarginsF
@@ -686,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-=()
@@ -696,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+=()
@@ -705,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/=()
*/
@@ -714,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*=()
*/
@@ -723,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 447037daaa..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
*****************************************************************************/
@@ -51,29 +22,31 @@ QT_BEGIN_NAMESPACE
class QMargins
{
public:
- Q_DECL_CONSTEXPR QMargins() noexcept;
- Q_DECL_CONSTEXPR QMargins(int left, int top, int right, int bottom) noexcept;
-
- Q_DECL_CONSTEXPR bool isNull() const noexcept;
-
- Q_DECL_CONSTEXPR int left() const noexcept;
- Q_DECL_CONSTEXPR int top() const noexcept;
- Q_DECL_CONSTEXPR int right() const noexcept;
- Q_DECL_CONSTEXPR int bottom() const noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR void setLeft(int left) noexcept;
- Q_DECL_RELAXED_CONSTEXPR void setTop(int top) noexcept;
- Q_DECL_RELAXED_CONSTEXPR void setRight(int right) noexcept;
- Q_DECL_RELAXED_CONSTEXPR void setBottom(int bottom) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator+=(const QMargins &margins) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator-=(const QMargins &margins) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator+=(int) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator-=(int) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator*=(int) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator/=(int);
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator*=(qreal) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMargins &operator/=(qreal);
+ constexpr QMargins() noexcept;
+ constexpr QMargins(int left, int top, int right, int bottom) noexcept;
+
+ constexpr bool isNull() const noexcept;
+
+ constexpr int left() const noexcept;
+ constexpr int top() const noexcept;
+ constexpr int right() const noexcept;
+ constexpr int bottom() const noexcept;
+
+ constexpr void setLeft(int left) noexcept;
+ constexpr void setTop(int top) noexcept;
+ constexpr void setRight(int right) noexcept;
+ constexpr void setBottom(int bottom) noexcept;
+
+ constexpr QMargins &operator+=(const QMargins &margins) noexcept;
+ constexpr QMargins &operator-=(const QMargins &margins) noexcept;
+ constexpr QMargins &operator+=(int) noexcept;
+ constexpr QMargins &operator-=(int) noexcept;
+ constexpr QMargins &operator*=(int) noexcept;
+ constexpr QMargins &operator/=(int);
+ constexpr QMargins &operator*=(qreal) noexcept;
+ constexpr QMargins &operator/=(qreal);
+
+ [[nodiscard]] constexpr inline QMarginsF toMarginsF() const noexcept;
private:
int m_left;
@@ -81,11 +54,38 @@ private:
int m_right;
int m_bottom;
- friend Q_DECL_CONSTEXPR inline bool operator==(const QMargins &, const QMargins &) noexcept;
- friend Q_DECL_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
@@ -99,134 +99,122 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QMargins &);
QMargins inline functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QMargins::QMargins() noexcept : m_left(0), m_top(0), m_right(0), m_bottom(0) {}
+constexpr inline QMargins::QMargins() noexcept : m_left(0), m_top(0), m_right(0), m_bottom(0) {}
-Q_DECL_CONSTEXPR inline QMargins::QMargins(int aleft, int atop, int aright, int abottom) noexcept
+constexpr inline QMargins::QMargins(int aleft, int atop, int aright, int abottom) noexcept
: m_left(aleft), m_top(atop), m_right(aright), m_bottom(abottom) {}
-Q_DECL_CONSTEXPR inline bool QMargins::isNull() const noexcept
+constexpr inline bool QMargins::isNull() const noexcept
{ return m_left==0 && m_top==0 && m_right==0 && m_bottom==0; }
-Q_DECL_CONSTEXPR inline int QMargins::left() const noexcept
+constexpr inline int QMargins::left() const noexcept
{ return m_left; }
-Q_DECL_CONSTEXPR inline int QMargins::top() const noexcept
+constexpr inline int QMargins::top() const noexcept
{ return m_top; }
-Q_DECL_CONSTEXPR inline int QMargins::right() const noexcept
+constexpr inline int QMargins::right() const noexcept
{ return m_right; }
-Q_DECL_CONSTEXPR inline int QMargins::bottom() const noexcept
+constexpr inline int QMargins::bottom() const noexcept
{ return m_bottom; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMargins::setLeft(int aleft) noexcept
+constexpr inline void QMargins::setLeft(int aleft) noexcept
{ m_left = aleft; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMargins::setTop(int atop) noexcept
+constexpr inline void QMargins::setTop(int atop) noexcept
{ m_top = atop; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMargins::setRight(int aright) noexcept
+constexpr inline void QMargins::setRight(int aright) noexcept
{ m_right = aright; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMargins::setBottom(int abottom) noexcept
+constexpr inline void QMargins::setBottom(int abottom) noexcept
{ m_bottom = abottom; }
-Q_DECL_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;
-}
-
-Q_DECL_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;
-}
-
-Q_DECL_CONSTEXPR inline QMargins operator+(const QMargins &m1, const QMargins &m2) noexcept
+constexpr inline QMargins operator+(const QMargins &m1, const QMargins &m2) noexcept
{
return QMargins(m1.left() + m2.left(), m1.top() + m2.top(),
m1.right() + m2.right(), m1.bottom() + m2.bottom());
}
-Q_DECL_CONSTEXPR inline QMargins operator-(const QMargins &m1, const QMargins &m2) noexcept
+constexpr inline QMargins operator-(const QMargins &m1, const QMargins &m2) noexcept
{
return QMargins(m1.left() - m2.left(), m1.top() - m2.top(),
m1.right() - m2.right(), m1.bottom() - m2.bottom());
}
-Q_DECL_CONSTEXPR inline QMargins operator+(const QMargins &lhs, int rhs) noexcept
+constexpr inline QMargins operator+(const QMargins &lhs, int rhs) noexcept
{
return QMargins(lhs.left() + rhs, lhs.top() + rhs,
lhs.right() + rhs, lhs.bottom() + rhs);
}
-Q_DECL_CONSTEXPR inline QMargins operator+(int lhs, const QMargins &rhs) noexcept
+constexpr inline QMargins operator+(int lhs, const QMargins &rhs) noexcept
{
return QMargins(rhs.left() + lhs, rhs.top() + lhs,
rhs.right() + lhs, rhs.bottom() + lhs);
}
-Q_DECL_CONSTEXPR inline QMargins operator-(const QMargins &lhs, int rhs) noexcept
+constexpr inline QMargins operator-(const QMargins &lhs, int rhs) noexcept
{
return QMargins(lhs.left() - rhs, lhs.top() - rhs,
lhs.right() - rhs, lhs.bottom() - rhs);
}
-Q_DECL_CONSTEXPR inline QMargins operator*(const QMargins &margins, int factor) noexcept
+constexpr inline QMargins operator*(const QMargins &margins, int factor) noexcept
{
return QMargins(margins.left() * factor, margins.top() * factor,
margins.right() * factor, margins.bottom() * factor);
}
-Q_DECL_CONSTEXPR inline QMargins operator*(int factor, const QMargins &margins) noexcept
+constexpr inline QMargins operator*(int factor, const QMargins &margins) noexcept
{
return QMargins(margins.left() * factor, margins.top() * factor,
margins.right() * factor, margins.bottom() * factor);
}
-Q_DECL_CONSTEXPR inline QMargins operator*(const QMargins &margins, qreal factor) noexcept
+constexpr inline QMargins operator*(const QMargins &margins, qreal factor) noexcept
{
return QMargins(qRound(margins.left() * factor), qRound(margins.top() * factor),
qRound(margins.right() * factor), qRound(margins.bottom() * factor));
}
-Q_DECL_CONSTEXPR inline QMargins operator*(qreal factor, const QMargins &margins) noexcept
+constexpr inline QMargins operator*(qreal factor, const QMargins &margins) noexcept
{
return QMargins(qRound(margins.left() * factor), qRound(margins.top() * factor),
qRound(margins.right() * factor), qRound(margins.bottom() * factor));
}
-Q_DECL_CONSTEXPR inline QMargins operator/(const QMargins &margins, int divisor)
+constexpr inline QMargins operator/(const QMargins &margins, int divisor)
{
return QMargins(margins.left() / divisor, margins.top() / divisor,
margins.right() / divisor, margins.bottom() / divisor);
}
-Q_DECL_CONSTEXPR inline QMargins operator/(const QMargins &margins, qreal divisor)
+constexpr inline QMargins operator/(const QMargins &margins, qreal divisor)
{
return QMargins(qRound(margins.left() / divisor), qRound(margins.top() / divisor),
qRound(margins.right() / divisor), qRound(margins.bottom() / divisor));
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator+=(const QMargins &margins) noexcept
+constexpr inline QMargins operator|(const QMargins &m1, const QMargins &m2) noexcept
+{
+ return QMargins(qMax(m1.left(), m2.left()), qMax(m1.top(), m2.top()),
+ qMax(m1.right(), m2.right()), qMax(m1.bottom(), m2.bottom()));
+}
+
+constexpr inline QMargins &QMargins::operator+=(const QMargins &margins) noexcept
{
return *this = *this + margins;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator-=(const QMargins &margins) noexcept
+constexpr inline QMargins &QMargins::operator-=(const QMargins &margins) noexcept
{
return *this = *this - margins;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator+=(int margin) noexcept
+constexpr inline QMargins &QMargins::operator+=(int margin) noexcept
{
m_left += margin;
m_top += margin;
@@ -235,7 +223,7 @@ Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator+=(int margin) noexc
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator-=(int margin) noexcept
+constexpr inline QMargins &QMargins::operator-=(int margin) noexcept
{
m_left -= margin;
m_top -= margin;
@@ -244,32 +232,32 @@ Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator-=(int margin) noexc
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator*=(int factor) noexcept
+constexpr inline QMargins &QMargins::operator*=(int factor) noexcept
{
return *this = *this * factor;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator/=(int divisor)
+constexpr inline QMargins &QMargins::operator/=(int divisor)
{
return *this = *this / divisor;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator*=(qreal factor) noexcept
+constexpr inline QMargins &QMargins::operator*=(qreal factor) noexcept
{
return *this = *this * factor;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMargins &QMargins::operator/=(qreal divisor)
+constexpr inline QMargins &QMargins::operator/=(qreal divisor)
{
return *this = *this / divisor;
}
-Q_DECL_CONSTEXPR inline QMargins operator+(const QMargins &margins) noexcept
+constexpr inline QMargins operator+(const QMargins &margins) noexcept
{
return margins;
}
-Q_DECL_CONSTEXPR inline QMargins operator-(const QMargins &margins) noexcept
+constexpr inline QMargins operator-(const QMargins &margins) noexcept
{
return QMargins(-margins.left(), -margins.top(), -margins.right(), -margins.bottom());
}
@@ -285,39 +273,68 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QMargins &);
class QMarginsF
{
public:
- Q_DECL_CONSTEXPR QMarginsF() noexcept;
- Q_DECL_CONSTEXPR QMarginsF(qreal left, qreal top, qreal right, qreal bottom) noexcept;
- Q_DECL_CONSTEXPR QMarginsF(const QMargins &margins) noexcept;
+ constexpr QMarginsF() noexcept;
+ constexpr QMarginsF(qreal left, qreal top, qreal right, qreal bottom) noexcept;
+ constexpr QMarginsF(const QMargins &margins) noexcept;
- Q_DECL_CONSTEXPR bool isNull() const noexcept;
+ constexpr bool isNull() const noexcept;
- Q_DECL_CONSTEXPR qreal left() const noexcept;
- Q_DECL_CONSTEXPR qreal top() const noexcept;
- Q_DECL_CONSTEXPR qreal right() const noexcept;
- Q_DECL_CONSTEXPR qreal bottom() const noexcept;
+ constexpr qreal left() const noexcept;
+ constexpr qreal top() const noexcept;
+ constexpr qreal right() const noexcept;
+ constexpr qreal bottom() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR void setLeft(qreal left) noexcept;
- Q_DECL_RELAXED_CONSTEXPR void setTop(qreal top) noexcept;
- Q_DECL_RELAXED_CONSTEXPR void setRight(qreal right) noexcept;
- Q_DECL_RELAXED_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;
- Q_DECL_RELAXED_CONSTEXPR QMarginsF &operator+=(const QMarginsF &margins) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMarginsF &operator-=(const QMarginsF &margins) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMarginsF &operator+=(qreal addend) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMarginsF &operator-=(qreal subtrahend) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMarginsF &operator*=(qreal factor) noexcept;
- Q_DECL_RELAXED_CONSTEXPR QMarginsF &operator/=(qreal divisor);
+ constexpr QMarginsF &operator+=(const QMarginsF &margins) noexcept;
+ constexpr QMarginsF &operator-=(const QMarginsF &margins) noexcept;
+ constexpr QMarginsF &operator+=(qreal addend) noexcept;
+ constexpr QMarginsF &operator-=(qreal subtrahend) noexcept;
+ constexpr QMarginsF &operator*=(qreal factor) noexcept;
+ constexpr QMarginsF &operator/=(qreal divisor);
- Q_DECL_CONSTEXPR inline QMargins toMargins() const noexcept;
+ constexpr inline QMargins toMargins() const noexcept;
private:
qreal m_left;
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
@@ -332,115 +349,109 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QMarginsF &);
QMarginsF inline functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QMarginsF::QMarginsF() noexcept
+constexpr inline QMarginsF::QMarginsF() noexcept
: m_left(0), m_top(0), m_right(0), m_bottom(0) {}
-Q_DECL_CONSTEXPR inline QMarginsF::QMarginsF(qreal aleft, qreal atop, qreal aright, qreal abottom) noexcept
+constexpr inline QMarginsF::QMarginsF(qreal aleft, qreal atop, qreal aright, qreal abottom) noexcept
: m_left(aleft), m_top(atop), m_right(aright), m_bottom(abottom) {}
-Q_DECL_CONSTEXPR inline QMarginsF::QMarginsF(const QMargins &margins) noexcept
+constexpr inline QMarginsF::QMarginsF(const QMargins &margins) noexcept
: m_left(margins.left()), m_top(margins.top()), m_right(margins.right()), m_bottom(margins.bottom()) {}
-Q_DECL_CONSTEXPR inline bool QMarginsF::isNull() const noexcept
+constexpr inline bool QMarginsF::isNull() const noexcept
{ return qFuzzyIsNull(m_left) && qFuzzyIsNull(m_top) && qFuzzyIsNull(m_right) && qFuzzyIsNull(m_bottom); }
-Q_DECL_CONSTEXPR inline qreal QMarginsF::left() const noexcept
+constexpr inline qreal QMarginsF::left() const noexcept
{ return m_left; }
-Q_DECL_CONSTEXPR inline qreal QMarginsF::top() const noexcept
+constexpr inline qreal QMarginsF::top() const noexcept
{ return m_top; }
-Q_DECL_CONSTEXPR inline qreal QMarginsF::right() const noexcept
+constexpr inline qreal QMarginsF::right() const noexcept
{ return m_right; }
-Q_DECL_CONSTEXPR inline qreal QMarginsF::bottom() const noexcept
+constexpr inline qreal QMarginsF::bottom() const noexcept
{ return m_bottom; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMarginsF::setLeft(qreal aleft) noexcept
+constexpr inline void QMarginsF::setLeft(qreal aleft) noexcept
{ m_left = aleft; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMarginsF::setTop(qreal atop) noexcept
+constexpr inline void QMarginsF::setTop(qreal atop) noexcept
{ m_top = atop; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMarginsF::setRight(qreal aright) noexcept
+constexpr inline void QMarginsF::setRight(qreal aright) noexcept
{ m_right = aright; }
-Q_DECL_RELAXED_CONSTEXPR inline void QMarginsF::setBottom(qreal abottom) noexcept
+constexpr inline void QMarginsF::setBottom(qreal abottom) noexcept
{ m_bottom = abottom; }
-Q_DECL_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());
-}
-
-Q_DECL_CONSTEXPR inline bool operator!=(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
-{
- return !operator==(lhs, rhs);
-}
-
-Q_DECL_CONSTEXPR inline QMarginsF operator+(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
+constexpr inline QMarginsF operator+(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
return QMarginsF(lhs.left() + rhs.left(), lhs.top() + rhs.top(),
lhs.right() + rhs.right(), lhs.bottom() + rhs.bottom());
}
-Q_DECL_CONSTEXPR inline QMarginsF operator-(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
+constexpr inline QMarginsF operator-(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
return QMarginsF(lhs.left() - rhs.left(), lhs.top() - rhs.top(),
lhs.right() - rhs.right(), lhs.bottom() - rhs.bottom());
}
-Q_DECL_CONSTEXPR inline QMarginsF operator+(const QMarginsF &lhs, qreal rhs) noexcept
+constexpr inline QMarginsF operator+(const QMarginsF &lhs, qreal rhs) noexcept
{
return QMarginsF(lhs.left() + rhs, lhs.top() + rhs,
lhs.right() + rhs, lhs.bottom() + rhs);
}
-Q_DECL_CONSTEXPR inline QMarginsF operator+(qreal lhs, const QMarginsF &rhs) noexcept
+constexpr inline QMarginsF operator+(qreal lhs, const QMarginsF &rhs) noexcept
{
return QMarginsF(rhs.left() + lhs, rhs.top() + lhs,
rhs.right() + lhs, rhs.bottom() + lhs);
}
-Q_DECL_CONSTEXPR inline QMarginsF operator-(const QMarginsF &lhs, qreal rhs) noexcept
+constexpr inline QMarginsF operator-(const QMarginsF &lhs, qreal rhs) noexcept
{
return QMarginsF(lhs.left() - rhs, lhs.top() - rhs,
lhs.right() - rhs, lhs.bottom() - rhs);
}
-Q_DECL_CONSTEXPR inline QMarginsF operator*(const QMarginsF &lhs, qreal rhs) noexcept
+constexpr inline QMarginsF operator*(const QMarginsF &lhs, qreal rhs) noexcept
{
return QMarginsF(lhs.left() * rhs, lhs.top() * rhs,
lhs.right() * rhs, lhs.bottom() * rhs);
}
-Q_DECL_CONSTEXPR inline QMarginsF operator*(qreal lhs, const QMarginsF &rhs) noexcept
+constexpr inline QMarginsF operator*(qreal lhs, const QMarginsF &rhs) noexcept
{
return QMarginsF(rhs.left() * lhs, rhs.top() * lhs,
rhs.right() * lhs, rhs.bottom() * lhs);
}
-Q_DECL_CONSTEXPR inline QMarginsF operator/(const QMarginsF &lhs, qreal divisor)
+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);
}
-Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator+=(const QMarginsF &margins) noexcept
+constexpr inline QMarginsF operator|(const QMarginsF &m1, const QMarginsF &m2) noexcept
+{
+ return QMarginsF(qMax(m1.left(), m2.left()), qMax(m1.top(), m2.top()),
+ qMax(m1.right(), m2.right()), qMax(m1.bottom(), m2.bottom()));
+}
+
+constexpr inline QMarginsF &QMarginsF::operator+=(const QMarginsF &margins) noexcept
{
return *this = *this + margins;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator-=(const QMarginsF &margins) noexcept
+constexpr inline QMarginsF &QMarginsF::operator-=(const QMarginsF &margins) noexcept
{
return *this = *this - margins;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator+=(qreal addend) noexcept
+constexpr inline QMarginsF &QMarginsF::operator+=(qreal addend) noexcept
{
m_left += addend;
m_top += addend;
@@ -449,7 +460,7 @@ Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator+=(qreal addend) n
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator-=(qreal subtrahend) noexcept
+constexpr inline QMarginsF &QMarginsF::operator-=(qreal subtrahend) noexcept
{
m_left -= subtrahend;
m_top -= subtrahend;
@@ -458,27 +469,29 @@ Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator-=(qreal subtrahen
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator*=(qreal factor) noexcept
+constexpr inline QMarginsF &QMarginsF::operator*=(qreal factor) noexcept
{
return *this = *this * factor;
}
-Q_DECL_RELAXED_CONSTEXPR inline QMarginsF &QMarginsF::operator/=(qreal divisor)
+constexpr inline QMarginsF &QMarginsF::operator/=(qreal divisor)
{
return *this = *this / divisor;
}
-Q_DECL_CONSTEXPR inline QMarginsF operator+(const QMarginsF &margins) noexcept
+constexpr inline QMarginsF operator+(const QMarginsF &margins) noexcept
{
return margins;
}
-Q_DECL_CONSTEXPR inline QMarginsF operator-(const QMarginsF &margins) noexcept
+constexpr inline QMarginsF operator-(const QMarginsF &margins) noexcept
{
return QMarginsF(-margins.left(), -margins.top(), -margins.right(), -margins.bottom());
}
-Q_DECL_CONSTEXPR inline QMargins QMarginsF::toMargins() const noexcept
+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));
}
@@ -489,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 40a1193622..0000000000
--- a/src/corelib/tools/qmessageauthenticationcode.cpp
+++ /dev/null
@@ -1,305 +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"
-
-/*
- 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"
-
-#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;
- }
- 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
new file mode 100644
index 0000000000..0b05192817
--- /dev/null
+++ b/src/corelib/tools/qmultimap.qdoc
@@ -0,0 +1,1543 @@
+// 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
+ \inmodule QtCore
+ \brief The QMultiMap class is a template class that provides an associative array with multiple equivalent keys.
+
+ \ingroup tools
+ \ingroup shared
+
+ \reentrant
+
+ QMultiMap\<Key, T\> is one of Qt's generic \l{container classes}. It
+ stores (key, value) pairs and provides fast lookup by key.
+
+ QMultiMap and QMultiHash provide very similar functionality. The
+ differences are:
+
+ \list
+ \li QMultiHash provides average faster lookups than QMultiMap. (See \l{Algorithmic
+ Complexity} for details.)
+ \li When iterating over a QMultiHash, the items are arbitrarily ordered.
+ With QMultiMap, the items are always sorted by key.
+ \li The key type of a QMultiHash must provide operator==() and a global
+ qHash(Key) function. The key type of a QMultiMap must provide
+ operator<() specifying a total order. Since Qt 5.8.1 it is also safe
+ to use a pointer type as key, even if the underlying operator<()
+ does not provide a total order.
+ \endlist
+
+ Here's an example QMultiMap with QString keys and \c int values:
+ \snippet code/src_corelib_tools_qmultimap.cpp 0
+
+ To insert a (key, value) pair into the multi map, you can use insert():
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 2
+
+ This inserts the following three (key, value) pairs into the
+ QMultiMap: ("a", 1), ("b", 3), ("c", 7), and ("c", -5); note
+ that duplicate keys are allowed.
+
+ To look up a value, use find() or value():
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 3
+
+ If there is no item with the specified key in the map, these
+ functions return a \l{default-constructed value}.
+
+ If you want to check whether the map contains a certain key, use
+ contains():
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 4
+
+ There is also a value() overload that uses its second argument as
+ a default value if there is no item with the specified key:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 5
+
+ If you want to navigate through all the (key, value) pairs stored
+ in a QMultiMap, you can use an iterator. QMultiMap provides both
+ \l{Java-style iterators} (QMultiMapIterator and QMutableMultiMapIterator)
+ and \l{STL-style iterators} (QMultiMap::const_iterator and
+ QMultiMap::iterator). Here's how to iterate over a QMultiMap<QString, int>
+ using a Java-style iterator:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 7
+
+ Here's the same code, but using an STL-style iterator this time:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 8
+
+ The items are traversed in ascending key order.
+
+ A QMultiMap allows multiple values per key. If you call
+ insert() with a key that already exists in the map, a
+ new (key, value) pair will be inserted. For example:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 9
+
+ 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_qmultimap.cpp 10
+
+ The items that share the same key are available from most
+ recently to least recently inserted. 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_qmultimap.cpp 11
+
+ If you only need to extract the values from a map (not the keys),
+ you can also use range-based for:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 12
+
+ Items can be removed from the multi map in several ways. One way is to
+ call remove(); this will remove any item with the given key.
+ Another way is to use QMutableMultiMapIterator::remove(). In addition,
+ you can clear the entire map using clear().
+
+ It is possible to merge two multi maps by calling unite(), by
+ using operator+(), and by using operator+=(). Example:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 25
+
+ QMultiMap's key and value data types must be \l{assignable data
+ types}. This covers most data types you are likely to encounter,
+ but the compiler won't let you, for example, store a QWidget as a
+ value; instead, store a QWidget *. In addition, QMultiMap's key type
+ must provide operator<(). QMap uses it to keep its items sorted,
+ and assumes that two keys \c x and \c y are equal if neither \c{x
+ < y} nor \c{y < x} is true.
+
+ Example:
+ \snippet code/src_corelib_tools_qmultimap.cpp 13
+
+ In the example, we start by comparing the employees' names. If
+ they're equal, we compare their dates of birth to break the tie.
+
+ \sa QMultiMapIterator, QMutableMultiMapIterator, QMultiHash
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap()
+
+ Constructs an empty multi map.
+
+ \sa clear()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(QMultiMap<Key, T> &&other)
+
+ Move-constructs a QMultiMap instance, making it point at the same
+ object that \a other was pointing to.
+
+ \since 5.2
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(const QMultiMap<Key, T> &other)
+
+ Constructs a copy of \a other.
+
+ This operation occurs in \l{constant time}, because QMultiMap is
+ \l{implicitly shared}. This makes returning a QMultiMap from a
+ function very fast. If a shared instance is modified, it will be
+ copied (copy-on-write), and this takes \l{linear time}.
+
+ \sa operator=()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::operator=(const QMultiMap<Key, T> &other)
+
+ Assigns \a other to this multi map and returns a reference to this multi map.
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::operator=(QMultiMap<Key, T> &&other)
+
+ Move-assigns \a other to this QMultiMap instance.
+
+ \since 5.2
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::~QMultiMap()
+
+ Destroys the multi map. References to the values in the multi map, and all
+ iterators over this multi map, become invalid.
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(std::initializer_list<std::pair<Key,T> > list)
+ \since 5.1
+
+ Constructs a multi map with a copy of each of the elements in the
+ initializer list \a list.
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(const QMap<Key, T> &other)
+ \since 6.0
+
+ Constructs a multi map as a copy of \a other.
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(QMap<Key, T> &&other)
+ \since 6.0
+
+ If \a other is shared, constructs a multi map as a copy of \a other.
+ Otherwise, constructs a multi map by moving the elements from \a other.
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(const std::multimap<Key, T> &other)
+
+ Constructs a copy of \a other.
+
+ \sa toStdMultiMap()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::QMultiMap(std::multimap<Key, T> &&other)
+
+ Constructs a multi map by moving from \a other.
+
+ \sa toStdMultiMap()
+*/
+
+/*! \fn template <class Key, class T> std::multimap<Key, T> QMultiMap<Key, T>::toStdMap() const
+ \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 &
+
+ Returns an STL multi map equivalent to this QMultiMap.
+*/
+
+/*! \fn template <class Key, class T> void QMultiMap<Key, T>::swap(QMultiMap<Key, T> &other)
+ \since 4.8
+
+ Swaps multi map \a other with this multi map. This operation is very
+ fast and never fails.
+*/
+
+/*! \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 lhs is equal to \a rhs; otherwise returns
+ false.
+
+ Two multi maps are considered equal if they contain the same (key,
+ value) pairs, in the same order (which matters for duplicate keys).
+
+ This function requires the key and the value types to implement \c
+ operator==().
+
+ \sa operator!=()
+*/
+
+/*! \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 lhs is not equal to \a rhs; otherwise
+ returns \c false.
+
+ Two multi maps are considered equal if they contain the same (key,
+ value) pairs, in the same order (which matters for duplicate keys).
+
+ This function requires the key and the value types to implement \c
+ operator==().
+
+ \sa operator==()
+*/
+
+/*! \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::size() const
+
+ Returns the number of (key, value) pairs in the multi map.
+
+ \sa isEmpty(), count()
+*/
+
+/*!
+ \fn template <class Key, class T> bool QMultiMap<Key, T>::isEmpty() const
+
+ Returns \c true if the multi map contains no items; otherwise returns
+ false.
+
+ \sa size()
+*/
+
+/*! \fn template <class Key, class T> void QMultiMap<Key, T>::detach()
+
+ \internal
+
+ Detaches this map from any other multi maps with which it may share
+ data.
+
+ \sa isDetached()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::isDetached() const
+
+ \internal
+
+ Returns \c true if the multi map's internal data isn't shared with any
+ other map object; otherwise returns \c false.
+
+ \sa detach()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::isSharedWith(const QMultiMap<Key, T> &other) const
+
+ \internal
+*/
+
+/*! \fn template <class Key, class T> void QMultiMap<Key, T>::clear()
+
+ Removes all items from the multi map.
+
+ \sa remove()
+*/
+
+/*! \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::remove(const Key &key)
+
+ Removes all the items that have the key \a key from the multi map.
+ Returns the number of items removed.
+
+ \sa clear(), take()
+*/
+
+/*! \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::remove(const Key &key, const T &value)
+
+ Removes all the items that have the key \a key and value \a value
+ from the multi map.
+ Returns the number of items removed.
+
+ \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
+ the value associated with it.
+
+ If the item does not exist in the multi 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.
+
+ If you don't use the return value, remove() is more efficient.
+
+ \sa remove()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::contains(const Key &key) const
+
+ Returns \c true if the multi map contains an item with key \a key;
+ otherwise returns \c false.
+
+ \sa count()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::contains(const Key &key, const T &value) const
+ \since 4.3
+
+ Returns \c true if the multi map contains an item with key \a key
+ and value \a value; otherwise returns \c false.
+
+ \sa count()
+*/
+
+/*!
+ \fn template <class Key, class T> Key QMultiMap<Key, T>::key(const T &value, const Key &defaultKey) const
+ \since 4.3
+ \overload
+
+ Returns the first key with value \a value, or \a defaultKey if
+ the multi map contains no item with value \a value. If no \a defaultKey
+ is provided the function returns a
+ \l{default-constructed value}{default-constructed key}.
+
+ This function can be slow (\l{linear time}), because QMultiMap's
+ internal data structure is optimized for fast lookup by key, not
+ by value.
+
+ \sa value(), keys()
+*/
+
+/*! \fn template <class Key, class T> T QMultiMap<Key, T>::value(const Key &key, const T &defaultValue) const
+
+ Returns the value associated with the key \a key.
+
+ If the multi map contains no item with key \a key, the function returns
+ \a defaultValue. If no \a defaultValue is specified, the function
+ returns a \l{default-constructed value}. If there are multiple
+ items for \a key in the multi map, the value of the most recently
+ inserted one is returned.
+
+ \sa key(), values(), contains()
+*/
+
+/*! \fn template <class Key, class T> QList<Key> QMultiMap<Key, T>::keys() const
+
+ Returns a list containing all the keys in the multi map in ascending
+ order. Keys that occur multiple times in the multi map
+ also occur multiple times in the list.
+
+ The order is guaranteed to be the same as that used by values().
+
+ This function creates a new list, in \l {linear time}. The time and memory
+ use that entails can be avoided by iterating from \l keyBegin() to
+ \l keyEnd().
+
+ \sa values(), key()
+*/
+
+/*! \fn template <class Key, class T> QList<Key> QMultiMap<Key, T>::keys(const T &value) const
+
+ \overload
+
+ Returns a list containing all the keys associated with value \a
+ value in ascending order.
+
+ This function can be slow (\l{linear time}), because QMultiMap's
+ internal data structure is optimized for fast lookup by key, not
+ by value.
+*/
+
+/*! \fn template <class Key, class T> QList<Key> QMultiMap<Key, T>::uniqueKeys() const
+ \since 4.2
+
+ Returns a list containing all the keys in the map in ascending
+ order. Keys that occur multiple times in the map occur only
+ once in the returned list.
+*/
+
+/*! \fn template <class Key, class T> QList<T> QMultiMap<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.
+
+ \sa keys(), value()
+*/
+
+/*! \fn template <class Key, class T> QList<T> QMultiMap<Key, T>::values(const Key &key) const
+
+ Returns a list containing all the values associated with key
+ \a key, from the most recently inserted to the least recently
+ inserted one.
+
+ \sa keys(), value()
+*/
+
+/*! \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::count() const
+
+ \overload
+
+ Same as size().
+*/
+
+/*! \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::count(const Key &key) const
+
+ Returns the number of items associated with key \a key.
+
+ \sa contains(), QMultiMap::count()
+*/
+
+/*! \fn template <class Key, class T> qsizetype QMultiMap<Key, T>::count(const Key &key, const T &value) const
+
+ Returns the number of items with key \a key and value \a value.
+
+ \sa contains(), QMultiMap::count()
+*/
+
+
+/*! \fn template <class Key, class T> const Key &QMultiMap<Key, T>::firstKey() const
+ \since 5.2
+
+ Returns a reference to the smallest key in the multi map.
+ This function assumes that the multi map is not empty.
+
+ This executes in \l{constant time}.
+
+ \sa lastKey(), first(), keyBegin(), isEmpty()
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiMap<Key, T>::lastKey() const
+ \since 5.2
+
+ Returns a reference to the largest key in the multi map.
+ This function assumes that the multi map is not empty.
+
+ This executes in \l{logarithmic time}.
+
+ \sa firstKey(), last(), keyEnd(), isEmpty()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiMap<Key, T>::first()
+ \since 5.2
+
+ Returns a reference to the first value in the multi map, that is the value mapped
+ to the smallest key. This function assumes that the multi map is not empty.
+
+ When unshared (or const version is called), this executes in \l{constant time}.
+
+ \sa last(), firstKey(), isEmpty()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiMap<Key, T>::first() const
+ \since 5.2
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> T &QMultiMap<Key, T>::last()
+ \since 5.2
+
+ Returns a reference to the last value in the multi map, that is the value mapped
+ to the largest key. This function assumes that the map is not empty.
+
+ When unshared (or const version is called), this executes in \l{logarithmic time}.
+
+ \sa first(), lastKey(), isEmpty()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiMap<Key, T>::last() const
+ \since 5.2
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::begin()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
+ the multi map.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::begin() const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::cbegin() const
+ \since 5.0
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
+ in the multi map.
+
+ \sa begin(), cend()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::constBegin() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
+ in the multi map.
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::key_iterator QMultiMap<Key, T>::keyBegin() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
+ in the multi map.
+
+ \sa keyEnd(), firstKey()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::end()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
+ after the last item in the multi map.
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::end() const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::cend() const
+ \since 5.0
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the multi map.
+
+ \sa cbegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::constEnd() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the multi map.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::key_iterator QMultiMap<Key, T>::keyEnd() const
+ \since 5.6
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last key in the multi map.
+
+ \sa keyBegin(), lastKey()
+*/
+
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::key_value_iterator QMultiMap<Key, T>::keyValueBegin()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the multi map.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::key_value_iterator QMultiMap<Key, T>::keyValueEnd()
+ \since 5.10
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the multi map.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_key_value_iterator QMultiMap<Key, T>::keyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the multi map.
+
+ \sa keyValueEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_key_value_iterator QMultiMap<Key, T>::constKeyValueBegin() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
+ in the multi map.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_key_value_iterator QMultiMap<Key, T>::keyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the multi map.
+
+ \sa keyValueBegin()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_key_value_iterator QMultiMap<Key, T>::constKeyValueEnd() const
+ \since 5.10
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ entry after the last entry in the multi map.
+
+ \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()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::erase(const_iterator first, const_iterator last)
+ \since 6.0
+
+ Removes the (key, value) pairs pointed to by the iterator range
+ [\a first, \a last) from the multi map.
+ 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()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::find(const Key &key)
+
+ Returns an iterator pointing to the item with key \a key in the
+ multi map.
+
+ If the multi map contains no item with key \a key, the function
+ returns end().
+
+ If the map contains multiple items with key \a key, this
+ function returns an iterator that points to the most recently
+ inserted value. The other values are accessible by incrementing
+ the iterator. For example, here's some code that iterates over all
+ the items with the same key:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 11
+
+ \sa constFind(), value(), values(), lowerBound(), upperBound()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::find(const Key &key) const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::constFind(const Key &key) const
+ \since 4.1
+
+ Returns an const iterator pointing to the item with key \a key in the
+ multi map.
+
+ If the multi map contains no item with key \a key, the function
+ returns constEnd().
+
+ \sa find(), QMultiMap::constFind()
+*/
+
+/*!
+ \fn template <class Key, class T> typename QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::find(const Key &key, const T &value) const
+ \since 4.3
+ \overload
+
+ Returns a const iterator pointing to the item with the given \a key and
+ \a value in the map.
+
+ If the map contains no such item, the function returns end().
+
+ If the map contains multiple items with the specified \a key, this
+ function returns a const iterator that points to the most recently
+ inserted value.
+*/
+
+/*!
+ \fn template <class Key, class T> typename QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::constFind(const Key &key, const T &value) const
+ \since 4.3
+
+ Returns an iterator pointing to the item with key \a key and the
+ value \a value in the map.
+
+ If the map contains no such item, the function returns
+ constEnd().
+
+ \sa QMap::constFind()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::lowerBound(const Key &key)
+
+ Returns an iterator pointing to the first item with key \a key in
+ the map. If the map contains no item with key \a key, the
+ function returns an iterator to the nearest item with a greater
+ key.
+
+ Example:
+ \snippet code/src_corelib_tools_qmultimap.cpp 15
+
+ If the map contains multiple items with key \a key, this
+ function returns an iterator that points to the most recently
+ inserted value. The other values are accessible by incrementing
+ the iterator. For example, here's some code that iterates over all
+ the items with the same key:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 16
+
+ \sa upperBound(), find()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::lowerBound(const Key &key) const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::upperBound(const Key &key)
+
+ Returns an iterator pointing to the item that immediately follows
+ the last item with key \a key in the map. If the map contains no
+ item with key \a key, the function returns an iterator to the
+ nearest item with a greater key.
+
+ Example:
+ \snippet code/src_corelib_tools_qmultimap.cpp 17
+
+ \sa lowerBound(), find()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::upperBound(const Key &key) const
+
+ \overload
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const Key &key, const T &value)
+
+ Inserts a new item with the key \a key and a value of \a value.
+
+ If there is already an item with the same key in the map, this
+ function will simply create a new one. (This behavior is
+ different from replace(), which overwrites the value of an
+ existing item.)
+
+ Returns an iterator pointing to the new element.
+
+ \sa replace()
+*/
+
+/*! \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
+ suggesting where to do the insert.
+
+ If constBegin() is used as hint it indicates that the \a key is less than any key in the multi map
+ while constEnd() suggests that the \a key is (strictly) larger than any key in the multi map.
+ Otherwise the hint should meet the condition (\a pos - 1).key() < \a key <= pos.key().
+ If the hint \a pos is wrong it is ignored and a regular insert is done.
+
+ If the hint is correct and the multi map is unshared, the insert executes in amortized \l{constant time}.
+
+ If there is already an item with the same key in the map, this function will simply create a new one.
+
+ When creating a multi map from sorted data inserting the largest key first with constBegin()
+ 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.
+
+ 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
+
+ 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.
+
+ 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)
+
+ Inserts a new item with the key \a key and a value of \a value.
+
+ If there is already an item with the key \a key, that item's value
+ is replaced with \a value.
+
+ 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::iterator.
+*/
+
+/*! \typedef QMultiMap::ConstIterator
+
+ Qt-style synonym for QMultiMap::const_iterator.
+*/
+
+/*! \typedef QMultiMap::difference_type
+
+ Typedef for ptrdiff_t. Provided for STL compatibility.
+*/
+
+/*! \typedef QMultiMap::key_type
+
+ Typedef for Key. Provided for STL compatibility.
+*/
+
+/*! \typedef QMultiMap::mapped_type
+
+ Typedef for T. Provided for STL compatibility.
+*/
+
+/*! \typedef QMultiMap::size_type
+
+ Typedef for int. Provided for STL compatibility.
+*/
+
+/*!
+ \fn template <class Key, class T> bool QMultiMap<Key, T>::empty() const
+
+ This function is provided for STL compatibility. It is equivalent
+ to isEmpty(), returning true if the map is empty; otherwise
+ returning false.
+*/
+
+/*!
+ \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> 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 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<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 rhs map into the \a lhs map and
+ returns the resulting map.
+
+ \sa insert(), operator+()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
+ \relates QMultiMap
+
+ Returns a map that contains all the items in the \a lhs map in
+ addition to all the items in \a rhs. If a key is common to both
+ maps, the resulting map will contain the key multiple times.
+
+ \sa operator+=()
+*/
+
+/*! \class QMultiMap::iterator
+ \inmodule QtCore
+ \brief The QMultiMap::iterator class provides an STL-style non-const iterator for QMultiMap.
+
+ 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
+ should use QMultiMap::const_iterator. It is generally good practice to
+ use QMultiMap::const_iterator on a non-const QMultiMap as well, unless you
+ need to change the QMultiMap through the iterator. Const iterators are
+ slightly faster, and can improve code readability.
+
+ The default QMultiMap::iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QMultiMap function like
+ QMultiMap::begin(), QMultiMap::end(), or QMultiMap::find() before you can
+ start iterating. Here's a typical loop that prints all the (key,
+ value) pairs stored in a map:
+
+ 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.
+
+ Here's an example that increments every value stored in the QMultiMap
+ by 2:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 19
+
+ 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
+
+ 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
+ will become dangling iterators.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiMap::const_iterator, QMultiMap::key_iterator, QMultiMap::key_value_iterator
+*/
+
+/*! \typedef QMultiMap::iterator::difference_type
+
+ \internal
+*/
+
+/*! \typedef QMultiMap::iterator::iterator_category
+
+ A synonym for \e {std::bidirectional_iterator_tag} indicating
+ this iterator is a bidirectional iterator.
+*/
+
+/*! \typedef QMultiMap::iterator::pointer
+
+ \internal
+*/
+
+/*! \typedef QMultiMap::iterator::reference
+
+ \internal
+*/
+
+/*! \typedef QMultiMap::iterator::value_type
+
+ \internal
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator::iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QMultiMap::begin(), QMultiMap::end()
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiMap<Key, T>::iterator::key() const
+
+ Returns the current item's key as a const reference.
+
+ There is no direct way of changing an item's key through an
+ iterator, although it can be done by calling QMultiMap::erase()
+ followed by QMultiMap::insert().
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiMap<Key, T>::iterator::value() const
+
+ Returns a modifiable reference to the current item's value.
+
+ You can change the value of an item by using value() on
+ the left side of an assignment, for example:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 23
+
+ \sa key(), operator*()
+*/
+
+/*! \fn template <class Key, class T> T &QMultiMap<Key, T>::iterator::operator*() const
+
+ Returns a modifiable reference to the current item's value.
+
+ Same as value().
+
+ \sa key()
+*/
+
+/*! \fn template <class Key, class T> T *QMultiMap<Key, T>::iterator::operator->() const
+
+ Returns a pointer to the current item's value.
+
+ \sa value()
+*/
+
+/*!
+ \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 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 &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 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 \c{++} operator (\c{++i}) advances the iterator to the
+ next item in the multi map and returns an iterator to the new current
+ item.
+
+ Calling this function on QMultiMap::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator++(int)
+
+ \overload
+
+ 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 \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
+ results.
+
+ \sa operator++()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::iterator QMultiMap<Key, T>::iterator::operator--(int)
+
+ \overload
+
+ 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\<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
+ good practice to use QMultiMap::const_iterator on a non-const QMultiMap as
+ well, unless you need to change the QMultiMap through the iterator.
+ Const iterators are slightly faster, and can improve code
+ readability.
+
+ The default QMultiMap::const_iterator constructor creates an
+ uninitialized iterator. You must initialize it using a QMultiMap
+ 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,
+ from the most recently to the least recently inserted value.
+
+ Multiple iterators can be used on the same multi 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
+ will become dangling iterators.
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiMap::iterator, QMultiMap::key_iterator, QMultiMap::const_key_value_iterator
+*/
+
+/*! \typedef QMultiMap::const_iterator::difference_type
+
+ \internal
+*/
+
+/*! \typedef QMultiMap::const_iterator::iterator_category
+
+ A synonym for \e {std::bidirectional_iterator_tag} indicating
+ this iterator is a bidirectional iterator.
+*/
+
+/*! \typedef QMultiMap::const_iterator::pointer
+
+ \internal
+*/
+
+/*! \typedef QMultiMap::const_iterator::reference
+
+ \internal
+*/
+
+/*! \typedef QMultiMap::const_iterator::value_type
+
+ \internal
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator::const_iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like key(), value(), and operator++() must not be
+ called on an uninitialized iterator. Use operator=() to assign a
+ value to it before using it.
+
+ \sa QMultiMap::constBegin(), QMultiMap::constEnd()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator::const_iterator(const iterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn template <class Key, class T> const Key &QMultiMap<Key, T>::const_iterator::key() const
+
+ Returns the current item's key.
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiMap<Key, T>::const_iterator::value() const
+
+ Returns the current item's value.
+
+ \sa key(), operator*()
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiMap<Key, T>::const_iterator::operator*() const
+
+ Returns the current item's value.
+
+ Same as value().
+
+ \sa key()
+*/
+
+/*! \fn template <class Key, class T> const T *QMultiMap<Key, T>::const_iterator::operator->() const
+
+ Returns a pointer to the current item's value.
+
+ \sa value()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator &QMultiMap<Key, T>::const_iterator::operator++()
+
+ 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.
+
+ Calling this function on QMultiMap::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator++(int)
+
+ \overload
+
+ 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 \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
+ results.
+
+ \sa operator++()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::const_iterator QMultiMap<Key, T>::const_iterator::operator--(int)
+
+ \overload
+
+ 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
+ \brief The QMultiMap::key_iterator class provides an STL-style const iterator for QMultiMap keys.
+
+ QMultiMap::key_iterator is essentially the same as QMultiMap::const_iterator
+ with the difference that operator*() and operator->() return a key
+ instead of a value.
+
+ For most uses QMultiMap::iterator and QMultiMap::const_iterator should be used,
+ you can easily access the key by calling QMultiMap::iterator::key():
+
+ \snippet code/src_corelib_tools_qmultimap.cpp keyiterator1
+
+ However, to have interoperability between QMultiMap's keys and STL-style
+ algorithms we need an iterator that dereferences to a key instead
+ of a value. With QMultiMap::key_iterator we can apply an algorithm to a
+ range of keys without having to call QMultiMap::keys(), which is inefficient
+ as it costs one QMultiMap iteration and memory allocation to create a temporary
+ QList.
+
+ \snippet code/src_corelib_tools_qmultimap.cpp keyiterator2
+
+ QMultiMap::key_iterator is const, it's not possible to modify the key.
+
+ The default QMultiMap::key_iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QMultiMap function like
+ QMultiMap::keyBegin() or QMultiMap::keyEnd().
+
+ \warning Iterators on implicitly shared containers do not work
+ exactly like STL-iterators. You should avoid copying a container
+ while iterators are active on that container. For more information,
+ read \l{Implicit sharing iterator problem}.
+
+ \sa QMultiMap::const_iterator, QMultiMap::iterator
+*/
+
+/*! \typedef QMultiMap::key_iterator::difference_type
+ \internal
+*/
+
+/*! \typedef QMultiMap::key_iterator::iterator_category
+ \internal
+*/
+
+/*! \typedef QMultiMap::key_iterator::pointer
+ \internal
+*/
+
+/*! \typedef QMultiMap::key_iterator::reference
+ \internal
+*/
+
+/*! \typedef QMultiMap::key_iterator::value_type
+ \internal
+*/
+
+/*! \fn template <class Key, class T> const T &QMultiMap<Key, T>::key_iterator::operator*() const
+
+ Returns the current item's key.
+*/
+
+/*! \fn template <class Key, class T> const T *QMultiMap<Key, T>::key_iterator::operator->() const
+
+ Returns a pointer to the current item's key.
+*/
+
+/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::key_iterator::operator==(key_iterator other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn template <class Key, class T> bool QMultiMap<Key, T>::key_iterator::operator!=(key_iterator other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn template <class Key, class T> QMultiMap<Key, T>::key_iterator &QMultiMap<Key, T>::key_iterator::operator++()
+
+ 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.
+
+ Calling this function on QMultiMap::keyEnd() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::key_iterator QMultiMap<Key, T>::key_iterator::operator++(int)
+
+ \overload
+
+ 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 \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
+ results.
+
+ \sa operator++()
+*/
+
+/*! \fn template <class Key, class T> QMultiMap<Key, T>::key_iterator QMultiMap<Key, T>::key_iterator::operator--(int)
+
+ \overload
+
+ The postfix \c{--} operator (\c{i--}) makes the preceding item
+ current and returns an iterator pointing to the previous
+ item.
+*/
+
+/*! \fn template <class Key, class T> const_iterator QMultiMap<Key, T>::key_iterator::base() const
+ Returns the underlying const_iterator this key_iterator is based on.
+*/
+
+/*! \typedef QMultiMap::const_key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMultiMap::const_key_value_iterator typedef provides an STL-style iterator for QMultiMap.
+
+ QMultiMap::const_key_value_iterator is essentially the same as QMultiMap::const_iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
+/*! \typedef QMultiMap::key_value_iterator
+ \inmodule QtCore
+ \since 5.10
+ \brief The QMultiMap::key_value_iterator typedef provides an STL-style iterator for QMultiMap.
+
+ QMultiMap::key_value_iterator is essentially the same as QMultiMap::iterator
+ with the difference that operator*() returns a key/value pair instead of a
+ value.
+
+ \sa QKeyValueIterator
+*/
+
+/*! \fn template <class Key, class T> QDataStream &operator<<(QDataStream &out, const QMultiMap<Key, T> &map)
+ \relates QMultiMap
+
+ Writes the multi map \a map to stream \a out.
+
+ This function requires the key and value types to implement \c
+ operator<<().
+
+ \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
+*/
+
+/*! \fn template <class Key, class T> QDataStream &operator>>(QDataStream &in, QMultiMap<Key, T> &map)
+ \relates QMultiMap
+
+ Reads a map from stream \a in into \a map.
+
+ This function requires the key and value types to implement \c
+ operator>>().
+
+ \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 4dd9e9603b..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 9ebf88bc8f..84f99075e1 100644
--- a/src/corelib/tools/qpair.h
+++ b/src/corelib/tools/qpair.h
@@ -1,158 +1,28 @@
-/****************************************************************************
-**
-** 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
-
-template <class T1, class T2>
-struct QPair
-{
- typedef T1 first_type;
- typedef T2 second_type;
-
- Q_DECL_CONSTEXPR QPair()
- noexcept((std::is_nothrow_default_constructible<T1>::value &&
- std::is_nothrow_default_constructible<T2>::value))
- : first(), second() {}
- Q_DECL_CONSTEXPR QPair(const T1 &t1, const T2 &t2)
- noexcept((std::is_nothrow_copy_constructible<T1>::value &&
- std::is_nothrow_copy_constructible<T2>::value))
- : first(t1), second(t2) {}
- // compiler-generated copy/move ctor/assignment operators are fine!
-
- template <typename TT1, typename TT2>
- Q_DECL_CONSTEXPR QPair(const QPair<TT1, TT2> &p)
- noexcept((std::is_nothrow_constructible<T1, TT1&>::value &&
- std::is_nothrow_constructible<T2, TT2&>::value))
- : first(p.first), second(p.second) {}
- template <typename TT1, typename TT2>
- Q_DECL_RELAXED_CONSTEXPR QPair &operator=(const QPair<TT1, TT2> &p)
- noexcept((std::is_nothrow_assignable<T1, TT1&>::value &&
- std::is_nothrow_assignable<T2, TT2&>::value))
- { first = p.first; second = p.second; return *this; }
- template <typename TT1, typename TT2>
- Q_DECL_CONSTEXPR QPair(QPair<TT1, TT2> &&p)
- noexcept((std::is_nothrow_constructible<T1, TT1>::value &&
- std::is_nothrow_constructible<T2, TT2>::value))
- // can't use std::move here as it's not constexpr in C++11:
- : first(static_cast<TT1 &&>(p.first)), second(static_cast<TT2 &&>(p.second)) {}
- template <typename TT1, typename TT2>
- Q_DECL_RELAXED_CONSTEXPR QPair &operator=(QPair<TT1, TT2> &&p)
- noexcept((std::is_nothrow_assignable<T1, TT1>::value &&
- std::is_nothrow_assignable<T2, TT2>::value))
- { first = std::move(p.first); second = std::move(p.second); return *this; }
-
- Q_DECL_RELAXED_CONSTEXPR void swap(QPair &other)
- noexcept(noexcept(qSwap(other.first, other.first)) && noexcept(qSwap(other.second, other.second)))
- {
- // use qSwap() to pick up ADL swaps automatically:
- qSwap(first, other.first);
- qSwap(second, other.second);
- }
-
- T1 first;
- T2 second;
-};
-
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
-template<class T1, class T2>
-QPair(T1, T2) -> QPair<T1, T2>;
+#if 0
+#pragma qt_class(QPair)
#endif
-template <typename T1, typename T2>
-void swap(QPair<T1, T2> &lhs, QPair<T1, T2> &rhs) noexcept(noexcept(lhs.swap(rhs)))
-{ lhs.swap(rhs); }
-
-// mark QPair<T1,T2> as complex/movable/primitive depending on the
-// typeinfos of the constituents:
-template<class T1, class T2>
-class QTypeInfo<QPair<T1, T2> > : public QTypeInfoMerger<QPair<T1, T2>, T1, T2> {}; // Q_DECLARE_TYPEINFO
+#ifndef QT_NO_QPAIR
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator==(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
- noexcept(noexcept(p1.first == p2.first && p1.second == p2.second))
-{ return p1.first == p2.first && p1.second == p2.second; }
-
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator!=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
- noexcept(noexcept(!(p1 == p2)))
-{ return !(p1 == p2); }
-
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator<(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
- noexcept(noexcept(p1.first < p2.first || (!(p2.first < p1.first) && p1.second < p2.second)))
-{
- return p1.first < p2.first || (!(p2.first < p1.first) && p1.second < p2.second);
-}
-
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator>(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
- noexcept(noexcept(p2 < p1))
-{
- return p2 < p1;
-}
-
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator<=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
- noexcept(noexcept(!(p2 < p1)))
-{
- return !(p2 < p1);
-}
-
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator>=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
- noexcept(noexcept(!(p1 < p2)))
+template <typename T1, typename T2>
+constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2)
+ noexcept(noexcept(std::make_pair(std::forward<T1>(value1), std::forward<T2>(value2))))
{
- return !(p1 < p2);
+ return std::make_pair(std::forward<T1>(value1), std::forward<T2>(value2));
}
-template <class T1, class T2>
-Q_DECL_CONSTEXPR Q_OUTOFLINE_TEMPLATE QPair<T1, T2> qMakePair(const T1 &x, const T2 &y)
- noexcept(noexcept(QPair<T1, T2>(x, y)))
-{
- return QPair<T1, T2>(x, y);
-}
+#endif // QT_NO_QPAIR
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc
index 65576ef2e6..3aaee157d4 100644
--- a/src/corelib/tools/qpair.qdoc
+++ b/src/corelib/tools/qpair.qdoc
@@ -1,282 +1,19 @@
-/****************************************************************************
-**
-** 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
- \reentrant
- \brief The QPair class is a template class that stores a pair of items.
-
- \ingroup tools
-
- QPair\<T1, T2\> can be used in your application if the STL \c
- pair type is not available. It stores one value of type T1 and
- one value of type T2. It can be used as a return value for a
- function that needs to return two values, or as the value type of
- a \l{Container classes}{generic container}.
-
- Here's an example of a QPair that stores one QString and one \c
- double value:
-
- \snippet code/doc_src_qpair.cpp 0
-
- The components are accessible as public data members called \l
- first and \l second. For example:
-
- \snippet code/doc_src_qpair.cpp 1
-
- Note, however, that it is almost always preferable to define a small struct
- to hold the result of a function with multiple return values. A struct
- trivially generalizes to more than two values, and allows more descriptive
- member names than \c{first} and \c{second}:
-
- \snippet code/doc_src_qpair.cpp struct
-
- The advent of C++11 automatic variable type deduction (\c{auto}) shifts the
- emphasis from the type name to the name of functions and members. Thus, QPair,
- like \c{std::pair} and \c{std::tuple}, is mostly useful in generic (template)
- code, where defining a dedicated type is not possible.
-
- QPair's template data types (T1 and T2) must be \l{assignable
- data types}. You cannot, for example, store a QWidget as a value;
- instead, store a QWidget *. A few functions have additional
- requirements; these requirements are documented on a per-function
- basis.
-
- \sa {Container Classes}
-*/
-
-/*! \typedef QPair::first_type
-
- The type of the first element in the pair (T1).
-
- \sa first
-*/
-
-/*! \typedef QPair::second_type
-
- The type of the second element in the pair (T2).
-
- \sa second
-*/
-
-/*! \variable QPair::first
-
- The first element in the pair.
-*/
-
-/*! \variable QPair::second
-
- The second element in the pair.
-*/
-
-/*! \fn template <class T1, class T2> QPair<T1, T2>::QPair()
-
- Constructs an empty pair. The \c first and \c second elements are
- initialized with \l{default-constructed value}s.
-*/
-
-/*!
- \fn template <class T1, class T2> QPair<T1, T2>::QPair(const T1 &value1, const T2 &value2)
-
- Constructs a pair and initializes the \c first element with \a
- value1 and the \c second element with \a value2.
-
- \sa qMakePair()
-*/
-
-/*!
-\fn template <class T1, class T2> void QPair<T1, T2>::swap(QPair &other)
-
- \since 5.5
- Swaps this pair with \a other.
-
- Equivalent to
- \code
- qSwap(this->first, other.first);
- qSwap(this->second, other.second);
- \endcode
-
- Swap overloads are found in namespace \c std as well as via
- argument-dependent lookup (ADL) in the namespace of \c{T} .
-*/
-
-/*!
-\fn template <class T1, class T2> void swap(QPair<T1, T2> &lhs, QPair<T1, T2> &rhs)
- \overload
- \relates QPair
- \since 5.5
-
- Swaps \a lhs with \a rhs.
-*/
-
-/*!
- \fn template <class T1, class T2> template <typename TT1, typename TT2> QPair<T1, T2>::QPair(const QPair<TT1, TT2> &p)
- \since 5.2
-
- Constructs a pair from the other pair \a p, of types TT1 and TT2. This
- constructor will fail if \c first cannot be initialized from \c p.first or
- if \c second cannot be initialized from \c p.second.
-
- \sa qMakePair()
-*/
-
-/*!
- \fn template <class T1, class T2> template <typename TT1, typename TT2> QPair<T1, T2>::QPair(QPair<TT1, TT2> &&p)
- \since 5.2
-
- Move-constructs a QPair instance, making it point to the same object that \a p was pointing to.
-*/
-
-/*!
- \fn template <class T1, class T2> template <typename TT1, typename TT2> QPair & QPair<T1, T2>::operator=(const QPair<TT1, TT2> &p)
- \since 5.2
-
- Copies pair \a p into this pair.
-
- \sa qMakePair()
-*/
-
-/*!
- \fn template <class T1, class T2> template <typename TT1, typename TT2> QPair & QPair<T1, T2>::operator=(QPair<TT1, TT2> &&p)
- \since 5.2
-
- Move-assigns pair \a p into this pair instance.
-*/
-
-/*! \fn template <class T1, class T2> bool operator==(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
-
+ \typealias QPair
\relates QPair
-
- Returns \c true if \a p1 is equal to \a p2; otherwise returns \c false.
- Two pairs compare equal if their \c first data members compare
- equal and if their \c second data members compare equal.
-
- This function requires the T1 and T2 types to have an
- implementation of \c operator==().
-*/
-
-/*! \fn template <class T1, class T2> bool operator!=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
-
- \relates QPair
-
- Returns \c true if \a p1 is not equal to \a p2; otherwise returns
- false. Two pairs compare as not equal if their \c first data
- members are not equal or if their \c second data members are not
- equal.
-
- This function requires the T1 and T2 types to have an
- implementation of \c operator==().
-*/
-
-/*! \fn template <class T1, class T2> bool operator<(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
-
- \relates QPair
-
- Returns \c true if \a p1 is less than \a p2; otherwise returns
- false. The comparison is done on the \c first members of \a p1
- and \a p2; if they compare equal, the \c second members are
- compared to break the tie.
-
- This function requires the T1 and T2 types to have an
- implementation of \c operator<().
-*/
-
-/*! \fn template <class T1, class T2> bool operator>(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
-
- \relates QPair
-
- Returns \c true if \a p1 is greater than \a p2; otherwise returns
- false. The comparison is done on the \c first members of \a p1
- and \a p2; if they compare equal, the \c second members are
- compared to break the tie.
-
- This function requires the T1 and T2 types to have an
- implementation of \c operator<().
-*/
-
-/*! \fn template <class T1, class T2> bool operator<=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
-
- \relates QPair
-
- Returns \c true if \a p1 is less than or equal to \a p2; otherwise
- returns \c false. The comparison is done on the \c first members of
- \a p1 and \a p2; if they compare equal, the \c second members are
- compared to break the tie.
-
- This function requires the T1 and T2 types to have an
- implementation of \c operator<().
-*/
-
-/*! \fn template <class T1, class T2> bool operator>=(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2)
-
- \relates QPair
-
- Returns \c true if \a p1 is greater than or equal to \a p2;
- otherwise returns \c false. The comparison is done on the \c first
- members of \a p1 and \a p2; if they compare equal, the \c second
- members are compared to break the tie.
-
- This function requires the T1 and T2 types to have an
- implementation of \c operator<().
+ \since 6.0
+ Typedef for std::pair\<T1, T2\>.
*/
/*!
- \fn template <class T1, class T2> QPair<T1, T2> qMakePair(const T1 &value1, const T2 &value2)
-
- \relates QPair
-
- Returns a QPair\<T1, T2\> that contains \a value1 and \a value2.
- Example:
-
- \snippet code/doc_src_qpair.cpp 2
-
- This is equivalent to QPair<T1, T2>(\a value1, \a value2), but
- usually requires less typing.
-*/
-
-/*! \fn template <class T1, class T2> QDataStream &operator>>(QDataStream &in, QPair<T1, T2> &pair)
-
- \relates QPair
-
- Reads a pair from stream \a in into \a pair.
-
- This function requires the T1 and T2 types to implement \c operator>>().
-
- \sa {Serializing Qt Data Types}
-*/
-
-/*! \fn template <class T1, class T2> QDataStream &operator<<(QDataStream &out, const QPair<T1, T2> &pair)
-
+ \fn template <class T1, class T2> QPair<T1, T2> qMakePair(T1 &&value1, T2 &&value2)
+ \deprecated
\relates QPair
- Writes the pair \a pair to stream \a out.
-
- This function requires the T1 and T2 types to implement \c operator<<().
-
- \sa {Serializing Qt Data Types}
+ qMakePair forwards its arguments to std::make_pair, and returns
+ the resulting std::pair. It is provided for backwards compatibility.
+ Use std::make_pair directly instead.
*/
diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp
index 432fb33297..d1f3b12a68 100644
--- a/src/corelib/tools/qpoint.cpp
+++ b/src/corelib/tools/qpoint.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** 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"
#include <private/qdebug_p.h>
+#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -243,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.
@@ -268,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.
@@ -278,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.
@@ -290,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.
@@ -302,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.
@@ -311,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.
@@ -324,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.
@@ -337,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.
@@ -347,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.
@@ -381,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.
@@ -393,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
*****************************************************************************/
@@ -484,6 +445,19 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
#endif
/*!
+ \fn size_t qHash(QPoint 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.
+*/
+size_t qHash(QPoint key, size_t seed) noexcept
+{
+ return qHashMulti(seed, key.x(), key.y());
+}
+
+/*!
\class QPointF
\inmodule QtCore
\ingroup painting
@@ -494,7 +468,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
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
@@ -531,7 +505,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
Constructs a copy of the given \a point.
- \sa toPoint()
+ \sa toPoint(), QPoint::toPointF()
*/
/*!
@@ -580,7 +554,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
/*!
\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()
*/
@@ -588,7 +562,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
/*!
\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()
*/
@@ -654,7 +628,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
/*!
\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
@@ -670,12 +644,13 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
\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.
@@ -684,8 +659,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
*/
/*!
- \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.
@@ -694,49 +668,46 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
*/
/*!
- \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/=()
*/
@@ -746,7 +717,7 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
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()
*/
/*!
@@ -759,17 +730,27 @@ QDebug operator<<(QDebug dbg, const QPointF &p)
*/
/*!
- \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.
- Returns \c true if \a p1 is 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.
+
+ \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 fe952f95da..7df4d49005 100644
--- a/src/corelib/tools/qpoint.h
+++ b/src/corelib/tools/qpoint.h
@@ -1,111 +1,107 @@
-/****************************************************************************
-**
-** 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 Q_CORE_EXPORT QPoint
+class QPoint
{
public:
- Q_DECL_CONSTEXPR QPoint();
- Q_DECL_CONSTEXPR QPoint(int xpos, int ypos);
+ constexpr QPoint() noexcept;
+ constexpr QPoint(int xpos, int ypos) noexcept;
- Q_DECL_CONSTEXPR inline bool isNull() const;
+ constexpr inline bool isNull() const noexcept;
- Q_DECL_CONSTEXPR inline int x() const;
- Q_DECL_CONSTEXPR inline int y() const;
- Q_DECL_RELAXED_CONSTEXPR inline void setX(int x);
- Q_DECL_RELAXED_CONSTEXPR inline void setY(int y);
+ constexpr inline int x() const noexcept;
+ constexpr inline int y() const noexcept;
+ constexpr inline void setX(int x) noexcept;
+ constexpr inline void setY(int y) noexcept;
- Q_DECL_CONSTEXPR inline int manhattanLength() const;
+ constexpr inline int manhattanLength() const;
- Q_DECL_CONSTEXPR QPoint transposed() const noexcept { return {yp, xp}; }
+ constexpr QPoint transposed() const noexcept { return {yp, xp}; }
- Q_DECL_RELAXED_CONSTEXPR inline int &rx();
- Q_DECL_RELAXED_CONSTEXPR inline int &ry();
+ constexpr inline int &rx() noexcept;
+ constexpr inline int &ry() noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QPoint &operator+=(const QPoint &p);
- Q_DECL_RELAXED_CONSTEXPR inline QPoint &operator-=(const QPoint &p);
+ constexpr inline QPoint &operator+=(const QPoint &p);
+ constexpr inline QPoint &operator-=(const QPoint &p);
- Q_DECL_RELAXED_CONSTEXPR inline QPoint &operator*=(float factor);
- Q_DECL_RELAXED_CONSTEXPR inline QPoint &operator*=(double factor);
- Q_DECL_RELAXED_CONSTEXPR inline QPoint &operator*=(int factor);
+ constexpr inline QPoint &operator*=(float factor);
+ constexpr inline QPoint &operator*=(double factor);
+ constexpr inline QPoint &operator*=(int factor);
- Q_DECL_RELAXED_CONSTEXPR inline QPoint &operator/=(qreal divisor);
+ constexpr inline QPoint &operator/=(qreal divisor);
- Q_DECL_CONSTEXPR static inline int dotProduct(const QPoint &p1, const QPoint &p2)
+ constexpr static inline int dotProduct(const QPoint &p1, const QPoint &p2)
{ return p1.xp * p2.xp + p1.yp * p2.yp; }
- friend Q_DECL_CONSTEXPR inline bool operator==(const QPoint &, const QPoint &);
- friend Q_DECL_CONSTEXPR inline bool operator!=(const QPoint &, const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator+(const QPoint &, const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator-(const QPoint &, const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator*(const QPoint &, float);
- friend Q_DECL_CONSTEXPR inline const QPoint operator*(float, const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator*(const QPoint &, double);
- friend Q_DECL_CONSTEXPR inline const QPoint operator*(double, const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator*(const QPoint &, int);
- friend Q_DECL_CONSTEXPR inline const QPoint operator*(int, const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator+(const QPoint &);
- friend Q_DECL_CONSTEXPR inline const QPoint operator-(const QPoint &);
- friend Q_DECL_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 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
@@ -119,160 +115,192 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QPoint &);
QPoint inline functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QPoint::QPoint() : xp(0), yp(0) {}
-
-Q_DECL_CONSTEXPR inline QPoint::QPoint(int xpos, int ypos) : xp(xpos), yp(ypos) {}
-
-Q_DECL_CONSTEXPR inline bool QPoint::isNull() const
-{ return xp == 0 && yp == 0; }
-
-Q_DECL_CONSTEXPR inline int QPoint::x() const
-{ return xp; }
-
-Q_DECL_CONSTEXPR inline int QPoint::y() const
-{ return yp; }
-
-Q_DECL_RELAXED_CONSTEXPR inline void QPoint::setX(int xpos)
-{ xp = xpos; }
-
-Q_DECL_RELAXED_CONSTEXPR inline void QPoint::setY(int ypos)
-{ yp = ypos; }
-
-inline int Q_DECL_CONSTEXPR QPoint::manhattanLength() const
-{ return qAbs(x())+qAbs(y()); }
-
-Q_DECL_RELAXED_CONSTEXPR inline int &QPoint::rx()
-{ return xp; }
-
-Q_DECL_RELAXED_CONSTEXPR inline int &QPoint::ry()
-{ return yp; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QPoint &QPoint::operator+=(const QPoint &p)
-{ xp+=p.xp; yp+=p.yp; return *this; }
+constexpr inline QPoint::QPoint() noexcept : xp(0), yp(0) {}
-Q_DECL_RELAXED_CONSTEXPR inline QPoint &QPoint::operator-=(const QPoint &p)
-{ xp-=p.xp; yp-=p.yp; return *this; }
+constexpr inline QPoint::QPoint(int xpos, int ypos) noexcept : xp(xpos), yp(ypos) {}
-Q_DECL_RELAXED_CONSTEXPR inline QPoint &QPoint::operator*=(float factor)
-{ xp = qRound(xp*factor); yp = qRound(yp*factor); return *this; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QPoint &QPoint::operator*=(double factor)
-{ xp = qRound(xp*factor); yp = qRound(yp*factor); return *this; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QPoint &QPoint::operator*=(int factor)
-{ xp = xp*factor; yp = yp*factor; return *this; }
-
-Q_DECL_CONSTEXPR inline bool operator==(const QPoint &p1, const QPoint &p2)
-{ return p1.xp == p2.xp && p1.yp == p2.yp; }
+constexpr inline bool QPoint::isNull() const noexcept
+{
+ return xp == 0 && yp == 0;
+}
-Q_DECL_CONSTEXPR inline bool operator!=(const QPoint &p1, const QPoint &p2)
-{ return p1.xp != p2.xp || p1.yp != p2.yp; }
+constexpr inline int QPoint::x() const noexcept
+{
+ return xp;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator+(const QPoint &p1, const QPoint &p2)
-{ return QPoint(p1.xp+p2.xp, p1.yp+p2.yp); }
+constexpr inline int QPoint::y() const noexcept
+{
+ return yp;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator-(const QPoint &p1, const QPoint &p2)
-{ return QPoint(p1.xp-p2.xp, p1.yp-p2.yp); }
+constexpr inline void QPoint::setX(int xpos) noexcept
+{
+ xp = xpos;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator*(const QPoint &p, float factor)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
+constexpr inline void QPoint::setY(int ypos) noexcept
+{
+ yp = ypos;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator*(const QPoint &p, double factor)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
+inline int constexpr QPoint::manhattanLength() const
+{
+ return qAbs(x()) + qAbs(y());
+}
-Q_DECL_CONSTEXPR inline const QPoint operator*(const QPoint &p, int factor)
-{ return QPoint(p.xp*factor, p.yp*factor); }
+constexpr inline int &QPoint::rx() noexcept
+{
+ return xp;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator*(float factor, const QPoint &p)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
+constexpr inline int &QPoint::ry() noexcept
+{
+ return yp;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator*(double factor, const QPoint &p)
-{ return QPoint(qRound(p.xp*factor), qRound(p.yp*factor)); }
+constexpr inline QPoint &QPoint::operator+=(const QPoint &p)
+{
+ xp += p.xp;
+ yp += p.yp;
+ return *this;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator*(int factor, const QPoint &p)
-{ return QPoint(p.xp*factor, p.yp*factor); }
+constexpr inline QPoint &QPoint::operator-=(const QPoint &p)
+{
+ xp -= p.xp;
+ yp -= p.yp;
+ return *this;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator+(const QPoint &p)
-{ return p; }
+constexpr inline QPoint &QPoint::operator*=(float factor)
+{
+ xp = qRound(xp * factor);
+ yp = qRound(yp * factor);
+ return *this;
+}
-Q_DECL_CONSTEXPR inline const QPoint operator-(const QPoint &p)
-{ return QPoint(-p.xp, -p.yp); }
+constexpr inline QPoint &QPoint::operator*=(double factor)
+{
+ xp = qRound(xp * factor);
+ yp = qRound(yp * factor);
+ return *this;
+}
-Q_DECL_RELAXED_CONSTEXPR inline QPoint &QPoint::operator/=(qreal c)
+constexpr inline QPoint &QPoint::operator*=(int factor)
{
- xp = qRound(xp/c);
- yp = qRound(yp/c);
+ xp = xp * factor;
+ yp = yp * factor;
return *this;
}
-Q_DECL_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
Q_CORE_EXPORT QDebug operator<<(QDebug, const QPoint &);
#endif
+Q_CORE_EXPORT size_t qHash(QPoint key, size_t seed = 0) noexcept;
-class Q_CORE_EXPORT QPointF
+class QPointF
{
public:
- Q_DECL_CONSTEXPR QPointF();
- Q_DECL_CONSTEXPR QPointF(const QPoint &p);
- Q_DECL_CONSTEXPR QPointF(qreal xpos, qreal ypos);
-
- Q_DECL_CONSTEXPR inline qreal manhattanLength() const;
-
- inline bool isNull() const;
-
- Q_DECL_CONSTEXPR inline qreal x() const;
- Q_DECL_CONSTEXPR inline qreal y() const;
- Q_DECL_RELAXED_CONSTEXPR inline void setX(qreal x);
- Q_DECL_RELAXED_CONSTEXPR inline void setY(qreal y);
-
- Q_DECL_CONSTEXPR QPointF transposed() const noexcept { return {yp, xp}; }
-
- Q_DECL_RELAXED_CONSTEXPR inline qreal &rx();
- Q_DECL_RELAXED_CONSTEXPR inline qreal &ry();
-
- Q_DECL_RELAXED_CONSTEXPR inline QPointF &operator+=(const QPointF &p);
- Q_DECL_RELAXED_CONSTEXPR inline QPointF &operator-=(const QPointF &p);
- Q_DECL_RELAXED_CONSTEXPR inline QPointF &operator*=(qreal c);
- Q_DECL_RELAXED_CONSTEXPR inline QPointF &operator/=(qreal c);
-
- Q_DECL_CONSTEXPR static inline qreal dotProduct(const QPointF &p1, const QPointF &p2)
- { return p1.xp * p2.xp + p1.yp * p2.yp; }
-
- friend Q_DECL_CONSTEXPR inline bool operator==(const QPointF &, const QPointF &);
- friend Q_DECL_CONSTEXPR inline bool operator!=(const QPointF &, const QPointF &);
- friend Q_DECL_CONSTEXPR inline const QPointF operator+(const QPointF &, const QPointF &);
- friend Q_DECL_CONSTEXPR inline const QPointF operator-(const QPointF &, const QPointF &);
- friend Q_DECL_CONSTEXPR inline const QPointF operator*(qreal, const QPointF &);
- friend Q_DECL_CONSTEXPR inline const QPointF operator*(const QPointF &, qreal);
- friend Q_DECL_CONSTEXPR inline const QPointF operator+(const QPointF &);
- friend Q_DECL_CONSTEXPR inline const QPointF operator-(const QPointF &);
- friend Q_DECL_CONSTEXPR inline const QPointF operator/(const QPointF &, qreal);
-
- Q_DECL_CONSTEXPR QPoint toPoint() const;
+ constexpr QPointF() noexcept;
+ constexpr QPointF(const QPoint &p) noexcept;
+ constexpr QPointF(qreal xpos, qreal ypos) noexcept;
+
+ constexpr inline qreal manhattanLength() const;
+
+ inline bool isNull() const noexcept;
+
+ constexpr inline qreal x() const noexcept;
+ constexpr inline qreal y() const noexcept;
+ constexpr inline void setX(qreal x) noexcept;
+ constexpr inline void setY(qreal y) noexcept;
+
+ constexpr QPointF transposed() const noexcept { return {yp, xp}; }
+
+ constexpr inline qreal &rx() noexcept;
+ constexpr inline qreal &ry() noexcept;
+
+ constexpr inline QPointF &operator+=(const QPointF &p);
+ constexpr inline QPointF &operator-=(const QPointF &p);
+ constexpr inline QPointF &operator*=(qreal c);
+ 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;
+ }
+
+ 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 static QPointF fromCGPoint(CGPoint point) noexcept;
- Q_REQUIRED_RESULT CGPoint toCGPoint() const noexcept;
+ [[nodiscard]] Q_CORE_EXPORT static QPointF fromCGPoint(CGPoint point) noexcept;
+ [[nodiscard]] Q_CORE_EXPORT CGPoint toCGPoint() const noexcept;
#endif
private:
- friend class QMatrix;
friend class QTransform;
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
@@ -286,129 +314,84 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QPointF &);
QPointF inline functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QPointF::QPointF() : xp(0), yp(0) { }
+constexpr inline QPointF::QPointF() noexcept : xp(0), yp(0) { }
-Q_DECL_CONSTEXPR inline QPointF::QPointF(qreal xpos, qreal ypos) : xp(xpos), yp(ypos) { }
+constexpr inline QPointF::QPointF(qreal xpos, qreal ypos) noexcept : xp(xpos), yp(ypos) { }
-Q_DECL_CONSTEXPR inline QPointF::QPointF(const QPoint &p) : xp(p.x()), yp(p.y()) { }
+constexpr inline QPointF::QPointF(const QPoint &p) noexcept : xp(p.x()), yp(p.y()) { }
-Q_DECL_CONSTEXPR inline qreal QPointF::manhattanLength() const
+constexpr inline qreal QPointF::manhattanLength() const
{
- return qAbs(x())+qAbs(y());
+ return qAbs(x()) + qAbs(y());
}
-inline bool QPointF::isNull() const
+inline bool QPointF::isNull() const noexcept
{
return qIsNull(xp) && qIsNull(yp);
}
-Q_DECL_CONSTEXPR inline qreal QPointF::x() const
+constexpr inline qreal QPointF::x() const noexcept
{
return xp;
}
-Q_DECL_CONSTEXPR inline qreal QPointF::y() const
+constexpr inline qreal QPointF::y() const noexcept
{
return yp;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QPointF::setX(qreal xpos)
+constexpr inline void QPointF::setX(qreal xpos) noexcept
{
xp = xpos;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QPointF::setY(qreal ypos)
+constexpr inline void QPointF::setY(qreal ypos) noexcept
{
yp = ypos;
}
-Q_DECL_RELAXED_CONSTEXPR inline qreal &QPointF::rx()
+constexpr inline qreal &QPointF::rx() noexcept
{
return xp;
}
-Q_DECL_RELAXED_CONSTEXPR inline qreal &QPointF::ry()
+constexpr inline qreal &QPointF::ry() noexcept
{
return yp;
}
-Q_DECL_RELAXED_CONSTEXPR inline QPointF &QPointF::operator+=(const QPointF &p)
+constexpr inline QPointF &QPointF::operator+=(const QPointF &p)
{
- xp+=p.xp;
- yp+=p.yp;
+ xp += p.xp;
+ yp += p.yp;
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QPointF &QPointF::operator-=(const QPointF &p)
-{
- xp-=p.xp; yp-=p.yp; return *this;
-}
-
-Q_DECL_RELAXED_CONSTEXPR inline QPointF &QPointF::operator*=(qreal c)
-{
- xp*=c; yp*=c; return *this;
-}
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
-QT_WARNING_DISABLE_GCC("-Wfloat-equal")
-
-Q_DECL_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));
-}
-
-Q_DECL_CONSTEXPR inline bool operator!=(const QPointF &p1, const QPointF &p2)
+constexpr inline QPointF &QPointF::operator-=(const QPointF &p)
{
- return !(p1 == p2);
-}
-
-QT_WARNING_POP
-
-Q_DECL_CONSTEXPR inline const QPointF operator+(const QPointF &p1, const QPointF &p2)
-{
- return QPointF(p1.xp+p2.xp, p1.yp+p2.yp);
-}
-
-Q_DECL_CONSTEXPR inline const QPointF operator-(const QPointF &p1, const QPointF &p2)
-{
- return QPointF(p1.xp-p2.xp, p1.yp-p2.yp);
-}
-
-Q_DECL_CONSTEXPR inline const QPointF operator*(const QPointF &p, qreal c)
-{
- return QPointF(p.xp*c, p.yp*c);
-}
-
-Q_DECL_CONSTEXPR inline const QPointF operator*(qreal c, const QPointF &p)
-{
- return QPointF(p.xp*c, p.yp*c);
-}
-
-Q_DECL_CONSTEXPR inline const QPointF operator+(const QPointF &p)
-{
- return p;
+ xp -= p.xp;
+ yp -= p.yp;
+ return *this;
}
-Q_DECL_CONSTEXPR inline const QPointF operator-(const QPointF &p)
+constexpr inline QPointF &QPointF::operator*=(qreal c)
{
- return QPointF(-p.xp, -p.yp);
+ xp *= c;
+ yp *= c;
+ return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QPointF &QPointF::operator/=(qreal divisor)
+constexpr inline QPointF &QPointF::operator/=(qreal divisor)
{
- xp/=divisor;
- yp/=divisor;
+ Q_ASSERT(divisor > 0 || divisor < 0);
+ xp /= divisor;
+ yp /= divisor;
return *this;
}
-Q_DECL_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; }
-Q_DECL_CONSTEXPR inline QPoint QPointF::toPoint() const
+constexpr inline QPoint QPointF::toPoint() const
{
return QPoint(qRound(xp), qRound(yp));
}
@@ -419,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 d5a60ada56..4863499f2a 100644
--- a/src/corelib/tools/qqueue.h
+++ b/src/corelib/tools/qqueue.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 QQUEUE_H
#define QQUEUE_H
@@ -51,11 +15,6 @@ class QQueue : public QList<T>
public:
// compiler-generated special member functions are fine!
inline void swap(QQueue<T> &other) noexcept { QList<T>::swap(other); } // prevent QList<->QQueue swaps
-#ifndef Q_QDOC
- // bring in QList::swap(int, int). We cannot say using QList<T>::swap,
- // because we don't want to make swap(QList&) available.
- Q_DECL_DEPRECATED inline void swap(int i, int j) { QList<T>::swapItemsAt(i, j); }
-#endif
inline void enqueue(const T &t) { QList<T>::append(t); }
inline T dequeue() { return QList<T>::takeFirst(); }
inline T &head() { return QList<T>::first(); }
diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp
index cd20102a2b..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"
@@ -81,7 +45,7 @@ QT_BEGIN_NAMESPACE
position, and the translated() function returns a translated copy
of this rectangle.
- The size() function returns the rectange's dimensions as a
+ The size() function returns the rectangle's dimensions as a
QSize. The dimensions can also be retrieved separately using the
width() and height() functions. To manipulate the dimensions use
the setSize(), setWidth() or setHeight() functions. Alternatively,
@@ -223,9 +187,14 @@ QT_BEGIN_NAMESPACE
/*!
\fn QRect::QRect(const QPoint &topLeft, const QPoint &bottomRight)
- Constructs a rectangle with the given \a topLeft and \a bottomRight corners.
+ Constructs a rectangle with the given \a topLeft and \a bottomRight corners, both included.
- \sa setTopLeft(), setBottomRight()
+ If \a bottomRight is to higher and to the left of \a topLeft, the rectangle defined
+ is instead non-inclusive of the corners.
+
+ \note To ensure both points are included regardless of relative order, use span().
+
+ \sa setTopLeft(), setBottomRight(), span()
*/
@@ -295,27 +264,22 @@ QT_BEGIN_NAMESPACE
non-negative width and height.
If width() < 0 the function swaps the left and right corners, and
- it swaps the top and bottom corners if height() < 0.
+ it swaps the top and bottom corners if height() < 0. The corners
+ are at the same time changed from being non-inclusive to inclusive.
\sa isValid(), isEmpty()
*/
QRect QRect::normalized() const noexcept
{
- QRect r;
- if (x2 < x1 - 1) { // swap bad x values
- r.x1 = x2;
- r.x2 = x1;
- } else {
- r.x1 = x1;
- r.x2 = x2;
+ QRect r(*this);
+ if (x2 < x1) { // swap bad x values
+ r.x1 = x2 + 1;
+ r.x2 = x1 - 1;
}
- if (y2 < y1 - 1) { // swap bad y values
- r.y1 = y2;
- r.y2 = y1;
- } else {
- r.y1 = y1;
- r.y2 = y2;
+ if (y2 < y1) { // swap bad y values
+ r.y1 = y2 + 1;
+ r.y2 = y1 - 1;
}
return r;
}
@@ -824,8 +788,8 @@ bool QRect::contains(const QPoint &p, bool proper) const noexcept
{
int l, r;
if (x2 < x1 - 1) {
- l = x2;
- r = x1;
+ l = x2 + 1;
+ r = x1 - 1;
} else {
l = x1;
r = x2;
@@ -839,8 +803,8 @@ bool QRect::contains(const QPoint &p, bool proper) const noexcept
}
int t, b;
if (y2 < y1 - 1) {
- t = y2;
- b = y1;
+ t = y2 + 1;
+ b = y1 - 1;
} else {
t = y1;
b = y2;
@@ -890,16 +854,16 @@ bool QRect::contains(const QRect &r, bool proper) const noexcept
return false;
int l1 = x1;
- int r1 = x1;
- if (x2 - x1 + 1 < 0)
- l1 = x2;
+ int r1 = x1 - 1;
+ if (x2 < x1 - 1)
+ l1 = x2 + 1;
else
r1 = x2;
int l2 = r.x1;
- int r2 = r.x1;
- if (r.x2 - r.x1 + 1 < 0)
- l2 = r.x2;
+ int r2 = r.x1 - 1;
+ if (r.x2 < r.x1 - 1)
+ l2 = r.x2 + 1;
else
r2 = r.x2;
@@ -912,16 +876,16 @@ bool QRect::contains(const QRect &r, bool proper) const noexcept
}
int t1 = y1;
- int b1 = y1;
- if (y2 - y1 + 1 < 0)
- t1 = y2;
+ int b1 = y1 - 1;
+ if (y2 < y1 - 1)
+ t1 = y2 + 1;
else
b1 = y2;
int t2 = r.y1;
- int b2 = r.y1;
- if (r.y2 - r.y1 + 1 < 0)
- t2 = r.y2;
+ int b2 = r.y1 - 1;
+ if (r.y2 < r.y1 - 1)
+ t2 = r.y2 + 1;
else
b2 = r.y2;
@@ -970,30 +934,30 @@ QRect QRect::operator|(const QRect &r) const noexcept
return *this;
int l1 = x1;
- int r1 = x1;
- if (x2 - x1 + 1 < 0)
- l1 = x2;
+ int r1 = x1 - 1;
+ if (x2 < x1 - 1)
+ l1 = x2 + 1;
else
r1 = x2;
int l2 = r.x1;
- int r2 = r.x1;
- if (r.x2 - r.x1 + 1 < 0)
- l2 = r.x2;
+ int r2 = r.x1 - 1;
+ if (r.x2 < r.x1 - 1)
+ l2 = r.x2 + 1;
else
r2 = r.x2;
int t1 = y1;
- int b1 = y1;
- if (y2 - y1 + 1 < 0)
- t1 = y2;
+ int b1 = y1 - 1;
+ if (y2 < y1 - 1)
+ t1 = y2 + 1;
else
b1 = y2;
int t2 = r.y1;
- int b2 = r.y1;
- if (r.y2 - r.y1 + 1 < 0)
- t2 = r.y2;
+ int b2 = r.y1 - 1;
+ if (r.y2 < r.y1 - 1)
+ t2 = r.y2 + 1;
else
b2 = r.y2;
@@ -1006,13 +970,6 @@ QRect QRect::operator|(const QRect &r) const noexcept
}
/*!
- \fn QRect QRect::unite(const QRect &rectangle) const
- \obsolete
-
- Use united(\a rectangle) instead.
-*/
-
-/*!
\fn QRect QRect::united(const QRect &rectangle) const
\since 4.2
@@ -1039,35 +996,35 @@ QRect QRect::operator&(const QRect &r) const noexcept
return QRect();
int l1 = x1;
- int r1 = x1;
- if (x2 - x1 + 1 < 0)
- l1 = x2;
- else
- r1 = x2;
+ int r1 = x2;
+ if (x2 < x1 - 1) {
+ l1 = x2 + 1;
+ r1 = x1 - 1;
+ }
int l2 = r.x1;
- int r2 = r.x1;
- if (r.x2 - r.x1 + 1 < 0)
- l2 = r.x2;
- else
- r2 = r.x2;
+ int r2 = r.x2;
+ if (r.x2 < r.x1 - 1) {
+ l2 = r.x2 + 1;
+ r2 = r.x1 - 1;
+ }
if (l1 > r2 || l2 > r1)
return QRect();
int t1 = y1;
- int b1 = y1;
- if (y2 - y1 + 1 < 0)
- t1 = y2;
- else
- b1 = y2;
+ int b1 = y2;
+ if (y2 < y1 - 1) {
+ t1 = y2 + 1;
+ b1 = y1 - 1;
+ }
int t2 = r.y1;
- int b2 = r.y1;
- if (r.y2 - r.y1 + 1 < 0)
- t2 = r.y2;
- else
- b2 = r.y2;
+ int b2 = r.y2;
+ if (r.y2 < r.y1 - 1) {
+ t2 = r.y2 + 1;
+ b2 = r.y1 - 1;
+ }
if (t1 > b2 || t2 > b1)
return QRect();
@@ -1081,13 +1038,6 @@ QRect QRect::operator&(const QRect &r) const noexcept
}
/*!
- \fn QRect QRect::intersect(const QRect &rectangle) const
- \obsolete
-
- Use intersected(\a rectangle) instead.
-*/
-
-/*!
\fn QRect QRect::intersected(const QRect &rectangle) const
\since 4.2
@@ -1118,35 +1068,35 @@ bool QRect::intersects(const QRect &r) const noexcept
return false;
int l1 = x1;
- int r1 = x1;
- if (x2 - x1 + 1 < 0)
- l1 = x2;
- else
- r1 = x2;
+ int r1 = x2;
+ if (x2 < x1 - 1) {
+ l1 = x2 + 1;
+ r1 = x1 - 1;
+ }
int l2 = r.x1;
- int r2 = r.x1;
- if (r.x2 - r.x1 + 1 < 0)
- l2 = r.x2;
- else
- r2 = r.x2;
+ int r2 = r.x2;
+ if (r.x2 < r.x1 - 1) {
+ l2 = r.x2 + 1;
+ r2 = r.x1 - 1;
+ }
if (l1 > r2 || l2 > r1)
return false;
int t1 = y1;
- int b1 = y1;
- if (y2 - y1 + 1 < 0)
- t1 = y2;
- else
- b1 = y2;
+ int b1 = y2;
+ if (y2 < y1 - 1) {
+ t1 = y2 + 1;
+ b1 = y1 - 1;
+ }
int t2 = r.y1;
- int b2 = r.y1;
- if (r.y2 - r.y1 + 1 < 0)
- t2 = r.y2;
- else
- b2 = r.y2;
+ int b2 = r.y2;
+ if (r.y2 < r.y1 - 1) {
+ t2 = r.y2 + 1;
+ b2 = r.y1 - 1;
+ }
if (t1 > b2 || t2 > b1)
return false;
@@ -1155,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.
@@ -1164,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.
@@ -1239,6 +1187,26 @@ bool QRect::intersects(const QRect &r) const noexcept
\since 5.1
*/
+/*!
+ \fn static QRect QRect::span(const QPoint &p1, const QPoint &p2)
+
+ Returns a rectangle spanning the two points \a p1 and \a p2, including both and
+ everything in between.
+
+ \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
@@ -1311,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
@@ -1340,7 +1308,7 @@ QDebug operator<<(QDebug dbg, const QRect &r)
current position, and the translated() function returns a
translated copy of this rectangle.
- The size() function returns the rectange's dimensions as a
+ The size() function returns the rectangle's dimensions as a
QSizeF. The dimensions can also be retrieved separately using the
width() and height() functions. To manipulate the dimensions use
the setSize(), setWidth() or setHeight() functions. Alternatively,
@@ -1477,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()
*/
@@ -1488,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()
*/
/*!
@@ -1577,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.
@@ -1589,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.
@@ -1601,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.
@@ -1611,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.
@@ -1621,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.
@@ -1633,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.
@@ -1715,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()
@@ -1725,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()
*/
@@ -1735,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()
@@ -1746,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()
@@ -1796,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()
*/
@@ -1815,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()
*/
@@ -1837,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()
*/
@@ -1868,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()
*/
@@ -1880,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()
*/
@@ -1890,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()
*/
@@ -1897,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()
*/
@@ -1928,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()
@@ -1938,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()
@@ -1948,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()
@@ -2136,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&()
*/
@@ -2189,13 +2161,6 @@ QRectF QRectF::operator|(const QRectF &r) const noexcept
}
/*!
- \fn QRectF QRectF::unite(const QRectF &rectangle) const
- \obsolete
-
- Use united(\a rectangle) instead.
-*/
-
-/*!
\fn QRectF QRectF::united(const QRectF &rectangle) const
\since 4.2
@@ -2270,13 +2235,6 @@ QRectF QRectF::operator&(const QRectF &r) const noexcept
}
/*!
- \fn QRectF QRectF::intersect(const QRectF &rectangle) const
- \obsolete
-
- Use intersected(\a rectangle) instead.
-*/
-
-/*!
\fn QRectF QRectF::intersected(const QRectF &rectangle) const
\since 4.2
@@ -2355,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()
*/
/*!
@@ -2388,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 7aa2312f38..e69a217f48 100644
--- a/src/corelib/tools/qrect.h
+++ b/src/corelib/tools/qrect.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) 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
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qmargins.h>
#include <QtCore/qsize.h>
#include <QtCore/qpoint.h>
@@ -51,111 +16,119 @@
#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:
- Q_DECL_CONSTEXPR QRect() noexcept : x1(0), y1(0), x2(-1), y2(-1) {}
- Q_DECL_CONSTEXPR QRect(const QPoint &topleft, const QPoint &bottomright) noexcept;
- Q_DECL_CONSTEXPR QRect(const QPoint &topleft, const QSize &size) noexcept;
- Q_DECL_CONSTEXPR QRect(int left, int top, int width, int height) noexcept;
-
- Q_DECL_CONSTEXPR inline bool isNull() const noexcept;
- Q_DECL_CONSTEXPR inline bool isEmpty() const noexcept;
- Q_DECL_CONSTEXPR inline bool isValid() const noexcept;
-
- Q_DECL_CONSTEXPR inline int left() const noexcept;
- Q_DECL_CONSTEXPR inline int top() const noexcept;
- Q_DECL_CONSTEXPR inline int right() const noexcept;
- Q_DECL_CONSTEXPR inline int bottom() const noexcept;
- Q_REQUIRED_RESULT QRect normalized() const noexcept;
-
- Q_DECL_CONSTEXPR inline int x() const noexcept;
- Q_DECL_CONSTEXPR inline int y() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setLeft(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setTop(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setRight(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setBottom(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setX(int x) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setY(int y) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void setTopLeft(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setBottomRight(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setTopRight(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setBottomLeft(const QPoint &p) noexcept;
-
- Q_DECL_CONSTEXPR inline QPoint topLeft() const noexcept;
- Q_DECL_CONSTEXPR inline QPoint bottomRight() const noexcept;
- Q_DECL_CONSTEXPR inline QPoint topRight() const noexcept;
- Q_DECL_CONSTEXPR inline QPoint bottomLeft() const noexcept;
- Q_DECL_CONSTEXPR inline QPoint center() const noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void moveLeft(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTop(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveRight(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveBottom(int pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTopLeft(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveBottomRight(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTopRight(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveBottomLeft(const QPoint &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveCenter(const QPoint &p) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void translate(int dx, int dy) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void translate(const QPoint &p) noexcept;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRect translated(int dx, int dy) const noexcept;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRect translated(const QPoint &p) const noexcept;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRect transposed() const noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void moveTo(int x, int t) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTo(const QPoint &p) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void setRect(int x, int y, int w, int h) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void getRect(int *x, int *y, int *w, int *h) const;
-
- Q_DECL_RELAXED_CONSTEXPR inline void setCoords(int x1, int y1, int x2, int y2) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void getCoords(int *x1, int *y1, int *x2, int *y2) const;
-
- Q_DECL_RELAXED_CONSTEXPR inline void adjust(int x1, int y1, int x2, int y2) noexcept;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRect adjusted(int x1, int y1, int x2, int y2) const noexcept;
-
- Q_DECL_CONSTEXPR inline QSize size() const noexcept;
- Q_DECL_CONSTEXPR inline int width() const noexcept;
- Q_DECL_CONSTEXPR inline int height() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setWidth(int w) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setHeight(int h) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setSize(const QSize &s) noexcept;
+ constexpr QRect() noexcept : x1(0), y1(0), x2(-1), y2(-1) {}
+ constexpr QRect(const QPoint &topleft, const QPoint &bottomright) noexcept;
+ constexpr QRect(const QPoint &topleft, const QSize &size) noexcept;
+ constexpr QRect(int left, int top, int width, int height) noexcept;
+
+ constexpr inline bool isNull() const noexcept;
+ constexpr inline bool isEmpty() const noexcept;
+ constexpr inline bool isValid() const noexcept;
+
+ constexpr inline int left() const noexcept;
+ constexpr inline int top() const noexcept;
+ constexpr inline int right() const noexcept;
+ constexpr inline int bottom() const noexcept;
+ [[nodiscard]] QRect normalized() const noexcept;
+
+ constexpr inline int x() const noexcept;
+ constexpr inline int y() const noexcept;
+ constexpr inline void setLeft(int pos) noexcept;
+ constexpr inline void setTop(int pos) noexcept;
+ constexpr inline void setRight(int pos) noexcept;
+ constexpr inline void setBottom(int pos) noexcept;
+ constexpr inline void setX(int x) noexcept;
+ constexpr inline void setY(int y) noexcept;
+
+ constexpr inline void setTopLeft(const QPoint &p) noexcept;
+ constexpr inline void setBottomRight(const QPoint &p) noexcept;
+ constexpr inline void setTopRight(const QPoint &p) noexcept;
+ constexpr inline void setBottomLeft(const QPoint &p) noexcept;
+
+ constexpr inline QPoint topLeft() const noexcept;
+ constexpr inline QPoint bottomRight() const noexcept;
+ constexpr inline QPoint topRight() const noexcept;
+ constexpr inline QPoint bottomLeft() const noexcept;
+ constexpr inline QPoint center() const noexcept;
+
+ constexpr inline void moveLeft(int pos) noexcept;
+ constexpr inline void moveTop(int pos) noexcept;
+ constexpr inline void moveRight(int pos) noexcept;
+ constexpr inline void moveBottom(int pos) noexcept;
+ constexpr inline void moveTopLeft(const QPoint &p) noexcept;
+ constexpr inline void moveBottomRight(const QPoint &p) noexcept;
+ constexpr inline void moveTopRight(const QPoint &p) noexcept;
+ constexpr inline void moveBottomLeft(const QPoint &p) noexcept;
+ constexpr inline void moveCenter(const QPoint &p) noexcept;
+
+ constexpr inline void translate(int dx, int dy) noexcept;
+ constexpr inline void translate(const QPoint &p) 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;
+
+ constexpr inline void setRect(int x, int y, int w, int h) noexcept;
+ constexpr inline void getRect(int *x, int *y, int *w, int *h) const;
+
+ constexpr inline void setCoords(int x1, int y1, int x2, int y2) noexcept;
+ 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;
+ [[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;
+ constexpr inline int height() const noexcept;
+ constexpr inline void setWidth(int w) noexcept;
+ constexpr inline void setHeight(int h) noexcept;
+ constexpr inline void setSize(const QSize &s) noexcept;
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;
- Q_DECL_CONSTEXPR inline QRect marginsAdded(const QMargins &margins) const noexcept;
- Q_DECL_CONSTEXPR inline QRect marginsRemoved(const QMargins &margins) const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QRect &operator+=(const QMargins &margins) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QRect &operator-=(const QMargins &margins) noexcept;
+ constexpr inline QRect marginsAdded(const QMargins &margins) const noexcept;
+ constexpr inline QRect marginsRemoved(const QMargins &margins) const noexcept;
+ constexpr inline QRect &operator+=(const QMargins &margins) noexcept;
+ constexpr inline QRect &operator-=(const QMargins &margins) noexcept;
-#if QT_DEPRECATED_SINCE(5, 0)
- Q_REQUIRED_RESULT QT_DEPRECATED QRect unite(const QRect &r) const noexcept { return united(r); }
- Q_REQUIRED_RESULT QT_DEPRECATED QRect intersect(const QRect &r) const noexcept { return intersected(r); }
-#endif
+ [[nodiscard]] static constexpr inline QRect span(const QPoint &p1, const QPoint &p2) noexcept;
- friend Q_DECL_CONSTEXPR inline bool operator==(const QRect &, const QRect &) noexcept;
- friend Q_DECL_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;
@@ -163,10 +136,7 @@ private:
int x2;
int y2;
};
-Q_DECLARE_TYPEINFO(QRect, Q_MOVABLE_TYPE);
-
-Q_DECL_CONSTEXPR inline bool operator==(const QRect &, const QRect &) noexcept;
-Q_DECL_CONSTEXPR inline bool operator!=(const QRect &, const QRect &) noexcept;
+Q_DECLARE_TYPEINFO(QRect, Q_RELOCATABLE_TYPE);
/*****************************************************************************
@@ -181,97 +151,97 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QRect &);
QRect inline member functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QRect::QRect(int aleft, int atop, int awidth, int aheight) noexcept
+constexpr inline QRect::QRect(int aleft, int atop, int awidth, int aheight) noexcept
: x1(aleft), y1(atop), x2(aleft + awidth - 1), y2(atop + aheight - 1) {}
-Q_DECL_CONSTEXPR inline QRect::QRect(const QPoint &atopLeft, const QPoint &abottomRight) noexcept
+constexpr inline QRect::QRect(const QPoint &atopLeft, const QPoint &abottomRight) noexcept
: x1(atopLeft.x()), y1(atopLeft.y()), x2(abottomRight.x()), y2(abottomRight.y()) {}
-Q_DECL_CONSTEXPR inline QRect::QRect(const QPoint &atopLeft, const QSize &asize) noexcept
+constexpr inline QRect::QRect(const QPoint &atopLeft, const QSize &asize) noexcept
: x1(atopLeft.x()), y1(atopLeft.y()), x2(atopLeft.x()+asize.width() - 1), y2(atopLeft.y()+asize.height() - 1) {}
-Q_DECL_CONSTEXPR inline bool QRect::isNull() const noexcept
+constexpr inline bool QRect::isNull() const noexcept
{ return x2 == x1 - 1 && y2 == y1 - 1; }
-Q_DECL_CONSTEXPR inline bool QRect::isEmpty() const noexcept
+constexpr inline bool QRect::isEmpty() const noexcept
{ return x1 > x2 || y1 > y2; }
-Q_DECL_CONSTEXPR inline bool QRect::isValid() const noexcept
+constexpr inline bool QRect::isValid() const noexcept
{ return x1 <= x2 && y1 <= y2; }
-Q_DECL_CONSTEXPR inline int QRect::left() const noexcept
+constexpr inline int QRect::left() const noexcept
{ return x1; }
-Q_DECL_CONSTEXPR inline int QRect::top() const noexcept
+constexpr inline int QRect::top() const noexcept
{ return y1; }
-Q_DECL_CONSTEXPR inline int QRect::right() const noexcept
+constexpr inline int QRect::right() const noexcept
{ return x2; }
-Q_DECL_CONSTEXPR inline int QRect::bottom() const noexcept
+constexpr inline int QRect::bottom() const noexcept
{ return y2; }
-Q_DECL_CONSTEXPR inline int QRect::x() const noexcept
+constexpr inline int QRect::x() const noexcept
{ return x1; }
-Q_DECL_CONSTEXPR inline int QRect::y() const noexcept
+constexpr inline int QRect::y() const noexcept
{ return y1; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setLeft(int pos) noexcept
+constexpr inline void QRect::setLeft(int pos) noexcept
{ x1 = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setTop(int pos) noexcept
+constexpr inline void QRect::setTop(int pos) noexcept
{ y1 = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setRight(int pos) noexcept
+constexpr inline void QRect::setRight(int pos) noexcept
{ x2 = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setBottom(int pos) noexcept
+constexpr inline void QRect::setBottom(int pos) noexcept
{ y2 = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setTopLeft(const QPoint &p) noexcept
+constexpr inline void QRect::setTopLeft(const QPoint &p) noexcept
{ x1 = p.x(); y1 = p.y(); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setBottomRight(const QPoint &p) noexcept
+constexpr inline void QRect::setBottomRight(const QPoint &p) noexcept
{ x2 = p.x(); y2 = p.y(); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setTopRight(const QPoint &p) noexcept
+constexpr inline void QRect::setTopRight(const QPoint &p) noexcept
{ x2 = p.x(); y1 = p.y(); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setBottomLeft(const QPoint &p) noexcept
+constexpr inline void QRect::setBottomLeft(const QPoint &p) noexcept
{ x1 = p.x(); y2 = p.y(); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setX(int ax) noexcept
+constexpr inline void QRect::setX(int ax) noexcept
{ x1 = ax; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setY(int ay) noexcept
+constexpr inline void QRect::setY(int ay) noexcept
{ y1 = ay; }
-Q_DECL_CONSTEXPR inline QPoint QRect::topLeft() const noexcept
+constexpr inline QPoint QRect::topLeft() const noexcept
{ return QPoint(x1, y1); }
-Q_DECL_CONSTEXPR inline QPoint QRect::bottomRight() const noexcept
+constexpr inline QPoint QRect::bottomRight() const noexcept
{ return QPoint(x2, y2); }
-Q_DECL_CONSTEXPR inline QPoint QRect::topRight() const noexcept
+constexpr inline QPoint QRect::topRight() const noexcept
{ return QPoint(x2, y1); }
-Q_DECL_CONSTEXPR inline QPoint QRect::bottomLeft() const noexcept
+constexpr inline QPoint QRect::bottomLeft() const noexcept
{ return QPoint(x1, y2); }
-Q_DECL_CONSTEXPR inline QPoint QRect::center() const noexcept
+constexpr inline QPoint QRect::center() const noexcept
{ return QPoint(int((qint64(x1)+x2)/2), int((qint64(y1)+y2)/2)); } // cast avoids overflow on addition
-Q_DECL_CONSTEXPR inline int QRect::width() const noexcept
+constexpr inline int QRect::width() const noexcept
{ return x2 - x1 + 1; }
-Q_DECL_CONSTEXPR inline int QRect::height() const noexcept
+constexpr inline int QRect::height() const noexcept
{ return y2 - y1 + 1; }
-Q_DECL_CONSTEXPR inline QSize QRect::size() const noexcept
+constexpr inline QSize QRect::size() const noexcept
{ return QSize(width(), height()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::translate(int dx, int dy) noexcept
+constexpr inline void QRect::translate(int dx, int dy) noexcept
{
x1 += dx;
y1 += dy;
@@ -279,7 +249,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::translate(int dx, int dy) noexcept
y2 += dy;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::translate(const QPoint &p) noexcept
+constexpr inline void QRect::translate(const QPoint &p) noexcept
{
x1 += p.x();
y1 += p.y();
@@ -287,16 +257,16 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::translate(const QPoint &p) noexcept
y2 += p.y();
}
-Q_DECL_CONSTEXPR inline QRect QRect::translated(int dx, int dy) const noexcept
+constexpr inline QRect QRect::translated(int dx, int dy) const noexcept
{ return QRect(QPoint(x1 + dx, y1 + dy), QPoint(x2 + dx, y2 + dy)); }
-Q_DECL_CONSTEXPR inline QRect QRect::translated(const QPoint &p) const noexcept
+constexpr inline QRect QRect::translated(const QPoint &p) const noexcept
{ return QRect(QPoint(x1 + p.x(), y1 + p.y()), QPoint(x2 + p.x(), y2 + p.y())); }
-Q_DECL_CONSTEXPR inline QRect QRect::transposed() const noexcept
+constexpr inline QRect QRect::transposed() const noexcept
{ return QRect(topLeft(), size().transposed()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTo(int ax, int ay) noexcept
+constexpr inline void QRect::moveTo(int ax, int ay) noexcept
{
x2 += ax - x1;
y2 += ay - y1;
@@ -304,7 +274,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTo(int ax, int ay) noexcept
y1 = ay;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTo(const QPoint &p) noexcept
+constexpr inline void QRect::moveTo(const QPoint &p) noexcept
{
x2 += p.x() - x1;
y2 += p.y() - y1;
@@ -312,49 +282,49 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTo(const QPoint &p) noexcept
y1 = p.y();
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveLeft(int pos) noexcept
+constexpr inline void QRect::moveLeft(int pos) noexcept
{ x2 += (pos - x1); x1 = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTop(int pos) noexcept
+constexpr inline void QRect::moveTop(int pos) noexcept
{ y2 += (pos - y1); y1 = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveRight(int pos) noexcept
+constexpr inline void QRect::moveRight(int pos) noexcept
{
x1 += (pos - x2);
x2 = pos;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveBottom(int pos) noexcept
+constexpr inline void QRect::moveBottom(int pos) noexcept
{
y1 += (pos - y2);
y2 = pos;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTopLeft(const QPoint &p) noexcept
+constexpr inline void QRect::moveTopLeft(const QPoint &p) noexcept
{
moveLeft(p.x());
moveTop(p.y());
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveBottomRight(const QPoint &p) noexcept
+constexpr inline void QRect::moveBottomRight(const QPoint &p) noexcept
{
moveRight(p.x());
moveBottom(p.y());
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTopRight(const QPoint &p) noexcept
+constexpr inline void QRect::moveTopRight(const QPoint &p) noexcept
{
moveRight(p.x());
moveTop(p.y());
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveBottomLeft(const QPoint &p) noexcept
+constexpr inline void QRect::moveBottomLeft(const QPoint &p) noexcept
{
moveLeft(p.x());
moveBottom(p.y());
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveCenter(const QPoint &p) noexcept
+constexpr inline void QRect::moveCenter(const QPoint &p) noexcept
{
int w = x2 - x1;
int h = y2 - y1;
@@ -364,7 +334,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveCenter(const QPoint &p) noexcept
y2 = y1 + h;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::getRect(int *ax, int *ay, int *aw, int *ah) const
+constexpr inline void QRect::getRect(int *ax, int *ay, int *aw, int *ah) const
{
*ax = x1;
*ay = y1;
@@ -372,7 +342,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::getRect(int *ax, int *ay, int *aw, i
*ah = y2 - y1 + 1;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setRect(int ax, int ay, int aw, int ah) noexcept
+constexpr inline void QRect::setRect(int ax, int ay, int aw, int ah) noexcept
{
x1 = ax;
y1 = ay;
@@ -380,7 +350,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::setRect(int ax, int ay, int aw, int
y2 = (ay + ah - 1);
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::getCoords(int *xp1, int *yp1, int *xp2, int *yp2) const
+constexpr inline void QRect::getCoords(int *xp1, int *yp1, int *xp2, int *yp2) const
{
*xp1 = x1;
*yp1 = y1;
@@ -388,7 +358,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::getCoords(int *xp1, int *yp1, int *x
*yp2 = y2;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setCoords(int xp1, int yp1, int xp2, int yp2) noexcept
+constexpr inline void QRect::setCoords(int xp1, int yp1, int xp2, int yp2) noexcept
{
x1 = xp1;
y1 = yp1;
@@ -396,10 +366,10 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::setCoords(int xp1, int yp1, int xp2,
y2 = yp2;
}
-Q_DECL_CONSTEXPR inline QRect QRect::adjusted(int xp1, int yp1, int xp2, int yp2) const noexcept
+constexpr inline QRect QRect::adjusted(int xp1, int yp1, int xp2, int yp2) const noexcept
{ return QRect(QPoint(x1 + xp1, y1 + yp1), QPoint(x2 + xp2, y2 + yp2)); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::adjust(int dx1, int dy1, int dx2, int dy2) noexcept
+constexpr inline void QRect::adjust(int dx1, int dy1, int dx2, int dy2) noexcept
{
x1 += dx1;
y1 += dy1;
@@ -407,13 +377,13 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRect::adjust(int dx1, int dy1, int dx2, in
y2 += dy2;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setWidth(int w) noexcept
+constexpr inline void QRect::setWidth(int w) noexcept
{ x2 = (x1 + w - 1); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setHeight(int h) noexcept
+constexpr inline void QRect::setHeight(int h) noexcept
{ y2 = (y1 + h - 1); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRect::setSize(const QSize &s) noexcept
+constexpr inline void QRect::setSize(const QSize &s) noexcept
{
x2 = (s.width() + x1 - 1);
y2 = (s.height() + y1 - 1);
@@ -429,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;
@@ -451,58 +421,59 @@ inline QRect QRect::united(const QRect &r) const noexcept
return *this | r;
}
-Q_DECL_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;
-}
-
-Q_DECL_CONSTEXPR inline bool operator!=(const QRect &r1, const QRect &r2) noexcept
+constexpr inline size_t qHash(const QRect &r, size_t seed = 0) noexcept
{
- return r1.x1!=r2.x1 || r1.x2!=r2.x2 || r1.y1!=r2.y1 || r1.y2!=r2.y2;
+ return qHashMulti(seed, r.x1, r.x2, r.y1, r.y2);
}
-Q_DECL_CONSTEXPR inline QRect operator+(const QRect &rectangle, const QMargins &margins) noexcept
+constexpr inline QRect operator+(const QRect &rectangle, const QMargins &margins) noexcept
{
return QRect(QPoint(rectangle.left() - margins.left(), rectangle.top() - margins.top()),
QPoint(rectangle.right() + margins.right(), rectangle.bottom() + margins.bottom()));
}
-Q_DECL_CONSTEXPR inline QRect operator+(const QMargins &margins, const QRect &rectangle) noexcept
+constexpr inline QRect operator+(const QMargins &margins, const QRect &rectangle) noexcept
{
return QRect(QPoint(rectangle.left() - margins.left(), rectangle.top() - margins.top()),
QPoint(rectangle.right() + margins.right(), rectangle.bottom() + margins.bottom()));
}
-Q_DECL_CONSTEXPR inline QRect operator-(const QRect &lhs, const QMargins &rhs) noexcept
+constexpr inline QRect operator-(const QRect &lhs, const QMargins &rhs) noexcept
{
return QRect(QPoint(lhs.left() + rhs.left(), lhs.top() + rhs.top()),
QPoint(lhs.right() - rhs.right(), lhs.bottom() - rhs.bottom()));
}
-Q_DECL_CONSTEXPR inline QRect QRect::marginsAdded(const QMargins &margins) const noexcept
+constexpr inline QRect QRect::marginsAdded(const QMargins &margins) const noexcept
{
return QRect(QPoint(x1 - margins.left(), y1 - margins.top()),
QPoint(x2 + margins.right(), y2 + margins.bottom()));
}
-Q_DECL_CONSTEXPR inline QRect QRect::marginsRemoved(const QMargins &margins) const noexcept
+constexpr inline QRect QRect::marginsRemoved(const QMargins &margins) const noexcept
{
return QRect(QPoint(x1 + margins.left(), y1 + margins.top()),
QPoint(x2 - margins.right(), y2 - margins.bottom()));
}
-Q_DECL_RELAXED_CONSTEXPR inline QRect &QRect::operator+=(const QMargins &margins) noexcept
+constexpr inline QRect &QRect::operator+=(const QMargins &margins) noexcept
{
*this = marginsAdded(margins);
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QRect &QRect::operator-=(const QMargins &margins) noexcept
+constexpr inline QRect &QRect::operator-=(const QMargins &margins) noexcept
{
*this = marginsRemoved(margins);
return *this;
}
+constexpr QRect QRect::span(const QPoint &p1, const QPoint &p2) noexcept
+{
+ return QRect(QPoint(qMin(p1.x(), p2.x()), qMin(p1.y(), p2.y())),
+ QPoint(qMax(p1.x(), p2.x()), qMax(p1.y(), p2.y())));
+}
+
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QRect &);
#endif
@@ -511,110 +482,118 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QRect &);
class Q_CORE_EXPORT QRectF
{
public:
- Q_DECL_CONSTEXPR QRectF() noexcept : xp(0.), yp(0.), w(0.), h(0.) {}
- Q_DECL_CONSTEXPR QRectF(const QPointF &topleft, const QSizeF &size) noexcept;
- Q_DECL_CONSTEXPR QRectF(const QPointF &topleft, const QPointF &bottomRight) noexcept;
- Q_DECL_CONSTEXPR QRectF(qreal left, qreal top, qreal width, qreal height) noexcept;
- Q_DECL_CONSTEXPR QRectF(const QRect &rect) noexcept;
-
- Q_DECL_CONSTEXPR inline bool isNull() const noexcept;
- Q_DECL_CONSTEXPR inline bool isEmpty() const noexcept;
- Q_DECL_CONSTEXPR inline bool isValid() const noexcept;
- Q_REQUIRED_RESULT QRectF normalized() const noexcept;
-
- Q_DECL_CONSTEXPR inline qreal left() const noexcept { return xp; }
- Q_DECL_CONSTEXPR inline qreal top() const noexcept { return yp; }
- Q_DECL_CONSTEXPR inline qreal right() const noexcept { return xp + w; }
- Q_DECL_CONSTEXPR inline qreal bottom() const noexcept { return yp + h; }
-
- Q_DECL_CONSTEXPR inline qreal x() const noexcept;
- Q_DECL_CONSTEXPR inline qreal y() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setLeft(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setTop(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setRight(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setBottom(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setX(qreal pos) noexcept { setLeft(pos); }
- Q_DECL_RELAXED_CONSTEXPR inline void setY(qreal pos) noexcept { setTop(pos); }
-
- Q_DECL_CONSTEXPR inline QPointF topLeft() const noexcept { return QPointF(xp, yp); }
- Q_DECL_CONSTEXPR inline QPointF bottomRight() const noexcept { return QPointF(xp+w, yp+h); }
- Q_DECL_CONSTEXPR inline QPointF topRight() const noexcept { return QPointF(xp+w, yp); }
- Q_DECL_CONSTEXPR inline QPointF bottomLeft() const noexcept { return QPointF(xp, yp+h); }
- Q_DECL_CONSTEXPR inline QPointF center() const noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void setTopLeft(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setBottomRight(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setTopRight(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setBottomLeft(const QPointF &p) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void moveLeft(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTop(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveRight(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveBottom(qreal pos) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTopLeft(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveBottomRight(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTopRight(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveBottomLeft(const QPointF &p) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveCenter(const QPointF &p) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void translate(qreal dx, qreal dy) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void translate(const QPointF &p) noexcept;
-
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRectF translated(qreal dx, qreal dy) const noexcept;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRectF translated(const QPointF &p) const noexcept;
-
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRectF transposed() const noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void moveTo(qreal x, qreal y) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void moveTo(const QPointF &p) noexcept;
-
- Q_DECL_RELAXED_CONSTEXPR inline void setRect(qreal x, qreal y, qreal w, qreal h) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void getRect(qreal *x, qreal *y, qreal *w, qreal *h) const;
-
- Q_DECL_RELAXED_CONSTEXPR inline void setCoords(qreal x1, qreal y1, qreal x2, qreal y2) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void getCoords(qreal *x1, qreal *y1, qreal *x2, qreal *y2) const;
-
- Q_DECL_RELAXED_CONSTEXPR inline void adjust(qreal x1, qreal y1, qreal x2, qreal y2) noexcept;
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept;
-
- Q_DECL_CONSTEXPR inline QSizeF size() const noexcept;
- Q_DECL_CONSTEXPR inline qreal width() const noexcept;
- Q_DECL_CONSTEXPR inline qreal height() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setWidth(qreal w) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setHeight(qreal h) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setSize(const QSizeF &s) noexcept;
+ constexpr QRectF() noexcept : xp(0.), yp(0.), w(0.), h(0.) {}
+ constexpr QRectF(const QPointF &topleft, const QSizeF &size) noexcept;
+ constexpr QRectF(const QPointF &topleft, const QPointF &bottomRight) noexcept;
+ constexpr QRectF(qreal left, qreal top, qreal width, qreal height) noexcept;
+ constexpr QRectF(const QRect &rect) noexcept;
+
+ constexpr inline bool isNull() const noexcept;
+ constexpr inline bool isEmpty() const noexcept;
+ constexpr inline bool isValid() const noexcept;
+ [[nodiscard]] QRectF normalized() const noexcept;
+
+ constexpr inline qreal left() const noexcept { return xp; }
+ constexpr inline qreal top() const noexcept { return yp; }
+ constexpr inline qreal right() const noexcept { return xp + w; }
+ constexpr inline qreal bottom() const noexcept { return yp + h; }
+
+ constexpr inline qreal x() const noexcept;
+ constexpr inline qreal y() const noexcept;
+ constexpr inline void setLeft(qreal pos) noexcept;
+ constexpr inline void setTop(qreal pos) noexcept;
+ constexpr inline void setRight(qreal pos) noexcept;
+ constexpr inline void setBottom(qreal pos) noexcept;
+ constexpr inline void setX(qreal pos) noexcept { setLeft(pos); }
+ constexpr inline void setY(qreal pos) noexcept { setTop(pos); }
+
+ constexpr inline QPointF topLeft() const noexcept { return QPointF(xp, yp); }
+ constexpr inline QPointF bottomRight() const noexcept { return QPointF(xp+w, yp+h); }
+ constexpr inline QPointF topRight() const noexcept { return QPointF(xp+w, yp); }
+ constexpr inline QPointF bottomLeft() const noexcept { return QPointF(xp, yp+h); }
+ constexpr inline QPointF center() const noexcept;
+
+ constexpr inline void setTopLeft(const QPointF &p) noexcept;
+ constexpr inline void setBottomRight(const QPointF &p) noexcept;
+ constexpr inline void setTopRight(const QPointF &p) noexcept;
+ constexpr inline void setBottomLeft(const QPointF &p) noexcept;
+
+ constexpr inline void moveLeft(qreal pos) noexcept;
+ constexpr inline void moveTop(qreal pos) noexcept;
+ constexpr inline void moveRight(qreal pos) noexcept;
+ constexpr inline void moveBottom(qreal pos) noexcept;
+ constexpr inline void moveTopLeft(const QPointF &p) noexcept;
+ constexpr inline void moveBottomRight(const QPointF &p) noexcept;
+ constexpr inline void moveTopRight(const QPointF &p) noexcept;
+ constexpr inline void moveBottomLeft(const QPointF &p) noexcept;
+ constexpr inline void moveCenter(const QPointF &p) noexcept;
+
+ constexpr inline void translate(qreal dx, qreal dy) noexcept;
+ constexpr inline void translate(const QPointF &p) noexcept;
+
+ [[nodiscard]] constexpr inline QRectF translated(qreal dx, qreal dy) const noexcept;
+ [[nodiscard]] constexpr inline QRectF translated(const QPointF &p) 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;
+
+ constexpr inline void setRect(qreal x, qreal y, qreal w, qreal h) noexcept;
+ constexpr inline void getRect(qreal *x, qreal *y, qreal *w, qreal *h) const;
+
+ constexpr inline void setCoords(qreal x1, qreal y1, qreal x2, qreal y2) noexcept;
+ 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;
+ [[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;
+ constexpr inline qreal height() const noexcept;
+ constexpr inline void setWidth(qreal w) noexcept;
+ constexpr inline void setHeight(qreal h) noexcept;
+ constexpr inline void setSize(const QSizeF &s) noexcept;
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;
- Q_DECL_CONSTEXPR inline QRectF marginsAdded(const QMarginsF &margins) const noexcept;
- Q_DECL_CONSTEXPR inline QRectF marginsRemoved(const QMarginsF &margins) const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QRectF &operator+=(const QMarginsF &margins) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QRectF &operator-=(const QMarginsF &margins) noexcept;
+ constexpr inline QRectF marginsAdded(const QMarginsF &margins) const noexcept;
+ constexpr inline QRectF marginsRemoved(const QMarginsF &margins) const noexcept;
+ constexpr inline QRectF &operator+=(const QMarginsF &margins) noexcept;
+ constexpr inline QRectF &operator-=(const QMarginsF &margins) 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();
+ }
+
+ [[nodiscard]] constexpr inline QRect toRect() const noexcept;
+ [[nodiscard]] QRect toAlignedRect() const noexcept;
-#if QT_DEPRECATED_SINCE(5, 0)
- Q_REQUIRED_RESULT QT_DEPRECATED QRectF unite(const QRectF &r) const noexcept { return united(r); }
- Q_REQUIRED_RESULT QT_DEPRECATED QRectF intersect(const QRectF &r) const noexcept { return intersected(r); }
+#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
+ [[nodiscard]] static QRectF fromCGRect(CGRect rect) noexcept;
+ [[nodiscard]] CGRect toCGRect() const noexcept;
#endif
- friend Q_DECL_CONSTEXPR inline bool operator==(const QRectF &, const QRectF &) noexcept;
- friend Q_DECL_CONSTEXPR inline bool operator!=(const QRectF &, const QRectF &) noexcept;
-
- Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QRect toRect() const noexcept;
- Q_REQUIRED_RESULT 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;
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+ [[nodiscard]] static QRectF fromDOMRect(emscripten::val domRect);
+ [[nodiscard]] emscripten::val toDOMRect() const;
#endif
private:
@@ -623,10 +602,7 @@ private:
qreal w;
qreal h;
};
-Q_DECLARE_TYPEINFO(QRectF, Q_MOVABLE_TYPE);
-
-Q_DECL_CONSTEXPR inline bool operator==(const QRectF &, const QRectF &) noexcept;
-Q_DECL_CONSTEXPR inline bool operator!=(const QRectF &, const QRectF &) noexcept;
+Q_DECLARE_TYPEINFO(QRectF, Q_RELOCATABLE_TYPE);
/*****************************************************************************
@@ -641,145 +617,146 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QRectF &);
QRectF inline member functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QRectF::QRectF(qreal aleft, qreal atop, qreal awidth, qreal aheight) noexcept
+constexpr inline QRectF::QRectF(qreal aleft, qreal atop, qreal awidth, qreal aheight) noexcept
: xp(aleft), yp(atop), w(awidth), h(aheight)
{
}
-Q_DECL_CONSTEXPR inline QRectF::QRectF(const QPointF &atopLeft, const QSizeF &asize) noexcept
+constexpr inline QRectF::QRectF(const QPointF &atopLeft, const QSizeF &asize) noexcept
: xp(atopLeft.x()), yp(atopLeft.y()), w(asize.width()), h(asize.height())
{
}
-Q_DECL_CONSTEXPR inline QRectF::QRectF(const QPointF &atopLeft, const QPointF &abottomRight) noexcept
+constexpr inline QRectF::QRectF(const QPointF &atopLeft, const QPointF &abottomRight) noexcept
: xp(atopLeft.x()), yp(atopLeft.y()), w(abottomRight.x() - atopLeft.x()), h(abottomRight.y() - atopLeft.y())
{
}
-Q_DECL_CONSTEXPR inline QRectF::QRectF(const QRect &r) noexcept
+constexpr inline QRectF::QRectF(const QRect &r) noexcept
: xp(r.x()), yp(r.y()), w(r.width()), h(r.height())
{
}
QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
-QT_WARNING_DISABLE_GCC("-Wfloat-equal")
+QT_WARNING_DISABLE_FLOAT_COMPARE
-Q_DECL_CONSTEXPR inline bool QRectF::isNull() const noexcept
+constexpr inline bool QRectF::isNull() const noexcept
{ return w == 0. && h == 0.; }
-Q_DECL_CONSTEXPR inline bool QRectF::isEmpty() const noexcept
+constexpr inline bool QRectF::isEmpty() const noexcept
{ return w <= 0. || h <= 0.; }
QT_WARNING_POP
-Q_DECL_CONSTEXPR inline bool QRectF::isValid() const noexcept
+constexpr inline bool QRectF::isValid() const noexcept
{ return w > 0. && h > 0.; }
-Q_DECL_CONSTEXPR inline qreal QRectF::x() const noexcept
+constexpr inline qreal QRectF::x() const noexcept
{ return xp; }
-Q_DECL_CONSTEXPR inline qreal QRectF::y() const noexcept
+constexpr inline qreal QRectF::y() const noexcept
{ return yp; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setLeft(qreal pos) noexcept
+constexpr inline void QRectF::setLeft(qreal pos) noexcept
{ qreal diff = pos - xp; xp += diff; w -= diff; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setRight(qreal pos) noexcept
+constexpr inline void QRectF::setRight(qreal pos) noexcept
{ w = pos - xp; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setTop(qreal pos) noexcept
+constexpr inline void QRectF::setTop(qreal pos) noexcept
{ qreal diff = pos - yp; yp += diff; h -= diff; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setBottom(qreal pos) noexcept
+constexpr inline void QRectF::setBottom(qreal pos) noexcept
{ h = pos - yp; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setTopLeft(const QPointF &p) noexcept
+constexpr inline void QRectF::setTopLeft(const QPointF &p) noexcept
{ setLeft(p.x()); setTop(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setTopRight(const QPointF &p) noexcept
+constexpr inline void QRectF::setTopRight(const QPointF &p) noexcept
{ setRight(p.x()); setTop(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setBottomLeft(const QPointF &p) noexcept
+constexpr inline void QRectF::setBottomLeft(const QPointF &p) noexcept
{ setLeft(p.x()); setBottom(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setBottomRight(const QPointF &p) noexcept
+constexpr inline void QRectF::setBottomRight(const QPointF &p) noexcept
{ setRight(p.x()); setBottom(p.y()); }
-Q_DECL_CONSTEXPR inline QPointF QRectF::center() const noexcept
+constexpr inline QPointF QRectF::center() const noexcept
{ return QPointF(xp + w/2, yp + h/2); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveLeft(qreal pos) noexcept
+constexpr inline void QRectF::moveLeft(qreal pos) noexcept
{ xp = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveTop(qreal pos) noexcept
+constexpr inline void QRectF::moveTop(qreal pos) noexcept
{ yp = pos; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveRight(qreal pos) noexcept
+constexpr inline void QRectF::moveRight(qreal pos) noexcept
{ xp = pos - w; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveBottom(qreal pos) noexcept
+constexpr inline void QRectF::moveBottom(qreal pos) noexcept
{ yp = pos - h; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveTopLeft(const QPointF &p) noexcept
+constexpr inline void QRectF::moveTopLeft(const QPointF &p) noexcept
{ moveLeft(p.x()); moveTop(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveTopRight(const QPointF &p) noexcept
+constexpr inline void QRectF::moveTopRight(const QPointF &p) noexcept
{ moveRight(p.x()); moveTop(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveBottomLeft(const QPointF &p) noexcept
+constexpr inline void QRectF::moveBottomLeft(const QPointF &p) noexcept
{ moveLeft(p.x()); moveBottom(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveBottomRight(const QPointF &p) noexcept
+constexpr inline void QRectF::moveBottomRight(const QPointF &p) noexcept
{ moveRight(p.x()); moveBottom(p.y()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveCenter(const QPointF &p) noexcept
+constexpr inline void QRectF::moveCenter(const QPointF &p) noexcept
{ xp = p.x() - w/2; yp = p.y() - h/2; }
-Q_DECL_CONSTEXPR inline qreal QRectF::width() const noexcept
+constexpr inline qreal QRectF::width() const noexcept
{ return w; }
-Q_DECL_CONSTEXPR inline qreal QRectF::height() const noexcept
+constexpr inline qreal QRectF::height() const noexcept
{ return h; }
-Q_DECL_CONSTEXPR inline QSizeF QRectF::size() const noexcept
+constexpr inline QSizeF QRectF::size() const noexcept
{ return QSizeF(w, h); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::translate(qreal dx, qreal dy) noexcept
+constexpr inline void QRectF::translate(qreal dx, qreal dy) noexcept
{
xp += dx;
yp += dy;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::translate(const QPointF &p) noexcept
+constexpr inline void QRectF::translate(const QPointF &p) noexcept
{
xp += p.x();
yp += p.y();
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveTo(qreal ax, qreal ay) noexcept
+constexpr inline void QRectF::moveTo(qreal ax, qreal ay) noexcept
{
xp = ax;
yp = ay;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::moveTo(const QPointF &p) noexcept
+constexpr inline void QRectF::moveTo(const QPointF &p) noexcept
{
xp = p.x();
yp = p.y();
}
-Q_DECL_CONSTEXPR inline QRectF QRectF::translated(qreal dx, qreal dy) const noexcept
-{ return QRectF(xp + dx, yp + dy, w, h); }
+constexpr inline QRectF QRectF::translated(qreal dx, qreal dy) const noexcept
+{
+ return QRectF(xp + dx, yp + dy, w, h);
+}
-Q_DECL_CONSTEXPR inline QRectF QRectF::translated(const QPointF &p) const noexcept
+constexpr inline QRectF QRectF::translated(const QPointF &p) const noexcept
{ return QRectF(xp + p.x(), yp + p.y(), w, h); }
-Q_DECL_CONSTEXPR inline QRectF QRectF::transposed() const noexcept
+constexpr inline QRectF QRectF::transposed() const noexcept
{ return QRectF(topLeft(), size().transposed()); }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::getRect(qreal *ax, qreal *ay, qreal *aaw, qreal *aah) const
+constexpr inline void QRectF::getRect(qreal *ax, qreal *ay, qreal *aaw, qreal *aah) const
{
*ax = this->xp;
*ay = this->yp;
@@ -787,7 +764,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRectF::getRect(qreal *ax, qreal *ay, qreal
*aah = this->h;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setRect(qreal ax, qreal ay, qreal aaw, qreal aah) noexcept
+constexpr inline void QRectF::setRect(qreal ax, qreal ay, qreal aaw, qreal aah) noexcept
{
this->xp = ax;
this->yp = ay;
@@ -795,7 +772,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setRect(qreal ax, qreal ay, qreal a
this->h = aah;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::getCoords(qreal *xp1, qreal *yp1, qreal *xp2, qreal *yp2) const
+constexpr inline void QRectF::getCoords(qreal *xp1, qreal *yp1, qreal *xp2, qreal *yp2) const
{
*xp1 = xp;
*yp1 = yp;
@@ -803,7 +780,7 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRectF::getCoords(qreal *xp1, qreal *yp1, q
*yp2 = yp + h;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setCoords(qreal xp1, qreal yp1, qreal xp2, qreal yp2) noexcept
+constexpr inline void QRectF::setCoords(qreal xp1, qreal yp1, qreal xp2, qreal yp2) noexcept
{
xp = xp1;
yp = yp1;
@@ -811,19 +788,26 @@ Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setCoords(qreal xp1, qreal yp1, qre
h = yp2 - yp1;
}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::adjust(qreal xp1, qreal yp1, qreal xp2, qreal yp2) noexcept
-{ xp += xp1; yp += yp1; w += xp2 - xp1; h += yp2 - yp1; }
+constexpr inline void QRectF::adjust(qreal xp1, qreal yp1, qreal xp2, qreal yp2) noexcept
+{
+ xp += xp1;
+ yp += yp1;
+ w += xp2 - xp1;
+ h += yp2 - yp1;
+}
-Q_DECL_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); }
+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);
+}
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setWidth(qreal aw) noexcept
+constexpr inline void QRectF::setWidth(qreal aw) noexcept
{ this->w = aw; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setHeight(qreal ah) noexcept
+constexpr inline void QRectF::setHeight(qreal ah) noexcept
{ this->h = ah; }
-Q_DECL_RELAXED_CONSTEXPR inline void QRectF::setSize(const QSizeF &s) noexcept
+constexpr inline void QRectF::setSize(const QSizeF &s) noexcept
{
w = s.width();
h = s.height();
@@ -834,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;
@@ -856,60 +840,57 @@ inline QRectF QRectF::united(const QRectF &r) const noexcept
return *this | r;
}
-Q_DECL_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);
-}
-
-Q_DECL_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; }
-Q_DECL_CONSTEXPR inline QRect QRectF::toRect() const noexcept
+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);
}
-Q_DECL_CONSTEXPR inline QRectF operator+(const QRectF &lhs, const QMarginsF &rhs) noexcept
+constexpr inline QRectF operator+(const QRectF &lhs, const QMarginsF &rhs) noexcept
{
return QRectF(QPointF(lhs.left() - rhs.left(), lhs.top() - rhs.top()),
QSizeF(lhs.width() + rhs.left() + rhs.right(), lhs.height() + rhs.top() + rhs.bottom()));
}
-Q_DECL_CONSTEXPR inline QRectF operator+(const QMarginsF &lhs, const QRectF &rhs) noexcept
+constexpr inline QRectF operator+(const QMarginsF &lhs, const QRectF &rhs) noexcept
{
return QRectF(QPointF(rhs.left() - lhs.left(), rhs.top() - lhs.top()),
QSizeF(rhs.width() + lhs.left() + lhs.right(), rhs.height() + lhs.top() + lhs.bottom()));
}
-Q_DECL_CONSTEXPR inline QRectF operator-(const QRectF &lhs, const QMarginsF &rhs) noexcept
+constexpr inline QRectF operator-(const QRectF &lhs, const QMarginsF &rhs) noexcept
{
return QRectF(QPointF(lhs.left() + rhs.left(), lhs.top() + rhs.top()),
QSizeF(lhs.width() - rhs.left() - rhs.right(), lhs.height() - rhs.top() - rhs.bottom()));
}
-Q_DECL_CONSTEXPR inline QRectF QRectF::marginsAdded(const QMarginsF &margins) const noexcept
+constexpr inline QRectF QRectF::marginsAdded(const QMarginsF &margins) const noexcept
{
return QRectF(QPointF(xp - margins.left(), yp - margins.top()),
QSizeF(w + margins.left() + margins.right(), h + margins.top() + margins.bottom()));
}
-Q_DECL_CONSTEXPR inline QRectF QRectF::marginsRemoved(const QMarginsF &margins) const noexcept
+constexpr inline QRectF QRectF::marginsRemoved(const QMarginsF &margins) const noexcept
{
return QRectF(QPointF(xp + margins.left(), yp + margins.top()),
QSizeF(w - margins.left() - margins.right(), h - margins.top() - margins.bottom()));
}
-Q_DECL_RELAXED_CONSTEXPR inline QRectF &QRectF::operator+=(const QMarginsF &margins) noexcept
+constexpr inline QRectF &QRectF::operator+=(const QMarginsF &margins) noexcept
{
*this = marginsAdded(margins);
return *this;
}
-Q_DECL_RELAXED_CONSTEXPR inline QRectF &QRectF::operator-=(const QMarginsF &margins) noexcept
+constexpr inline QRectF &QRectF::operator-=(const QMarginsF &margins) noexcept
{
*this = marginsRemoved(margins);
return *this;
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 838cb31697..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
@@ -53,7 +17,7 @@
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
@@ -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);
@@ -265,13 +221,12 @@ public:
}
private:
- QVector<QRingChunk> buffers;
+ QList<QRingChunk> buffers;
qint64 bufferSize;
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 af0c0ed336..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;
@@ -95,8 +69,8 @@ typedef QScopedPointerObjectDeleteLater<QObject> QScopedPointerDeleteLater;
template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer
{
- typedef T *QScopedPointer:: *RestrictedBool;
public:
+ Q_NODISCARD_CTOR
explicit QScopedPointer(T *p = nullptr) noexcept : d(p)
{
}
@@ -123,17 +97,10 @@ public:
return !d;
}
-#if defined(Q_QDOC)
- inline operator bool() const
- {
- return isNull() ? nullptr : &QScopedPointer::d;
- }
-#else
- operator RestrictedBool() const noexcept
+ explicit operator bool() const
{
- return isNull() ? nullptr : &QScopedPointer::d;
+ return !isNull();
}
-#endif
T *data() const noexcept
{
@@ -154,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>
@@ -226,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
@@ -259,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 f904b8dfcb..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
@@ -48,23 +12,28 @@ template <typename T>
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;
}
@@ -73,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 45c3f93da4..9be6634cc8 100644
--- a/src/corelib/tools/qscopeguard.h
+++ b/src/corelib/tools/qscopeguard.h
@@ -1,71 +1,41 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@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) 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
#include <QtCore/qglobal.h>
+#include <type_traits>
+#include <utility>
QT_BEGIN_NAMESPACE
-
-template <typename F> class QScopeGuard;
-template <typename F> QScopeGuard<F> qScopeGuard(F f);
-
template <typename F>
-class
-#if QT_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))
{
}
- ~QScopeGuard()
+ ~QScopeGuard() noexcept
{
if (m_invoke)
m_func();
@@ -77,26 +47,19 @@ public:
}
private:
- explicit QScopeGuard(F &&f) noexcept
- : m_func(std::move(f))
- {
- }
-
Q_DISABLE_COPY(QScopeGuard)
F m_func;
bool m_invoke = true;
- friend QScopeGuard qScopeGuard<F>(F);
};
+template <typename F> QScopeGuard(F(&)()) -> QScopeGuard<F(*)()>;
+//! [qScopeGuard]
template <typename F>
-#if QT_HAS_CPP_ATTRIBUTE(nodiscard)
-Q_REQUIRED_RESULT
-#endif
-QScopeGuard<F> qScopeGuard(F f)
+[[nodiscard]] QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f)
{
- return QScopeGuard<F>(std::move(f));
+ return QScopeGuard<typename std::decay<F>::type>(std::forward<F>(f));
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qscopeguard.qdoc b/src/corelib/tools/qscopeguard.qdoc
index 5a9b7fd210..6d9874842a 100644
--- a/src/corelib/tools/qscopeguard.qdoc
+++ b/src/corelib/tools/qscopeguard.qdoc
@@ -1,29 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
-** 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"
@@ -35,6 +12,30 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\brief Provides a scope guard for calling a function at the end of
a scope.
+
+ QScopeGuard<F> is a class of which the sole purpose is to run the function
+ \a f in its destructor. This is useful for guaranteeing
+ your cleanup code is executed, whether the function is exited normally,
+ exited early by a return statement, or exited by an exception.
+
+ \note Exceptions are not supported. The callable shouldn't throw when
+ executed, copied or moved.
+
+ \sa QScopedValueRollback
+*/
+
+/*!
+ \fn template <typename F> QScopeGuard<F>::QScopeGuard(F &&f)
+ \fn template <typename F> QScopeGuard<F>::QScopeGuard(const F &f)
+
+ Create a scope guard that will execute \a f at the end of the scope.
+
+ If \e F is a lambda, its type cannot be written. In that case you need to
+ either rely on class template argument deduction (C++17 feature) and leave
+ the template parameter out completely or use the helper function
+ qScopeGuard() instead of this constructor.
+
+ \since 5.15
*/
/*! \fn template <typename F> void QScopeGuard<F>::dismiss()
@@ -44,30 +45,24 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename F> const QScopeGuard<F> qScopeGuard(F f)
+ \fn [qScopeGuard] template <typename F> QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f)
\inmodule QtCore
\relates QScopeGuard
\brief The qScopeGuard function can be used to call a function at the end
of the scope.
\ingroup misc
- QScopeGuard<F> is a class which sole purpose is to run a function \e F in
- its destructor. This is useful for guaranteeing your cleanup code is
- executed, whether the function is exited normally, exited early by a return
- statement, or exited by an exception.
+ Create a scope guard that will execute \a f at the end of the scope.
- If \e F is a lambda then you cannot instantiate the template directly,
- therefore the qScopeGuard() helper is provided and QScopeGuard<F> is made a
- private implementation detail.
+ This helper function is provided so that you can easily construct a
+ QScopeGuard without having to name the template parameter for the type of
+ the callable. If \e F is a lambda then you cannot write its type and relying
+ on this helper or class template argument deduction is necessary.
Example usage is as follows:
\snippet code/src_corelib_tools_qscopeguard.cpp 0
- \note Exceptions are not supported. The callable shouldn't throw when
- executed, copied or moved.
-
- \sa QScopedValueRollback
*/
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index f98bb051ec..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,17 +35,24 @@ public:
inline void swap(QSet<T> &other) noexcept { q_hash.swap(other.q_hash); }
- inline bool operator==(const QSet<T> &other) const
- { return q_hash == other.q_hash; }
- inline bool operator!=(const QSet<T> &other) const
- { return q_hash != other.q_hash; }
+#ifndef Q_QDOC
+ template <typename U = T>
+ QTypeTraits::compare_eq_result_container<QSet, U> operator==(const QSet<T> &other) const
+ { return q_hash == other.q_hash; }
+ template <typename U = T>
+ 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 int size() const { return q_hash.size(); }
+ inline qsizetype size() const { return q_hash.size(); }
inline bool isEmpty() const { return q_hash.isEmpty(); }
- inline int capacity() const { return q_hash.capacity(); }
- inline void reserve(int size);
+ inline qsizetype capacity() const { return q_hash.capacity(); }
+ inline void reserve(qsizetype size);
inline void squeeze() { q_hash.squeeze(); }
inline void detach() { q_hash.detach(); }
@@ -91,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;
@@ -105,11 +82,7 @@ public:
friend class QSet<T>;
public:
-#if QT_DEPRECATED_SINCE(5, 15)
- typedef std::bidirectional_iterator_tag iterator_category;
-#else
typedef std::forward_iterator_tag iterator_category;
-#endif
typedef qptrdiff difference_type;
typedef T value_type;
typedef const T *pointer;
@@ -129,15 +102,6 @@ public:
{ return i != o.i; }
inline iterator &operator++() { ++i; return *this; }
inline iterator operator++(int) { iterator r = *this; ++i; return r; }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED iterator &operator--() { --i; return *this; }
- inline QT_DEPRECATED iterator operator--(int) { iterator r = *this; --i; return r; }
- inline QT_DEPRECATED iterator operator+(int j) const { return i + j; }
- inline QT_DEPRECATED iterator operator-(int j) const { return i - j; }
- friend inline QT_DEPRECATED iterator operator+(int j, iterator k) { return k + j; }
- inline QT_DEPRECATED iterator &operator+=(int j) { i += j; return *this; }
- inline QT_DEPRECATED iterator &operator-=(int j) { i -= j; return *this; }
-#endif
};
class const_iterator
@@ -148,11 +112,7 @@ public:
friend class QSet<T>;
public:
-#if QT_DEPRECATED_SINCE(5, 15)
- typedef std::bidirectional_iterator_tag iterator_category;
-#else
typedef std::forward_iterator_tag iterator_category;
-#endif
typedef qptrdiff difference_type;
typedef T value_type;
typedef const T *pointer;
@@ -170,15 +130,6 @@ public:
inline bool operator!=(const const_iterator &o) const { return i != o.i; }
inline const_iterator &operator++() { ++i; return *this; }
inline const_iterator operator++(int) { const_iterator r = *this; ++i; return r; }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED const_iterator &operator--() { --i; return *this; }
- inline QT_DEPRECATED const_iterator operator--(int) { const_iterator r = *this; --i; return r; }
- inline QT_DEPRECATED const_iterator operator+(int j) const { return i + j; }
- inline QT_DEPRECATED const_iterator operator-(int j) const { return i - j; }
- friend inline QT_DEPRECATED const_iterator operator+(int j, const_iterator k) { return k + j; }
- inline QT_DEPRECATED const_iterator &operator+=(int j) { i += j; return *this; }
- inline QT_DEPRECATED const_iterator &operator-=(int j) { i -= j; return *this; }
-#endif
};
// STL style
@@ -191,32 +142,20 @@ public:
inline const_iterator cend() const noexcept { return q_hash.end(); }
inline const_iterator constEnd() const noexcept { return q_hash.constEnd(); }
-#if QT_DEPRECATED_SINCE(5, 15)
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- reverse_iterator QT_DEPRECATED rbegin() { return reverse_iterator(end()); }
- reverse_iterator QT_DEPRECATED rend() { return reverse_iterator(begin()); }
- const_reverse_iterator QT_DEPRECATED rbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator QT_DEPRECATED rend() const noexcept { return const_reverse_iterator(begin()); }
- const_reverse_iterator QT_DEPRECATED crbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator QT_DEPRECATED crend() const noexcept { return const_reverse_iterator(begin()); }
-#endif
-
- iterator erase(iterator i)
- { return erase(m2c(i)); }
iterator erase(const_iterator i)
{
- Q_ASSERT_X(isValidIterator(i), "QSet::erase", "The specified const_iterator argument 'i' is invalid");
- return q_hash.erase(reinterpret_cast<typename Hash::const_iterator &>(i));
+ Q_ASSERT(i != constEnd());
+ return q_hash.erase(i.i);
}
// more Qt
typedef iterator Iterator;
typedef const_iterator ConstIterator;
- inline int 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); }
@@ -233,9 +172,12 @@ public:
typedef value_type &reference;
typedef const value_type &const_reference;
typedef qptrdiff difference_type;
- typedef int size_type;
+ 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; }
@@ -247,42 +189,32 @@ 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;
private:
Hash q_hash;
-
- static const_iterator m2c(iterator it) noexcept
- { return const_iterator(typename Hash::const_iterator(it.i.i)); }
-
- bool isValidIterator(const iterator &i) const
- {
- return q_hash.isValidIterator(reinterpret_cast<const typename Hash::iterator&>(i));
- }
- bool isValidIterator(const const_iterator &i) const noexcept
- {
- return q_hash.isValidIterator(reinterpret_cast<const typename Hash::const_iterator&>(i));
- }
};
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
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>
-uint qHash(const QSet<T> &key, uint seed = 0)
+size_t qHash(const QSet<T> &key, size_t seed = 0)
noexcept(noexcept(qHashRangeCommutative(key.begin(), key.end(), seed)))
{
return qHashRangeCommutative(key.begin(), key.end(), seed);
@@ -291,15 +223,18 @@ noexcept(noexcept(qHashRangeCommutative(key.begin(), key.end(), seed)))
// inline function implementations
template <class T>
-Q_INLINE_TEMPLATE void QSet<T>::reserve(int asize) { q_hash.reserve(asize); }
+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;
}
@@ -316,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);
}
@@ -329,24 +264,14 @@ Q_INLINE_TEMPLATE bool QSet<T>::intersects(const QSet<T> &other) const
const bool otherIsBigger = other.size() > size();
const QSet &smallestSet = otherIsBigger ? *this : other;
const QSet &biggestSet = otherIsBigger ? other : *this;
- const bool equalSeeds = q_hash.d->seed == other.q_hash.d->seed;
typename QSet::const_iterator i = smallestSet.cbegin();
typename QSet::const_iterator e = smallestSet.cend();
- if (Q_LIKELY(equalSeeds)) {
- // If seeds are equal we take the fast path so no hash is recalculated.
- while (i != e) {
- if (*biggestSet.q_hash.findNode(*i, i.i.i->h) != biggestSet.q_hash.e)
- return true;
- ++i;
- }
- } else {
- while (i != e) {
- if (biggestSet.contains(*i))
- return true;
- ++i;
- }
- }
+ while (i != e) {
+ if (biggestSet.contains(*i))
+ return true;
+ ++i;
+ }
return false;
}
@@ -415,17 +340,15 @@ public:
inline const T &value() const { Q_ASSERT(item_exists()); return *n; }
inline bool findNext(const T &t)
{ while (c->constEnd() != (n = i)) if (*i++ == t) return true; return false; }
-#if QT_DEPRECATED_SINCE(5, 15)
- inline QT_DEPRECATED bool hasPrevious() const { return c->constBegin() != i; }
- inline QT_DEPRECATED const T &previous() { n = --i; return *n; }
- inline QT_DEPRECATED const T &peekPrevious() const { iterator p = i; return *--p; }
- inline QT_DEPRECATED bool findPrevious(const T &t)
- { while (c->constBegin() != i) if (*(n = --i) == t) return true;
- n = c->end(); return false; }
-#endif
};
#endif // QT_NO_JAVA_STYLE_ITERATORS
+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 33a0697e12..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,52 +373,6 @@
\sa constBegin(), end()
*/
-/*! \fn template <class T> QSet<T>::reverse_iterator QSet<T>::rbegin()
- \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
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QSet<T>::const_reverse_iterator QSet<T>::crbegin() const
- \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()
- \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
- \since 5.6
- \overload
-*/
-
-/*! \fn template <class T> QSet<T>::const_reverse_iterator QSet<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 set, in reverse order.
-
- \sa end(), rend(), rbegin()
-*/
-
/*!
\typedef QSet::Iterator
\since 4.2
@@ -505,40 +434,8 @@
Typedef for T. Provided for STL compatibility.
*/
-/*! \typedef QSet::reverse_iterator
- \since 5.6
-
- 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
-
- 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
@@ -592,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().
@@ -622,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-=()
*/
@@ -630,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-=()
*/
@@ -640,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.
*/
@@ -648,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&()
*/
@@ -919,126 +833,19 @@
current item.
*/
-/*!
- \fn template <class T> QSet<T>::iterator &QSet<T>::iterator::operator--()
- \fn template <class T> QSet<T>::const_iterator &QSet<T>::const_iterator::operator--()
- \obsolete
-
- 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)
- \fn template <class T> QSet<T>::const_iterator QSet<T>::const_iterator::operator--(int)
- \obsolete
-
- \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
- \fn template <class T> QSet<T>::const_iterator QSet<T>::const_iterator::operator+(int j) const
- \obsolete
-
- 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
- \fn template <class T> QSet<T>::const_iterator QSet<T>::const_iterator::operator-(int j) const
- \obsolete
-
- 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)
- \fn template <class T> QSet<T>::const_iterator &QSet<T>::const_iterator::operator+=(int j)
- \obsolete
-
- 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)
- \fn template <class T> QSet<T>::const_iterator &QSet<T>::const_iterator::operator-=(int j)
- \obsolete
-
- 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
- \sa fromList(), QList::fromSet()
+ 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().
*/
-/*! \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
@@ -1062,7 +869,7 @@
*/
/*!
- \fn template <class T> uint qHash(const QSet<T> &key, uint seed = 0)
+ \fn template <class T> size_t qHash(const QSet<T> &key, size_t seed = 0)
\relates QHash
\since 5.5
@@ -1071,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 2748f9d95f..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.
@@ -285,11 +263,35 @@ QT_BEGIN_NAMESPACE
\sa constData()
*/
+/*! \fn template <class T> T* QSharedDataPointer<T>::get()
+ \since 6.0
+
+ Same as data(). This function is provided for STL compatibility.
+*/
+
/*! \fn template <class T> const T* QSharedDataPointer<T>::data() const
Returns a pointer to the shared data object.
This function does \e not call detach().
*/
+/*! \fn template <class T> const T* QSharedDataPointer<T>::get() const
+ \since 6.0
+
+ 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().
@@ -297,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.
@@ -310,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().
*/
@@ -344,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
@@ -457,6 +487,12 @@ QT_BEGIN_NAMESPACE
Returns a pointer to the shared data object.
*/
+/*! \fn template <class T> T* QExplicitlySharedDataPointer<T>::get() const
+ \since 6.0
+
+ Same as data(). This function is provided for STL compatibility.
+*/
+
/*! \fn template <class T> const T* QExplicitlySharedDataPointer<T>::constData() const
Returns a const pointer to the shared data object.
@@ -468,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}.
*/
/*!
@@ -480,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()
@@ -572,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 f123f8e7b9..4c4153a506 100644
--- a/src/corelib/tools/qshareddata.h
+++ b/src/corelib/tools/qshareddata.h
@@ -1,133 +1,120 @@
-/****************************************************************************
-**
-** 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 QSHAREDDATA_H
#define QSHAREDDATA_H
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
-#if QT_DEPRECATED_SINCE(5, 6)
-#include <QtCore/qhash.h>
-#endif
#include <QtCore/qhashfunctions.h>
+#include <functional>
+
QT_BEGIN_NAMESPACE
template <class T> class QSharedDataPointer;
-class
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-Q_CORE_EXPORT
-#endif
-QSharedData
+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 const T *data() 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();
@@ -138,100 +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 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; }
- inline bool operator!() const { return !d; }
+ void swap(QExplicitlySharedDataPointer &other) noexcept
+ { qt_ptr_swap(d, other.d); }
- inline void swap(QExplicitlySharedDataPointer &other) noexcept
- { qSwap(d, other.d); }
+ DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const QExplicitlySharedDataPointer &p2, p2.d)
+ DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const T *ptr, ptr)
+ 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)
+
+#undef DECLARE_COMPARE_SET
protected:
T *clone();
@@ -242,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();
@@ -263,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();
@@ -279,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 uint qHash(const QSharedDataPointer<T> &ptr, uint 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 uint qHash(const QExplicitlySharedDataPointer<T> &ptr, uint 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
new file mode 100644
index 0000000000..e0b4695e36
--- /dev/null
+++ b/src/corelib/tools/qshareddata_impl.h
@@ -0,0 +1,142 @@
+// 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
+#pragma qt_sync_stop_processing
+#endif
+
+#ifndef QSHAREDDATA_IMPL_H
+#define QSHAREDDATA_IMPL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+template <typename T>
+class QExplicitlySharedDataPointerV2
+{
+ T *d;
+
+public:
+ constexpr QExplicitlySharedDataPointerV2() noexcept : d(nullptr) {}
+
+ explicit QExplicitlySharedDataPointerV2(T *t) noexcept
+ : d(t)
+ {
+ if (d)
+ d->ref.ref();
+ }
+
+ QExplicitlySharedDataPointerV2(T *t, QAdoptSharedDataTag) noexcept
+ : d(t)
+ {
+ }
+
+ QExplicitlySharedDataPointerV2(const QExplicitlySharedDataPointerV2 &other) noexcept
+ : d(other.d)
+ {
+ if (d)
+ d->ref.ref();
+ }
+
+ QExplicitlySharedDataPointerV2 &operator=(const QExplicitlySharedDataPointerV2 &other) noexcept
+ {
+ QExplicitlySharedDataPointerV2 copy(other);
+ swap(copy);
+ return *this;
+ }
+
+ QExplicitlySharedDataPointerV2(QExplicitlySharedDataPointerV2 &&other) noexcept
+ : d(std::exchange(other.d, nullptr))
+ {
+ }
+
+ QExplicitlySharedDataPointerV2 &operator=(QExplicitlySharedDataPointerV2 &&other) noexcept
+ {
+ QExplicitlySharedDataPointerV2 moved(std::move(other));
+ swap(moved);
+ return *this;
+ }
+
+ ~QExplicitlySharedDataPointerV2()
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ }
+
+ void detach()
+ {
+ if (!d) {
+ // should this codepath be here on in all user's detach()?
+ d = new T;
+ d->ref.ref();
+ } else if (d->ref.loadRelaxed() != 1) {
+ // TODO: qAtomicDetach here...?
+ QExplicitlySharedDataPointerV2 copy(new T(*d));
+ swap(copy);
+ }
+ }
+
+ void reset(T *t = nullptr) noexcept
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = t;
+ if (d)
+ d->ref.ref();
+ }
+
+ constexpr T *take() noexcept
+ {
+ return std::exchange(d, nullptr);
+ }
+
+ bool isShared() const noexcept
+ {
+ return d && d->ref.loadRelaxed() != 1;
+ }
+
+ constexpr void swap(QExplicitlySharedDataPointerV2 &other) noexcept
+ {
+ qt_ptr_swap(d, other.d);
+ }
+
+ // important change from QExplicitlySharedDataPointer: deep const
+ constexpr T &operator*() { return *d; }
+ constexpr T *operator->() { return d; }
+ constexpr const T &operator*() const { return *d; }
+ constexpr const T *operator->() const { return d; }
+
+ constexpr T *data() noexcept { return d; }
+ constexpr const T *data() const noexcept { return d; }
+
+ constexpr explicit operator bool() const noexcept { return d; }
+
+ constexpr friend bool operator==(const QExplicitlySharedDataPointerV2 &lhs,
+ const QExplicitlySharedDataPointerV2 &rhs) noexcept
+ {
+ return lhs.d == rhs.d;
+ }
+
+ constexpr friend bool operator!=(const QExplicitlySharedDataPointerV2 &lhs,
+ const QExplicitlySharedDataPointerV2 &rhs) noexcept
+ {
+ return lhs.d != rhs.d;
+ }
+};
+
+template <typename T>
+constexpr void swap(QExplicitlySharedDataPointerV2<T> &lhs, QExplicitlySharedDataPointerV2<T> &rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+
+} // namespace QtPrivate
+
+QT_END_NAMESPACE
+
+#endif // QSHAREDDATA_IMPL_H
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index f185d2f23f..217a3a4ff4 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $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"
@@ -174,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
@@ -210,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.
@@ -249,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.
@@ -478,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
@@ -706,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.
@@ -847,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,
@@ -931,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.
@@ -944,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.
@@ -957,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.
@@ -970,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.
@@ -983,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
@@ -997,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
@@ -1011,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.
@@ -1024,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.
@@ -1037,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.
@@ -1130,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.
@@ -1143,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
@@ -1158,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
@@ -1179,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
@@ -1195,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
@@ -1217,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
@@ -1229,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
@@ -1247,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
@@ -1285,6 +1340,8 @@
\relates QSharedPointer
\since 5.14
+ Returns a shared pointer to the pointer held by \a src.
+
Same as qSharedPointerObjectCast(). This function is provided for STL
compatibility.
*/
@@ -1317,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
@@ -1343,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
@@ -1363,6 +1420,7 @@
QT_BEGIN_NAMESPACE
+QT6_ONLY(
/*!
\internal
This function is called for a just-created QObject \a obj, to enable
@@ -1370,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
@@ -1383,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)
{
@@ -1397,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
@@ -1408,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;
@@ -1421,7 +1482,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
*/
QSharedPointer<QObject> QtSharedPointer::sharedPointerFromVariant_internal(const QVariant &variant)
{
- Q_ASSERT(QMetaType::typeFlags(variant.userType()) & QMetaType::SharedPointerToQObject);
+ Q_ASSERT(variant.metaType().flags() & QMetaType::SharedPointerToQObject);
return *reinterpret_cast<const QSharedPointer<QObject>*>(variant.constData());
}
@@ -1432,7 +1493,8 @@ QSharedPointer<QObject> QtSharedPointer::sharedPointerFromVariant_internal(const
*/
QWeakPointer<QObject> QtSharedPointer::weakPointerFromVariant_internal(const QVariant &variant)
{
- Q_ASSERT(QMetaType::typeFlags(variant.userType()) & QMetaType::WeakPointerToQObject || QMetaType::typeFlags(variant.userType()) & QMetaType::TrackingPointerToQObject);
+ Q_ASSERT(variant.metaType().flags() & QMetaType::WeakPointerToQObject ||
+ variant.metaType().flags() & QMetaType::TrackingPointerToQObject);
return *reinterpret_cast<const QWeakPointer<QObject>*>(variant.constData());
}
@@ -1446,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
@@ -1560,12 +1622,18 @@ void QtSharedPointer::internalSafetyCheckAdd(const void *d_ptr, const volatile v
if (!kp)
return; // end-game: the application is being destroyed already
+ if (!ptr) {
+ // nullptr is allowed to be tracked by more than one QSharedPointer, so we
+ // need something else to put in our tracking structures
+ ptr = d_ptr;
+ }
+
QMutexLocker lock(&kp->mutex);
Q_ASSERT(!kp->dPointers.contains(d_ptr));
//qDebug("Adding d=%p value=%p", d_ptr, ptr);
- const void *other_d_ptr = kp->dataPointers.value(ptr, 0);
+ const void *other_d_ptr = kp->dataPointers.value(ptr, nullptr);
if (Q_UNLIKELY(other_d_ptr)) {
# ifdef BACKTRACE_SUPPORTED
printBacktrace(knownPointers()->dPointers.value(other_d_ptr).backtrace);
@@ -1628,7 +1696,7 @@ void QtSharedPointer::internalSafetyCheckCleanCheck()
qFatal("Internal consistency error: the number of pointers is not equal!");
if (Q_UNLIKELY(!kp->dPointers.isEmpty()))
- qFatal("Pointer cleaning failed: %d entries remaining", kp->dPointers.size());
+ qFatal("Pointer cleaning failed: %d entries remaining", int(kp->dPointers.size()));
# endif
}
diff --git a/src/corelib/tools/qsharedpointer.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 362d57fb9a..456be91d03 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -1,42 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $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
@@ -61,16 +26,18 @@ QT_END_NAMESPACE
#include <new>
#include <QtCore/qatomic.h>
-#include <QtCore/qobject.h> // for qobject_cast
-#if QT_DEPRECATED_SINCE(5, 6)
-#include <QtCore/qhash.h>
-#endif
#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
//
@@ -107,7 +74,7 @@ namespace QtSharedPointer {
template <class T, typename Klass, typename RetVal>
inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)())
- { (t->*memberDeleter)(); }
+ { if (t) (t->*memberDeleter)(); }
template <class T, typename Deleter>
inline void executeDeleter(T *t, Deleter d)
{ d(t); }
@@ -149,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 *) { }
};
@@ -282,7 +257,6 @@ namespace QtSharedPointer {
template <class T> class QSharedPointer
{
- typedef T *QSharedPointer:: *RestrictedBool;
typedef QtSharedPointer::ExternalRefCountData Data;
template <typename X>
using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type;
@@ -300,27 +274,34 @@ public:
T *data() const noexcept { return value; }
T *get() const noexcept { return value; }
bool isNull() const noexcept { return !data(); }
- operator RestrictedBool() const noexcept { return isNull() ? nullptr : &QSharedPointer::value; }
+ explicit operator bool() const noexcept { return !isNull(); }
bool operator !() const noexcept { return isNull(); }
T &operator*() const { return *data(); }
T *operator->() const noexcept { return data(); }
- Q_DECL_CONSTEXPR QSharedPointer() noexcept : value(nullptr), d(nullptr) { }
+ Q_NODISCARD_CTOR
+ constexpr QSharedPointer() noexcept : value(nullptr), d(nullptr) { }
~QSharedPointer() { deref(); }
- Q_DECL_CONSTEXPR QSharedPointer(std::nullptr_t) noexcept : value(nullptr), d(nullptr) { }
+ 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>
- QSharedPointer(std::nullptr_t, Deleter) : value(nullptr), d(nullptr) { }
+ 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
@@ -329,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)
{
@@ -359,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(); }
@@ -371,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; }
@@ -416,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
@@ -444,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
@@ -470,11 +490,6 @@ private:
template <typename X, typename Deleter>
inline void internalConstruct(X *ptr, Deleter deleter)
{
- if (!ptr) {
- d = nullptr;
- return;
- }
-
typedef QtSharedPointer::ExternalRefCountWithCustomDeleter<X, Deleter> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
typename Private::DestroyerFn actualDeleter = &Private::safetyCheckDeleter;
@@ -486,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)
@@ -518,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;
@@ -542,11 +550,16 @@ public:
template <class T>
class QWeakPointer
{
- typedef T *QWeakPointer:: *RestrictedBool;
typedef QtSharedPointer::ExternalRefCountData Data;
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;
@@ -557,42 +570,50 @@ public:
typedef qptrdiff difference_type;
bool isNull() const noexcept { return d == nullptr || d->strongref.loadRelaxed() == 0 || value == nullptr; }
- operator RestrictedBool() const noexcept { return isNull() ? nullptr : &QWeakPointer::value; }
+ explicit operator bool() const noexcept { return !isNull(); }
bool operator !() const noexcept { return isNull(); }
-#if QT_DEPRECATED_SINCE(5, 14)
- QT_DEPRECATED_X("Use toStrongRef() instead, and data() on the returned QSharedPointer")
- T *data() const noexcept { return internalData(); }
-#endif
-
- 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; }
-#ifndef QT_NO_QOBJECT
- // special constructor that is enabled only if X derives from QObject
-#if QT_DEPRECATED_SINCE(5, 0)
- template <class X, IfCompatible<X> = true>
- QT_DEPRECATED inline QWeakPointer(X *ptr) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
- { }
-#endif
-#endif
-
-#if QT_DEPRECATED_SINCE(5, 0)
- template <class X, IfCompatible<X> = true>
- QT_DEPRECATED inline QWeakPointer &operator=(X *ptr)
- { return *this = QWeakPointer(ptr); }
-#endif
-
+ 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);
@@ -602,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)
@@ -615,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; }
@@ -627,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; }
@@ -646,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; }
@@ -654,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
@@ -694,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;
@@ -728,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
{
@@ -744,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>
@@ -882,9 +835,9 @@ Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer<X> &ptr2)
// qHash
//
template <class T>
-Q_INLINE_TEMPLATE uint qHash(const QSharedPointer<T> &ptr, uint seed = 0)
+Q_INLINE_TEMPLATE size_t qHash(const QSharedPointer<T> &ptr, size_t seed = 0)
{
- return QT_PREPEND_NAMESPACE(qHash)(ptr.data(), seed);
+ return qHash(ptr.data(), seed);
}
@@ -985,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)
@@ -1015,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>();
}
@@ -1042,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/qsimd.cpp b/src/corelib/tools/qsimd.cpp
deleted file mode 100644
index d7c1d8c4a9..0000000000
--- a/src/corelib/tools/qsimd.cpp
+++ /dev/null
@@ -1,718 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2019 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsimd_p.h"
-#include "qalgorithms.h"
-#include <QByteArray>
-#include <stdio.h>
-
-#ifdef Q_OS_LINUX
-# include "../testlib/3rdparty/valgrind_p.h"
-#endif
-
-#if defined(Q_OS_WIN)
-# if !defined(Q_CC_GNU)
-# include <intrin.h>
-# endif
-#elif defined(Q_OS_LINUX) && (defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS_32))
-#include "private/qcore_unix_p.h"
-
-// the kernel header definitions for HWCAP_*
-// (the ones we need/may need anyway)
-
-// copied from <asm/hwcap.h> (ARM)
-#define HWCAP_CRUNCH 1024
-#define HWCAP_THUMBEE 2048
-#define HWCAP_NEON 4096
-#define HWCAP_VFPv3 8192
-#define HWCAP_VFPv3D16 16384
-
-// copied from <asm/hwcap.h> (ARM):
-#define HWCAP2_CRC32 (1 << 4)
-
-// copied from <asm/hwcap.h> (Aarch64)
-#define HWCAP_CRC32 (1 << 7)
-
-// copied from <linux/auxvec.h>
-#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
-#define AT_HWCAP2 26 /* extension of AT_HWCAP */
-
-#elif defined(Q_CC_GHS)
-#include <INTEGRITY_types.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*
- * Use kdesdk/scripts/generate_string_table.pl to update the table below. Note
- * we remove the terminating -1 that the script adds.
- */
-
-// begin generated
-#if defined(Q_PROCESSOR_ARM)
-/* Data:
- neon
- crc32
- */
-static const char features_string[] =
- " neon\0"
- " crc32\0"
- "\0";
-static const int features_indices[] = { 0, 6 };
-#elif defined(Q_PROCESSOR_MIPS)
-/* Data:
- dsp
- dspr2
-*/
-static const char features_string[] =
- " dsp\0"
- " dspr2\0"
- "\0";
-
-static const int features_indices[] = {
- 0, 5
-};
-#elif defined(Q_PROCESSOR_X86)
-# include "qsimd_x86.cpp" // generated by util/x86simdgen
-#else
-static const char features_string[] = "";
-static const int features_indices[] = { };
-#endif
-// end generated
-
-#if defined (Q_OS_NACL)
-static inline uint detectProcessorFeatures()
-{
- return 0;
-}
-#elif defined(Q_PROCESSOR_ARM)
-static inline quint64 detectProcessorFeatures()
-{
- quint64 features = 0;
-
-#if defined(Q_OS_LINUX)
-# if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64)
- features |= Q_UINT64_C(1) << CpuFeatureNEON; // NEON is always available on ARMv8 64bit.
-# endif
- int auxv = qt_safe_open("/proc/self/auxv", O_RDONLY);
- if (auxv != -1) {
- unsigned long vector[64];
- int nread;
- while (features == 0) {
- nread = qt_safe_read(auxv, (char *)vector, sizeof vector);
- if (nread <= 0) {
- // EOF or error
- break;
- }
-
- int max = nread / (sizeof vector[0]);
- for (int i = 0; i < max; i += 2) {
- if (vector[i] == AT_HWCAP) {
-# if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64)
- // For Aarch64:
- if (vector[i+1] & HWCAP_CRC32)
- features |= Q_UINT64_C(1) << CpuFeatureCRC32;
-# endif
- // Aarch32, or ARMv7 or before:
- if (vector[i+1] & HWCAP_NEON)
- features |= Q_UINT64_C(1) << CpuFeatureNEON;
- }
-# if defined(Q_PROCESSOR_ARM_32)
- // For Aarch32:
- if (vector[i] == AT_HWCAP2) {
- if (vector[i+1] & HWCAP2_CRC32)
- features |= Q_UINT64_C(1) << CpuFeatureCRC32;
- }
-# endif
- }
- }
-
- qt_safe_close(auxv);
- return features;
- }
- // fall back if /proc/self/auxv wasn't found
-#endif
-
-#if defined(__ARM_NEON__)
- features |= Q_UINT64_C(1) << CpuFeatureNEON;
-#endif
-#if defined(__ARM_FEATURE_CRC32)
- features |= Q_UINT64_C(1) << CpuFeatureCRC32;
-#endif
-
- return features;
-}
-
-#elif defined(Q_PROCESSOR_X86)
-
-#ifdef Q_PROCESSOR_X86_32
-# define PICreg "%%ebx"
-#else
-# define PICreg "%%rbx"
-#endif
-
-static bool checkRdrndWorks() noexcept;
-
-static int maxBasicCpuidSupported()
-{
-#if defined(Q_CC_EMSCRIPTEN)
- return 6; // All features supported by Emscripten
-#elif defined(Q_CC_GNU)
- qregisterint tmp1;
-
-# if Q_PROCESSOR_X86 < 5
- // check if the CPUID instruction is supported
- long cpuid_supported;
- asm ("pushf\n"
- "pop %0\n"
- "mov %0, %1\n"
- "xor $0x00200000, %0\n"
- "push %0\n"
- "popf\n"
- "pushf\n"
- "pop %0\n"
- "xor %1, %0\n" // %eax is now 0 if CPUID is not supported
- : "=a" (cpuid_supported), "=r" (tmp1)
- );
- if (!cpuid_supported)
- return 0;
-# endif
-
- int result;
- asm ("xchg " PICreg", %1\n"
- "cpuid\n"
- "xchg " PICreg", %1\n"
- : "=&a" (result), "=&r" (tmp1)
- : "0" (0)
- : "ecx", "edx");
- return result;
-#elif defined(Q_OS_WIN)
- // Use the __cpuid function; if the CPUID instruction isn't supported, it will return 0
- int info[4];
- __cpuid(info, 0);
- return info[0];
-#elif defined(Q_CC_GHS)
- unsigned int info[4];
- __CPUID(0, info);
- return info[0];
-#else
- return 0;
-#endif
-}
-
-static void cpuidFeatures01(uint &ecx, uint &edx)
-{
-#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
- qregisterint tmp1;
- asm ("xchg " PICreg", %2\n"
- "cpuid\n"
- "xchg " PICreg", %2\n"
- : "=&c" (ecx), "=&d" (edx), "=&r" (tmp1)
- : "a" (1));
-#elif defined(Q_OS_WIN)
- int info[4];
- __cpuid(info, 1);
- ecx = info[2];
- edx = info[3];
-#elif defined(Q_CC_GHS)
- unsigned int info[4];
- __CPUID(1, info);
- ecx = info[2];
- edx = info[3];
-#else
- Q_UNUSED(ecx);
- Q_UNUSED(edx);
-#endif
-}
-
-#ifdef Q_OS_WIN
-inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));}
-#endif
-
-static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
-{
-#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
- qregisteruint rbx; // in case it's 64-bit
- qregisteruint rcx = 0;
- qregisteruint rdx = 0;
- asm ("xchg " PICreg", %0\n"
- "cpuid\n"
- "xchg " PICreg", %0\n"
- : "=&r" (rbx), "+&c" (rcx), "+&d" (rdx)
- : "a" (7));
- ebx = rbx;
- ecx = rcx;
- edx = rdx;
-#elif defined(Q_OS_WIN)
- int info[4];
- __cpuidex(info, 7, 0);
- ebx = info[1];
- ecx = info[2];
- edx = info[3];
-#elif defined(Q_CC_GHS)
- unsigned int info[4];
- __CPUIDEX(7, 0, info);
- ebx = info[1];
- ecx = info[2];
- edx = info[3];
-#else
- Q_UNUSED(ebx);
- Q_UNUSED(ecx);
- Q_UNUSED(edx);
-#endif
-}
-
-#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS))
-// fallback overload in case this intrinsic does not exist: unsigned __int64 _xgetbv(unsigned int);
-inline quint64 _xgetbv(__int64) { return 0; }
-#endif
-static void xgetbv(uint in, uint &eax, uint &edx)
-{
-#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
- asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction
- : "=a" (eax), "=d" (edx)
- : "c" (in));
-#elif defined(Q_OS_WIN)
- quint64 result = _xgetbv(in);
- eax = result;
- edx = result >> 32;
-#else
- Q_UNUSED(in);
- Q_UNUSED(eax);
- Q_UNUSED(edx);
-#endif
-}
-
-static quint64 detectProcessorFeatures()
-{
- // Flags from the CR0 / XCR0 state register
- enum XCR0Flags {
- X87 = 1 << 0,
- XMM0_15 = 1 << 1,
- YMM0_15Hi128 = 1 << 2,
- BNDRegs = 1 << 3,
- BNDCSR = 1 << 4,
- OpMask = 1 << 5,
- ZMM0_15Hi256 = 1 << 6,
- ZMM16_31 = 1 << 7,
-
- SSEState = XMM0_15,
- AVXState = XMM0_15 | YMM0_15Hi128,
- AVX512State = AVXState | OpMask | ZMM0_15Hi256 | ZMM16_31
- };
- static const quint64 AllAVX2 = CpuFeatureAVX2 | AllAVX512;
- static const quint64 AllAVX = CpuFeatureAVX | AllAVX2;
-
- quint64 features = 0;
- int cpuidLevel = maxBasicCpuidSupported();
-#if Q_PROCESSOR_X86 < 5
- if (cpuidLevel < 1)
- return 0;
-#else
- Q_ASSERT(cpuidLevel >= 1);
-#endif
-
- uint results[X86CpuidMaxLeaf] = {};
- cpuidFeatures01(results[Leaf1ECX], results[Leaf1EDX]);
- if (cpuidLevel >= 7)
- cpuidFeatures07_00(results[Leaf7_0EBX], results[Leaf7_0ECX], results[Leaf7_0EDX]);
-
- // populate our feature list
- for (uint i = 0; i < sizeof(x86_locators) / sizeof(x86_locators[0]); ++i) {
- uint word = x86_locators[i] / 32;
- uint bit = 1U << (x86_locators[i] % 32);
- quint64 feature = Q_UINT64_C(1) << (i + 1);
- if (results[word] & bit)
- features |= feature;
- }
-
- // now check the AVX state
- uint xgetbvA = 0, xgetbvD = 0;
- if (results[Leaf1ECX] & (1u << 27)) {
- // XGETBV enabled
- xgetbv(0, xgetbvA, xgetbvD);
- }
-
- if ((xgetbvA & AVXState) != AVXState) {
- // support for YMM registers is disabled, disable all AVX
- features &= ~AllAVX;
- } else if ((xgetbvA & AVX512State) != AVX512State) {
- // support for ZMM registers or mask registers is disabled, disable all AVX512
- features &= ~AllAVX512;
- }
-
- if (features & CpuFeatureRDRND && !checkRdrndWorks())
- features &= ~(CpuFeatureRDRND | CpuFeatureRDSEED);
-
- return features;
-}
-
-#elif defined(Q_PROCESSOR_MIPS_32)
-
-#if defined(Q_OS_LINUX)
-//
-// Do not use QByteArray: it could use SIMD instructions itself at
-// some point, thus creating a recursive dependency. Instead, use a
-// QSimpleBuffer, which has the bare minimum needed to use memory
-// dynamically and read lines from /proc/cpuinfo of arbitrary sizes.
-//
-struct QSimpleBuffer {
- static const int chunk_size = 256;
- char *data;
- unsigned alloc;
- unsigned size;
-
- QSimpleBuffer(): data(0), alloc(0), size(0) {}
- ~QSimpleBuffer() { ::free(data); }
-
- void resize(unsigned newsize) {
- if (newsize > alloc) {
- unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1);
- if (newalloc < newsize) newalloc = newsize;
- if (newalloc != alloc) {
- data = static_cast<char*>(::realloc(data, newalloc));
- alloc = newalloc;
- }
- }
- size = newsize;
- }
- void append(const QSimpleBuffer &other, unsigned appendsize) {
- unsigned oldsize = size;
- resize(oldsize + appendsize);
- ::memcpy(data + oldsize, other.data, appendsize);
- }
- void popleft(unsigned amount) {
- if (amount >= size) return resize(0);
- size -= amount;
- ::memmove(data, data + amount, size);
- }
- char* cString() {
- if (!alloc) resize(1);
- return (data[size] = '\0', data);
- }
-};
-
-//
-// Uses a scratch "buffer" (which must be used for all reads done in the
-// same file descriptor) to read chunks of data from a file, to read
-// one line at a time. Lines include the trailing newline character ('\n').
-// On EOF, line.size is zero.
-//
-static void bufReadLine(int fd, QSimpleBuffer &line, QSimpleBuffer &buffer)
-{
- for (;;) {
- char *newline = static_cast<char*>(::memchr(buffer.data, '\n', buffer.size));
- if (newline) {
- unsigned piece_size = newline - buffer.data + 1;
- line.append(buffer, piece_size);
- buffer.popleft(piece_size);
- line.resize(line.size - 1);
- return;
- }
- if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) {
- int oldsize = buffer.size;
- buffer.resize(buffer.size + QSimpleBuffer::chunk_size);
- buffer.size = oldsize;
- }
- ssize_t read_bytes = ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size);
- if (read_bytes > 0) buffer.size += read_bytes;
- else return;
- }
-}
-
-//
-// Checks if any line with a given prefix from /proc/cpuinfo contains
-// a certain string, surrounded by spaces.
-//
-static bool procCpuinfoContains(const char *prefix, const char *string)
-{
- int cpuinfo_fd = ::qt_safe_open("/proc/cpuinfo", O_RDONLY);
- if (cpuinfo_fd == -1)
- return false;
-
- unsigned string_len = ::strlen(string);
- unsigned prefix_len = ::strlen(prefix);
- QSimpleBuffer line, buffer;
- bool present = false;
- do {
- line.resize(0);
- bufReadLine(cpuinfo_fd, line, buffer);
- char *colon = static_cast<char*>(::memchr(line.data, ':', line.size));
- if (colon && line.size > prefix_len + string_len) {
- if (!::strncmp(prefix, line.data, prefix_len)) {
- // prefix matches, next character must be ':' or space
- if (line.data[prefix_len] == ':' || ::isspace(line.data[prefix_len])) {
- // Does it contain the string?
- char *found = ::strstr(line.cString(), string);
- if (found && ::isspace(found[-1]) &&
- (::isspace(found[string_len]) || found[string_len] == '\0')) {
- present = true;
- break;
- }
- }
- }
- }
- } while (line.size);
-
- ::qt_safe_close(cpuinfo_fd);
- return present;
-}
-#endif
-
-static inline quint64 detectProcessorFeatures()
-{
- // NOTE: MIPS 74K cores are the only ones supporting DSPr2.
- quint64 flags = 0;
-
-#if defined __mips_dsp
- flags |= Q_UINT64_C(1) << CpuFeatureDSP;
-# if defined __mips_dsp_rev && __mips_dsp_rev >= 2
- flags |= Q_UINT64_C(1) << CpuFeatureDSPR2;
-# elif defined(Q_OS_LINUX)
- if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf"))
- flags |= Q_UINT64_C(1) << CpuFeatureDSPR2;
-# endif
-#elif defined(Q_OS_LINUX)
- if (procCpuinfoContains("ASEs implemented", "dsp")) {
- flags |= Q_UINT64_C(1) << CpuFeatureDSP;
- if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf"))
- flags |= Q_UINT64_C(1) << CpuFeatureDSPR2;
- }
-#endif
-
- return flags;
-}
-
-#else
-static inline uint detectProcessorFeatures()
-{
- return 0;
-}
-#endif
-
-static const int features_count = (sizeof features_indices) / (sizeof features_indices[0]);
-
-// record what CPU features were enabled by default in this Qt build
-static const quint64 minFeature = qCompilerCpuFeatures;
-
-#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
-Q_CORE_EXPORT QBasicAtomicInteger<quint64> qt_cpu_features[1] = { Q_BASIC_ATOMIC_INITIALIZER(0) };
-#else
-Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2] = { Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) };
-#endif
-
-quint64 qDetectCpuFeatures()
-{
- quint64 f = detectProcessorFeatures();
- QByteArray disable = qgetenv("QT_NO_CPU_FEATURE");
- if (!disable.isEmpty()) {
- disable.prepend(' ');
- for (int i = 0; i < features_count; ++i) {
- if (disable.contains(features_string + features_indices[i]))
- f &= ~(Q_UINT64_C(1) << i);
- }
- }
-
-#ifdef RUNNING_ON_VALGRIND
- bool runningOnValgrind = RUNNING_ON_VALGRIND;
-#else
- bool runningOnValgrind = false;
-#endif
- if (Q_UNLIKELY(!runningOnValgrind && minFeature != 0 && (f & minFeature) != minFeature)) {
- quint64 missing = minFeature & ~f;
- fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n ");
- for (int i = 0; i < features_count; ++i) {
- if (missing & (Q_UINT64_C(1) << i))
- fprintf(stderr, "%s", features_string + features_indices[i]);
- }
- fprintf(stderr, "\n");
- fflush(stderr);
- qFatal("Aborted. Incompatible processor: missing feature 0x%llx -%s.", missing,
- features_string + features_indices[qCountTrailingZeroBits(missing)]);
- }
-
- qt_cpu_features[0].storeRelaxed(f | quint32(QSimdInitialized));
-#ifndef Q_ATOMIC_INT64_IS_SUPPORTED
- qt_cpu_features[1].storeRelaxed(f >> 32);
-#endif
- return f;
-}
-
-void qDumpCPUFeatures()
-{
- quint64 features = qCpuFeatures() & ~quint64(QSimdInitialized);
- printf("Processor features: ");
- for (int i = 0; i < features_count; ++i) {
- if (features & (Q_UINT64_C(1) << i))
- printf("%s%s", features_string + features_indices[i],
- minFeature & (Q_UINT64_C(1) << i) ? "[required]" : "");
- }
- if ((features = (qCompilerCpuFeatures & ~features))) {
- printf("\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
- for (int i = 0; i < features_count; ++i) {
- if (features & (Q_UINT64_C(1) << i))
- printf("%s", features_string + features_indices[i]);
- }
- printf("\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!");
- }
- puts("");
-}
-
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
-
-# ifdef Q_PROCESSOR_X86_64
-# define _rdrandXX_step _rdrand64_step
-# define _rdseedXX_step _rdseed64_step
-# else
-# define _rdrandXX_step _rdrand32_step
-# define _rdseedXX_step _rdseed32_step
-# endif
-
-# if QT_COMPILER_SUPPORTS_HERE(RDSEED)
-static QT_FUNCTION_TARGET(RDSEED) unsigned *qt_random_rdseed(unsigned *ptr, unsigned *end) noexcept
-{
- // Unlike for the RDRAND code below, the Intel whitepaper describing the
- // use of the RDSEED instruction indicates we should not retry in a loop.
- // If the independent bit generator used by RDSEED is out of entropy, it
- // may take time to replenish.
- // https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
- while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
- if (_rdseedXX_step(reinterpret_cast<qregisteruint *>(ptr)) == 0)
- goto out;
- ptr += sizeof(qregisteruint)/sizeof(*ptr);
- }
-
- if (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
- if (_rdseed32_step(ptr) == 0)
- goto out;
- ++ptr;
- }
-
-out:
- return ptr;
-}
-# else
-static unsigned *qt_random_rdseed(unsigned *ptr, unsigned *)
-{
- return ptr;
-}
-# endif
-
-static QT_FUNCTION_TARGET(RDRND) unsigned *qt_random_rdrnd(unsigned *ptr, unsigned *end) noexcept
-{
- int retries = 10;
- while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
- if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
- ptr += sizeof(qregisteruint)/sizeof(*ptr);
- else if (--retries == 0)
- goto out;
- }
-
- while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
- bool ok = _rdrand32_step(ptr);
- if (!ok && --retries)
- continue;
- if (ok)
- ++ptr;
- break;
- }
-
-out:
- return ptr;
-}
-
-static QT_FUNCTION_TARGET(RDRND) Q_DECL_COLD_FUNCTION bool checkRdrndWorks() noexcept
-{
- /*
- * Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
- * failing random generation instruction, which always returns
- * 0xffffffff, even when generation was "successful".
- *
- * This code checks if hardware random generator generates four consecutive
- * equal numbers. If it does, then we probably have a failing one and
- * should disable it completely.
- *
- * https://bugreports.qt.io/browse/QTBUG-69423
- */
- constexpr qsizetype TestBufferSize = 4;
- unsigned testBuffer[TestBufferSize] = {};
-
- unsigned *end = qt_random_rdrnd(testBuffer, testBuffer + TestBufferSize);
- if (end < testBuffer + 3) {
- // Random generation didn't produce enough data for us to make a
- // determination whether it's working or not. Assume it isn't, but
- // don't print a warning.
- return false;
- }
-
- // Check the results for equality
- if (testBuffer[0] == testBuffer[1]
- && testBuffer[0] == testBuffer[2]
- && end == testBuffer + TestBufferSize && testBuffer[0] == testBuffer[3]) {
- fprintf(stderr, "WARNING: CPU random generator seem to be failing, "
- "disabling hardware random number generation\n"
- "WARNING: RDRND generated:");
- for (unsigned *ptr = testBuffer; ptr < end; ++ptr)
- fprintf(stderr, " 0x%x", *ptr);
- fprintf(stderr, "\n");
- return false;
- }
-
- // We're good
- return true;
-}
-
-QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
-{
- unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
- unsigned *end = ptr + count;
-
- if (qCpuHasFeature(RDSEED))
- ptr = qt_random_rdseed(ptr, end);
-
- // fill the buffer with RDRND if RDSEED didn't
- ptr = qt_random_rdrnd(ptr, end);
- return ptr - reinterpret_cast<unsigned *>(buffer);
-}
-#elif defined(Q_PROCESSOR_X86) && !defined(Q_OS_NACL) && !defined(Q_PROCESSOR_ARM)
-static bool checkRdrndWorks() noexcept { return false; }
-#endif // Q_PROCESSOR_X86 && RDRND
-
-QT_END_NAMESPACE
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
deleted file mode 100644
index c28624a25e..0000000000
--- a/src/corelib/tools/qsimd_p.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSIMD_P_H
-#define QSIMD_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/private/qglobal_p.h>
-
-/*
- * qt_module_config.prf defines the QT_COMPILER_SUPPORTS_XXX macros.
- * They mean the compiler supports the necessary flags and the headers
- * for the x86 and ARM intrinsics:
- * - GCC: the -mXXX or march=YYY flag is necessary before #include
- * up to 4.8; GCC >= 4.9 can include unconditionally
- * - Intel CC: #include can happen unconditionally
- * - MSVC: #include can happen unconditionally
- * - RVCT: ???
- *
- * We will try to include all headers possible under this configuration.
- *
- * MSVC does not define __SSE2__ & family, so we will define them. MSVC 2013 &
- * up do define __AVX__ if the -arch:AVX option is passed on the command-line.
- *
- * Supported XXX are:
- * Flag | Arch | GCC | Intel CC | MSVC |
- * ARM_NEON | ARM | I & C | None | ? |
- * SSE2 | x86 | I & C | I & C | I & C |
- * SSE3 | x86 | I & C | I & C | I only |
- * SSSE3 | x86 | I & C | I & C | I only |
- * SSE4_1 | x86 | I & C | I & C | I only |
- * SSE4_2 | x86 | I & C | I & C | I only |
- * AVX | x86 | I & C | I & C | I & C |
- * AVX2 | x86 | I & C | I & C | I only |
- * AVX512xx | x86 | I & C | I & C | I only |
- * I = intrinsics; C = code generation
- *
- * Code can use the following constructs to determine compiler support & status:
- * - #ifdef __XXX__ (e.g: #ifdef __AVX__ or #ifdef __ARM_NEON__)
- * If this test passes, then the compiler is already generating code for that
- * given sub-architecture. The intrinsics for that sub-architecture are
- * #included and can be used without restriction or runtime check.
- *
- * - #if QT_COMPILER_SUPPORTS(XXX)
- * If this test passes, then the compiler is able to generate code for that
- * given sub-architecture in another translation unit, given the right set of
- * flags. Use of the intrinsics is not guaranteed. This is useful with
- * runtime detection (see below).
- *
- * - #if QT_COMPILER_SUPPORTS_HERE(XXX)
- * If this test passes, then the compiler is able to generate code for that
- * given sub-architecture in this translation unit, even if it is not doing
- * that now (it might be). Individual functions may be tagged with
- * QT_FUNCTION_TARGET(XXX) to cause the compiler to generate code for that
- * sub-arch. Only inside such functions is the use of the intrisics
- * guaranteed to work. This is useful with runtime detection (see below).
- *
- * Runtime detection of a CPU sub-architecture can be done with the
- * qCpuHasFeature(XXX) function. There are two strategies for generating
- * optimized code like that:
- *
- * 1) place the optimized code in a different translation unit (C or assembly
- * sources) and pass the correct flags to the compiler to enable support. Those
- * sources must not include qglobal.h, which means they cannot include this
- * file either. The dispatcher function would look like this:
- *
- * void foo()
- * {
- * #if QT_COMPILER_SUPPORTS(XXX)
- * if (qCpuHasFeature(XXX)) {
- * foo_optimized_xxx();
- * return;
- * }
- * #endif
- * foo_plain();
- * }
- *
- * 2) place the optimized code in a function tagged with QT_FUNCTION_TARGET and
- * surrounded by #if QT_COMPILER_SUPPORTS_HERE(XXX). That code can freely use
- * other Qt code. The dispatcher function would look like this:
- *
- * void foo()
- * {
- * #if QT_COMPILER_SUPPORTS_HERE(XXX)
- * if (qCpuHasFeature(XXX)) {
- * foo_optimized_xxx();
- * return;
- * }
- * #endif
- * foo_plain();
- * }
- */
-
-#if defined(__MINGW64_VERSION_MAJOR) || defined(Q_CC_MSVC)
-#include <intrin.h>
-#endif
-
-#define QT_COMPILER_SUPPORTS(x) (QT_COMPILER_SUPPORTS_ ## x - 0)
-
-#if defined(Q_PROCESSOR_ARM)
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ARM_FEATURE_ ## x)
-# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 600
- /* GCC requires attributes for a function */
-# define QT_FUNCTION_TARGET(x) __attribute__((__target__(QT_FUNCTION_TARGET_STRING_ ## x)))
-# else
-# define QT_FUNCTION_TARGET(x)
-# endif
-# if !defined(__ARM_FEATURE_NEON) && defined(__ARM_NEON__)
-# define __ARM_FEATURE_NEON // also support QT_COMPILER_SUPPORTS_HERE(NEON)
-# endif
-#elif defined(Q_PROCESSOR_MIPS)
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ ## x ## __)
-# define QT_FUNCTION_TARGET(x)
-# if !defined(__MIPS_DSP__) && defined(__mips_dsp) && defined(Q_PROCESSOR_MIPS_32)
-# define __MIPS_DSP__
-# endif
-# if !defined(__MIPS_DSPR2__) && defined(__mips_dspr2) && defined(Q_PROCESSOR_MIPS_32)
-# define __MIPS_DSPR2__
-# endif
-#elif defined(Q_PROCESSOR_X86) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)
-# define QT_COMPILER_SUPPORTS_HERE(x) ((__ ## x ## __) || QT_COMPILER_SUPPORTS(x))
-# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
- /* GCC requires attributes for a function */
-# define QT_FUNCTION_TARGET(x) __attribute__((__target__(QT_FUNCTION_TARGET_STRING_ ## x)))
-# else
-# define QT_FUNCTION_TARGET(x)
-# endif
-#else
-# define QT_COMPILER_SUPPORTS_HERE(x) (__ ## x ## __)
-# define QT_FUNCTION_TARGET(x)
-#endif
-
-#ifdef Q_PROCESSOR_X86
-/* -- x86 intrinsic support -- */
-
-# if defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP >= 2)
-// MSVC doesn't define __SSE2__, so do it ourselves
-# define __SSE__ 1
-# define __SSE2__ 1
-# endif
-
-# ifdef __SSE2__
-// #include the intrinsics
-# include <immintrin.h>
-# endif
-
-# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
-// GCC 4.4 and Clang 2.8 added a few more intrinsics there
-# include <x86intrin.h>
-# endif
-
-# if defined(Q_CC_MSVC) && (defined(_M_AVX) || defined(__AVX__))
-// Visual Studio defines __AVX__ when /arch:AVX is passed, but not the earlier macros
-// See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx
-# define __SSE3__ 1
-# define __SSSE3__ 1
-// no Intel CPU supports SSE4a, so don't define it
-# define __SSE4_1__ 1
-# define __SSE4_2__ 1
-# ifndef __AVX__
-# define __AVX__ 1
-# endif
-# endif
-
-# if defined(__SSE4_2__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
-// POPCNT instructions:
-// All processors that support SSE4.2 support POPCNT
-// (but neither MSVC nor the Intel compiler define this macro)
-# define __POPCNT__ 1
-# endif
-
-// AVX intrinsics
-# if defined(__AVX__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
-// AES, PCLMULQDQ instructions:
-// All processors that support AVX support PCLMULQDQ
-// (but neither MSVC nor the Intel compiler define this macro)
-# define __PCLMUL__ 1
-# endif
-
-# if defined(__AVX2__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC))
-// F16C & RDRAND instructions:
-// All processors that support AVX2 support F16C & RDRAND:
-// (but neither MSVC nor the Intel compiler define these macros)
-# define __F16C__ 1
-# define __RDRND__ 1
-# endif
-
-# if defined(__BMI__) && !defined(__BMI2__) && defined(Q_CC_INTEL)
-// BMI2 instructions:
-// All processors that support BMI support BMI2 (and AVX2)
-// (but neither MSVC nor the Intel compiler define this macro)
-# define __BMI2__ 1
-# endif
-
-# include "qsimd_x86_p.h"
-
-// Haswell sub-architecture
-//
-// The Intel Core 4th generation was codenamed "Haswell" and introduced AVX2,
-// BMI1, BMI2, FMA, LZCNT, MOVBE, which makes it a good divider for a
-// sub-target for us. The first AMD processor with AVX2 support (Zen) has the
-// same features.
-//
-// macOS's fat binaries support the "x86_64h" sub-architecture and the GNU libc
-// ELF loader also supports a "haswell/" subdir (e.g., /usr/lib/haswell).
-# define QT_FUNCTION_TARGET_STRING_ARCH_HASWELL "arch=haswell"
-# if defined(__AVX2__) && defined(__BMI__) && defined(__BMI2__) && defined(__F16C__) && \
- defined(__FMA__) && defined(__LZCNT__) && defined(__RDRND__)
-# define __haswell__ 1
-# endif
-
-// This constant does not include all CPU features found in a Haswell, only
-// those that we'd have optimized code for.
-// Note: must use Q_CONSTEXPR here, as this file may be compiled in C mode.
-QT_BEGIN_NAMESPACE
-static const quint64 CpuFeatureArchHaswell = 0
- | CpuFeatureSSE2
- | CpuFeatureSSE3
- | CpuFeatureSSSE3
- | CpuFeatureSSE4_1
- | CpuFeatureSSE4_2
- | CpuFeatureFMA
- | CpuFeaturePOPCNT
- | CpuFeatureAVX
- | CpuFeatureF16C
- | CpuFeatureAVX2
- | CpuFeatureBMI
- | CpuFeatureBMI2;
-QT_END_NAMESPACE
-
-#endif /* Q_PROCESSOR_X86 */
-
-// Clang compiler fix, see http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20160222/151168.html
-// This should be tweaked with an "upper version" of clang once we know which release fixes the
-// issue. At that point we can rely on __ARM_FEATURE_CRC32 again.
-#if defined(Q_CC_CLANG) && defined(Q_OS_DARWIN) && defined (__ARM_FEATURE_CRC32)
-# undef __ARM_FEATURE_CRC32
-#endif
-
-// NEON intrinsics
-// note: as of GCC 4.9, does not support function targets for ARM
-#if defined(__ARM_NEON) || defined(__ARM_NEON__)
-#include <arm_neon.h>
-#define QT_FUNCTION_TARGET_STRING_NEON "+neon" // unused: gcc doesn't support function targets on non-aarch64, and on Aarch64 NEON is always available.
-#ifndef __ARM_NEON__
-// __ARM_NEON__ is not defined on AArch64, but we need it in our NEON detection.
-#define __ARM_NEON__
-#endif
-#endif
-// AArch64/ARM64
-#if defined(Q_PROCESSOR_ARM_V8) && defined(__ARM_FEATURE_CRC32)
-#if defined(Q_PROCESSOR_ARM_64)
-// only available on aarch64
-#define QT_FUNCTION_TARGET_STRING_CRC32 "+crc"
-#endif
-# include <arm_acle.h>
-#endif
-
-#ifdef __cplusplus
-#include <qatomic.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef Q_PROCESSOR_X86
-enum CPUFeatures {
-#if defined(Q_PROCESSOR_ARM)
- CpuFeatureNEON = 2,
- CpuFeatureARM_NEON = CpuFeatureNEON,
- CpuFeatureCRC32 = 4,
-#elif defined(Q_PROCESSOR_MIPS)
- CpuFeatureDSP = 2,
- CpuFeatureDSPR2 = 4,
-#endif
-
- // used only to indicate that the CPU detection was initialised
- QSimdInitialized = 1
-};
-
-static const quint64 qCompilerCpuFeatures = 0
-#if defined __ARM_NEON__
- | CpuFeatureNEON
-#endif
-#if defined __ARM_FEATURE_CRC32
- | CpuFeatureCRC32
-#endif
-#if defined __mips_dsp
- | CpuFeatureDSP
-#endif
-#if defined __mips_dspr2
- | CpuFeatureDSPR2
-#endif
- ;
-#endif
-
-#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
-extern Q_CORE_EXPORT QBasicAtomicInteger<quint64> qt_cpu_features[1];
-#else
-extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2];
-#endif
-Q_CORE_EXPORT quint64 qDetectCpuFeatures();
-
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
-Q_CORE_EXPORT qsizetype qRandomCpu(void *, qsizetype) noexcept;
-#else
-static inline qsizetype qRandomCpu(void *, qsizetype) noexcept
-{
- return 0;
-}
-#endif
-
-static inline quint64 qCpuFeatures()
-{
- quint64 features = qt_cpu_features[0].loadRelaxed();
-#ifndef Q_ATOMIC_INT64_IS_SUPPORTED
- features |= quint64(qt_cpu_features[1].loadRelaxed()) << 32;
-#endif
- if (Q_UNLIKELY(features == 0)) {
- features = qDetectCpuFeatures();
- Q_ASSUME(features != 0);
- }
- return features;
-}
-
-#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
- || ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
-
-inline bool qHasHwrng()
-{
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
- return qCpuHasFeature(RDRND);
-#else
- return false;
-#endif
-}
-
-#define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \
- for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i)
-
-#define ALIGNMENT_PROLOGUE_32BYTES(ptr, i, length) \
- for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((8 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x7)) & 0x7))); ++i)
-
-QT_END_NAMESPACE
-
-#endif // __cplusplus
-
-#define SIMD_EPILOGUE(i, length, max) \
- for (int _i = 0; _i < max && i < length; ++i, ++_i)
-
-#endif // QSIMD_P_H
diff --git a/src/corelib/tools/qsimd_x86.cpp b/src/corelib/tools/qsimd_x86.cpp
deleted file mode 100644
index 509af464b2..0000000000
--- a/src/corelib/tools/qsimd_x86.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// This is a generated file. DO NOT EDIT.
-// Please see util/x86simdgen/generate.pl
-#include "qsimd_p.h"
-
-static const char features_string[] =
- " sse2\0"
- " sse3\0"
- " ssse3\0"
- " fma\0"
- " sse4.1\0"
- " sse4.2\0"
- " movbe\0"
- " popcnt\0"
- " aes\0"
- " avx\0"
- " f16c\0"
- " rdrnd\0"
- " bmi\0"
- " hle\0"
- " avx2\0"
- " bmi2\0"
- " rtm\0"
- " avx512f\0"
- " avx512dq\0"
- " rdseed\0"
- " avx512ifma\0"
- " avx512pf\0"
- " avx512er\0"
- " avx512cd\0"
- " sha\0"
- " avx512bw\0"
- " avx512vl\0"
- " avx512vbmi\0"
- " avx512vbmi2\0"
- " gfni\0"
- " vaes\0"
- " avx512vnni\0"
- " avx512bitalg\0"
- " avx512vpopcntdq\0"
- " avx5124nniw\0"
- " avx5124fmaps\0"
- "\0";
-
-static const quint16 features_indices[] = {
- 306, 0, 6, 12, 19, 24, 32, 40,
- 47, 55, 60, 65, 71, 78, 83, 88,
- 94, 100, 105, 114, 124, 132, 144, 154,
- 164, 174, 179, 189, 199, 211, 224, 230,
- 236, 248, 262, 279, 292
-};
-
-enum X86CpuidLeaves {
- Leaf1ECX,
- Leaf1EDX,
- Leaf7_0EBX,
- Leaf7_0ECX,
- Leaf7_0EDX,
- X86CpuidMaxLeaf
-};
-
-static const quint8 x86_locators[] = {
- Leaf1EDX*32 + 26, // sse2
- Leaf1ECX*32 + 0, // sse3
- Leaf1ECX*32 + 9, // ssse3
- Leaf1ECX*32 + 12, // fma
- Leaf1ECX*32 + 19, // sse4.1
- Leaf1ECX*32 + 20, // sse4.2
- Leaf1ECX*32 + 22, // movbe
- Leaf1ECX*32 + 23, // popcnt
- Leaf1ECX*32 + 25, // aes
- Leaf1ECX*32 + 28, // avx
- Leaf1ECX*32 + 29, // f16c
- Leaf1ECX*32 + 30, // rdrnd
- Leaf7_0EBX*32 + 3, // bmi
- Leaf7_0EBX*32 + 4, // hle
- Leaf7_0EBX*32 + 5, // avx2
- Leaf7_0EBX*32 + 8, // bmi2
- Leaf7_0EBX*32 + 11, // rtm
- Leaf7_0EBX*32 + 16, // avx512f
- Leaf7_0EBX*32 + 17, // avx512dq
- Leaf7_0EBX*32 + 18, // rdseed
- Leaf7_0EBX*32 + 21, // avx512ifma
- Leaf7_0EBX*32 + 26, // avx512pf
- Leaf7_0EBX*32 + 27, // avx512er
- Leaf7_0EBX*32 + 28, // avx512cd
- Leaf7_0EBX*32 + 29, // sha
- Leaf7_0EBX*32 + 30, // avx512bw
- Leaf7_0EBX*32 + 31, // avx512vl
- Leaf7_0ECX*32 + 1, // avx512vbmi
- Leaf7_0ECX*32 + 6, // avx512vbmi2
- Leaf7_0ECX*32 + 8, // gfni
- Leaf7_0ECX*32 + 9, // vaes
- Leaf7_0ECX*32 + 11, // avx512vnni
- Leaf7_0ECX*32 + 12, // avx512bitalg
- Leaf7_0ECX*32 + 14, // avx512vpopcntdq
- Leaf7_0EDX*32 + 2, // avx5124nniw
- Leaf7_0EDX*32 + 3 // avx5124fmaps
-};
-
-// List of AVX512 features (see detectProcessorFeatures())
-static const quint64 AllAVX512 = 0
- | CpuFeatureAVX512F
- | CpuFeatureAVX512DQ
- | CpuFeatureAVX512IFMA
- | CpuFeatureAVX512PF
- | CpuFeatureAVX512ER
- | CpuFeatureAVX512CD
- | CpuFeatureAVX512BW
- | CpuFeatureAVX512VL
- | CpuFeatureAVX512VBMI
- | CpuFeatureAVX512VBMI2
- | CpuFeatureAVX512VNNI
- | CpuFeatureAVX512BITALG
- | CpuFeatureAVX512VPOPCNTDQ
- | CpuFeatureAVX5124NNIW
- | CpuFeatureAVX5124FMAPS;
diff --git a/src/corelib/tools/qsimd_x86_p.h b/src/corelib/tools/qsimd_x86_p.h
deleted file mode 100644
index 2434e2b797..0000000000
--- a/src/corelib/tools/qsimd_x86_p.h
+++ /dev/null
@@ -1,222 +0,0 @@
-// This is a generated file. DO NOT EDIT.
-// Please see util/x86simdgen/generate.pl
-#ifndef QSIMD_P_H
-# error "Please include <private/qsimd_p.h> instead"
-#endif
-#ifndef QSIMD_X86_P_H
-#define QSIMD_X86_P_H
-
-#include "qsimd_p.h"
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-QT_BEGIN_NAMESPACE
-
-// used only to indicate that the CPU detection was initialized
-#define QSimdInitialized (Q_UINT64_C(1) << 0)
-
-// in CPUID Leaf 1, EDX:
-#define CpuFeatureSSE2 (Q_UINT64_C(1) << 1)
-#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
-
-// in CPUID Leaf 1, ECX:
-#define CpuFeatureSSE3 (Q_UINT64_C(1) << 2)
-#define QT_FUNCTION_TARGET_STRING_SSE3 "sse3"
-#define CpuFeatureSSSE3 (Q_UINT64_C(1) << 3)
-#define QT_FUNCTION_TARGET_STRING_SSSE3 "ssse3"
-#define CpuFeatureFMA (Q_UINT64_C(1) << 4)
-#define QT_FUNCTION_TARGET_STRING_FMA "fma"
-#define CpuFeatureSSE4_1 (Q_UINT64_C(1) << 5)
-#define QT_FUNCTION_TARGET_STRING_SSE4_1 "sse4.1"
-#define CpuFeatureSSE4_2 (Q_UINT64_C(1) << 6)
-#define QT_FUNCTION_TARGET_STRING_SSE4_2 "sse4.2"
-#define CpuFeatureMOVBE (Q_UINT64_C(1) << 7)
-#define QT_FUNCTION_TARGET_STRING_MOVBE "movbe"
-#define CpuFeaturePOPCNT (Q_UINT64_C(1) << 8)
-#define QT_FUNCTION_TARGET_STRING_POPCNT "popcnt"
-#define CpuFeatureAES (Q_UINT64_C(1) << 9)
-#define QT_FUNCTION_TARGET_STRING_AES "aes,sse4.2"
-#define CpuFeatureAVX (Q_UINT64_C(1) << 10)
-#define QT_FUNCTION_TARGET_STRING_AVX "avx"
-#define CpuFeatureF16C (Q_UINT64_C(1) << 11)
-#define QT_FUNCTION_TARGET_STRING_F16C "f16c"
-#define CpuFeatureRDRND (Q_UINT64_C(1) << 12)
-#define QT_FUNCTION_TARGET_STRING_RDRND "rdrnd"
-
-// in CPUID Leaf 7, Sub-leaf 0, EBX:
-#define CpuFeatureBMI (Q_UINT64_C(1) << 13)
-#define QT_FUNCTION_TARGET_STRING_BMI "bmi"
-#define CpuFeatureHLE (Q_UINT64_C(1) << 14)
-#define QT_FUNCTION_TARGET_STRING_HLE "hle"
-#define CpuFeatureAVX2 (Q_UINT64_C(1) << 15)
-#define QT_FUNCTION_TARGET_STRING_AVX2 "avx2"
-#define CpuFeatureBMI2 (Q_UINT64_C(1) << 16)
-#define QT_FUNCTION_TARGET_STRING_BMI2 "bmi2"
-#define CpuFeatureRTM (Q_UINT64_C(1) << 17)
-#define QT_FUNCTION_TARGET_STRING_RTM "rtm"
-#define CpuFeatureAVX512F (Q_UINT64_C(1) << 18)
-#define QT_FUNCTION_TARGET_STRING_AVX512F "avx512f"
-#define CpuFeatureAVX512DQ (Q_UINT64_C(1) << 19)
-#define QT_FUNCTION_TARGET_STRING_AVX512DQ "avx512dq"
-#define CpuFeatureRDSEED (Q_UINT64_C(1) << 20)
-#define QT_FUNCTION_TARGET_STRING_RDSEED "rdseed"
-#define CpuFeatureAVX512IFMA (Q_UINT64_C(1) << 21)
-#define QT_FUNCTION_TARGET_STRING_AVX512IFMA "avx512ifma"
-#define CpuFeatureAVX512PF (Q_UINT64_C(1) << 22)
-#define QT_FUNCTION_TARGET_STRING_AVX512PF "avx512pf"
-#define CpuFeatureAVX512ER (Q_UINT64_C(1) << 23)
-#define QT_FUNCTION_TARGET_STRING_AVX512ER "avx512er"
-#define CpuFeatureAVX512CD (Q_UINT64_C(1) << 24)
-#define QT_FUNCTION_TARGET_STRING_AVX512CD "avx512cd"
-#define CpuFeatureSHA (Q_UINT64_C(1) << 25)
-#define QT_FUNCTION_TARGET_STRING_SHA "sha"
-#define CpuFeatureAVX512BW (Q_UINT64_C(1) << 26)
-#define QT_FUNCTION_TARGET_STRING_AVX512BW "avx512bw"
-#define CpuFeatureAVX512VL (Q_UINT64_C(1) << 27)
-#define QT_FUNCTION_TARGET_STRING_AVX512VL "avx512vl"
-
-// in CPUID Leaf 7, Sub-leaf 0, ECX:
-#define CpuFeatureAVX512VBMI (Q_UINT64_C(1) << 28)
-#define QT_FUNCTION_TARGET_STRING_AVX512VBMI "avx512vbmi"
-#define CpuFeatureAVX512VBMI2 (Q_UINT64_C(1) << 29)
-#define QT_FUNCTION_TARGET_STRING_AVX512VBMI2 "avx512vbmi2"
-#define CpuFeatureGFNI (Q_UINT64_C(1) << 30)
-#define QT_FUNCTION_TARGET_STRING_GFNI "gfni"
-#define CpuFeatureVAES (Q_UINT64_C(1) << 31)
-#define QT_FUNCTION_TARGET_STRING_VAES "vaes"
-#define CpuFeatureAVX512VNNI (Q_UINT64_C(1) << 32)
-#define QT_FUNCTION_TARGET_STRING_AVX512VNNI "avx512vnni"
-#define CpuFeatureAVX512BITALG (Q_UINT64_C(1) << 33)
-#define QT_FUNCTION_TARGET_STRING_AVX512BITALG "avx512bitalg"
-#define CpuFeatureAVX512VPOPCNTDQ (Q_UINT64_C(1) << 34)
-#define QT_FUNCTION_TARGET_STRING_AVX512VPOPCNTDQ "avx512vpopcntdq"
-
-// in CPUID Leaf 7, Sub-leaf 0, EDX:
-#define CpuFeatureAVX5124NNIW (Q_UINT64_C(1) << 35)
-#define QT_FUNCTION_TARGET_STRING_AVX5124NNIW "avx5124nniw"
-#define CpuFeatureAVX5124FMAPS (Q_UINT64_C(1) << 36)
-#define QT_FUNCTION_TARGET_STRING_AVX5124FMAPS "avx5124fmaps"
-
-static const quint64 qCompilerCpuFeatures = 0
-#ifdef __SSE2__
- | CpuFeatureSSE2
-#endif
-#ifdef __SSE3__
- | CpuFeatureSSE3
-#endif
-#ifdef __SSSE3__
- | CpuFeatureSSSE3
-#endif
-#ifdef __FMA__
- | CpuFeatureFMA
-#endif
-#ifdef __SSE4_1__
- | CpuFeatureSSE4_1
-#endif
-#ifdef __SSE4_2__
- | CpuFeatureSSE4_2
-#endif
-#ifdef __MOVBE__
- | CpuFeatureMOVBE
-#endif
-#ifdef __POPCNT__
- | CpuFeaturePOPCNT
-#endif
-#ifdef __AES__
- | CpuFeatureAES
-#endif
-#ifdef __AVX__
- | CpuFeatureAVX
-#endif
-#ifdef __F16C__
- | CpuFeatureF16C
-#endif
-#ifdef __RDRND__
- | CpuFeatureRDRND
-#endif
-#ifdef __BMI__
- | CpuFeatureBMI
-#endif
-#ifdef __HLE__
- | CpuFeatureHLE
-#endif
-#ifdef __AVX2__
- | CpuFeatureAVX2
-#endif
-#ifdef __BMI2__
- | CpuFeatureBMI2
-#endif
-#ifdef __RTM__
- | CpuFeatureRTM
-#endif
-#ifdef __AVX512F__
- | CpuFeatureAVX512F
-#endif
-#ifdef __AVX512DQ__
- | CpuFeatureAVX512DQ
-#endif
-#ifdef __RDSEED__
- | CpuFeatureRDSEED
-#endif
-#ifdef __AVX512IFMA__
- | CpuFeatureAVX512IFMA
-#endif
-#ifdef __AVX512PF__
- | CpuFeatureAVX512PF
-#endif
-#ifdef __AVX512ER__
- | CpuFeatureAVX512ER
-#endif
-#ifdef __AVX512CD__
- | CpuFeatureAVX512CD
-#endif
-#ifdef __SHA__
- | CpuFeatureSHA
-#endif
-#ifdef __AVX512BW__
- | CpuFeatureAVX512BW
-#endif
-#ifdef __AVX512VL__
- | CpuFeatureAVX512VL
-#endif
-#ifdef __AVX512VBMI__
- | CpuFeatureAVX512VBMI
-#endif
-#ifdef __AVX512VBMI2__
- | CpuFeatureAVX512VBMI2
-#endif
-#ifdef __GFNI__
- | CpuFeatureGFNI
-#endif
-#ifdef __VAES__
- | CpuFeatureVAES
-#endif
-#ifdef __AVX512VNNI__
- | CpuFeatureAVX512VNNI
-#endif
-#ifdef __AVX512BITALG__
- | CpuFeatureAVX512BITALG
-#endif
-#ifdef __AVX512VPOPCNTDQ__
- | CpuFeatureAVX512VPOPCNTDQ
-#endif
-#ifdef __AVX5124NNIW__
- | CpuFeatureAVX5124NNIW
-#endif
-#ifdef __AVX5124FMAPS__
- | CpuFeatureAVX5124FMAPS
-#endif
- ;
-
-QT_END_NAMESPACE
-
-#endif // QSIMD_X86_P_H
diff --git a/src/corelib/tools/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 06de1cd63f..a5eaf34afe 100644
--- a/src/corelib/tools/qsize.h
+++ b/src/corelib/tools/qsize.h
@@ -1,110 +1,103 @@
-/****************************************************************************
-**
-** 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
#include <QtCore/qnamespace.h>
+#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
{
public:
- Q_DECL_CONSTEXPR QSize() noexcept;
- Q_DECL_CONSTEXPR QSize(int w, int h) noexcept;
+ constexpr QSize() noexcept;
+ constexpr QSize(int w, int h) noexcept;
- Q_DECL_CONSTEXPR inline bool isNull() const noexcept;
- Q_DECL_CONSTEXPR inline bool isEmpty() const noexcept;
- Q_DECL_CONSTEXPR inline bool isValid() const noexcept;
+ constexpr inline bool isNull() const noexcept;
+ constexpr inline bool isEmpty() const noexcept;
+ constexpr inline bool isValid() const noexcept;
- Q_DECL_CONSTEXPR inline int width() const noexcept;
- Q_DECL_CONSTEXPR inline int height() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setWidth(int w) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setHeight(int h) noexcept;
+ constexpr inline int width() const noexcept;
+ constexpr inline int height() const noexcept;
+ constexpr inline void setWidth(int w) noexcept;
+ constexpr inline void setHeight(int h) noexcept;
void transpose() noexcept;
- Q_REQUIRED_RESULT Q_DECL_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 Q_DECL_CONSTEXPR inline QSize expandedTo(const QSize &) const noexcept;
- Q_REQUIRED_RESULT Q_DECL_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 Q_DECL_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 Q_DECL_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()}; }
- Q_DECL_RELAXED_CONSTEXPR inline int &rwidth() noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline int &rheight() noexcept;
+ constexpr inline int &rwidth() noexcept;
+ constexpr inline int &rheight() noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QSize &operator+=(const QSize &) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QSize &operator-=(const QSize &) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QSize &operator*=(qreal c) noexcept;
+ constexpr inline QSize &operator+=(const QSize &) noexcept;
+ constexpr inline QSize &operator-=(const QSize &) noexcept;
+ constexpr inline QSize &operator*=(qreal c) noexcept;
inline QSize &operator/=(qreal c);
- friend inline Q_DECL_CONSTEXPR bool operator==(const QSize &, const QSize &) noexcept;
- friend inline Q_DECL_CONSTEXPR bool operator!=(const QSize &, const QSize &) noexcept;
- friend inline Q_DECL_CONSTEXPR const QSize operator+(const QSize &, const QSize &) noexcept;
- friend inline Q_DECL_CONSTEXPR const QSize operator-(const QSize &, const QSize &) noexcept;
- friend inline Q_DECL_CONSTEXPR const QSize operator*(const QSize &, qreal) noexcept;
- friend inline Q_DECL_CONSTEXPR const QSize operator*(qreal, const QSize &) noexcept;
- friend inline const QSize operator/(const QSize &, qreal);
+ 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;
#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
@@ -120,32 +113,32 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QSize &);
QSize inline functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QSize::QSize() noexcept : wd(-1), ht(-1) {}
+constexpr inline QSize::QSize() noexcept : wd(-1), ht(-1) {}
-Q_DECL_CONSTEXPR inline QSize::QSize(int w, int h) noexcept : wd(w), ht(h) {}
+constexpr inline QSize::QSize(int w, int h) noexcept : wd(w), ht(h) {}
-Q_DECL_CONSTEXPR inline bool QSize::isNull() const noexcept
-{ return wd==0 && ht==0; }
+constexpr inline bool QSize::isNull() const noexcept
+{ return wd == 0 && ht == 0; }
-Q_DECL_CONSTEXPR inline bool QSize::isEmpty() const noexcept
-{ return wd<1 || ht<1; }
+constexpr inline bool QSize::isEmpty() const noexcept
+{ return wd < 1 || ht < 1; }
-Q_DECL_CONSTEXPR inline bool QSize::isValid() const noexcept
-{ return wd>=0 && ht>=0; }
+constexpr inline bool QSize::isValid() const noexcept
+{ return wd >= 0 && ht >= 0; }
-Q_DECL_CONSTEXPR inline int QSize::width() const noexcept
+constexpr inline int QSize::width() const noexcept
{ return wd; }
-Q_DECL_CONSTEXPR inline int QSize::height() const noexcept
+constexpr inline int QSize::height() const noexcept
{ return ht; }
-Q_DECL_RELAXED_CONSTEXPR inline void QSize::setWidth(int w) noexcept
+constexpr inline void QSize::setWidth(int w) noexcept
{ wd = w; }
-Q_DECL_RELAXED_CONSTEXPR inline void QSize::setHeight(int h) noexcept
+constexpr inline void QSize::setHeight(int h) noexcept
{ ht = h; }
-Q_DECL_CONSTEXPR inline QSize QSize::transposed() const noexcept
+constexpr inline QSize QSize::transposed() const noexcept
{ return QSize(ht, wd); }
inline void QSize::scale(int w, int h, Qt::AspectRatioMode mode) noexcept
@@ -157,58 +150,50 @@ inline void QSize::scale(const QSize &s, Qt::AspectRatioMode mode) noexcept
inline QSize QSize::scaled(int w, int h, Qt::AspectRatioMode mode) const noexcept
{ return scaled(QSize(w, h), mode); }
-Q_DECL_RELAXED_CONSTEXPR inline int &QSize::rwidth() noexcept
+constexpr inline int &QSize::rwidth() noexcept
{ return wd; }
-Q_DECL_RELAXED_CONSTEXPR inline int &QSize::rheight() noexcept
+constexpr inline int &QSize::rheight() noexcept
{ return ht; }
-Q_DECL_RELAXED_CONSTEXPR inline QSize &QSize::operator+=(const QSize &s) noexcept
-{ wd+=s.wd; ht+=s.ht; return *this; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QSize &QSize::operator-=(const QSize &s) noexcept
-{ wd-=s.wd; ht-=s.ht; return *this; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QSize &QSize::operator*=(qreal c) noexcept
-{ wd = qRound(wd*c); ht = qRound(ht*c); return *this; }
-
-Q_DECL_CONSTEXPR inline bool operator==(const QSize &s1, const QSize &s2) noexcept
-{ return s1.wd == s2.wd && s1.ht == s2.ht; }
-
-Q_DECL_CONSTEXPR inline bool operator!=(const QSize &s1, const QSize &s2) noexcept
-{ return s1.wd != s2.wd || s1.ht != s2.ht; }
-
-Q_DECL_CONSTEXPR inline const QSize operator+(const QSize & s1, const QSize & s2) noexcept
-{ return QSize(s1.wd+s2.wd, s1.ht+s2.ht); }
-
-Q_DECL_CONSTEXPR inline const QSize operator-(const QSize &s1, const QSize &s2) noexcept
-{ return QSize(s1.wd-s2.wd, s1.ht-s2.ht); }
-
-Q_DECL_CONSTEXPR inline const QSize operator*(const QSize &s, qreal c) noexcept
-{ return QSize(qRound(s.wd*c), qRound(s.ht*c)); }
+constexpr inline QSize &QSize::operator+=(const QSize &s) noexcept
+{
+ wd += s.wd;
+ ht += s.ht;
+ return *this;
+}
-Q_DECL_CONSTEXPR inline const QSize operator*(qreal c, const QSize &s) noexcept
-{ return QSize(qRound(s.wd*c), qRound(s.ht*c)); }
+constexpr inline QSize &QSize::operator-=(const QSize &s) noexcept
+{
+ wd -= s.wd;
+ ht -= s.ht;
+ return *this;
+}
-inline QSize &QSize::operator/=(qreal c)
+constexpr inline QSize &QSize::operator*=(qreal c) noexcept
{
- 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)
+constexpr inline size_t qHash(const QSize &s, size_t seed = 0) noexcept
+{ return qHashMulti(seed, s.wd, s.ht); }
+
+inline QSize &QSize::operator/=(qreal c)
{
Q_ASSERT(!qFuzzyIsNull(c));
- return QSize(qRound(s.wd/c), qRound(s.ht/c));
+ wd = qRound(wd / c);
+ ht = qRound(ht / c);
+ return *this;
}
-Q_DECL_CONSTEXPR inline QSize QSize::expandedTo(const QSize & otherSize) const noexcept
+constexpr inline QSize QSize::expandedTo(const QSize & otherSize) const noexcept
{
return QSize(qMax(wd,otherSize.wd), qMax(ht,otherSize.ht));
}
-Q_DECL_CONSTEXPR inline QSize QSize::boundedTo(const QSize & otherSize) const noexcept
+constexpr inline QSize QSize::boundedTo(const QSize & otherSize) const noexcept
{
return QSize(qMin(wd,otherSize.wd), qMin(ht,otherSize.ht));
}
@@ -221,62 +206,87 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QSize &);
class Q_CORE_EXPORT QSizeF
{
public:
- Q_DECL_CONSTEXPR QSizeF() noexcept;
- Q_DECL_CONSTEXPR QSizeF(const QSize &sz) noexcept;
- Q_DECL_CONSTEXPR QSizeF(qreal w, qreal h) noexcept;
+ constexpr QSizeF() noexcept;
+ constexpr QSizeF(const QSize &sz) noexcept;
+ constexpr QSizeF(qreal w, qreal h) noexcept;
inline bool isNull() const noexcept;
- Q_DECL_CONSTEXPR inline bool isEmpty() const noexcept;
- Q_DECL_CONSTEXPR inline bool isValid() const noexcept;
+ constexpr inline bool isEmpty() const noexcept;
+ constexpr inline bool isValid() const noexcept;
- Q_DECL_CONSTEXPR inline qreal width() const noexcept;
- Q_DECL_CONSTEXPR inline qreal height() const noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setWidth(qreal w) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline void setHeight(qreal h) noexcept;
+ constexpr inline qreal width() const noexcept;
+ constexpr inline qreal height() const noexcept;
+ constexpr inline void setWidth(qreal w) noexcept;
+ constexpr inline void setHeight(qreal h) noexcept;
void transpose() noexcept;
- Q_REQUIRED_RESULT Q_DECL_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 Q_DECL_CONSTEXPR inline QSizeF expandedTo(const QSizeF &) const noexcept;
- Q_REQUIRED_RESULT Q_DECL_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 Q_DECL_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 Q_DECL_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()}; }
- Q_DECL_RELAXED_CONSTEXPR inline qreal &rwidth() noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline qreal &rheight() noexcept;
+ constexpr inline qreal &rwidth() noexcept;
+ constexpr inline qreal &rheight() noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QSizeF &operator+=(const QSizeF &) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QSizeF &operator-=(const QSizeF &) noexcept;
- Q_DECL_RELAXED_CONSTEXPR inline QSizeF &operator*=(qreal c) noexcept;
+ constexpr inline QSizeF &operator+=(const QSizeF &) noexcept;
+ constexpr inline QSizeF &operator-=(const QSizeF &) noexcept;
+ constexpr inline QSizeF &operator*=(qreal c) noexcept;
inline QSizeF &operator/=(qreal c);
- friend Q_DECL_CONSTEXPR inline bool operator==(const QSizeF &, const QSizeF &) noexcept;
- friend Q_DECL_CONSTEXPR inline bool operator!=(const QSizeF &, const QSizeF &) noexcept;
- friend Q_DECL_CONSTEXPR inline const QSizeF operator+(const QSizeF &, const QSizeF &) noexcept;
- friend Q_DECL_CONSTEXPR inline const QSizeF operator-(const QSizeF &, const QSizeF &) noexcept;
- friend Q_DECL_CONSTEXPR inline const QSizeF operator*(const QSizeF &, qreal) noexcept;
- friend Q_DECL_CONSTEXPR inline const QSizeF operator*(qreal, const QSizeF &) noexcept;
- friend inline const QSizeF operator/(const QSizeF &, qreal);
-
- Q_DECL_CONSTEXPR inline QSize toSize() const noexcept;
+ 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);
/*****************************************************************************
@@ -293,34 +303,34 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QSizeF &);
QSizeF inline functions
*****************************************************************************/
-Q_DECL_CONSTEXPR inline QSizeF::QSizeF() noexcept : wd(-1.), ht(-1.) {}
+constexpr inline QSizeF::QSizeF() noexcept : wd(-1.), ht(-1.) {}
-Q_DECL_CONSTEXPR inline QSizeF::QSizeF(const QSize &sz) noexcept : wd(sz.width()), ht(sz.height()) {}
+constexpr inline QSizeF::QSizeF(const QSize &sz) noexcept : wd(sz.width()), ht(sz.height()) {}
-Q_DECL_CONSTEXPR inline QSizeF::QSizeF(qreal w, qreal h) noexcept : wd(w), ht(h) {}
+constexpr inline QSizeF::QSizeF(qreal w, qreal h) noexcept : wd(w), ht(h) {}
inline bool QSizeF::isNull() const noexcept
{ return qIsNull(wd) && qIsNull(ht); }
-Q_DECL_CONSTEXPR inline bool QSizeF::isEmpty() const noexcept
+constexpr inline bool QSizeF::isEmpty() const noexcept
{ return wd <= 0. || ht <= 0.; }
-Q_DECL_CONSTEXPR inline bool QSizeF::isValid() const noexcept
+constexpr inline bool QSizeF::isValid() const noexcept
{ return wd >= 0. && ht >= 0.; }
-Q_DECL_CONSTEXPR inline qreal QSizeF::width() const noexcept
+constexpr inline qreal QSizeF::width() const noexcept
{ return wd; }
-Q_DECL_CONSTEXPR inline qreal QSizeF::height() const noexcept
+constexpr inline qreal QSizeF::height() const noexcept
{ return ht; }
-Q_DECL_RELAXED_CONSTEXPR inline void QSizeF::setWidth(qreal w) noexcept
+constexpr inline void QSizeF::setWidth(qreal w) noexcept
{ wd = w; }
-Q_DECL_RELAXED_CONSTEXPR inline void QSizeF::setHeight(qreal h) noexcept
+constexpr inline void QSizeF::setHeight(qreal h) noexcept
{ ht = h; }
-Q_DECL_CONSTEXPR inline QSizeF QSizeF::transposed() const noexcept
+constexpr inline QSizeF QSizeF::transposed() const noexcept
{ return QSizeF(ht, wd); }
inline void QSizeF::scale(qreal w, qreal h, Qt::AspectRatioMode mode) noexcept
@@ -332,71 +342,82 @@ inline void QSizeF::scale(const QSizeF &s, Qt::AspectRatioMode mode) noexcept
inline QSizeF QSizeF::scaled(qreal w, qreal h, Qt::AspectRatioMode mode) const noexcept
{ return scaled(QSizeF(w, h), mode); }
-Q_DECL_RELAXED_CONSTEXPR inline qreal &QSizeF::rwidth() noexcept
+constexpr inline qreal &QSizeF::rwidth() noexcept
{ return wd; }
-Q_DECL_RELAXED_CONSTEXPR inline qreal &QSizeF::rheight() noexcept
+constexpr inline qreal &QSizeF::rheight() noexcept
{ return ht; }
-Q_DECL_RELAXED_CONSTEXPR inline QSizeF &QSizeF::operator+=(const QSizeF &s) noexcept
-{ wd += s.wd; ht += s.ht; return *this; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QSizeF &QSizeF::operator-=(const QSizeF &s) noexcept
-{ wd -= s.wd; ht -= s.ht; return *this; }
-
-Q_DECL_RELAXED_CONSTEXPR inline QSizeF &QSizeF::operator*=(qreal c) noexcept
-{ wd *= c; ht *= c; return *this; }
-
-Q_DECL_CONSTEXPR inline bool operator==(const QSizeF &s1, const QSizeF &s2) noexcept
-{ return qFuzzyCompare(s1.wd, s2.wd) && qFuzzyCompare(s1.ht, s2.ht); }
-
-Q_DECL_CONSTEXPR inline bool operator!=(const QSizeF &s1, const QSizeF &s2) noexcept
-{ return !qFuzzyCompare(s1.wd, s2.wd) || !qFuzzyCompare(s1.ht, s2.ht); }
-
-Q_DECL_CONSTEXPR inline const QSizeF operator+(const QSizeF & s1, const QSizeF & s2) noexcept
-{ return QSizeF(s1.wd+s2.wd, s1.ht+s2.ht); }
-
-Q_DECL_CONSTEXPR inline const QSizeF operator-(const QSizeF &s1, const QSizeF &s2) noexcept
-{ return QSizeF(s1.wd-s2.wd, s1.ht-s2.ht); }
-
-Q_DECL_CONSTEXPR inline const QSizeF operator*(const QSizeF &s, qreal c) noexcept
-{ return QSizeF(s.wd*c, s.ht*c); }
+constexpr inline QSizeF &QSizeF::operator+=(const QSizeF &s) noexcept
+{
+ wd += s.wd;
+ ht += s.ht;
+ return *this;
+}
-Q_DECL_CONSTEXPR inline const QSizeF operator*(qreal c, const QSizeF &s) noexcept
-{ return QSizeF(s.wd*c, s.ht*c); }
+constexpr inline QSizeF &QSizeF::operator-=(const QSizeF &s) noexcept
+{
+ wd -= s.wd;
+ ht -= s.ht;
+ return *this;
+}
-inline QSizeF &QSizeF::operator/=(qreal c)
+constexpr inline QSizeF &QSizeF::operator*=(qreal c) noexcept
{
- 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;
}
-Q_DECL_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));
}
-Q_DECL_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));
}
-Q_DECL_CONSTEXPR inline QSize QSizeF::toSize() const noexcept
+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 af72313a67..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
@@ -61,10 +25,10 @@
The example will output 3, 2, 1 in that order.
- QStack inherits from QVector. All of QVector's functionality also
+ QStack inherits from QList. All of QList's functionality also
applies to QStack. For example, you can use isEmpty() to test
whether the stack is empty, and you can traverse a QStack using
- QVector's iterator classes (for example, QVectorIterator). But in
+ QList's iterator classes (for example, QListIterator). But in
addition, QStack provides three convenience functions that make
it easy to implement LIFO semantics: push(), pop(), and top().
@@ -73,7 +37,7 @@
won't let you, for example, store a QWidget as a value; instead,
store a QWidget *.
- \sa QVector, QQueue
+ \sa QList, QQueue
*/
/*!
@@ -89,7 +53,7 @@
Adds element \a t to the top of the stack.
- This is the same as QVector::append().
+ This is the same as QList::append().
\sa pop(), top()
*/
@@ -100,7 +64,7 @@
Returns a reference to the stack's top item. This function
assumes that the stack isn't empty.
- This is the same as QVector::last().
+ This is the same as QList::last().
\sa pop(), push(), isEmpty()
*/
diff --git a/src/corelib/tools/qstack.h b/src/corelib/tools/qstack.h
index e59212aa2a..11ffb13328 100644
--- a/src/corelib/tools/qstack.h
+++ b/src/corelib/tools/qstack.h
@@ -1,75 +1,25 @@
-/****************************************************************************
-**
-** 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
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
-
template<class T>
-class QStack : public QVector<T>
+class QStack : public QList<T>
{
public:
// compiler-generated special member functions are fine!
- inline void swap(QStack<T> &other) noexcept { QVector<T>::swap(other); } // prevent QVector<->QStack swaps
- inline void push(const T &t) { QVector<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/qt_attribution.json b/src/corelib/tools/qt_attribution.json
new file mode 100644
index 0000000000..928ff537ca
--- /dev/null
+++ b/src/corelib/tools/qt_attribution.json
@@ -0,0 +1,15 @@
+{
+ "Id": "siphash",
+ "Name": "SipHash Algorithm",
+ "QDocModule": "qtcore",
+ "QtUsage": "Used in Qt Core (QHash)",
+
+ "Description": "Implements the SipHash algorithm.",
+ "Homepage": "https://131002.net/siphash/",
+ "DownloadLocation": "https://raw.githubusercontent.com/veorq/SipHash/adcbf09b1684a718f594faa650ffc56bacdb0777/siphash24.c",
+
+ "License": "Creative Commons Zero v1.0 Universal",
+ "LicenseId": "CC0-1.0",
+ "LicenseFile": "LICENSE.siphash",
+ "Copyright": "(C) 2012-2014 Jean-Philippe Aumasson, (C) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>"
+}
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h
new file mode 100644
index 0000000000..6c467d59f8
--- /dev/null
+++ b/src/corelib/tools/qtaggedpointer.h
@@ -0,0 +1,189 @@
+// 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
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qalgorithms.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qtypeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+ constexpr quint8 nextByteSize(quint8 bits) { return quint8((bits + 7) / 8); }
+
+ template <typename T>
+ struct TagInfo
+ {
+ static constexpr size_t alignment = alignof(T);
+ static_assert((alignment & (alignment - 1)) == 0,
+ "Alignment of template parameter must be power of two");
+
+ static constexpr quint8 tagBits = quint8{QtPrivate::qConstexprCountTrailingZeroBits(alignment)};
+ static_assert(tagBits > 0,
+ "Alignment of template parameter does not allow any tags");
+
+ static constexpr size_t tagSize = QtPrivate::qConstexprNextPowerOfTwo(nextByteSize(tagBits));
+ static_assert(tagSize < sizeof(quintptr),
+ "Alignment of template parameter allows tags masking away pointer");
+
+ using TagType = typename QIntegerForSize<tagSize>::Unsigned;
+ };
+}
+
+template <typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
+class QTaggedPointer
+{
+public:
+ using Type = T;
+ using TagType = Tag;
+
+ static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
+ static constexpr quintptr pointerMask() { return ~tagMask(); }
+
+ Q_NODISCARD_CTOR constexpr QTaggedPointer() noexcept : d(0) {}
+ Q_NODISCARD_CTOR constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
+
+ 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");
+ 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
+ {
+ Q_ASSERT(data());
+ return *data();
+ }
+
+ Type *operator->() const noexcept
+ {
+ return data();
+ }
+
+ explicit operator bool() const noexcept
+ {
+ return !isNull();
+ }
+
+#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
+ {
+ 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()));
+ }
+
+ void setTag(Tag tag)
+ {
+ Q_ASSERT_X(
+ (static_cast<quintptr>(tag) & pointerMask()) == 0,
+ "QTaggedPointer<T, Tag>::setTag",
+ "Tag is larger than allowed by number of available tag bits");
+
+ d = (d & pointerMask()) | static_cast<quintptr>(tag);
+ }
+
+ Tag tag() const noexcept
+ {
+ return TagType(typename QtPrivate::TagInfo<T>::TagType(d & tagMask()));
+ }
+
+ T* data() const noexcept
+ {
+ return reinterpret_cast<T*>(d & pointerMask());
+ }
+
+ bool isNull() const noexcept
+ {
+ return !data();
+ }
+
+ void swap(QTaggedPointer &other) noexcept
+ {
+ std::swap(d, other.d);
+ }
+
+ friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
+ {
+ return lhs.data() == rhs.data();
+ }
+
+ friend inline bool operator!=(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
+ {
+ return lhs.data() != rhs.data();
+ }
+
+ friend inline bool operator==(QTaggedPointer lhs, std::nullptr_t) noexcept
+ {
+ return lhs.isNull();
+ }
+
+ friend inline bool operator==(std::nullptr_t, QTaggedPointer rhs) noexcept
+ {
+ return rhs.isNull();
+ }
+
+ friend inline bool operator!=(QTaggedPointer lhs, std::nullptr_t) noexcept
+ {
+ return !lhs.isNull();
+ }
+
+ friend inline bool operator!=(std::nullptr_t, QTaggedPointer rhs) noexcept
+ {
+ return !rhs.isNull();
+ }
+
+ friend inline bool operator!(QTaggedPointer ptr) noexcept
+ {
+ return !ptr.data();
+ }
+
+ friend inline void swap(QTaggedPointer &p1, QTaggedPointer &p2) noexcept
+ {
+ p1.swap(p2);
+ }
+
+protected:
+ quintptr d;
+};
+
+template <typename T, typename Tag>
+constexpr inline std::size_t qHash(QTaggedPointer<T, Tag> p, std::size_t seed = 0) noexcept
+{ return qHash(p.data(), seed); }
+
+template <typename T, typename Tag>
+class QTypeInfo<QTaggedPointer<T, Tag>>
+ : public QTypeInfoMerger<QTaggedPointer<T, Tag>, quintptr> {};
+
+QT_END_NAMESPACE
+
+#endif // QTAGGEDPOINTER_H
diff --git a/src/corelib/tools/qtaggedpointer.qdoc b/src/corelib/tools/qtaggedpointer.qdoc
new file mode 100644
index 0000000000..f910e35b69
--- /dev/null
+++ b/src/corelib/tools/qtaggedpointer.qdoc
@@ -0,0 +1,194 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \class QTaggedPointer
+ \internal
+ \inmodule QtCore
+ \brief The QTaggedPointer class provides a low-level wrapper around raw
+ pointers that makes it possible to store additional information in otherwise unused bits.
+
+ \ingroup tools
+ \reentrant
+
+
+ Data structures in C++ tend to have a natural alignment in memory, based on
+ the alignment requirements of the members fields. For example a structure
+ containing an integer tends to be aligned to a 4-byte boundary in memory. That
+ means a pointer holding the address of an instance will always have the lower
+ two bits set to zero. QTaggedPointer makes it possible to store information
+ in these bits, such as a user provided enum. This is called a tag. The API allows
+ reading and writing the tag. When asked for the raw pointer, it will always return
+ a valid address with the bits used for the tag set to zero.
+
+ This pattern may be useful when creating low-level data structures that
+ need to be as dense as possible.
+
+ The first template parameter is the type the tagged pointer should point
+ to. The second template parameter is the type of the tag. If not specified it will
+ default to an unsigned integral. A more powerful pattern though is to define a
+ flag enum and use that as a tag type:
+
+ \code
+ struct LinkedListItem
+ {
+ enum MyFlag {
+ NoOption = 0x0,
+ SomeOption = 0x1,
+ ThirdWay = 0x2
+ };
+ Q_DECLARE_FLAGS(MyFlags, MyFlag)
+
+ QTaggedPointer<LinkedListItem, MyFlag> next;
+
+ ...
+ };
+
+ Q_DECLARE_OPERATORS_FOR_FLAGS(LinkedListItem::MyFlags)
+
+ LinkedListItem &listItem = ...
+ listItem.next = new LinkedListItem;
+ listItem.next.setTag(LinkedListItem::SomeOption | LinkedListItem::ThirdWay);
+ \endcode
+
+ \note QTaggedPointer does not provide ownership. You are responsible for deleting
+ the data the pointer points to.
+*/
+
+/*!
+ \typedef QTaggedPointer::Type
+
+ Typedef for T.
+*/
+
+/*!
+ \typedef QTaggedPointer::TagType
+
+ Typedef for Tag.
+*/
+
+
+/*!
+ \fn template <typename T, typename Tag> QTaggedPointer<T, Tag>::QTaggedPointer()
+
+ Creates a tagged pointer that contains nullptr and stores no tag.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> QTaggedPointer<T, Tag>::QTaggedPointer(std::nullptr_t)
+
+ Creates a tagged pointer that contains nullptr and stores no tag.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> explicit QTaggedPointer<T, Tag>::QTaggedPointer(T *pointer = nullptr, Tag tag = Tag()) noexcept
+
+ Creates a tagged pointer that points to \a pointer and stores the specified \a tag.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> T &QTaggedPointer<T, Tag>::operator*() const noexcept
+
+ Provides access to the pointer's members.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> T *QTaggedPointer<T, Tag>::operator->() const noexcept
+
+ Provides access to the pointer's members.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::operator!(QTaggedPointer<T, Tag> pointer) noexcept
+
+ Returns \c true if \a pointer is \nullptr.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> explicit QTaggedPointer<T, Tag>::operator bool() const noexcept
+
+ Returns \c true if the pointer is \e not null.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> QTaggedPointer<T, Tag> &QTaggedPointer<T, Tag>::operator=(T *other) noexcept
+
+ Sets the pointer of this to \a other. The tag remains unchanged.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> void QTaggedPointer<T, Tag>::setTag(Tag tag)
+
+ Sets the tag value to the specified \a tag. The pointer remains unchanged.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> Tag QTaggedPointer<T, Tag>::tag() const noexcept
+
+ Returns the tag stored in the tagged pointer.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> T *QTaggedPointer<T, Tag>::data() const noexcept
+
+ Returns the pointer stored in the tagged pointer.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> bool QTaggedPointer<T, Tag>::isNull() const noexcept
+
+ Returns \c true if the pointer is \nullptr; otherwise returns \c false.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> void QTaggedPointer<T, Tag>::swap(QTaggedPointer<T, Tag> &other) noexcept
+
+ Swaps this instance's pointer and tag with the pointer and tag in \a other.
+*/
+
+/*!
+ \fn template <typename T, typename Tag> 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.
+
+ Two tagged pointers are considered equal if they point to the same object. Their tags are not compared.
+*/
+
+/*!
+ \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.
+
+ Two tagged pointers are considered equal if they point to the same object. Their tags are not compared.
+*/
+
+/*!
+ \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> 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> 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> 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 = 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 0b11e7c77b..5512da867f 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** 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
#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;
}
/*!
@@ -185,7 +158,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
\snippet code/src_corelib_tools_qtimeline.cpp 0
- By default the timeline runs once, from the beginning and towards the end,
+ By default the timeline runs once, from its beginning to its end,
upon which you must call start() again to restart from the beginning. To
make the timeline loop, you can call setLoopCount(), passing the number of
times the timeline should run before finishing. The direction can also be
@@ -193,8 +166,8 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
setDirection(). You can also pause and unpause the timeline while it's
running by calling setPaused(). For interactive control, the
setCurrentTime() function is provided, which sets the time position of the
- time line directly. Although most useful in NotRunning state, (e.g.,
- connected to a valueChanged() signal in a QSlider,) this function can be
+ time line directly. Although most useful in NotRunning state (e.g.,
+ connected to a valueChanged() signal in a QSlider), this function can be
called at any time.
The frame interface is useful for standard widgets, but QTimeLine can be
@@ -205,13 +178,12 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
step. When running, QTimeLine generates values between 0 and 1 by calling
valueForTime() and emitting valueChanged(). By default, valueForTime()
applies an interpolation algorithm to generate these value. You can choose
- from a set of predefined timeline algorithms by calling
- setCurveShape().
+ from a set of predefined timeline algorithms by calling setEasingCurve().
- Note that by default, QTimeLine uses the EaseInOut curve shape,
- which provides a value that grows slowly, then grows steadily, and
- finally grows slowly. For a custom timeline, you can reimplement
- valueForTime(), in which case QTimeLine's curveShape property is ignored.
+ Note that, by default, QTimeLine uses QEasingCurve::InOutSine, which
+ provides a value that grows slowly, then grows steadily, and finally grows
+ slowly. For a custom timeline, you can reimplement valueForTime(), in which
+ case QTimeLine's easingCurve property is ignored.
\sa QProgressBar, QProgressDialog
*/
@@ -251,24 +223,6 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
*/
/*!
- \enum QTimeLine::CurveShape
-
- This enum describes the default shape of QTimeLine's value curve. The
- default, shape is EaseInOutCurve. The curve defines the relation
- between the value and the timeline.
-
- \value EaseInCurve The value starts growing slowly, then increases in speed.
- \value EaseOutCurve The value starts growing steadily, then ends slowly.
- \value EaseInOutCurve The value starts growing slowly, then runs steadily, then grows slowly again.
- \value LinearCurve The value grows linearly (e.g., if the duration is 1000 ms,
- the value at time 500 ms is 0.5).
- \value SineCurve The value grows sinusoidally.
- \value CosineCurve The value grows cosinusoidally.
-
- \sa setCurveShape()
-*/
-
-/*!
\fn void QTimeLine::valueChanged(qreal value)
QTimeLine emits this signal at regular intervals when in \l Running state,
@@ -338,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;
}
/*!
@@ -362,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
@@ -372,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;
}
/*!
@@ -401,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;
}
/*!
@@ -491,59 +475,10 @@ void QTimeLine::setUpdateInterval(int interval)
Q_D(QTimeLine);
d->updateInterval = interval;
}
-
-/*!
- \property QTimeLine::curveShape
- \brief the shape of the timeline curve.
-
- The curve shape describes the relation between the time and value for the
- base implementation of valueForTime().
-
- If you have reimplemented valueForTime(), this value is ignored.
-
- By default, this property is set to \l EaseInOutCurve.
-
- \sa valueForTime()
-*/
-QTimeLine::CurveShape QTimeLine::curveShape() const
-{
- Q_D(const QTimeLine);
- switch (d->easingCurve.type()) {
- default:
- case QEasingCurve::InOutSine:
- return EaseInOutCurve;
- case QEasingCurve::InCurve:
- return EaseInCurve;
- case QEasingCurve::OutCurve:
- return EaseOutCurve;
- case QEasingCurve::Linear:
- return LinearCurve;
- case QEasingCurve::SineCurve:
- return SineCurve;
- case QEasingCurve::CosineCurve:
- return CosineCurve;
- }
- return EaseInOutCurve;
-}
-
-static QEasingCurve::Type convert(QTimeLine::CurveShape shape)
+QBindable<int> QTimeLine::bindableUpdateInterval()
{
- switch (shape) {
-#define CASE(x, y) case QTimeLine::x: return QEasingCurve::y
- CASE(EaseInOutCurve, InOutSine);
- CASE(EaseInCurve, InCurve);
- CASE(EaseOutCurve, OutCurve);
- CASE(LinearCurve, Linear);
- CASE(SineCurve, SineCurve);
- CASE(CosineCurve, CosineCurve);
-#undef CASE
- }
- Q_UNREACHABLE();
-}
-
-void QTimeLine::setCurveShape(CurveShape shape)
-{
- setEasingCurve(convert(shape));
+ Q_D(QTimeLine);
+ return &d->updateInterval;
}
/*!
@@ -552,9 +487,9 @@ void QTimeLine::setCurveShape(CurveShape shape)
\since 4.6
Specifies the easing curve that the timeline will use.
- If both easing curve and curveShape are set, the last set property will
- override the previous one. (If valueForTime() is reimplemented it will
- override both)
+ If valueForTime() is reimplemented, this value is ignored.
+
+ \sa valueForTime()
*/
QEasingCurve QTimeLine::easingCurve() const
@@ -563,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.
@@ -578,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
@@ -639,15 +584,15 @@ int QTimeLine::frameForTime(int msec) const
Reimplement this function to provide a custom curve shape for your
timeline.
- \sa CurveShape, frameForTime()
+ \sa easingCurve, frameForTime()
*/
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);
}
/*!
@@ -751,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 9a60cd679f..4bdcceaebd 100644
--- a/src/corelib/tools/qtimeline.h
+++ b/src/corelib/tools/qtimeline.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 QTIMELINE_H
#define QTIMELINE_H
@@ -54,13 +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(CurveShape curveShape READ curveShape WRITE setCurveShape)
- 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,
@@ -71,14 +36,6 @@ public:
Forward,
Backward
};
- enum CurveShape {
- EaseInCurve,
- EaseOutCurve,
- EaseInOutCurve,
- LinearCurve,
- SineCurve,
- CosineCurve
- };
explicit QTimeLine(int duration = 1000, QObject *parent = nullptr);
virtual ~QTimeLine();
@@ -87,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);
@@ -102,14 +62,14 @@ public:
int updateInterval() const;
void setUpdateInterval(int interval);
-
- CurveShape curveShape() const;
- void setCurveShape(CurveShape shape);
+ 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 d48318b474..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 {
-Q_DECL_CONSTEXPR inline char toHexUpper(uint value) noexcept
+constexpr inline char toHexUpper(char32_t value) noexcept
{
return "0123456789ABCDEF"[value & 0xF];
}
-Q_DECL_CONSTEXPR inline char toHexLower(uint value) noexcept
+constexpr inline char toHexLower(char32_t value) noexcept
{
return "0123456789abcdef"[value & 0xF];
}
-Q_DECL_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,32 +49,83 @@ Q_DECL_CONSTEXPR inline int fromHex(uint c) noexcept
/* otherwise */ -1;
}
-Q_DECL_CONSTEXPR inline char toOct(uint value) noexcept
+constexpr inline char toOct(char32_t value) noexcept
{
- return '0' + char(value & 0x7);
+ return char('0' + (value & 0x7));
}
-Q_DECL_CONSTEXPR inline int fromOct(uint c) noexcept
+[[nodiscard]] constexpr inline bool isOctalDigit(char32_t c) noexcept
{
- return ((c >= '0') && (c <= '7')) ? int(c - '0') : -1;
+ return c >= '0' && c <= '7';
}
+
+constexpr inline int fromOct(char32_t c) noexcept
+{
+ return isOctalDigit(c) ? int(c - '0') : -1;
}
-// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size.
-enum {
- MaxAllocSize = INT_MAX
-};
+[[nodiscard]] constexpr inline bool isAsciiDigit(char32_t c) noexcept
+{
+ return c >= '0' && c <= '9';
+}
+
+constexpr inline bool isAsciiUpper(char32_t c) noexcept
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+constexpr inline bool isAsciiLower(char32_t c) noexcept
+{
+ return c >= 'a' && c <= 'z';
+}
+
+constexpr inline bool isAsciiLetterOrNumber(char32_t c) noexcept
+{
+ return isAsciiDigit(c) || isAsciiLower(c) || isAsciiUpper(c);
+}
-struct CalculateGrowingBlockSizeResult {
- size_t size;
- size_t elementCount;
+constexpr inline char toAsciiLower(char ch) noexcept
+{
+ return isAsciiUpper(ch) ? ch - 'A' + 'a' : ch;
+}
+
+constexpr inline char toAsciiUpper(char ch) noexcept
+{
+ return isAsciiLower(ch) ? ch - 'a' + 'A' : ch;
+}
+
+constexpr inline int caseCompareAscii(char lhs, char rhs) noexcept
+{
+ const char lhsLower = QtMiscUtils::toAsciiLower(lhs);
+ const char rhsLower = QtMiscUtils::toAsciiLower(rhs);
+ return int(uchar(lhsLower)) - int(uchar(rhsLower));
+}
+
+constexpr inline int isAsciiPrintable(char32_t ch) noexcept
+{
+ return ch >= ' ' && ch < 0x7f;
+}
+
+constexpr inline int qt_lencmp(qsizetype lhs, qsizetype rhs) noexcept
+{
+ return lhs == rhs ? 0 :
+ lhs > rhs ? 1 :
+ /* else */ -1 ;
+}
+
+} // namespace QtMiscUtils
+
+struct CalculateGrowingBlockSizeResult
+{
+ qsizetype size;
+ qsizetype elementCount;
};
// Implemented in qarraydata.cpp:
-size_t Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
-qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t headerSize = 0) noexcept;
+qsizetype Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
+qCalculateBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize = 0) noexcept;
CalculateGrowingBlockSizeResult Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
-qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t headerSize = 0) noexcept ;
+qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize = 0) noexcept ;
QT_END_NAMESPACE
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 6be695e317..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,34 +18,335 @@
#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, int Prealloc>
+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 explicit QVarLengthArray(int size);
+#ifndef Q_QDOC
+ template <typename U = T, if_copyable<U> = true>
+#endif
+ explicit QVarLengthArray(qsizetype sz, const T &v)
+ : QVarLengthArray{}
+ {
+ resize(sz, v);
+ }
- inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
- : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
+ QVarLengthArray(const QVarLengthArray &other)
+ : QVarLengthArray{}
{
append(other.constData(), other.size());
}
+ QVarLengthArray(QVarLengthArray &&other)
+ noexcept(std::is_nothrow_move_constructible_v<T>)
+ : Base(other)
+ {
+ const auto otherInlineStorage = reinterpret_cast<T*>(other.array);
+ if (data() == otherInlineStorage) {
+ // inline buffer - move into our inline buffer:
+ this->ptr = this->array;
+ QtPrivate::q_uninitialized_relocate_n(otherInlineStorage, size(), data());
+ } else {
+ // heap buffer - we just stole the memory
+ }
+ // reset other to internal storage:
+ other.a = Prealloc;
+ other.s = 0;
+ other.ptr = otherInlineStorage;
+ }
+
QVarLengthArray(std::initializer_list<T> args)
: QVarLengthArray(args.begin(), args.end())
{
}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
inline QVarLengthArray(InputIterator first, InputIterator last)
: QVarLengthArray()
{
@@ -84,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)
{
@@ -102,83 +370,127 @@ public:
return *this;
}
+ QVarLengthArray &operator=(QVarLengthArray &&other)
+ noexcept(std::is_nothrow_move_constructible_v<T>)
+ {
+ // we're only required to be self-move-assignment-safe
+ // when we're in the moved-from state (Hinnant criterion)
+ // the moved-from state is the empty state, so we're good with the clear() here:
+ clear();
+ Q_ASSERT(capacity() >= Prealloc);
+ const auto otherInlineStorage = other.array;
+ if (other.ptr != otherInlineStorage) {
+ // heap storage: steal the external buffer, reset other to 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.data(), other.size(), data());
+ }
+ this->s = std::exchange(other.s, 0);
+ return *this;
+ }
+
QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list)
{
- resize(int(list.size())); // ### q6sizetype
- 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();
+ }
+#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();
}
- inline int size() const { return s; }
- inline int count() const { return s; }
- inline int length() const { return s; }
- inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T& first() const { Q_ASSERT(!isEmpty()); return *begin(); }
- T& last() { Q_ASSERT(!isEmpty()); return *(end() - 1); }
- const T& last() const { Q_ASSERT(!isEmpty()); return *(end() - 1); }
- inline bool isEmpty() const { return (s == 0); }
- inline void resize(int size);
+ 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 int capacity() const { return a; }
- inline void reserve(int size);
+#endif
+ void squeeze() { reallocate(size(), size()); }
- inline int indexOf(const T &t, int from = 0) const;
- inline int lastIndexOf(const T &t, int 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[](int 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[](int idx) const {
- Q_ASSERT(idx >= 0 && idx < s);
- return ptr[idx];
+ inline const T &operator[](qsizetype idx) const
+ {
+ verify(idx);
+ return data()[idx];
}
- inline const T &at(int idx) const { return operator[](idx); }
+#endif
+ using Base::operator[];
+ inline const T &at(qsizetype idx) const { return operator[](idx); }
- T value(int i) const;
- T value(int i, const T &defaultValue) const;
+#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);
- realloc(s, s<<1);
- const int idx = s++;
- if (QTypeInfo<T>::isComplex) {
- new (ptr + idx) T(std::move(copy));
- } else {
- ptr[idx] = std::move(copy);
- }
- } else {
- const int 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)
- realloc(s, s << 1);
- const int 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, int 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)
@@ -188,143 +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);
- void insert(int i, T &&t);
- void insert(int i, const T &t);
- void insert(int i, int n, const T &t);
- void replace(int i, const T &t);
- void remove(int i);
- void remove(int i, int n);
-
-
- inline T *data() { return ptr; }
- inline const T *data() const { return ptr; }
- inline const T * constData() const { return ptr; }
- typedef int size_type;
- typedef T value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef value_type &reference;
- typedef const value_type &const_reference;
- typedef qptrdiff difference_type;
-
-
- 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; }
+#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, 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, int 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 realloc(int size, int alloc);
-
- int a; // capacity
- int s; // size
- T *ptr; // data
- union {
- char array[Prealloc * sizeof(T)];
- qint64 q_for_alignment_1;
- double q_for_alignment_2;
- };
+ 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);
+ }
- 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(std::lexicographical_compare(lhs.begin(), lhs.end(),
+ rhs.begin(), rhs.end())))
{
- const std::less<const T*> less = {};
- return !less(cend(), i) && !less(i, cbegin());
+ return lhs.less_than(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 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, int Prealloc>
-Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(int asize)
- : s(asize) {
- Q_STATIC_ASSERT_X(Prealloc > 0, "QVarLengthArray Prealloc must be greater than 0.");
- Q_ASSERT_X(s >= 0, "QVarLengthArray::QVarLengthArray()", "Size must be greater than or equal to 0.");
- 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;
- }
-}
+template <class T, qsizetype Prealloc>
+Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(qsizetype asize)
+ : QVarLengthArray()
+{
+ Q_ASSERT_X(asize >= 0, "QVarLengthArray::QVarLengthArray(qsizetype)",
+ "Size must be greater than or equal to 0.");
-template <class T, int Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(int asize)
-{ realloc(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, int Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(int asize)
-{ if (asize > a) realloc(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, int Prealloc>
-Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::indexOf(const T &t, int 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, 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, int Prealloc>
-Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, int 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;
@@ -333,11 +735,12 @@ Q_INLINE_TEMPLATE int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &t, int
return -1;
}
-template <class T, int 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;
@@ -345,277 +748,275 @@ Q_INLINE_TEMPLATE bool QVarLengthArray<T, Prealloc>::contains(const T &t) const
return false;
}
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int increment)
+template <class T>
+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 int asize = s + increment;
+ const qsizetype asize = size() + increment;
+
+ if (asize >= capacity())
+ growBy(prealloc, array, increment);
- if (asize >= a)
- realloc(s, qMax(s*2, asize));
+ 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;
+}
- if (QTypeInfo<T>::isComplex) {
- // call constructor for new objects (which can throw)
- while (s < asize)
- new (ptr+(s++)) T(*abuf++);
+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, int Prealloc>
-Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::squeeze()
-{ realloc(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, int Prealloc>
-Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int 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;
- int osize = s;
-
- const int 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(data());
+ T *oldPtr = data();
+ qsizetype osize = size();
+
+ const qsizetype copySize = qMin(asize, osize);
+ 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 (!QTypeInfoQuery<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
- int 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, int Prealloc>
-Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i) const
+template <class T>
+Q_OUTOFLINE_TEMPLATE T QVLABase<T>::value(qsizetype i) const
{
- if (uint(i) >= uint(size())) {
+ if (size_t(i) >= size_t(size()))
return T();
- }
- return at(i);
+ return operator[](i);
}
-template <class T, int Prealloc>
-Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i, const T &defaultValue) const
+template <class T>
+Q_OUTOFLINE_TEMPLATE T QVLABase<T>::value(qsizetype i, const T &defaultValue) const
{
- return (uint(i) >= uint(size())) ? defaultValue : at(i);
+ return (size_t(i) >= size_t(size())) ? defaultValue : operator[](i);
}
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::insert(int i, T &&t)
-{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, T &&t)
+{ verify(i, 0);
insert(cbegin() + i, std::move(t)); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::insert(int i, const T &t)
-{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, const T &t)
+{ verify(i, 0);
insert(begin() + i, 1, t); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::insert(int i, int n, const T &t)
-{ Q_ASSERT_X(i >= 0 && i <= s, "QVarLengthArray::insert", "index out of range");
+template <class T, qsizetype Prealloc>
+inline void QVarLengthArray<T, Prealloc>::insert(qsizetype i, qsizetype n, const T &t)
+{ verify(i, 0);
insert(begin() + i, n, t); }
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::remove(int i, int 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, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::remove(int i)
-{ Q_ASSERT_X(i >= 0 && i < s, "QVarLengthArray::remove", "index out of range");
- erase(begin() + i, begin() + i + 1); }
-template <class T, int Prealloc>
+template <class T>
+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, int Prealloc>
+template <class T, qsizetype Prealloc>
inline void QVarLengthArray<T, Prealloc>::prepend(const T &t)
{ insert(begin(), 1, t); }
+#endif
-template <class T, int Prealloc>
-inline void QVarLengthArray<T, Prealloc>::replace(int 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, int 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");
-
- int offset = int(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, int 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");
- int offset = int(before - ptr);
- if (n != 0) {
- resize(s + n);
- const T copy(t);
- if (!QTypeInfoQuery<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, int 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");
- int f = int(abegin - ptr);
- int l = int(aend - ptr);
- int 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();
- }
+ qsizetype f = qsizetype(abegin - cbegin());
+ qsizetype l = qsizetype(aend - cbegin());
+ qsizetype n = l - f;
+
+ if (n == 0) // avoid UB in std::move() below
+ return data() + f;
+
+ Q_ASSERT(n > 0); // aend must be reachable from abegin
+
+ if constexpr (QTypeInfo<T>::isComplex) {
+ std::move(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;
}
-template <typename T, int Prealloc1, int Prealloc2>
+#ifdef Q_QDOC
+// Fake definitions for qdoc, only the redeclaration is used.
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
bool 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()));
-}
-
-template <typename T, int Prealloc1, int Prealloc2>
+{ return bool{}; }
+template <typename T, qsizetype Prealloc1, qsizetype Prealloc2>
bool operator!=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
-{
- return !(l == r);
-}
-
-template <typename T, int Prealloc1, int Prealloc2>
-bool operator<(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end())))
-{
- return std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end());
-}
-
-template <typename T, int Prealloc1, int Prealloc2>
-inline bool operator>(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return rhs < lhs;
-}
+{ 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>
+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>
+bool operator>=(const QVarLengthArray<T, Prealloc1> &l, const QVarLengthArray<T, Prealloc2> &r)
+{ return bool{}; }
+#endif
-template <typename T, int Prealloc1, int Prealloc2>
-inline bool operator<=(const QVarLengthArray<T, Prealloc1> &lhs, const QVarLengthArray<T, Prealloc2> &rhs)
- noexcept(noexcept(lhs < rhs))
+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, int Prealloc1, int Prealloc2>
-inline bool 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, int Prealloc>
-uint qHash(const QVarLengthArray<T, Prealloc> &key, uint 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 e5ba47b8ef..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
@@ -66,20 +42,20 @@
compiler won't let you, for example, store a QWidget as a value;
instead, store a QWidget *.
- QVarLengthArray, like QVector, provides a resizable array data
+ QVarLengthArray, like QList, provides a resizable array data
structure. The main differences between the two classes are:
\list
\li QVarLengthArray's API is much more low-level and it lacks
- some of QVector's functionality.
+ some of QList's functionality.
\li QVarLengthArray doesn't initialize the memory if the value is
- a basic type. (QVector always does.)
+ a basic type. (QList always does.)
- \li QVector uses \l{implicit sharing} as a memory optimization.
- QVarLengthArray doesn't provide that feature; however, it
- usually produces slightly better performance due to reduced
- overhead, especially in tight loops.
+ \li QList uses \l{implicit sharing} as a memory optimization.
+ QVarLengthArray doesn't provide that feature; however, it
+ usually produces slightly better performance due to reduced
+ overhead, especially in tight loops.
\endlist
In summary, QVarLengthArray is a low-level optimization class
@@ -87,10 +63,15 @@
places inside Qt and was added to Qt's public API for the
convenience of advanced users.
- \sa QVector, QList, QLinkedList
+ \sa QList
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(int size)
+/*! \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,45 +81,58 @@
\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, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(std::initializer_list<T> args)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(std::initializer_list<T> args)
\since 5.5
Constructs an array from the std::initializer_list given by \a args.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
-/*! \fn template<class T, int Prealloc> template<typename InputIterator> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
+/*! \fn template<class T, qsizetype Prealloc> template<typename InputIterator, QVarLengthArray<T, Prealloc>::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.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::~QVarLengthArray()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::~QVarLengthArray()
Destroys the array.
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::size() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::size() const
Returns the number of elements in the array.
\sa isEmpty(), resize()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::count() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::count() const
Same as size().
\sa isEmpty(), resize()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::length() const
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::length() const
\since 5.0
Same as size().
@@ -146,7 +140,16 @@
\sa isEmpty(), resize()
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::first()
+/*! \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
not be empty. If the array can be empty, check isEmpty() before
@@ -155,24 +158,24 @@
\sa last(), isEmpty()
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::first() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::first() const
\overload
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::front()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::front()
\since 5.0
Same as first(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::front() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::front() const
\since 5.0
\overload
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::last()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::last()
Returns a reference to the last item in the array. The array must
not be empty. If the array can be empty, check isEmpty() before
@@ -181,37 +184,37 @@
\sa first(), isEmpty()
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::last() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::last() const
\overload
*/
-/*! \fn template<class T, int Prealloc> T& QVarLengthArray<T, Prealloc>::back()
+/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::back()
\since 5.0
Same as last(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> const T& QVarLengthArray<T, Prealloc>::back() const
+/*! \fn template<class T, qsizetype Prealloc> const T& QVarLengthArray<T, Prealloc>::back() const
\since 5.0
\overload
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::shrink_to_fit()
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::shrink_to_fit()
\since 5.10
Same as squeeze(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> bool QVarLengthArray<T, Prealloc>::isEmpty() const
+/*! \fn template<class T, qsizetype Prealloc> bool QVarLengthArray<T, Prealloc>::isEmpty() const
Returns \c true if the array has size 0; otherwise returns \c false.
\sa size(), resize()
*/
-/*! \fn template<class T, int Prealloc> bool QVarLengthArray<T, Prealloc>::empty() const
+/*! \fn template<class T, qsizetype Prealloc> bool QVarLengthArray<T, Prealloc>::empty() const
\since 5.0
Returns \c true if the array has size 0; otherwise returns \c false.
@@ -219,14 +222,14 @@
Same as isEmpty(). Provided for STL-compatibility.
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::clear()
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::clear()
Removes all the elements from the array.
Same as resize(0).
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::resize(int size)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::resize(qsizetype size)
Sets the size of the array to \a size. If \a size is greater than
the current size, elements are added to the end. If \a size is
@@ -240,7 +243,20 @@
\sa size(), squeeze()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::capacity() const
+/*!
+ \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
array without forcing a reallocation.
@@ -253,7 +269,7 @@
\sa reserve(), squeeze()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::reserve(int size)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::reserve(qsizetype size)
Attempts to allocate memory for at least \a size elements. If you
know in advance how large the array can get, you can call this
@@ -270,7 +286,7 @@
\sa capacity(), squeeze()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::squeeze()
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::squeeze()
\since 5.1
Releases any memory not required to store the items.
@@ -284,7 +300,7 @@
\sa reserve(), capacity(), resize()
*/
-/*! \fn template<class T, int Prealloc> T &QVarLengthArray<T, Prealloc>::operator[](int i)
+/*! \fn template<class T, qsizetype Prealloc> T &QVarLengthArray<T, Prealloc>::operator[](qsizetype i)
Returns a reference to the item at index position \a i.
@@ -294,14 +310,14 @@
\sa data(), at()
*/
-/*! \fn template<class T, int Prealloc> const T &QVarLengthArray<T, Prealloc>::operator[](int i) const
+/*! \fn template<class T, qsizetype Prealloc> const T &QVarLengthArray<T, Prealloc>::operator[](qsizetype i) const
\overload
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::append(const T &t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::append(const T &t)
Appends item \a t to the array, extending the array if necessary.
@@ -309,7 +325,7 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::push_back(const T &t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::push_back(const T &t)
\since 5.0
Appends item \a t to the array, extending the array if necessary.
@@ -317,7 +333,7 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::append(T &&t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::append(T &&t)
\overload append
\since 5.9
@@ -331,7 +347,7 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::push_back(T &&t)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::push_back(T &&t)
\overload push_back
\since 5.9
@@ -345,7 +361,7 @@
*/
/*!
- \fn template<class T, int Prealloc> inline void QVarLengthArray<T, Prealloc>::removeLast()
+ \fn template<class T, qsizetype Prealloc> inline void QVarLengthArray<T, Prealloc>::removeLast()
\since 4.5
Decreases the size of the array by one. The allocated size is not changed.
@@ -354,20 +370,20 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::pop_back()
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::pop_back()
\since 5.0
Same as removeLast(). Provided for STL-compatibility.
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::append(const T *buf, int size)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::append(const T *buf, qsizetype size)
Appends \a size amount of items referenced by \a buf to this array.
*/
-/*! \fn template<class T, int Prealloc> T *QVarLengthArray<T, Prealloc>::data()
+/*! \fn template<class T, qsizetype Prealloc> T *QVarLengthArray<T, Prealloc>::data()
Returns a pointer to the data stored in the array. The pointer can
be used to access and modify the items in the array.
@@ -383,12 +399,12 @@
\sa constData(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> const T *QVarLengthArray<T, Prealloc>::data() const
+/*! \fn template<class T, qsizetype Prealloc> const T *QVarLengthArray<T, Prealloc>::data() const
\overload
*/
-/*! \fn template<class T, int Prealloc> const T *QVarLengthArray<T, Prealloc>::constData() const
+/*! \fn template<class T, qsizetype Prealloc> const T *QVarLengthArray<T, Prealloc>::constData() const
Returns a const pointer to the data stored in the array. The
pointer can be used to access the items in the array. The
@@ -400,24 +416,32 @@
\sa data(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(const QVarLengthArray<T, Prealloc> &other)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(const QVarLengthArray<T, Prealloc> &other)
Assigns \a other to this array and returns a reference to this array.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(std::initializer_list<T> list)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(QVarLengthArray<T, Prealloc> &&other)
+ Move-assigns \a other to this array and returns a reference to this array.
+ After the move, \a other is empty.
+ \since 6.0
+ */
+
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator=(std::initializer_list<T> list)
\since 5.5
Assigns the values of \a list to this array, and returns a reference to this array.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
Constructs a copy of \a other.
*/
-/*! \fn template<class T, int Prealloc> const T &QVarLengthArray<T, Prealloc>::at(int i) const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(QVarLengthArray<T, Prealloc> &&other)
+ Move-constructs this variable-length array from \a other. After the move, \a other is empty.
+ \since 6.0
+ */
+
+/*! \fn template<class T, qsizetype Prealloc> const T &QVarLengthArray<T, Prealloc>::at(qsizetype i) const
Returns a reference to the item at index position \a i.
@@ -427,7 +451,7 @@
\sa value(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> T QVarLengthArray<T, Prealloc>::value(int i) const
+/*! \fn template<class T, qsizetype Prealloc> T QVarLengthArray<T, Prealloc>::value(qsizetype i) const
Returns the value at index position \a i.
@@ -439,7 +463,7 @@
\sa at(), operator[]()
*/
-/*! \fn template<class T, int Prealloc> T QVarLengthArray<T, Prealloc>::value(int i, const T &defaultValue) const
+/*! \fn template<class T, qsizetype Prealloc> T QVarLengthArray<T, Prealloc>::value(qsizetype i, const T &defaultValue) const
\overload
@@ -447,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
@@ -525,10 +558,12 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::prepend(const T &value)
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::prepend(T &&value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::prepend(const T &value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::prepend(T &&value)
\since 4.8
+ \deprecated [6.3] This is slow. If you must, use \c{insert(cbegin(), ~~~)} instead.
+
Inserts \a value at the beginning of the array.
@@ -537,13 +572,12 @@
For large arrays, this operation can be slow (\l{linear time}),
because it requires moving all the items in the vector by one
position further in memory. If you want a container class that
- provides a fast prepend() function, use QList or QLinkedList
- instead.
+ provides a fast prepend() function, use std::list instead.
\sa append(), insert()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::replace(int i, const T &value)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::replace(qsizetype i, const T &value)
\since 4.8
Replaces the item at index position \a i with \a value.
@@ -554,17 +588,7 @@
\sa operator[](), remove()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::remove(int i)
-
- \overload
- \since 4.8
-
- Removes the element at index position \a i.
-
- \sa insert(), replace()
-*/
-
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::remove(int i, int count)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::remove(qsizetype i, qsizetype count)
\overload
\since 4.8
@@ -575,7 +599,7 @@
\sa insert(), replace()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::begin()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::begin()
\since 4.8
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
@@ -584,12 +608,12 @@
\sa constBegin(), end()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::begin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::begin() const
\since 4.8
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cbegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cbegin() const
\since 5.0
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
@@ -598,7 +622,7 @@
\sa begin(), cend()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constBegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constBegin() const
\since 4.8
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
@@ -607,7 +631,7 @@
\sa begin(), constEnd()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::end()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::end()
\since 4.8
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
@@ -616,13 +640,13 @@
\sa begin(), constEnd()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::end() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::end() const
\since 4.8
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cend() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::cend() const
\since 5.0
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
@@ -631,7 +655,7 @@
\sa cbegin(), end()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constEnd() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_iterator QVarLengthArray<T, Prealloc>::constEnd() const
\since 4.8
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
@@ -640,7 +664,7 @@
\sa constBegin(), end()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rbegin()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rbegin()
\since 5.6
Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
@@ -649,12 +673,12 @@
\sa begin(), crbegin(), rend()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rbegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rbegin() const
\since 5.6
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crbegin() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crbegin() const
\since 5.6
Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
@@ -663,7 +687,7 @@
\sa begin(), rbegin(), rend()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rend()
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::reverse_iterator QVarLengthArray<T, Prealloc>::rend()
\since 5.6
Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
@@ -672,12 +696,12 @@
\sa end(), crend(), rbegin()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rend() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::rend() const
\since 5.6
\overload
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crend() const
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::const_reverse_iterator QVarLengthArray<T, Prealloc>::crend() const
\since 5.6
Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
@@ -686,7 +710,7 @@
\sa end(), rend(), rbegin()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator pos)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator pos)
\since 4.8
Removes the item pointed to by the iterator \a pos from the
@@ -696,7 +720,7 @@
\sa insert(), remove()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator begin, const_iterator end)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::erase(const_iterator begin, const_iterator end)
\overload
\since 4.8
@@ -707,8 +731,8 @@
*/
/*!
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::insert(int i, const T &value)
- \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::insert(int i, T &&value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::insert(qsizetype i, const T &value)
+ \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::insert(qsizetype i, T &&value)
\since 4.8
Inserts \a value at index position \a i in the array. If \a i is
@@ -718,13 +742,13 @@
For large arrays, this operation can be slow (\l{linear time}),
because it requires moving all the items at indexes \a i and
above by one position further in memory. If you want a container
- class that provides a fast insert() function, use QLinkedList
+ class that provides a fast insert() function, use std::list
instead.
\sa remove()
*/
-/*! \fn template<class T, int Prealloc> void QVarLengthArray<T, Prealloc>::insert(int i, int count, const T &value)
+/*! \fn template<class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::insert(qsizetype i, qsizetype count, const T &value)
\overload
\since 4.8
@@ -733,8 +757,8 @@
vector.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value)
- \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value)
+ \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&value)
\overload
\since 4.8
@@ -743,7 +767,28 @@
\a before. Returns an iterator pointing at the inserted item.
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, int count, const T &value)
+/*!
+ \fn template <class T, qsizetype Prealloc> 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
Inserts \a count copies of \a value in front of the item pointed to
@@ -753,7 +798,7 @@
-/*! \fn template<class T, int Prealloc1, int Prealloc2> bool operator==(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
+/*! \fn template<class T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator==(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
\relates QVarLengthArray
\since 4.8
@@ -765,10 +810,10 @@
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, int Prealloc1, int Prealloc2> bool operator!=(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator!=(const QVarLengthArray<T, Prealloc1> &left, const QVarLengthArray<T, Prealloc2> &right)
\relates QVarLengthArray
\since 4.8
@@ -780,10 +825,10 @@
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, int Prealloc1, int Prealloc2> bool operator<(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator<(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -795,7 +840,7 @@
of \c operator<().
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator<=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator<=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -807,7 +852,7 @@
of \c operator<().
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator>(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator>(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -819,7 +864,7 @@
of \c operator<().
*/
-/*! \fn template<typename T, int Prealloc1, int Prealloc2> bool operator>=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
+/*! \fn template<typename T, qsizetype Prealloc1, qsizetype Prealloc2> bool operator>=(const QVarLengthArray<T,Prealloc1> &lhs, const QVarLengthArray<T,Prealloc2> &rhs)
\since 5.6
\relates QVarLengthArray
@@ -831,7 +876,7 @@
of \c operator<().
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(const T &value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(const T &value)
\since 4.8
Appends \a value to the array and returns a reference to this
@@ -840,7 +885,7 @@
\sa append(), operator+=()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(T &&value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator<<(T &&value)
\since 5.11
\overload
@@ -848,7 +893,7 @@
\sa append(), operator+=()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(const T &value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(const T &value)
\since 4.8
Appends \a value to the array and returns a reference to this vector.
@@ -856,7 +901,7 @@
\sa append(), operator<<()
*/
-/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(T &&value)
+/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc> &QVarLengthArray<T, Prealloc>::operator+=(T &&value)
\since 5.11
\overload
@@ -864,7 +909,7 @@
\sa append(), operator<<()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::indexOf(const T &value, int from = 0) const
+/*! \fn template<class T, qsizetype Prealloc> 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
@@ -877,7 +922,7 @@
\sa lastIndexOf(), contains()
*/
-/*! \fn template<class T, int Prealloc> int QVarLengthArray<T, Prealloc>::lastIndexOf(const T &value, int from = -1) const
+/*! \fn template<class T, qsizetype Prealloc> 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
@@ -891,7 +936,7 @@
\sa indexOf(), contains()
*/
-/*! \fn template<class T, int Prealloc> bool QVarLengthArray<T, Prealloc>::contains(const T &value) const
+/*! \fn template<class T, qsizetype Prealloc> 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;
@@ -904,10 +949,99 @@
*/
/*!
- template <typename T, int Prealloc> uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0)
+ \fn template <typename T, qsizetype Prealloc> size_t qHash(const QVarLengthArray<T, Prealloc> &key, size_t seed = 0)
\relates QVarLengthArray
\since 5.14
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 5def2eceb2..4fad2bce8f 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -1,1150 +1,27 @@
-/****************************************************************************
-**
-** 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 QVECTOR_H
#define QVECTOR_H
-#include <QtCore/qalgorithms.h>
-#include <QtCore/qiterator.h>
-#include <QtCore/qrefcount.h>
-#include <QtCore/qarraydata.h>
-#include <QtCore/qhashfunctions.h>
-#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qcontainerfwd.h>
-#include <iterator>
-#include <initializer_list>
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
-#include <vector>
+#if 0
+#pragma qt_class(QVector)
+#pragma qt_class(QMutableVectorIterator)
+#pragma qt_class(QVectorIterator)
#endif
-#include <stdlib.h>
-#include <string.h>
-
-#include <algorithm>
QT_BEGIN_NAMESPACE
-namespace QtPrivate {
- template <typename V, typename U> int indexOf(const QVector<V> &list, const U &u, int from);
- template <typename V, typename U> int lastIndexOf(const QVector<V> &list, const U &u, int from);
-}
-
-template <typename T> struct QVectorSpecialMethods
-{
-protected:
- ~QVectorSpecialMethods() = default;
-};
-template <> struct QVectorSpecialMethods<QByteArray>;
-template <> struct QVectorSpecialMethods<QString>;
-
-template <typename T>
-class QVector
-#ifndef Q_QDOC
- : public QVectorSpecialMethods<T>
-#endif
-{
- typedef QTypedArrayData<T> Data;
- Data *d;
-
- template <typename V, typename U> friend int QtPrivate::indexOf(const QVector<V> &list, const U &u, int from);
- template <typename V, typename U> friend int QtPrivate::lastIndexOf(const QVector<V> &list, const U &u, int from);
-
-public:
- inline QVector() noexcept : d(Data::sharedNull()) { }
- explicit QVector(int size);
- QVector(int size, const T &t);
- inline QVector(const QVector<T> &v);
- inline ~QVector() { if (!d->ref.deref()) freeData(d); }
- QVector<T> &operator=(const QVector<T> &v);
- QVector(QVector<T> &&other) noexcept : d(other.d) { other.d = Data::sharedNull(); }
- QVector<T> &operator=(QVector<T> &&other) noexcept
- { QVector moved(std::move(other)); swap(moved); return *this; }
- void swap(QVector<T> &other) noexcept { qSwap(d, other.d); }
- inline QVector(std::initializer_list<T> args);
- QVector<T> &operator=(std::initializer_list<T> args);
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
- inline QVector(InputIterator first, InputIterator last);
- explicit QVector(QArrayDataPointerRef<T> ref) noexcept : d(ref.ptr) {}
-
- bool operator==(const QVector<T> &v) const;
- inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
-
- inline int size() const { return d->size; }
-
- inline bool isEmpty() const { return d->size == 0; }
-
- void resize(int size);
-
- inline int capacity() const { return int(d->alloc); }
- void reserve(int size);
- inline void squeeze()
- {
- if (d->size < int(d->alloc)) {
- if (!d->size) {
- *this = QVector<T>();
- return;
- }
- realloc(d->size);
- }
- if (d->capacityReserved) {
- // capacity reserved in a read only memory would be useless
- // this checks avoid writing to such memory.
- d->capacityReserved = 0;
- }
- }
-
- inline void detach();
- inline bool isDetached() const { return !d->ref.isShared(); }
-
- inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
-
- inline T *data() { detach(); return d->begin(); }
- inline const T *data() const { return d->begin(); }
- inline const T *constData() const { return d->begin(); }
- void clear();
-
- const T &at(int i) const;
- T &operator[](int i);
- const T &operator[](int i) const;
- void append(const T &t);
- void append(T &&t);
- inline void append(const QVector<T> &l) { *this += l; }
- void prepend(T &&t);
- void prepend(const T &t);
- void insert(int i, T &&t);
- void insert(int i, const T &t);
- void insert(int i, int n, const T &t);
- void replace(int i, const T &t);
- void remove(int i);
- void remove(int i, int n);
- inline void removeFirst() { Q_ASSERT(!isEmpty()); erase(d->begin()); }
- inline void removeLast();
- T takeFirst() { Q_ASSERT(!isEmpty()); T r = std::move(first()); removeFirst(); return r; }
- T takeLast() { Q_ASSERT(!isEmpty()); T r = std::move(last()); removeLast(); return r; }
-
- QVector<T> &fill(const T &t, int size = -1);
-
- int indexOf(const T &t, int from = 0) const;
- int lastIndexOf(const T &t, int from = -1) const;
- bool contains(const T &t) const;
- int count(const T &t) const;
-
- // QList compatibility
- void removeAt(int i) { remove(i); }
- int removeAll(const T &t)
- {
- const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
- if (cit == ce)
- return 0;
- // next operation detaches, so ce, cit, t may become invalidated:
- const T tCopy = t;
- const int firstFoundIdx = std::distance(this->cbegin(), cit);
- const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, tCopy);
- const int result = std::distance(it, e);
- erase(it, e);
- return result;
- }
- bool removeOne(const T &t)
- {
- const int i = indexOf(t);
- if (i < 0)
- return false;
- remove(i);
- return true;
- }
- int length() const { return size(); }
- T takeAt(int i) { T t = std::move((*this)[i]); remove(i); return t; }
- void move(int from, int to)
- {
- Q_ASSERT_X(from >= 0 && from < size(), "QVector::move(int,int)", "'from' is out-of-range");
- Q_ASSERT_X(to >= 0 && to < size(), "QVector::move(int,int)", "'to' is out-of-range");
- if (from == to) // don't detach when no-op
- return;
- detach();
- T * const b = d->begin();
- if (from < to)
- std::rotate(b + from, b + from + 1, b + to + 1);
- else
- std::rotate(b + to, b + from, b + from + 1);
- }
-
- // STL-style
- typedef typename Data::iterator iterator;
- typedef typename Data::const_iterator const_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- inline iterator begin() { detach(); return d->begin(); }
- inline const_iterator begin() const noexcept { return d->constBegin(); }
- inline const_iterator cbegin() const noexcept { return d->constBegin(); }
- inline const_iterator constBegin() const noexcept { return d->constBegin(); }
- inline iterator end() { detach(); return d->end(); }
- inline const_iterator end() const noexcept { return d->constEnd(); }
- inline const_iterator cend() const noexcept { return d->constEnd(); }
- inline const_iterator constEnd() const noexcept { return d->constEnd(); }
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
- const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
- const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
- iterator insert(iterator before, int n, const T &x);
- inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
- inline iterator insert(iterator before, T &&x);
- iterator erase(iterator begin, iterator end);
- inline iterator erase(iterator pos) { return erase(pos, pos+1); }
-
- // more Qt
- inline int count() const { return d->size; }
- inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
- inline const T &constFirst() const { Q_ASSERT(!isEmpty()); return *begin(); }
- 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; }
- QVector<T> mid(int pos, int len = -1) const;
-
- T value(int i) const;
- T value(int i, const T &defaultValue) const;
-
- void swapItemsAt(int i, int j) {
- Q_ASSERT_X(i >= 0 && i < size() && j >= 0 && j < size(),
- "QVector<T>::swap", "index out of range");
- detach();
- qSwap(d->begin()[i], d->begin()[j]);
- }
-
- // STL compatibility
- typedef T value_type;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef qptrdiff difference_type;
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- typedef int size_type;
- inline void push_back(const T &t) { append(t); }
- void push_back(T &&t) { append(std::move(t)); }
- void push_front(T &&t) { prepend(std::move(t)); }
- inline void push_front(const T &t) { prepend(t); }
- void pop_back() { removeLast(); }
- void pop_front() { removeFirst(); }
- inline bool empty() const
- { return d->size == 0; }
- inline T& front() { return first(); }
- inline const_reference front() const { return first(); }
- inline reference back() { return last(); }
- inline const_reference back() const { return last(); }
- void shrink_to_fit() { squeeze(); }
-
- // comfort
- QVector<T> &operator+=(const QVector<T> &l);
- inline QVector<T> operator+(const QVector<T> &l) const
- { QVector n = *this; n += l; return n; }
- inline QVector<T> &operator+=(const T &t)
- { append(t); return *this; }
- inline QVector<T> &operator<< (const T &t)
- { append(t); return *this; }
- inline QVector<T> &operator<<(const QVector<T> &l)
- { *this += l; return *this; }
- inline QVector<T> &operator+=(T &&t)
- { append(std::move(t)); return *this; }
- inline QVector<T> &operator<<(T &&t)
- { append(std::move(t)); return *this; }
-
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- Q_DECL_DEPRECATED_X("Use QVector<T>(vector.begin(), vector.end()) instead.")
- static inline QVector<T> fromStdVector(const std::vector<T> &vector)
- { return QVector<T>(vector.begin(), vector.end()); }
- Q_DECL_DEPRECATED_X("Use std::vector<T>(vector.begin(), vector.end()) instead.")
- inline std::vector<T> toStdVector() const
- { return std::vector<T>(d->begin(), d->end()); }
-#endif
-
- // Consider deprecating in 6.4 or later
- static QVector<T> fromList(const QVector<T> &list) { return list; }
- QVector<T> toList() const { return *this; }
-
- static inline QVector<T> fromVector(const QVector<T> &vector) { return vector; }
- inline QVector<T> toVector() const { return *this; }
-
-private:
- // ### Qt6: remove methods, they are unused
- void reallocData(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
- void reallocData(const int sz) { reallocData(sz, d->alloc); }
- void realloc(int alloc, QArrayData::AllocationOptions options = QArrayData::Default);
- void freeData(Data *d);
- void defaultConstruct(T *from, T *to);
- void copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom);
- void destruct(T *from, T *to);
- bool isValidIterator(const iterator &i) const
- {
- const std::less<const T*> less = {};
- return !less(d->end(), i) && !less(i, d->begin());
- }
- class AlignmentDummy { Data header; T array[1]; };
-};
-
-#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>
-QVector(InputIterator, InputIterator) -> QVector<ValueType>;
-#endif
-
-#ifdef Q_CC_MSVC
-// behavior change: an object of POD type constructed with an initializer of the form ()
-// will be default-initialized
-# pragma warning ( push )
-# pragma warning ( disable : 4345 )
-# pragma warning(disable : 4127) // conditional expression is constant
-#endif
-
-template <typename T>
-void QVector<T>::defaultConstruct(T *from, T *to)
-{
- if (QTypeInfo<T>::isComplex) {
- while (from != to) {
- new (from++) T();
- }
- } else {
- ::memset(static_cast<void *>(from), 0, (to - from) * sizeof(T));
- }
-}
-
-template <typename T>
-void QVector<T>::copyConstruct(const T *srcFrom, const T *srcTo, T *dstFrom)
-{
- if (QTypeInfo<T>::isComplex) {
- while (srcFrom != srcTo)
- new (dstFrom++) T(*srcFrom++);
- } else {
- ::memcpy(static_cast<void *>(dstFrom), static_cast<const void *>(srcFrom), (srcTo - srcFrom) * sizeof(T));
- }
-}
-
-template <typename T>
-void QVector<T>::destruct(T *from, T *to)
-{
- if (QTypeInfo<T>::isComplex) {
- while (from != to) {
- from++->~T();
- }
- }
-}
-
-template <typename T>
-inline QVector<T>::QVector(const QVector<T> &v)
-{
- if (v.d->ref.ref()) {
- d = v.d;
- } else {
- if (v.d->capacityReserved) {
- d = Data::allocate(v.d->alloc);
- Q_CHECK_PTR(d);
- d->capacityReserved = true;
- } else {
- d = Data::allocate(v.d->size);
- Q_CHECK_PTR(d);
- }
- if (d->alloc) {
- copyConstruct(v.d->begin(), v.d->end(), d->begin());
- d->size = v.d->size;
- }
- }
-}
-
-#if defined(Q_CC_MSVC)
-#pragma warning( pop )
-#endif
-
-template <typename T>
-void QVector<T>::detach()
-{
- if (d->ref.isStatic())
- return;
-
- if (!isDetached())
- realloc(int(d->alloc));
- Q_ASSERT(isDetached());
-}
-
-template <typename T>
-void QVector<T>::reserve(int asize)
-{
- if (asize > int(d->alloc))
- realloc(asize);
- if (isDetached())
- d->capacityReserved = 1;
- Q_ASSERT(capacity() >= asize);
-}
-
-template <typename T>
-void QVector<T>::resize(int asize)
-{
- if (asize == d->size)
- return detach();
- if (asize > int(d->alloc) || !isDetached()) { // there is not enough space
- QArrayData::AllocationOptions opt = asize > int(d->alloc) ? QArrayData::Grow : QArrayData::Default;
- realloc(qMax(int(d->alloc), asize), opt);
- }
- if (asize < d->size)
- destruct(begin() + asize, end());
- else
- defaultConstruct(end(), begin() + asize);
- d->size = asize;
-}
-template <typename T>
-inline void QVector<T>::clear()
-{
- if (!d->size)
- return;
- destruct(begin(), end());
- d->size = 0;
-}
-template <typename T>
-inline const T &QVector<T>::at(int i) const
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
- return d->begin()[i]; }
-template <typename T>
-inline const T &QVector<T>::operator[](int i) const
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
- return d->begin()[i]; }
-template <typename T>
-inline T &QVector<T>::operator[](int i)
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
- return data()[i]; }
-template <typename T>
-inline void QVector<T>::insert(int i, const T &t)
-{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- insert(begin() + i, 1, t); }
-template <typename T>
-inline void QVector<T>::insert(int i, int n, const T &t)
-{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- insert(begin() + i, n, t); }
-template <typename T>
-inline void QVector<T>::insert(int i, T &&t)
-{ Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
- insert(begin() + i, std::move(t)); }
-template <typename T>
-inline void QVector<T>::remove(int i, int n)
-{ Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= d->size, "QVector<T>::remove", "index out of range");
- erase(d->begin() + i, d->begin() + i + n); }
-template <typename T>
-inline void QVector<T>::remove(int i)
-{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::remove", "index out of range");
- erase(d->begin() + i, d->begin() + i + 1); }
-template <typename T>
-inline void QVector<T>::prepend(const T &t)
-{ insert(begin(), 1, t); }
-template <typename T>
-inline void QVector<T>::prepend(T &&t)
-{ insert(begin(), std::move(t)); }
-
-template <typename T>
-inline void QVector<T>::replace(int i, const T &t)
-{
- Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::replace", "index out of range");
- const T copy(t);
- data()[i] = copy;
-}
-
-template <typename T>
-QVector<T> &QVector<T>::operator=(const QVector<T> &v)
-{
- if (v.d != d) {
- QVector<T> tmp(v);
- tmp.swap(*this);
- }
- return *this;
-}
-
-template <typename T>
-QVector<T>::QVector(int asize)
-{
- Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
- if (Q_LIKELY(asize > 0)) {
- d = Data::allocate(asize);
- Q_CHECK_PTR(d);
- d->size = asize;
- defaultConstruct(d->begin(), d->end());
- } else {
- d = Data::sharedNull();
- }
-}
-
-template <typename T>
-QVector<T>::QVector(int asize, const T &t)
-{
- Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0.");
- if (asize > 0) {
- d = Data::allocate(asize);
- Q_CHECK_PTR(d);
- d->size = asize;
- T* i = d->end();
- while (i != d->begin())
- new (--i) T(t);
- } else {
- d = Data::sharedNull();
- }
-}
-
-#if defined(Q_CC_MSVC)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
-#endif // Q_CC_MSVC
-
-template <typename T>
-QVector<T>::QVector(std::initializer_list<T> args)
-{
- if (args.size() > 0) {
- d = Data::allocate(args.size());
- Q_CHECK_PTR(d);
- // std::initializer_list<T>::iterator is guaranteed to be
- // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct
- copyConstruct(args.begin(), args.end(), d->begin());
- d->size = int(args.size());
- } else {
- d = Data::sharedNull();
- }
-}
-
-template <typename T>
-QVector<T> &QVector<T>::operator=(std::initializer_list<T> args)
-{
- QVector<T> tmp(args);
- tmp.swap(*this);
- return *this;
-}
-
-#if defined(Q_CC_MSVC)
-QT_WARNING_POP
-#endif // Q_CC_MSVC
-
-template <typename T>
-template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator>>
-QVector<T>::QVector(InputIterator first, InputIterator last)
- : QVector()
-{
- QtPrivate::reserveIfForwardIterator(this, first, last);
- std::copy(first, last, std::back_inserter(*this));
-}
-
-template <typename T>
-void QVector<T>::freeData(Data *x)
-{
- destruct(x->begin(), x->end());
- Data::deallocate(x);
-}
-
-#if defined(Q_CC_MSVC)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
-#endif
-
-template <typename T>
-void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::AllocationOptions options)
-{
- Q_ASSERT(asize >= 0 && asize <= aalloc);
- Data *x = d;
-
- const bool isShared = d->ref.isShared();
-
- if (aalloc != 0) {
- if (aalloc != int(d->alloc) || isShared) {
- QT_TRY {
- // allocate memory
- x = Data::allocate(aalloc, options);
- Q_CHECK_PTR(x);
- // aalloc is bigger then 0 so it is not [un]sharedEmpty
- Q_ASSERT(!x->ref.isStatic());
- x->size = asize;
-
- T *srcBegin = d->begin();
- T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
- T *dst = x->begin();
-
- if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
- QT_TRY {
- if (isShared || !std::is_nothrow_move_constructible<T>::value) {
- // we can not move the data, we need to copy construct it
- while (srcBegin != srcEnd)
- new (dst++) T(*srcBegin++);
- } else {
- while (srcBegin != srcEnd)
- new (dst++) T(std::move(*srcBegin++));
- }
- } QT_CATCH (...) {
- // destruct already copied objects
- destruct(x->begin(), dst);
- QT_RETHROW;
- }
- } else {
- ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
- dst += srcEnd - srcBegin;
-
- // destruct unused / not moved data
- if (asize < d->size)
- destruct(d->begin() + asize, d->end());
- }
-
- if (asize > d->size) {
- // construct all new objects when growing
- if (!QTypeInfo<T>::isComplex) {
- ::memset(static_cast<void *>(dst), 0, (static_cast<T *>(x->end()) - dst) * sizeof(T));
- } else {
- QT_TRY {
- while (dst != x->end())
- new (dst++) T();
- } QT_CATCH (...) {
- // destruct already copied objects
- destruct(x->begin(), dst);
- QT_RETHROW;
- }
- }
- }
- } QT_CATCH (...) {
- Data::deallocate(x);
- QT_RETHROW;
- }
- x->capacityReserved = d->capacityReserved;
- } else {
- Q_ASSERT(int(d->alloc) == aalloc); // resize, without changing allocation size
- Q_ASSERT(isDetached()); // can be done only on detached d
- Q_ASSERT(x == d); // in this case we do not need to allocate anything
- if (asize <= d->size) {
- destruct(x->begin() + asize, x->end()); // from future end to current end
- } else {
- defaultConstruct(x->end(), x->begin() + asize); // from current end to future end
- }
- x->size = asize;
- }
- } else {
- x = Data::sharedNull();
- }
- if (d != x) {
- if (!d->ref.deref()) {
- if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
- // data was copy constructed, we need to call destructors
- // or if !alloc we did nothing to the old 'd'.
- freeData(d);
- } else {
- Data::deallocate(d);
- }
- }
- d = x;
- }
-
- Q_ASSERT(d->data());
- Q_ASSERT(uint(d->size) <= d->alloc);
- Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull());
- Q_ASSERT(d->alloc >= uint(aalloc));
- Q_ASSERT(d->size == asize);
-}
-
-template<typename T>
-void QVector<T>::realloc(int aalloc, QArrayData::AllocationOptions options)
-{
- Q_ASSERT(aalloc >= d->size);
- Data *x = d;
-
- const bool isShared = d->ref.isShared();
-
- QT_TRY {
- // allocate memory
- x = Data::allocate(aalloc, options);
- Q_CHECK_PTR(x);
- // aalloc is bigger then 0 so it is not [un]sharedEmpty
- Q_ASSERT(!x->ref.isStatic());
- x->size = d->size;
-
- T *srcBegin = d->begin();
- T *srcEnd = d->end();
- T *dst = x->begin();
-
- if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
- QT_TRY {
- if (isShared || !std::is_nothrow_move_constructible<T>::value) {
- // we can not move the data, we need to copy construct it
- while (srcBegin != srcEnd)
- new (dst++) T(*srcBegin++);
- } else {
- while (srcBegin != srcEnd)
- new (dst++) T(std::move(*srcBegin++));
- }
- } QT_CATCH (...) {
- // destruct already copied objects
- destruct(x->begin(), dst);
- QT_RETHROW;
- }
- } else {
- ::memcpy(static_cast<void *>(dst), static_cast<void *>(srcBegin), (srcEnd - srcBegin) * sizeof(T));
- dst += srcEnd - srcBegin;
- }
-
- } QT_CATCH (...) {
- Data::deallocate(x);
- QT_RETHROW;
- }
- x->capacityReserved = d->capacityReserved;
-
- Q_ASSERT(d != x);
- if (!d->ref.deref()) {
- if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
- // data was copy constructed, we need to call destructors
- // or if !alloc we did nothing to the old 'd'.
- freeData(d);
- } else {
- Data::deallocate(d);
- }
- }
- d = x;
-
- Q_ASSERT(d->data());
- Q_ASSERT(uint(d->size) <= d->alloc);
- Q_ASSERT(d != Data::sharedNull());
- Q_ASSERT(d->alloc >= uint(aalloc));
-}
-
-#if defined(Q_CC_MSVC)
-QT_WARNING_POP
-#endif
-
+#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
template<typename T>
-Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
-{
- if (uint(i) >= uint(d->size)) {
- return T();
- }
- return d->begin()[i];
-}
+using QMutableVectorIterator = QMutableListIterator<T>;
template<typename T>
-Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
-{
- return uint(i) >= uint(d->size) ? defaultValue : d->begin()[i];
-}
-
-template <typename T>
-void QVector<T>::append(const T &t)
-{
- const bool isTooSmall = uint(d->size + 1) > d->alloc;
- if (!isDetached() || isTooSmall) {
- T copy(t);
- QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
- realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
-
- if (QTypeInfo<T>::isComplex)
- new (d->end()) T(std::move(copy));
- else
- *d->end() = std::move(copy);
-
- } else {
- if (QTypeInfo<T>::isComplex)
- new (d->end()) T(t);
- else
- *d->end() = t;
- }
- ++d->size;
-}
-
-template <typename T>
-void QVector<T>::append(T &&t)
-{
- const bool isTooSmall = uint(d->size + 1) > d->alloc;
- if (!isDetached() || isTooSmall) {
- QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
- realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
- }
-
- new (d->end()) T(std::move(t));
-
- ++d->size;
-}
-
-template <typename T>
-void QVector<T>::removeLast()
-{
- Q_ASSERT(!isEmpty());
- Q_ASSERT(d->alloc);
-
- if (d->ref.isShared())
- detach();
- --d->size;
- if (QTypeInfo<T>::isComplex)
- (d->data() + d->size)->~T();
-}
-
-template <typename T>
-typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
-{
- Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
-
- const auto offset = std::distance(d->begin(), before);
- if (n != 0) {
- const T copy(t);
- if (!isDetached() || d->size + n > int(d->alloc))
- realloc(d->size + n, QArrayData::Grow);
- if (!QTypeInfoQuery<T>::isRelocatable) {
- T *b = d->end();
- T *i = d->end() + n;
- while (i != b)
- new (--i) T;
- i = d->end();
- T *j = i + n;
- b = d->begin() + offset;
- while (i != b)
- *--j = *--i;
- i = b+n;
- while (i != b)
- *--i = copy;
- } else {
- T *b = d->begin() + offset;
- T *i = b + n;
- memmove(static_cast<void *>(i), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
- while (i != b)
- new (--i) T(copy);
- }
- d->size += n;
- }
- return d->begin() + offset;
-}
-
-template <typename T>
-typename QVector<T>::iterator QVector<T>::insert(iterator before, T &&t)
-{
- Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid");
-
- const auto offset = std::distance(d->begin(), before);
- if (!isDetached() || d->size + 1 > int(d->alloc))
- realloc(d->size + 1, QArrayData::Grow);
- if (!QTypeInfoQuery<T>::isRelocatable) {
- T *i = d->end();
- T *j = i + 1;
- T *b = d->begin() + offset;
- // The new end-element needs to be constructed, the rest must be move assigned
- if (i != b) {
- new (--j) T(std::move(*--i));
- while (i != b)
- *--j = std::move(*--i);
- *b = std::move(t);
- } else {
- new (b) T(std::move(t));
- }
- } else {
- T *b = d->begin() + offset;
- memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
- new (b) T(std::move(t));
- }
- d->size += 1;
- return d->begin() + offset;
-}
-
-template <typename T>
-typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
-{
- Q_ASSERT_X(isValidIterator(abegin), "QVector::erase", "The specified iterator argument 'abegin' is invalid");
- Q_ASSERT_X(isValidIterator(aend), "QVector::erase", "The specified iterator argument 'aend' is invalid");
-
- const auto itemsToErase = aend - abegin;
-
- if (!itemsToErase)
- return abegin;
-
- Q_ASSERT(abegin >= d->begin());
- Q_ASSERT(aend <= d->end());
- Q_ASSERT(abegin <= aend);
-
- const auto itemsUntouched = abegin - d->begin();
-
- // FIXME we could do a proper realloc, which copy constructs only needed data.
- // FIXME we are about to delete data - maybe it is good time to shrink?
- // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this.
- if (d->alloc) {
- detach();
- abegin = d->begin() + itemsUntouched;
- aend = abegin + itemsToErase;
- if (!QTypeInfoQuery<T>::isRelocatable) {
- iterator moveBegin = abegin + itemsToErase;
- iterator moveEnd = d->end();
- while (moveBegin != moveEnd) {
- if (QTypeInfo<T>::isComplex)
- static_cast<T *>(abegin)->~T();
- new (abegin++) T(*moveBegin++);
- }
- if (abegin < d->end()) {
- // destroy rest of instances
- destruct(abegin, d->end());
- }
- } else {
- destruct(abegin, aend);
- // QTBUG-53605: static_cast<void *> masks clang errors of the form
- // error: destination for this 'memmove' call is a pointer to class containing a dynamic class
- // FIXME maybe use std::is_polymorphic (as soon as allowed) to avoid the memmove
- memmove(static_cast<void *>(abegin), static_cast<void *>(aend),
- (d->size - itemsToErase - itemsUntouched) * sizeof(T));
- }
- d->size -= int(itemsToErase);
- }
- return d->begin() + itemsUntouched;
-}
-
-template <typename T>
-bool QVector<T>::operator==(const QVector<T> &v) const
-{
- if (d == v.d)
- return true;
- if (d->size != v.d->size)
- return false;
- const T *vb = v.d->begin();
- const T *b = d->begin();
- const T *e = d->end();
- return std::equal(b, e, QT_MAKE_CHECKED_ARRAY_ITERATOR(vb, v.d->size));
-}
-
-template <typename T>
-QVector<T> &QVector<T>::fill(const T &from, int asize)
-{
- const T copy(from);
- resize(asize < 0 ? d->size : asize);
- if (d->size) {
- T *i = d->end();
- T *b = d->begin();
- while (i != b)
- *--i = copy;
- }
- return *this;
-}
-
-template <typename T>
-QVector<T> &QVector<T>::operator+=(const QVector &l)
-{
- if (d->size == 0) {
- *this = l;
- } else {
- uint newSize = d->size + l.d->size;
- const bool isTooSmall = newSize > d->alloc;
- if (!isDetached() || isTooSmall) {
- QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
- realloc(isTooSmall ? newSize : d->alloc, opt);
- }
-
- if (d->alloc) {
- T *w = d->begin() + newSize;
- T *i = l.d->end();
- T *b = l.d->begin();
- while (i != b) {
- if (QTypeInfo<T>::isComplex)
- new (--w) T(*--i);
- else
- *--w = *--i;
- }
- d->size = newSize;
- }
- }
- return *this;
-}
-
-namespace QtPrivate {
-template <typename T, typename U>
-int indexOf(const QVector<T> &vector, const U &u, int from)
-{
- if (from < 0)
- from = qMax(from + vector.size(), 0);
- if (from < vector.size()) {
- auto n = vector.begin() + from - 1;
- auto e = vector.end();
- while (++n != e)
- if (*n == u)
- return n - vector.begin();
- }
- return -1;
-}
-
-template <typename T, typename U>
-int lastIndexOf(const QVector<T> &vector, const U &u, int from)
-{
- if (from < 0)
- from += vector.d->size;
- else if (from >= vector.size())
- from = vector.size() - 1;
- if (from >= 0) {
- auto b = vector.begin();
- auto n = vector.begin() + from + 1;
- while (n != b) {
- if (*--n == u)
- return n - b;
- }
- }
- return -1;
-}
-}
-
-template <typename T>
-int QVector<T>::indexOf(const T &t, int from) const
-{
- return QtPrivate::indexOf<T, T>(*this, t, from);
-}
-
-template <typename T>
-int QVector<T>::lastIndexOf(const T &t, int from) const
-{
- return QtPrivate::lastIndexOf(*this, t, from);
-}
-
-template <typename T>
-bool QVector<T>::contains(const T &t) const
-{
- const T *b = d->begin();
- const T *e = d->end();
- return std::find(b, e, t) != e;
-}
-
-template <typename T>
-int QVector<T>::count(const T &t) const
-{
- const T *b = d->begin();
- const T *e = d->end();
- return int(std::count(b, e, t));
-}
-
-template <typename T>
-Q_OUTOFLINE_TEMPLATE QVector<T> QVector<T>::mid(int pos, int len) const
-{
- using namespace QtPrivate;
- switch (QContainerImplHelper::mid(d->size, &pos, &len)) {
- case QContainerImplHelper::Null:
- case QContainerImplHelper::Empty:
- return QVector<T>();
- case QContainerImplHelper::Full:
- return *this;
- case QContainerImplHelper::Subset:
- break;
- }
-
- QVector<T> midResult;
- midResult.realloc(len);
- T *srcFrom = d->begin() + pos;
- T *srcTo = d->begin() + pos + len;
- midResult.copyConstruct(srcFrom, srcTo, midResult.data());
- midResult.d->size = len;
- return midResult;
-}
-
-Q_DECLARE_SEQUENTIAL_ITERATOR(Vector)
-Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector)
-
-template <typename T>
-uint qHash(const QVector<T> &key, uint seed = 0)
- noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
-{
- return qHashRange(key.cbegin(), key.cend(), seed);
-}
-
-template <typename T>
-bool operator<(const QVector<T> &lhs, const QVector<T> &rhs)
- noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end())))
-{
- return std::lexicographical_compare(lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end());
-}
-
-template <typename T>
-inline bool operator>(const QVector<T> &lhs, const QVector<T> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return rhs < lhs;
-}
-
-template <typename T>
-inline bool operator<=(const QVector<T> &lhs, const QVector<T> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return !(lhs > rhs);
-}
-
-template <typename T>
-inline bool operator>=(const QVector<T> &lhs, const QVector<T> &rhs)
- noexcept(noexcept(lhs < rhs))
-{
- return !(lhs < rhs);
-}
-
-/*
- ### Qt 5:
- ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
- ### Qt exports QPolygon and QPolygonF that inherit QVector<QPoint> and
- ### QVector<QPointF> respectively.
-*/
-
-#if defined(Q_CC_MSVC) && !defined(QT_BUILD_CORE_LIB)
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <QtCore/qpoint.h>
-QT_END_INCLUDE_NAMESPACE
-extern template class Q_CORE_EXPORT QVector<QPointF>;
-extern template class Q_CORE_EXPORT QVector<QPoint>;
+using QVectorIterator = QListIterator<T>;
#endif
-QVector<uint> QStringView::toUcs4() const { return QtPrivate::convertToUcs4(*this); }
-
-QVector<QStringRef> QString::splitRef(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{ return splitRef(sep, _sb(behavior), cs); }
-QVector<QStringRef> QString::splitRef(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{ return splitRef(sep, _sb(behavior), cs); }
-#ifndef QT_NO_REGEXP
-QVector<QStringRef> QString::splitRef(const QRegExp &sep, Qt::SplitBehavior behavior) const
-{ return splitRef(sep, _sb(behavior)); }
-#endif
-#if QT_CONFIG(regularexpression)
-QVector<QStringRef> QString::splitRef(const QRegularExpression &sep, Qt::SplitBehavior behavior) const
-{ return splitRef(sep, _sb(behavior)); }
-#endif
-QVector<QStringRef> QStringRef::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{ return split(sep, QString::_sb(behavior), cs); }
-QVector<QStringRef> QStringRef::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{ return split(sep, QString::_sb(behavior), cs); }
-
-
QT_END_NAMESPACE
-#include <QtCore/qbytearraylist.h>
-#include <QtCore/qstringlist.h>
-
#endif // QVECTOR_H
diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc
deleted file mode 100644
index 116d962411..0000000000
--- a/src/corelib/tools/qvector.qdoc
+++ /dev/null
@@ -1,1424 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-/*!
- \class QVector
- \inmodule QtCore
- \brief The QVector class is a template class that provides a dynamic array.
-
- \ingroup tools
- \ingroup shared
-
- \reentrant
-
- QVector\<T\> is one of Qt's generic \l{container classes}. It
- stores its items in adjacent memory locations and provides fast
- index-based access.
-
- QList\<T\>, QLinkedList\<T\>, QVector\<T\>, and QVarLengthArray\<T\>
- provide similar APIs and functionality. They are often interchangeable,
- but there are performance consequences. Here is an overview of use cases:
-
- \list
- \li QVector should be your default first choice.
- QVector\<T\> will usually give better performance than QList\<T\>,
- because QVector\<T\> always stores its items sequentially in memory,
- where QList\<T\> will allocate its items on the heap unless
- \c {sizeof(T) <= sizeof(void*)} and T has been declared to be
- either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
- \l {Q_DECLARE_TYPEINFO}. See the \l {Pros and Cons of Using QList}
- for an explanation.
- \li However, QList is used throughout the Qt APIs for passing
- parameters and for returning values. Use QList to interface with
- those APIs.
- \li If you need a real linked list, which guarantees
- \l{Algorithmic Complexity}{constant time} insertions mid-list and
- uses iterators to items rather than indexes, use QLinkedList.
- \endlist
-
- \note QVector and QVarLengthArray both guarantee C-compatible
- array layout. QList does not. This might be important if your
- application must interface with a C API.
-
- \note Iterators into a QLinkedList and references into
- heap-allocating QLists remain valid as long as the referenced items
- remain in the container. This is not true for iterators and
- references into a QVector and non-heap-allocating QLists.
-
- Here's an example of a QVector that stores integers and a QVector
- that stores QString values:
-
- \snippet code/src_corelib_tools_qvector.cpp 0
-
- QVector stores its items in a vector (array). Typically, vectors
- are created with an initial size. For example, the following code
- constructs a QVector with 200 elements:
-
- \snippet code/src_corelib_tools_qvector.cpp 1
-
- The elements are automatically initialized with a
- \l{default-constructed value}. If you want to initialize the
- vector with a different value, pass that value as the second
- argument to the constructor:
-
- \snippet code/src_corelib_tools_qvector.cpp 2
-
- You can also call fill() at any time to fill the vector with a
- value.
-
- QVector uses 0-based indexes, just like C++ arrays. To access the
- item at a particular index position, you can use operator[](). On
- non-const vectors, operator[]() returns a reference to the item
- that can be used on the left side of an assignment:
-
- \snippet code/src_corelib_tools_qvector.cpp 3
-
- For read-only access, an alternative syntax is to use at():
-
- \snippet code/src_corelib_tools_qvector.cpp 4
-
- at() can be faster than operator[](), because it never causes a
- \l{deep copy} to occur.
-
- Another way to access the data stored in a QVector is to call
- data(). The function returns a pointer to the first item in the
- vector. You can use the pointer to directly access and modify the
- elements stored in the vector. The pointer is also useful if you
- need to pass a QVector to a function that accepts a plain C++
- array.
-
- If you want to find all occurrences of a particular value in a
- vector, use indexOf() or lastIndexOf(). The former searches
- forward starting from a given index position, the latter searches
- backward. Both return the index of the matching item if they found
- one; otherwise, they return -1. For example:
-
- \snippet code/src_corelib_tools_qvector.cpp 5
-
- If you simply want to check whether a vector contains a
- particular value, use contains(). If you want to find out how
- many times a particular value occurs in the vector, use count().
-
- QVector provides these basic functions to add, move, and remove
- items: insert(), replace(), remove(), prepend(), append(). With
- the exception of append() and replace(), these functions can be slow
- (\l{linear time}) for large vectors, because they require moving many
- items in the vector by one position in memory. If you want a container
- class that provides fast insertion/removal in the middle, use
- QList or QLinkedList instead.
-
- Unlike plain C++ arrays, QVectors can be resized at any time by
- calling resize(). If the new size is larger than the old size,
- QVector might need to reallocate the whole vector. QVector tries
- 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 QVector
- will contain, you can call reserve(), asking QVector to
- preallocate a certain amount of memory. You can also call
- capacity() to find out how much memory QVector actually
- allocated.
-
- Note that using non-const operators and functions can cause
- QVector to do a deep copy of the data. This is due to \l{implicit sharing}.
-
- QVector's value type must be an \l{assignable data type}. This
- covers most data types that are commonly used, but the compiler
- won't let you, for example, store a QWidget as a value; instead,
- store a QWidget *. A few functions have additional requirements;
- for example, indexOf() and lastIndexOf() expect the value type to
- support \c operator==(). These requirements are documented on a
- per-function basis.
-
- Like the other container classes, QVector provides \l{Java-style
- iterators} (QVectorIterator and QMutableVectorIterator) and
- \l{STL-style iterators} (QVector::const_iterator and
- QVector::iterator). In practice, these are rarely used, because
- you can use indexes into the QVector.
-
- In addition to QVector, Qt also provides QVarLengthArray, a very
- low-level class with little functionality that is optimized for
- speed.
-
- QVector 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
- with STL containers, see \l {Understand the Qt Containers}.
-
- \section1 Maximum size and out-of-memory conditions
-
- The current version of QVector is limited to just under 2 GB (2^31 bytes)
- in size. The exact value is architecture-dependent, since it depends on the
- overhead required for managing the data block, but is no more than 32
- bytes. The number of elements that can be stored in a QVector is that size
- divided by the size of each element.
-
- In case memory allocation fails, QVector will use the \l Q_CHECK_PTR macro,
- which will throw 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.
-
- Note that the operating system may impose further limits on applications
- holding a lot of allocated memory, especially large, contiguous blocks.
- Such considerations, the configuration of such behavior or any mitigation
- are outside the scope of the Qt API.
-
- \sa QVectorIterator, QMutableVectorIterator, QList, QLinkedList
-*/
-
-/*!
- \fn template <typename T> QVector<T> QVector<T>::mid(int pos, int length = -1) const
-
- Returns a sub-vector which contains elements from this vector,
- starting at position \a pos. If \a length is -1 (the default), all
- elements after \a pos are included; otherwise \a length elements (or
- all remaining elements if there are less than \a length elements)
- are included.
-*/
-
-
-/*! \fn template <typename T> QVector<T>::QVector()
-
- Constructs an empty vector.
-
- \sa resize()
-*/
-
-/*!
- \fn template <typename T> QVector<T>::QVector(QVector<T> &&other)
-
- Move-constructs a QVector instance, making it point at the same
- object that \a other was pointing to.
-
- \since 5.2
-*/
-
-/*! \fn template <typename T> QVector<T>::QVector(int size)
-
- Constructs a vector with an initial size of \a size elements.
-
- The elements are initialized with a \l{default-constructed
- value}.
-
- \sa resize()
-*/
-
-/*! \fn template <typename T> QVector<T>::QVector(int size, const T &value)
-
- Constructs a vector with an initial size of \a size elements.
- Each element is initialized with \a value.
-
- \sa resize(), fill()
-*/
-
-/*! \fn template <typename T> QVector<T>::QVector(const QVector<T> &other)
-
- Constructs a copy of \a other.
-
- This operation takes \l{Algorithmic Complexity}{constant time},
- because QVector is \l{implicitly shared}. This makes returning
- a QVector from a function very fast. If a shared instance is
- modified, it will be copied (copy-on-write), and that takes
- \l{Algorithmic Complexity}{linear time}.
-
- \sa operator=()
-*/
-
-/*! \fn template <typename T> QVector<T>::QVector(std::initializer_list<T> args)
- \since 4.8
-
- Constructs a vector 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> QVector<T>::QVector(InputIterator first, InputIterator last)
- \since 5.14
-
- Constructs a vector with the contents in the iterator range [\a first, \a last).
-
- The value type of \c InputIterator must be convertible to \c T.
-*/
-
-/*!
- \fn template <typename T> QVector<T>::QVector(QArrayDataPointerRef<T> ref)
- \internal
-*/
-
-/*! \fn template <typename T> QVector<T>::~QVector()
-
- Destroys the vector.
-*/
-
-/*! \fn template <typename T> QVector<T> &QVector<T>::operator=(const QVector<T> &other)
-
- Assigns \a other to this vector and returns a reference to this
- vector.
-*/
-
-/*!
- \fn template <typename T> QVector<T> &QVector<T>::operator=(QVector<T> &&other)
-
- Move-assigns \a other to this QVector instance.
-
- \since 5.2
-*/
-
-/*!
- \fn template <typename T> QVector<T> &QVector<T>::operator=(std::initializer_list<T> args)
-
- Assigns the collection of values in \a args to this QVector instance.
-
- This operator is only enabled if the compiler supports C++11 initializer
- lists.
-
- \since 5.14
-*/
-
-/*! \fn template <typename T> void QVector<T>::swap(QVector<T> &other)
- \since 4.8
-
- Swaps vector \a other with this vector. This operation is very fast and
- never fails.
-*/
-
-/*! \fn template <typename T> void QVector<T>::swapItemsAt(int i, int j)
- \since 5.14
-
- Exchange the item at index position \a i with the item at index
- position \a j. This function assumes that both \a i and \a j are
- at least 0 but less than size(). To avoid failure, test that both
- \a i and \a j are at least 0 and less than size().
-*/
-
-
-/*! \fn template <typename T> bool QVector<T>::operator==(const QVector<T> &other) const
-
- Returns \c true if \a other is equal to this vector; otherwise
- returns \c false.
-
- Two vectors are considered equal if they contain the same values
- in the same order.
-
- This function requires the value type to have an implementation
- of \c operator==().
-
- \sa operator!=()
-*/
-
-/*! \fn template <typename T> bool QVector<T>::operator!=(const QVector<T> &other) const
-
- Returns \c true if \a other is not equal to this vector; otherwise
- returns \c false.
-
- Two vectors are considered equal if they contain the same values
- in the same order.
-
- This function requires the value type to have an implementation
- of \c operator==().
-
- \sa operator==()
-*/
-
-/*! \fn template <typename T> bool operator<(const QVector<T> &lhs, const QVector<T> &rhs)
- \since 5.6
- \relates QVector
-
- Returns \c true if vector \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically less than} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*! \fn template <typename T> bool operator<=(const QVector<T> &lhs, const QVector<T> &rhs)
- \since 5.6
- \relates QVector
-
- Returns \c true if vector \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically less than or equal to} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*! \fn template <typename T> bool operator>(const QVector<T> &lhs, const QVector<T> &rhs)
- \since 5.6
- \relates QVector
-
- Returns \c true if vector \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically greater than} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*! \fn template <typename T> bool operator>=(const QVector<T> &lhs, const QVector<T> &rhs)
- \since 5.6
- \relates QVector
-
- Returns \c true if vector \a lhs is
- \l{http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare}
- {lexicographically greater than or equal to} \a rhs; otherwise returns \c false.
-
- This function requires the value type to have an implementation
- of \c operator<().
-*/
-
-/*!
- \fn template <typename T> uint qHash(const QVector<T> &key, uint seed = 0)
- \since 5.6
- \relates QVector
-
- Returns the hash value for \a key,
- using \a seed to seed the calculation.
-
- This function requires qHash() to be overloaded for the value type \c T.
-*/
-
-/*! \fn template <typename T> int QVector<T>::size() const
-
- Returns the number of items in the vector.
-
- \sa isEmpty(), resize()
-*/
-
-/*! \fn template <typename T> bool QVector<T>::isEmpty() const
-
- Returns \c true if the vector has size 0; otherwise returns \c false.
-
- \sa size(), resize()
-*/
-
-/*! \fn template <typename T> void QVector<T>::resize(int size)
-
- Sets the size of the vector 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.
-
- Since Qt 5.6, resize() doesn't shrink the capacity anymore.
- To shed excess capacity, use squeeze().
-
- \sa size()
-*/
-
-/*! \fn template <typename T> int QVector<T>::capacity() const
-
- Returns the maximum number of items that can be stored in the
- vector without forcing a reallocation.
-
- The sole purpose of this function is to provide a means of fine
- tuning QVector's memory usage. In general, you will rarely ever
- need to call this function. If you want to know how many items are
- in the vector, call size().
-
- \sa reserve(), squeeze()
-*/
-
-/*! \fn template <typename T> void QVector<T>::reserve(int size)
-
- Attempts to allocate memory for at least \a size elements. If you
- know in advance how large the vector will be, you should call this
- function to prevent reallocations and memory fragmentation.
-
- If \a size is an underestimate, the worst that will happen is that
- the QVector will be a bit slower. If \a size is an overestimate, you
- may have used more memory than the normal QVector growth strategy
- would have allocated—or you may have used less.
-
- 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().
-
- \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.
-
- \sa squeeze(), capacity()
-*/
-
-/*! \fn template <typename T> void QVector<T>::squeeze()
-
- Releases any memory not required to store the items.
-
- The sole purpose of this function is to provide a means of fine
- tuning QVector's memory usage. In general, you will rarely ever
- need to call this function.
-
- \sa reserve(), capacity()
-*/
-
-/*! \fn template <typename T> void QVector<T>::detach()
-
- \internal
-*/
-
-/*! \fn template <typename T> bool QVector<T>::isDetached() const
-
- \internal
-*/
-
-/*! \fn template <typename T> void QVector<T>::setSharable(bool sharable)
-
- \internal
-*/
-
-/*! \fn template <typename T> bool QVector<T>::isSharedWith(const QVector<T> &other) const
-
- \internal
-*/
-
-/*! \fn template <typename T> T *QVector<T>::data()
-
- Returns a pointer to the data stored in the vector. The pointer
- can be used to access and modify the items in the vector.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 6
-
- The pointer remains valid as long as the vector isn't
- reallocated.
-
- This function is mostly useful to pass a vector to a function
- that accepts a plain C++ array.
-
- \sa constData(), operator[]()
-*/
-
-/*! \fn template <typename T> const T *QVector<T>::data() const
-
- \overload
-*/
-
-/*! \fn template <typename T> const T *QVector<T>::constData() const
-
- Returns a const pointer to the data stored in the vector. The
- pointer can be used to access the items in the vector.
- The pointer remains valid as long as the vector isn't
- reallocated.
-
- This function is mostly useful to pass a vector to a function
- that accepts a plain C++ array.
-
- \sa data(), operator[]()
-*/
-
-/*! \fn template <typename T> void QVector<T>::clear()
-
- Removes all the elements from the vector.
-
- \note Until Qt 5.6, this also released the memory used by
- the vector. From Qt 5.7, the capacity is preserved. To shed
- all capacity, swap with a default-constructed vector:
- \code
- QVector<T> v ...;
- QVector<T>().swap(v);
- Q_ASSERT(v.capacity() == 0);
- \endcode
- or call squeeze().
-
- \sa squeeze()
-*/
-
-/*! \fn template <typename T> const T &QVector<T>::at(int i) const
-
- Returns the item at index position \a i in the vector.
-
- \a i must be a valid index position in the vector (i.e., 0 <= \a
- i < size()).
-
- \sa value(), operator[]()
-*/
-
-/*! \fn template <typename T> T &QVector<T>::operator[](int i)
-
- Returns the item at index position \a i as a modifiable reference.
-
- \a i must be a valid index position in the vector (i.e., 0 <= \a i
- < size()).
-
- Note that using non-const operators can cause QVector to do a deep
- copy.
-
- \sa at(), value()
-*/
-
-/*! \fn template <typename T> const T &QVector<T>::operator[](int i) const
-
- \overload
-
- Same as at(\a i).
-*/
-
-/*!
- \fn template <typename T> void QVector<T>::append(const T &value)
-
- Inserts \a value at the end of the vector.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 7
-
- This is the same as calling resize(size() + 1) and assigning \a
- value to the new last element in the vector.
-
- This operation is relatively fast, because QVector typically
- allocates more memory than necessary, so it can grow without
- reallocating the entire vector each time.
-
- \sa operator<<(), prepend(), insert()
-*/
-
-/*!
- \fn template <typename T> void QVector<T>::append(T &&value)
- \since 5.6
-
- \overload
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp move-append
-*/
-
-/*! \fn template <typename T> void QVector<T>::append(const QVector<T> &value)
-
- \overload
-
- \since 5.5
-
- Appends the items of the \a value vector to this vector.
-
- \sa operator<<(), operator+=()
-*/
-
-
-/*!
- \fn template <typename T> void QVector<T>::prepend(const T &value)
- \fn template <typename T> void QVector<T>::prepend(T &&value)
-
- Inserts \a value at the beginning of the vector.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 8
-
- This is the same as vector.insert(0, \a value).
-
- For large vectors, this operation can be slow (\l{linear time}),
- because it requires moving all the items in the vector by one
- position further in memory. If you want a container class that
- provides a fast prepend() function, use QList or QLinkedList
- instead.
-
- \sa append(), insert()
-*/
-
-/*! \fn template <typename T> void QVector<T>::insert(int i, const T &value)
- \fn template <typename T> void QVector<T>::insert(int i, T &&value)
-
- Inserts \a value at index position \a i in the vector. If \a i is
- 0, the value is prepended to the vector. If \a i is size(), the
- value is appended to the vector.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 9
-
- For large vectors, this operation can be slow (\l{linear time}),
- because it requires moving all the items at indexes \a i and
- above by one position further in memory. If you want a container
- class that provides a fast insert() function, use QLinkedList
- instead.
-
- \sa append(), prepend(), remove()
-*/
-
-/*! \fn template <typename T> void QVector<T>::insert(int i, int count, const T &value)
-
- \overload
-
- Inserts \a count copies of \a value at index position \a i in the
- vector.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 10
-*/
-
-/*!
- \fn template <typename T> QVector<T>::iterator QVector<T>::insert(iterator before, const T &value)
- \fn template <typename T> QVector<T>::iterator QVector<T>::insert(iterator before, T &&value)
-
- \overload
-
- Inserts \a value in front of the item pointed to by the iterator
- \a before. Returns an iterator pointing at the inserted item.
-*/
-
-/*! \fn template <typename T> QVector<T>::iterator QVector<T>::insert(iterator before, int count, const T &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
- first of the inserted items.
-*/
-
-/*! \fn template <typename T> void QVector<T>::replace(int i, const T &value)
-
- Replaces the item at index position \a i with \a value.
-
- \a i must be a valid index position in the vector (i.e., 0 <= \a
- i < size()).
-
- \sa operator[](), remove()
-*/
-
-/*! \fn template <typename T> void QVector<T>::remove(int i)
-
- \overload
-
- Removes the element at index position \a i.
-
- \sa insert(), replace(), fill()
-*/
-
-/*! \fn template <typename T> void QVector<T>::remove(int i, int count)
-
- \overload
-
- Removes \a count elements from the middle of the vector, starting at
- index position \a i.
-
- \sa insert(), replace(), fill()
-*/
-
-/*! \fn template <typename T> void QVector<T>::removeAt(int i)
- \since 5.2
-
- Removes the element at index position \a i.
- Equivalent to
- \code
- remove(i);
- \endcode
-
- Provided for compatibility with QList.
-
- \sa remove(), QList::removeAt()
-*/
-
-/*! \fn template <typename T> int QVector<T>::removeAll(const T &t)
- \since 5.4
-
- Removes all elements that compare equal to \a t from the
- vector. Returns the number of elements removed, if any.
-
- Provided for compatibility with QList.
-
- \sa removeOne(), QList::removeAll()
-*/
-
-/*! \fn template <typename T> bool QVector<T>::removeOne(const T &t)
- \since 5.4
-
- Removes the first element that compares equal to \a t from the
- vector. Returns whether an element was, in fact, removed.
-
- Provided for compatibility with QList.
-
- \sa removeAll(), QList::removeOne()
-*/
-
-/*! \fn template <typename T> int QVector<T>::length() const
- \since 5.2
-
- Same as size() and count().
-
- Provided for compatibility with QList.
-
- \sa size(), count(), QList::length()
-*/
-
-/*! \fn template <typename T> T QVector<T>::takeAt(int i)
- \since 5.2
-
- Removes the element at index position \a i and returns it.
-
- Equivalent to
- \code
- T t = at(i);
- remove(i);
- return t;
- \endcode
-
- Provided for compatibility with QList.
-
- \sa takeFirst(), takeLast(), QList::takeAt()
-*/
-
-/*! \fn template <typename T> void QVector<T>::move(int from, int 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 QVector<T>::removeFirst()
- \since 5.1
- Removes the first item in the vector. Calling this function is
- equivalent to calling remove(0). The vector must not be empty. If
- the vector can be empty, call isEmpty() before calling this
- function.
-
- \sa remove(), takeFirst(), isEmpty()
-*/
-
-/*! \fn template <typename T> void QVector<T>::removeLast()
- \since 5.1
- Removes the last item in the vector. Calling this function is
- equivalent to calling remove(size() - 1). The vector must not be
- empty. If the vector can be empty, call isEmpty() before calling
- this function.
-
- \sa remove(), takeLast(), removeFirst(), isEmpty()
-*/
-
-/*! \fn template <typename T> T QVector<T>::takeFirst()
- \since 5.1
-
- Removes the first item in the vector and returns it. This function
- assumes the vector is not empty. To avoid failure, call isEmpty()
- before calling this function.
-
- \sa takeLast(), removeFirst()
-*/
-
-/*! \fn template <typename T> T QVector<T>::takeLast()
- \since 5.1
-
- Removes the last item in the list and returns it. This function
- assumes the vector is not empty. To avoid failure, call isEmpty()
- before calling this function.
-
- If you don't use the return value, removeLast() is more
- efficient.
-
- \sa takeFirst(), removeLast()
-*/
-
-
-/*! \fn template <typename T> QVector<T> &QVector<T>::fill(const T &value, int size = -1)
-
- Assigns \a value to all items in the vector. If \a size is
- different from -1 (the default), the vector is resized to size \a
- size beforehand.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 11
-
- \sa resize()
-*/
-
-/*! \fn template <typename T> int QVector<T>::indexOf(const T &value, int from = 0) const
-
- Returns the index position of the first occurrence of \a value in
- the vector, searching forward from index position \a from.
- Returns -1 if no item matched.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 12
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa lastIndexOf(), contains()
-*/
-
-/*! \fn template <typename T> int QVector<T>::lastIndexOf(const T &value, int from = -1) const
-
- Returns the index position of the last occurrence of the value \a
- value in the vector, searching backward from index position \a
- from. If \a from is -1 (the default), the search starts at the
- last item. Returns -1 if no item matched.
-
- Example:
- \snippet code/src_corelib_tools_qvector.cpp 13
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa indexOf()
-*/
-
-/*! \fn template <typename T> bool QVector<T>::contains(const T &value) const
-
- Returns \c true if the vector contains an occurrence of \a value;
- otherwise returns \c false.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa indexOf(), count()
-*/
-
-/*! \fn template <typename T> bool QVector<T>::startsWith(const T &value) const
- \since 4.5
-
- Returns \c true if this vector is not empty and its first
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), first()
-*/
-
-/*! \fn template <typename T> bool QVector<T>::endsWith(const T &value) const
- \since 4.5
-
- Returns \c true if this vector is not empty and its last
- item is equal to \a value; otherwise returns \c false.
-
- \sa isEmpty(), last()
-*/
-
-
-/*! \fn template <typename T> int QVector<T>::count(const T &value) const
-
- Returns the number of occurrences of \a value in the vector.
-
- This function requires the value type to have an implementation of
- \c operator==().
-
- \sa contains(), indexOf()
-*/
-
-/*! \fn template <typename T> int QVector<T>::count() const
-
- \overload
-
- Same as size().
-*/
-
-/*! \fn template <typename T> QVector<T>::iterator QVector<T>::begin()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
- the vector.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <typename T> QVector<T>::const_iterator QVector<T>::begin() const
-
- \overload
-*/
-
-/*! \fn template <typename T> QVector<T>::const_iterator QVector<T>::cbegin() const
- \since 5.0
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the vector.
-
- \sa begin(), cend()
-*/
-
-/*! \fn template <typename T> QVector<T>::const_iterator QVector<T>::constBegin() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
- in the vector.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <typename T> QVector<T>::iterator QVector<T>::end()
-
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
- after the last item in the vector.
-
- \sa begin(), constEnd()
-*/
-
-/*! \fn template <typename T> QVector<T>::const_iterator QVector<T>::end() const
-
- \overload
-*/
-
-/*! \fn template <typename T> QVector<T>::const_iterator QVector<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 vector.
-
- \sa cbegin(), end()
-*/
-
-/*! \fn template <typename T> QVector<T>::const_iterator QVector<T>::constEnd() const
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- item after the last item in the vector.
-
- \sa constBegin(), end()
-*/
-
-/*! \fn template <typename T> QVector<T>::reverse_iterator QVector<T>::rbegin()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the vector, in reverse order.
-
- \sa begin(), crbegin(), rend()
-*/
-
-/*! \fn template <typename T> QVector<T>::const_reverse_iterator QVector<T>::rbegin() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <typename T> QVector<T>::const_reverse_iterator QVector<T>::crbegin() const
- \since 5.6
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- item in the vector, in reverse order.
-
- \sa begin(), rbegin(), rend()
-*/
-
-/*! \fn template <typename T> QVector<T>::reverse_iterator QVector<T>::rend()
- \since 5.6
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last item in the vector, in reverse order.
-
- \sa end(), crend(), rbegin()
-*/
-
-/*! \fn template <typename T> QVector<T>::const_reverse_iterator QVector<T>::rend() const
- \since 5.6
- \overload
-*/
-
-/*! \fn template <typename T> QVector<T>::const_reverse_iterator QVector<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 vector, in reverse order.
-
- \sa end(), rend(), rbegin()
-*/
-
-/*! \fn template <typename T> QVector<T>::iterator QVector<T>::erase(iterator pos)
-
- Removes the item pointed to by the iterator \a pos from the
- vector, and returns an iterator to the next item in the vector
- (which may be end()).
-
- \sa insert(), remove()
-*/
-
-/*! \fn template <typename T> QVector<T>::iterator QVector<T>::erase(iterator begin, iterator end)
-
- \overload
-
- Removes all the items from \a begin up to (but not including) \a
- end. Returns an iterator to the same item that \a end referred to
- before the call.
-*/
-
-/*! \fn template <typename T> T& QVector<T>::first()
-
- Returns a reference to the first item in the vector. This
- function assumes that the vector isn't empty.
-
- \sa last(), isEmpty(), constFirst()
-*/
-
-/*! \fn template <typename T> const T& QVector<T>::first() const
-
- \overload
-*/
-
-/*! \fn template <typename T> const T& QVector<T>::constFirst() const
- \since 5.6
-
- Returns a const reference to the first item in the vector. This
- function assumes that the vector isn't empty.
-
- \sa constLast(), isEmpty(), first()
-*/
-
-/*! \fn template <typename T> T& QVector<T>::last()
-
- Returns a reference to the last item in the vector. This function
- assumes that the vector isn't empty.
-
- \sa first(), isEmpty(), constLast()
-*/
-
-/*! \fn template <typename T> const T& QVector<T>::last() const
-
- \overload
-*/
-
-/*! \fn template <typename T> const T& QVector<T>::constLast() const
- \since 5.6
-
- Returns a const reference to the last item in the vector. This function
- assumes that the vector isn't empty.
-
- \sa constFirst(), isEmpty(), last()
-*/
-
-/*! \fn template <typename T> T QVector<T>::value(int i) const
-
- Returns the value at index position \a i in the vector.
-
- If the index \a i is out of bounds, the function returns
- a \l{default-constructed value}. If you are certain that
- \a i is within bounds, you can use at() instead, which is slightly
- faster.
-
- \sa at(), operator[]()
-*/
-
-/*! \fn template <typename T> T QVector<T>::value(int i, const T &defaultValue) const
-
- \overload
-
- If the index \a i is out of bounds, the function returns
- \a defaultValue.
-*/
-
-/*! \fn template <typename T> void QVector<T>::push_back(const T &value)
-
- This function is provided for STL compatibility. It is equivalent
- to append(\a value).
-*/
-
-/*! \fn template <typename T> void QVector<T>::push_back(T &&value)
- \since 5.6
- \overload
-*/
-
-/*!
- \fn template <typename T> void QVector<T>::push_front(const T &value)
- \fn template <typename T> void QVector<T>::push_front(T &&value)
-
- This function is provided for STL compatibility. It is equivalent
- to prepend(\a value).
-*/
-
-/*! \fn template <typename T> void QVector<T>::pop_front()
-
- This function is provided for STL compatibility. It is equivalent
- to removeFirst().
-*/
-
-/*! \fn template <typename T> void QVector<T>::pop_back()
-
- This function is provided for STL compatibility. It is equivalent
- to removeLast().
-*/
-
-/*! \fn template <typename T> T& QVector<T>::front()
-
- This function is provided for STL compatibility. It is equivalent
- to first().
-*/
-
-/*! \fn template <typename T> QVector<T>::const_reference QVector<T>::front() const
-
- \overload
-*/
-
-/*! \fn template <typename T> QVector<T>::reference QVector<T>::back()
-
- This function is provided for STL compatibility. It is equivalent
- to last().
-*/
-
-/*! \fn template <typename T> QVector<T>::const_reference QVector<T>::back() const
-
- \overload
-*/
-
-/*! \fn template <typename T> void QVector<T>::shrink_to_fit()
- \since 5.10
-
- This function is provided for STL compatibility. It is equivalent
- to squeeze().
-*/
-
-/*! \fn template <typename T> bool QVector<T>::empty() const
-
- This function is provided for STL compatibility. It is equivalent
- to isEmpty(), returning \c true if the vector is empty; otherwise
- returns \c false.
-*/
-
-/*! \fn template <typename T> QVector<T> &QVector<T>::operator+=(const QVector<T> &other)
-
- Appends the items of the \a other vector to this vector and
- returns a reference to this vector.
-
- \sa operator+(), append()
-*/
-
-/*! \fn template <typename T> void QVector<T>::operator+=(const T &value)
-
- \overload
-
- Appends \a value to the vector.
-
- \sa append(), operator<<()
-*/
-
-/*! \fn template <typename T> void QVector<T>::operator+=(T &&value)
- \since 5.11
-
- \overload
-
- \sa append(), operator<<()
-*/
-
-/*! \fn template <typename T> QVector<T> QVector<T>::operator+(const QVector<T> &other) const
-
- Returns a vector that contains all the items in this vector
- followed by all the items in the \a other vector.
-
- \sa operator+=()
-*/
-
-/*! \fn template <typename T> QVector<T> &QVector<T>::operator<<(const T &value)
-
- Appends \a value to the vector and returns a reference to this
- vector.
-
- \sa append(), operator+=()
-*/
-
-/*! \fn template <typename T> QVector<T> &QVector<T>::operator<<(T &&value)
- \since 5.11
-
- \overload
-
- \sa append(), operator+=()
-*/
-
-
-/*! \fn template <typename T> QVector<T> &QVector<T>::operator<<(const QVector<T> &other)
-
- Appends \a other to the vector and returns a reference to the
- vector.
-*/
-
-/*! \typedef QVector::iterator
-
- The QVector::iterator typedef provides an STL-style non-const
- iterator for QVector and QStack.
-
- QVector 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).
-
- \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 QVector::begin(), QVector::end(), QVector::const_iterator, QMutableVectorIterator
-*/
-
-/*! \typedef QVector::const_iterator
-
- The QVector::const_iterator typedef provides an STL-style const
- iterator for QVector and QStack.
-
- QVector 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).
-
- \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 QVector::constBegin(), QVector::constEnd(), QVector::iterator, QVectorIterator
-*/
-
-/*! \typedef QVector::reverse_iterator
- \since 5.6
-
- The QVector::reverse_iterator typedef provides an STL-style non-const
- reverse iterator for QVector.
-
- It is simply a typedef for \c{std::reverse_iterator<T*>}.
-
- \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 QVector::rbegin(), QVector::rend(), QVector::const_reverse_iterator, QVector::iterator
-*/
-
-/*! \typedef QVector::const_reverse_iterator
- \since 5.6
-
- The QVector::const_reverse_iterator typedef provides an STL-style const
- reverse iterator for QVector.
-
- It is simply a typedef for \c{std::reverse_iterator<const T*>}.
-
- \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 QVector::rbegin(), QVector::rend(), QVector::reverse_iterator, QVector::const_iterator
-*/
-
-/*! \typedef QVector::Iterator
-
- Qt-style synonym for QVector::iterator.
-*/
-
-/*! \typedef QVector::ConstIterator
-
- Qt-style synonym for QVector::const_iterator.
-*/
-
-/*! \typedef QVector::const_pointer
-
- Typedef for const T *. Provided for STL compatibility.
-*/
-
-/*! \typedef QVector::const_reference
-
- Typedef for T &. Provided for STL compatibility.
-*/
-
-/*! \typedef QVector::difference_type
-
- Typedef for ptrdiff_t. Provided for STL compatibility.
-*/
-
-/*! \typedef QVector::pointer
-
- Typedef for T *. Provided for STL compatibility.
-*/
-
-/*! \typedef QVector::reference
-
- Typedef for T &. Provided for STL compatibility.
-*/
-
-/*! \typedef QVector::size_type
-
- Typedef for int. Provided for STL compatibility.
-*/
-
-/*! \typedef QVector::value_type
-
- Typedef for T. Provided for STL compatibility.
-*/
-
-/*! \fn template <typename T> QList<T> QVector<T>::toList() const
-
- Returns a QList object with the data contained in this QVector.
-
- Example:
-
- \snippet code/src_corelib_tools_qvector.cpp 14
-
- \include containers-range-constructor.qdocinc
-
- \sa fromList(), QList::fromVector()
-*/
-
-/*! \fn template <typename T> QVector<T> QVector<T>::fromList(const QList<T> &list)
-
- Returns a QVector object with the data contained in \a list.
-
- Example:
-
- \snippet code/src_corelib_tools_qvector.cpp 15
-
- \include containers-range-constructor.qdocinc
-
- \sa toList(), QList::toVector()
-*/
-
-/*! \fn template <typename T> QVector<T> QVector<T>::fromStdVector(const std::vector<T> &vector)
-
- Returns a QVector object with the data contained in \a vector. The
- order of the elements in the QVector is the same as in \a vector.
-
- Example:
-
- \snippet code/src_corelib_tools_qvector.cpp 16
-
- \include containers-range-constructor.qdocinc
-
- \sa toStdVector(), QList::fromStdList()
-*/
-
-/*! \fn template <typename T> std::vector<T> QVector<T>::toStdVector() const
-
- Returns a std::vector object with the data contained in this QVector.
- Example:
-
- \snippet code/src_corelib_tools_qvector.cpp 17
-
- \include containers-range-constructor.qdocinc
-
- \sa fromStdVector(), QList::toStdList()
-*/
-
-/*! \fn template <typename T> QDataStream &operator<<(QDataStream &out, const QVector<T> &vector)
- \relates QVector
-
- Writes the vector \a vector to stream \a out.
-
- This function requires the value type to implement \c operator<<().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
-
-/*! \fn template <typename T> QDataStream &operator>>(QDataStream &in, QVector<T> &vector)
- \relates QVector
-
- Reads a vector from stream \a in into \a vector.
-
- This function requires the value type to implement \c operator>>().
-
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
-*/
diff --git a/src/corelib/tools/qvector_msvc.cpp b/src/corelib/tools/qvector_msvc.cpp
deleted file mode 100644
index 7e87467d42..0000000000
--- a/src/corelib/tools/qvector_msvc.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-// ### Qt6: verify if we can remove this, somehow.
-// First, try to see if the extern template from qvector.h is necessary.
-// If it still is, check if removing the copy constructors in qarraydata.h
-// make the calling convention of both sets of begin() and end() functions
-// match, as it does for the IA-64 C++ ABI.
-
-#ifdef QVECTOR_H
-# error "This file must be compiled with no precompiled headers"
-#endif
-
-// the Q_TEMPLATE_EXTERN at the bottom of qvector.h will do the trick
-#include <QtCore/qvector.h>
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 58e3c15560..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
@@ -96,27 +62,32 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QVersionNumber::QVersionNumber(const QVector<int> &seg)
+ \fn QVersionNumber::QVersionNumber(const QList<int> &seg)
Constructs a version number from the list of numbers contained in \a seg.
*/
/*!
- \fn QVersionNumber::QVersionNumber(QVector<int> &&seg)
+ \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
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
+ Constructs a version number from the span specified by \a args.
+
+ \note In Qt versions prior to 6.8, QVersionNumber could only be constructed
+ from QList, QVarLenthArray or std::initializer_list.
*/
/*!
@@ -168,35 +139,35 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn const QVector<int>& QVersionNumber::segments() const
+ \fn QList<int> QVersionNumber::segments() const
Returns all of the numerical segments.
\sa majorVersion(), minorVersion(), microVersion()
*/
-QVector<int> QVersionNumber::segments() const
+QList<int> QVersionNumber::segments() const
{
if (m_segments.isUsingPointer())
return *m_segments.pointer_segments;
- QVector<int> result;
+ 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 @@ QVector<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 @@ QVector<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,79 +431,91 @@ 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)
{
- QVector<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)
{
- pointer_segments = new QVector<int>;
+ pointer_segments = new QList<int>;
pointer_segments->resize(len);
pointer_segments->data()[0] = maj;
if (len > 1) {
@@ -525,7 +553,7 @@ QDataStream& operator<<(QDataStream &out, const QVersionNumber &version)
QDataStream& operator>>(QDataStream &in, QVersionNumber &version)
{
if (!version.m_segments.isUsingPointer())
- version.m_segments.pointer_segments = new QVector<int>;
+ version.m_segments.pointer_segments = new QList<int>;
in >> *version.m_segments.pointer_segments;
return in;
}
@@ -535,20 +563,20 @@ 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 uint qHash(const QVersionNumber &key, uint seed)
\relates QHash
\since 5.6
Returns the hash value for the \a key, using \a seed to seed the
calculation.
*/
-uint qHash(const QVersionNumber &key, uint seed)
+size_t qHash(const QVersionNumber &key, size_t seed)
{
QtPrivate::QHashCombine hash;
for (int i = 0; i < key.segmentCount(); ++i)
@@ -557,4 +585,3 @@ uint qHash(const QVersionNumber &key, uint seed)
}
QT_END_NAMESPACE
-
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index d43b86ba51..95217a6eff 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -1,61 +1,30 @@
-/****************************************************************************
-**
-** 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/qvector.h>
-#include <QtCore/qmetatype.h>
#include <QtCore/qtypeinfo.h>
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 2
+#include <QtCore/qtyperevision.h>
+#endif // lean headers level 2
QT_BEGIN_NAMESPACE
class QVersionNumber;
-Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed = 0);
+Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed = 0);
#ifndef QT_NO_DATASTREAM
-Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QVersionNumber &version);
-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
@@ -70,37 +39,40 @@ 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
};
- Q_STATIC_ASSERT(InlineSegmentCount >= 3); // at least major, minor, micro
+ 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*)];
- QVector<int> *pointer_segments;
+ qint8 inline_segments[sizeof(void *)];
+ QList<int> *pointer_segments;
};
// set the InlineSegmentMarker and set length to zero
SegmentStorage() noexcept : dummy(1) {}
- SegmentStorage(const QVector<int> &seg)
+ 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 QVector<int>(seg);
+ setListData(seg);
}
+ Q_CORE_EXPORT void setListData(const QList<int> &seg);
+
SegmentStorage(const SegmentStorage &other)
{
if (other.isUsingPointer())
- pointer_segments = new QVector<int>(*other.pointer_segments);
+ setListData(*other.pointer_segments);
else
dummy = other.dummy;
}
@@ -110,7 +82,7 @@ class QVersionNumber
if (isUsingPointer() && other.isUsingPointer()) {
*pointer_segments = *other.pointer_segments;
} else if (other.isUsingPointer()) {
- pointer_segments = new QVector<int>(*other.pointer_segments);
+ setListData(*other.pointer_segments);
} else {
if (isUsingPointer())
delete pointer_segments;
@@ -125,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(QVector<int> &&seg)
+ 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 QVector<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 QVector<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] = 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) :
@@ -184,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
}
@@ -213,21 +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()
{}
- inline explicit QVersionNumber(const QVector<int> &seg)
- : m_segments(seg)
- {}
+ 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
- explicit QVersionNumber(QVector<int> &&seg)
- : m_segments(std::move(seg))
- {}
+ 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)
{}
@@ -240,77 +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 QVector<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;
+ [[nodiscard]] const_iterator begin() const noexcept { return const_iterator{this, 0}; }
+ [[nodiscard]] const_iterator end() const noexcept { return begin() + segmentCount(); }
+ [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator cend() const noexcept { return end(); }
+
+ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
+ [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
+ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ [[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); }
+
+ [[nodiscard]] const_iterator constBegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator constEnd() const noexcept { return end(); }
+
+ [[nodiscard]] Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const noexcept;
+
+ [[nodiscard]] Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept;
+
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
+
+ [[nodiscard]] Q_CORE_EXPORT QString toString() const;
+ [[nodiscard]] Q_CORE_EXPORT static QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex = nullptr);
+
+#if QT_DEPRECATED_SINCE(6, 4) && QT_POINTER_SIZE != 4
+ Q_WEAK_OVERLOAD
+ QT_DEPRECATED_VERSION_X_6_4("Use the 'qsizetype *suffixIndex' overload.")
+ [[nodiscard]] static QVersionNumber fromString(QAnyStringView string, int *suffixIndex)
+ {
+ QT_WARNING_PUSH
+ // fromString() writes to *n unconditionally, but GCC can't know that
+ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
+ qsizetype n;
+ auto r = fromString(string, &n);
+ if (suffixIndex) {
+ Q_ASSERT(int(n) == n);
+ *suffixIndex = int(n);
+ }
+ return r;
+ QT_WARNING_POP
+ }
+#endif
- 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);
+#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
- 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);
+
+ [[nodiscard]] friend bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) > 0; }
+
+ [[nodiscard]] friend bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) >= 0; }
+
+ [[nodiscard]] friend bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) < 0; }
+
+ [[nodiscard]] friend bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) <= 0; }
+
+ [[nodiscard]] friend bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) == 0; }
+
+ [[nodiscard]] friend bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
+ { return compare(lhs, rhs) != 0; }
private:
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
#endif
- friend Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed);
+ friend Q_CORE_EXPORT size_t qHash(const QVersionNumber &key, size_t seed);
};
-Q_DECLARE_TYPEINFO(QVersionNumber, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QVersionNumber, Q_RELOCATABLE_TYPE);
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version);
#endif
-Q_REQUIRED_RESULT inline bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) > 0; }
-
-Q_REQUIRED_RESULT inline bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) >= 0; }
-
-Q_REQUIRED_RESULT inline bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) < 0; }
-
-Q_REQUIRED_RESULT inline bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) <= 0; }
-
-Q_REQUIRED_RESULT inline bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) == 0; }
-
-Q_REQUIRED_RESULT inline bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
-{ return QVersionNumber::compare(lhs, rhs) != 0; }
-
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QVersionNumber)
+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 40c84157cd..0000000000
--- a/src/corelib/tools/tools.pri
+++ /dev/null
@@ -1,119 +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/qfreelist_p.h \
- tools/qhash.h \
- tools/qhashfunctions.h \
- tools/qiterator.h \
- tools/qline.h \
- tools/qlinkedlist.h \
- tools/qlist.h \
- tools/qmakearray_p.h \
- tools/qmap.h \
- 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/qsharedpointer.h \
- tools/qsharedpointer_impl.h \
- tools/qset.h \
- tools/qsimd_p.h \
- tools/qsize.h \
- tools/qstack.h \
- tools/qtools_p.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/qlinkedlist.cpp \
- tools/qlist.cpp \
- tools/qpoint.cpp \
- tools/qmap.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/qsimd.cpp \
- tools/qsize.cpp \
- tools/qversionnumber.cpp
-
-msvc: NO_PCH_SOURCES += tools/qvector_msvc.cpp
-false: SOURCES += $$NO_PCH_SOURCES # Hack for QtCreator
-
-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(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