diff options
Diffstat (limited to 'src/corelib/tools')
29 files changed, 427 insertions, 198 deletions
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index dcd95924c1..5e21186bbd 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -56,16 +56,16 @@ struct Q_CORE_EXPORT QArrayData void *data() { - Q_ASSERT(size == 0 - || offset < 0 || size_t(offset) >= sizeof(QArrayData)); - return reinterpret_cast<char *>(this) + offset; + Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); + const quintptr self = reinterpret_cast<qintptr>(this); + return reinterpret_cast<void *>(self + offset); } const void *data() const { - Q_ASSERT(size == 0 - || offset < 0 || size_t(offset) >= sizeof(QArrayData)); - return reinterpret_cast<const char *>(this) + offset; + Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); + const quintptr self = reinterpret_cast<qintptr>(this); + return reinterpret_cast<const void *>(self + offset); } // This refers to array data mutability, not "header data" represented by diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 8e19525f07..0b967a84f7 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -65,8 +65,10 @@ struct QPodArrayOps 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); + T *const begin = this->begin(); + do { + new (begin + this->size) T(); + } while (uint(++this->size) != newSize); } void copyAppend(const T *b, const T *e) @@ -154,7 +156,7 @@ struct QGenericArrayOps T *const begin = this->begin(); do { - new (begin + this->size) T; + new (begin + this->size) T(); } while (uint(++this->size) != newSize); } diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h index 3a0c4381f1..1716e0a5a8 100644 --- a/src/corelib/tools/qcontainertools_impl.h +++ b/src/corelib/tools/qcontainertools_impl.h @@ -53,6 +53,40 @@ 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<const T *>> +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 + + 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 (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); + } +} + template <typename Iterator> using IfIsInputIterator = typename std::enable_if< std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>::value, diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index fa8d21e07a..b46bbeb41e 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -40,6 +40,8 @@ #include <qcryptographichash.h> #include <qiodevice.h> +#include <qmutex.h> +#include <private/qlocking_p.h> #include "../../3rdparty/sha1/sha1.cpp" @@ -192,6 +194,8 @@ public: }; void sha3Finish(int bitCount, Sha3Variant sha3Variant); #endif + // protects result in result() + QMutex finalizeMutex; QByteArray result; }; @@ -448,6 +452,9 @@ bool QCryptographicHash::addData(QIODevice* device) */ QByteArray QCryptographicHash::result() const { + // result() is a const function, so concurrent calls are allowed; protect: + const auto lock = qt_scoped_lock(d->finalizeMutex); + // check that no other thread already finalized before us: if (!d->result.isEmpty()) return d->result; @@ -535,6 +542,7 @@ QByteArray QCryptographicHash::result() const } #endif } + return d->result; } diff --git a/src/corelib/tools/qduplicatetracker_p.h b/src/corelib/tools/qduplicatetracker_p.h index 99068c01a3..68284fb916 100644 --- a/src/corelib/tools/qduplicatetracker_p.h +++ b/src/corelib/tools/qduplicatetracker_p.h @@ -64,11 +64,18 @@ QT_BEGIN_NAMESPACE template <typename T, size_t Prealloc = 32> class QDuplicateTracker { #ifdef __cpp_lib_memory_resource - char buffer[Prealloc * sizeof(T)]; + struct node_guesstimate { void *next; size_t hash; T value; }; + static constexpr size_t bufferSize(size_t N) { + return N * sizeof(void*) // bucket list + + N * sizeof(node_guesstimate); // nodes + } + + char buffer[bufferSize(Prealloc)]; std::pmr::monotonic_buffer_resource res{buffer, sizeof buffer}; - std::pmr::unordered_set<T> set{&res}; + std::pmr::unordered_set<T> set{Prealloc, &res}; #else - QSet<T> set; + static QSet<T> makeQSet() { QSet<T> r; r.reserve(Prealloc); return r; } + QSet<T> set = makeQSet(); int setSize = 0; #endif Q_DISABLE_COPY_MOVE(QDuplicateTracker); diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index 62d2fa33ae..5cf548f4bf 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -1356,7 +1356,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. diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h index 5ba23b344b..9974102136 100644 --- a/src/corelib/tools/qfreelist_p.h +++ b/src/corelib/tools/qfreelist_p.h @@ -161,7 +161,7 @@ class QFreeList return i; x -= size; } - Q_ASSERT(false); + Q_UNREACHABLE(); return -1; } diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp index a2a7839a0b..7e13d4db92 100644 --- a/src/corelib/tools/qline.cpp +++ b/src/corelib/tools/qline.cpp @@ -529,12 +529,13 @@ 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. + 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. For lines with very short lengths + (represented by denormal floating-point values), results may be + imprecise. - A null line will not be rescaled. For non-null lines with very short lengths - (represented by denormal floating-point values), results may be imprecise. - - \sa length(), isNull(), unitVector() + \sa length(), unitVector() */ /*! diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h index 2b687c1a0a..b2f8f491ed 100644 --- a/src/corelib/tools/qline.h +++ b/src/corelib/tools/qline.h @@ -378,12 +378,11 @@ Q_DECL_CONSTEXPR inline QPointF QLineF::center() const inline void QLineF::setLength(qreal len) { - if (isNull()) - return; - Q_ASSERT(length() > 0); - const QLineF v = unitVector(); - len /= v.length(); // In case it's not quite exactly 1. - pt2 = QPointF(pt1.x() + len * v.dx(), pt1.y() + len * v.dy()); + const qreal oldLength = length(); + // 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 diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 5d5da20752..f0b92b5206 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -2017,7 +2017,7 @@ void **QListData::erase(void **xi) \include containers-range-constructor.qdocinc - \sa fromSet(), toVector(), QVector::toList() + \sa toVector(), QVector::toList() */ /*! \fn template <class T> QVector<T> QList<T>::toVector() const @@ -2030,61 +2030,91 @@ void **QListData::erase(void **xi) \include containers-range-constructor.qdocinc - \sa toSet(), fromVector(), QVector::fromList() + \sa fromVector(), QVector::fromList() */ /*! \fn template <class T> QList<T> QList<T>::fromSet(const QSet<T> &set) + \obsolete Returns a QList object with the data contained in \a set. The order of the elements in the QList is undefined. - Example: - - \snippet code/src_corelib_tools_qlistdata.cpp 23 - \include containers-range-constructor.qdocinc - \sa fromVector(), toSet(), QSet::toList() + \oldcode + QSet<int> set; + // ... + QList<int> list = QList<int>::fromSet(set); + \newcode + QSet<int> set; + // ... + QList<int> list(set.begin(), set.end()); + \endcode + + \sa QList(InputIterator, InputIterator), fromVector(), toSet(), QSet::toList() */ /*! \fn template <class T> QSet<T> QList<T>::toSet() const + \obsolete Returns a QSet object with the data contained in this QList. Since QSet doesn't allow duplicates, the resulting QSet might be smaller than the original list was. - Example: - - \snippet code/src_corelib_tools_qlistdata.cpp 24 - \include containers-range-constructor.qdocinc - \sa toVector(), fromSet(), QSet::fromList() + \oldcode + QStringList list; + // ... + QSet<QString> set = list.toSet(); + \newcode + QStringList list; + // ... + QSet<QString> set(list.begin(), list.end()); + \endcode + + \sa QSet::QSet(InputIterator, InputIterator), toVector(), fromSet(), QSet::fromList() */ /*! \fn template <class T> QList<T> QList<T>::fromStdList(const std::list<T> &list) + \obsolete Returns a QList object with the data contained in \a list. The order of the elements in the QList is the same as in \a list. - Example: - - \snippet code/src_corelib_tools_qlistdata.cpp 25 - \include containers-range-constructor.qdocinc - \sa toStdList(), QVector::fromStdVector() + \oldcode + std::list<double> stdlist; + // ... + QList<double> list = QList<double>::fromStdList(stdlist); + \newcode + std::list<double> stdlist; + // ... + QList<double> list(stdlist.begin(), stdlist.end()); + \endcode + + \sa QList(InputIterator, InputIterator), toStdList(), QVector::fromStdVector() */ /*! \fn template <class T> std::list<T> QList<T>::toStdList() const + \obsolete Returns a std::list object with the data contained in this QList. Example: - \snippet code/src_corelib_tools_qlistdata.cpp 26 - \include containers-range-constructor.qdocinc + \oldcode + QList<double> list; + // ... + std::list<double> stdlist = list.toStdList(); + \newcode + QList<double> list; + // ... + std::list<double> stdlist(list.begin(), list.end()); + \endcode + \sa fromStdList(), QVector::toStdVector() */ diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 0c69d13295..676d9a1fec 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -141,6 +141,7 @@ private: QMapNode() = delete; Q_DISABLE_COPY(QMapNode) + friend struct QMapNodeBase; }; template <class Key, class T> @@ -208,8 +209,11 @@ struct QMapData : public QMapDataBase // using reinterpret_cast because QMapDataBase::header is not // actually a QMapNode. +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wstrict-aliasing") const Node *end() const { return reinterpret_cast<const Node *>(&header); } Node *end() { return reinterpret_cast<Node *>(&header); } +QT_WARNING_POP 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(); } diff --git a/src/corelib/tools/qmargins.cpp b/src/corelib/tools/qmargins.cpp index 74be7bb2ba..3d6a62af64 100644 --- a/src/corelib/tools/qmargins.cpp +++ b/src/corelib/tools/qmargins.cpp @@ -460,7 +460,7 @@ QDebug operator<<(QDebug dbg, const QMargins &m) QMarginsF 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. + The isNull() function returns \c true only if all margins are very close to zero. QMarginsF objects can be streamed as well as compared. */ @@ -489,14 +489,16 @@ 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. */ /*! \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 qFuzzyIsNull */ @@ -557,14 +559,26 @@ QDebug operator<<(QDebug dbg, const QMargins &m) \fn bool operator==(const QMarginsF &lhs, const QMarginsF &rhs) \relates QMarginsF - Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false. + Returns \c true if \a lhs and \a rhs are approximately equal; otherwise + returns 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 - Returns \c true if \a lhs and \a rhs are different; otherwise returns \c false. + 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. + + \sa qFuzzyCompare */ /*! diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp index 40a1193622..40d120eb52 100644 --- a/src/corelib/tools/qmessageauthenticationcode.cpp +++ b/src/corelib/tools/qmessageauthenticationcode.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2023 The Qt Company Ltd. ** Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru> ** Contact: https://www.qt.io/licensing/ ** @@ -39,6 +40,8 @@ #include "qmessageauthenticationcode.h" #include "qvarlengtharray.h" +#include "qmutex.h" +#include "private/qlocking_p.h" /* These #defines replace the typedefs needed by the RFC6234 code. Normally @@ -125,11 +128,18 @@ public: QByteArray key; QByteArray result; + QMutex finalizeMutex; QCryptographicHash messageHash; QCryptographicHash::Algorithm method; bool messageHashInited; void initMessageHash(); + void finalize(); + + // when not called from the static hash() function, this function needs to be + // called with finalizeMutex held: + void finalizeUnchecked(); + // END functions that need to be called with finalizeMutex held }; void QMessageAuthenticationCodePrivate::initMessageHash() @@ -266,27 +276,36 @@ bool QMessageAuthenticationCode::addData(QIODevice *device) */ QByteArray QMessageAuthenticationCode::result() const { - if (!d->result.isEmpty()) - return d->result; + d->finalize(); + return d->result; +} - d->initMessageHash(); +void QMessageAuthenticationCodePrivate::finalize() +{ + const auto lock = qt_scoped_lock(finalizeMutex); + if (!result.isEmpty()) + return; + initMessageHash(); + finalizeUnchecked(); +} - const int blockSize = qt_hash_block_size(d->method); +void QMessageAuthenticationCodePrivate::finalizeUnchecked() +{ + const int blockSize = qt_hash_block_size(method); - QByteArray hashedMessage = d->messageHash.result(); + QByteArray hashedMessage = messageHash.result(); QVarLengthArray<char> oKeyPad(blockSize); - const char * const keyData = d->key.constData(); + const char * const keyData = key.constData(); for (int i = 0; i < blockSize; ++i) oKeyPad[i] = keyData[i] ^ 0x5c; - QCryptographicHash hash(d->method); + QCryptographicHash hash(method); hash.addData(oKeyPad.data(), oKeyPad.size()); hash.addData(hashedMessage); - d->result = hash.result(); - return d->result; + result = hash.result(); } /*! diff --git a/src/corelib/tools/qoffsetstringarray_p.h b/src/corelib/tools/qoffsetstringarray_p.h index 4dd9e9603b..e26a57ff43 100644 --- a/src/corelib/tools/qoffsetstringarray_p.h +++ b/src/corelib/tools/qoffsetstringarray_p.h @@ -55,6 +55,7 @@ #include <tuple> #include <array> +#include <limits> QT_BEGIN_NAMESPACE diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp index 432fb33297..5b9ae5314d 100644 --- a/src/corelib/tools/qpoint.cpp +++ b/src/corelib/tools/qpoint.cpp @@ -762,14 +762,26 @@ QDebug operator<<(QDebug dbg, const QPointF &p) \fn bool operator==(const QPointF &p1, const QPointF &p2) \relates QPointF - Returns \c true if \a p1 is equal to \a p2; otherwise returns \c false. + Returns \c true if \a p1 is approximately equal to \a p2; otherwise + returns \c false. + + \warning This function does not check for strict equality; instead, + it uses a fuzzy comparison to compare the points' coordinates. + + \sa qFuzzyCompare */ /*! \fn bool operator!=(const QPointF &p1, const QPointF &p2); \relates QPointF - Returns \c true if \a p1 is not equal to \a p2; otherwise returns \c false. + 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. + + \sa qFuzzyCompare */ #ifndef QT_NO_DATASTREAM diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp index 6f120b9d10..2d4c55ad85 100644 --- a/src/corelib/tools/qrect.cpp +++ b/src/corelib/tools/qrect.cpp @@ -2391,8 +2391,13 @@ QRect QRectF::toAlignedRect() const noexcept \fn bool operator==(const QRectF &r1, const QRectF &r2) \relates QRectF - 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 */ @@ -2400,8 +2405,11 @@ QRect QRectF::toAlignedRect() const noexcept \fn bool operator!=(const QRectF &r1, const QRectF &r2) \relates QRectF - 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/qscopedvaluerollback.cpp b/src/corelib/tools/qscopedvaluerollback.cpp index baca7c8229..0c1c43ac49 100644 --- a/src/corelib/tools/qscopedvaluerollback.cpp +++ b/src/corelib/tools/qscopedvaluerollback.cpp @@ -58,7 +58,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/qset.qdoc b/src/corelib/tools/qset.qdoc index 42dd1288ac..dcd6de3d5c 100644 --- a/src/corelib/tools/qset.qdoc +++ b/src/corelib/tools/qset.qdoc @@ -1071,17 +1071,32 @@ */ /*! \fn template <class T> QList<T> QSet<T>::toList() const + \obsolete Returns a new QList containing the elements in the set. The order of the elements in the QList is undefined. - Example: + \include containers-range-constructor.qdocinc - \snippet code/doc_src_qset.cpp 13 + \oldcode + QSet<QString> set; + // ... + QList<QString> list = set.toList(); + \newcode + QSet<QString> set; + // ... + QList<QString> list(set.begin(), set.end()); + \endcode - \include containers-range-constructor.qdocinc + or - \sa fromList(), QList::fromSet() + \code + QSet<QString> set; + // ... + QList<QString> list = set.values(); + \endcode + + \sa QList::QList(InputIterator, InputIterator), values(), fromList(), QList::fromSet() */ /*! \fn template <class T> QList<T> QSet<T>::values() const @@ -1089,28 +1104,44 @@ 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() + \oldcode + QSet<QString> set; + // ... + QList<QString> list = set.values(); + \newcode + QSet<QString> set; + // ... + QList<QString> list(set.begin(), set.end()); + \endcode + + + \sa QList::QList(InputIterator, InputIterator) */ /*! \fn template <class T> QSet<T> QSet<T>::fromList(const QList<T> &list) + \obsolete 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() + \oldcode + QStringList list; + // ... + QSet<QString> set = QSet<QString>::fromList(list); + \newcode + QStringList list; + // ... + QSet<QString> set(list.begin(), list.end()); + \endcode + + \sa QSet(InputIterator, InputIterator), values(), QList::toSet() */ /*! diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index a24b689181..bc7a5f80d7 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -479,6 +479,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 @@ -932,6 +972,15 @@ */ /*! + \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> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2) \relates QSharedPointer @@ -1400,7 +1449,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge } // we can create the refcount data because it doesn't exist - ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized); + ExternalRefCountData *x = ::new ExternalRefCountData(Qt::Uninitialized); x->strongref.storeRelaxed(-1); x->weakref.storeRelaxed(2); // the QWeakPointer that called us plus the QObject itself @@ -1411,7 +1460,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; diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h index 5d47369687..72e48d8a16 100644 --- a/src/corelib/tools/qsharedpointer.h +++ b/src/corelib/tools/qsharedpointer.h @@ -82,7 +82,12 @@ public: QSharedPointer<T> &operator=(const QSharedPointer<T> &other); 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; @@ -104,6 +109,9 @@ public: }; template <class T> +size_t qHash(const QSharedPointer<T> &key, size_t seed = 0) noexcept; + +template <class T> class QWeakPointer { public: diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 790c187cb9..d262e4ebc9 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -156,6 +156,12 @@ namespace QtSharedPointer { 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 *) { } }; @@ -881,7 +887,7 @@ Q_INLINE_TEMPLATE bool operator<(T *ptr1, const QSharedPointer<X> &ptr2) template <class T> Q_INLINE_TEMPLATE uint qHash(const QSharedPointer<T> &ptr, uint seed = 0) { - return QT_PREPEND_NAMESPACE(qHash)(ptr.data(), seed); + return qHash(ptr.data(), seed); } @@ -1012,15 +1018,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>(qExchange(src, nullptr), castResult); } return std::shared_ptr<X>(); } diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index 6ad6795fec..798ac93ad2 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -132,7 +132,7 @@ static inline quint64 detectProcessorFeatures() #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. + features |= CpuFeatureNEON; // NEON is always available on ARMv8 64bit. # endif int auxv = qt_safe_open("/proc/self/auxv", O_RDONLY); if (auxv != -1) { @@ -151,17 +151,17 @@ static inline quint64 detectProcessorFeatures() # 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; + features |= CpuFeatureCRC32; # endif // Aarch32, or ARMv7 or before: if (vector[i+1] & HWCAP_NEON) - features |= Q_UINT64_C(1) << CpuFeatureNEON; + features |= 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; + features |= CpuFeatureCRC32; } # endif } @@ -174,10 +174,10 @@ static inline quint64 detectProcessorFeatures() #endif #if defined(__ARM_NEON__) - features |= Q_UINT64_C(1) << CpuFeatureNEON; + features |= CpuFeatureNEON; #endif #if defined(__ARM_FEATURE_CRC32) - features |= Q_UINT64_C(1) << CpuFeatureCRC32; + features |= CpuFeatureCRC32; #endif return features; @@ -505,18 +505,18 @@ static inline quint64 detectProcessorFeatures() quint64 flags = 0; #if defined __mips_dsp - flags |= Q_UINT64_C(1) << CpuFeatureDSP; + flags |= CpuFeatureDSP; # if defined __mips_dsp_rev && __mips_dsp_rev >= 2 - flags |= Q_UINT64_C(1) << CpuFeatureDSPR2; + flags |= CpuFeatureDSPR2; # elif defined(Q_OS_LINUX) if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf")) - flags |= Q_UINT64_C(1) << CpuFeatureDSPR2; + flags |= CpuFeatureDSPR2; # endif #elif defined(Q_OS_LINUX) if (procCpuinfoContains("ASEs implemented", "dsp")) { - flags |= Q_UINT64_C(1) << CpuFeatureDSP; + flags |= CpuFeatureDSP; if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf")) - flags |= Q_UINT64_C(1) << CpuFeatureDSPR2; + flags |= CpuFeatureDSPR2; } #endif diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp index 2cbaae117d..1bc7d4c15b 100644 --- a/src/corelib/tools/qsize.cpp +++ b/src/corelib/tools/qsize.cpp @@ -751,15 +751,24 @@ QSizeF QSizeF::scaled(const QSizeF &s, Qt::AspectRatioMode mode) const noexcept \fn bool operator==(const QSizeF &s1, const QSizeF &s2) \relates QSizeF - 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 - 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. */ /*! diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h index d48318b474..ca52b15870 100644 --- a/src/corelib/tools/qtools_p.h +++ b/src/corelib/tools/qtools_p.h @@ -84,6 +84,17 @@ Q_DECL_CONSTEXPR inline int fromOct(uint c) noexcept { return ((c >= '0') && (c <= '7')) ? int(c - '0') : -1; } + +constexpr inline char toAsciiLower(char ch) noexcept +{ + return (ch >= 'A' && ch <= 'Z') ? ch - 'A' + 'a' : ch; +} + +constexpr inline char toAsciiUpper(char ch) noexcept +{ + return (ch >= 'a' && ch <= 'z') ? ch - 'a' + 'A' : ch; +} + } // We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size. diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index 6be695e317..f0e4342e06 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -49,6 +49,7 @@ #include <algorithm> #include <initializer_list> #include <iterator> +#include <memory> #include <new> #include <string.h> #include <stdlib.h> @@ -152,30 +153,18 @@ public: 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); - } + new (end()) T(std::move(copy)); } else { - const int idx = s++; - if (QTypeInfo<T>::isComplex) { - new (ptr + idx) T(t); - } else { - ptr[idx] = t; - } + new (end()) T(t); } + ++s; } 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); + new (end()) T(std::move(t)); + ++s; } void append(const T *buf, int size); @@ -249,6 +238,20 @@ public: private: void realloc(int size, int alloc); + void resize_impl(int newSize, const T &t) + { + const auto increment = newSize - size(); + if (increment > 0 && QtPrivate::q_points_into_range(&t, cbegin(), cend())) { + resize_impl(newSize, T(t)); + return; + } + realloc(qMin(size(), newSize), qMax(newSize, capacity())); + + if (increment > 0) + std::uninitialized_fill_n(end(), increment, t); + s = newSize; + } + int a; // capacity int s; // size T *ptr; // data @@ -487,57 +490,25 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA { 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; + const int offset = int(before - ptr); + append(std::move(t)); + 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) +Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, int n, const T &t) { 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 int offset = int(before - cbegin()); + resize_impl(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> @@ -549,6 +520,12 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA int f = int(abegin - ptr); int l = int(aend - ptr); int n = l - f; + + if (n == 0) // avoid UB in std::copy() below + return data() + f; + + Q_ASSERT(n > 0); // aend must be reachable from abegin + if (QTypeInfo<T>::isComplex) { std::copy(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f)); T *i = ptr + s; diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index 3dab41dd22..30f12478aa 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -90,6 +90,11 @@ \sa QVector, QList, QLinkedList */ +/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray() + + Constructs an array with an initial size of zero. +*/ + /*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(int size) Constructs an array with an initial size of \a size elements. diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 8d1b15b507..85393a3598 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -343,13 +343,8 @@ QVector(InputIterator, InputIterator) -> QVector<ValueType>; 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)); - } + while (from != to) + new (from++) T(); } template <typename T> @@ -528,7 +523,7 @@ QVector<T>::QVector(int asize, const T &t) d = Data::allocate(asize); Q_CHECK_PTR(d); d->size = asize; - T* i = d->end(); + auto i = d->end(); while (i != d->begin()) new (--i) T(t); } else { @@ -640,17 +635,13 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo 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_TRY { + while (dst != x->end()) + new (dst++) T(); + } QT_CATCH (...) { + // destruct already copied objects + destruct(x->begin(), dst); + QT_RETHROW; } } } QT_CATCH (...) { @@ -844,18 +835,25 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c 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 *const e = d->end(); + T *const b = d->begin() + offset; + + T *i = e; T *j = i + n; - b = d->begin() + offset; - while (i != b) - *--j = *--i; - i = b+n; + + // move old elements into the uninitialized space + while (i != b && j > e) + new (--j) T(std::move(*--i)); + // move the rest of old elements into the tail using assignment while (i != b) - *--i = copy; + *--j = std::move(*--i); + + // construct copies of t inside the uninitialized space + while (j != b && j > e) + new (--j) T(copy); + // use assignment to fill the recently-moved-from space + while (j != b) + *--j = copy; } else { T *b = d->begin() + offset; T *i = b + n; diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp index 58e3c15560..575d7b12a5 100644 --- a/src/corelib/tools/qversionnumber.cpp +++ b/src/corelib/tools/qversionnumber.cpp @@ -189,7 +189,7 @@ QVector<int> QVersionNumber::segments() const /*! \fn int QVersionNumber::segmentAt(int 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() diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h index d43b86ba51..d1180b54e6 100644 --- a/src/corelib/tools/qversionnumber.h +++ b/src/corelib/tools/qversionnumber.h @@ -133,8 +133,8 @@ class QVersionNumber explicit SegmentStorage(QVector<int> &&seg) { - if (dataFitsInline(seg.begin(), seg.size())) - setInlineData(seg.begin(), seg.size()); + if (dataFitsInline(seg.cbegin(), seg.size())) + setInlineData(seg.cbegin(), seg.size()); else pointer_segments = new QVector<int>(std::move(seg)); } @@ -269,14 +269,14 @@ public: Q_REQUIRED_RESULT Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept; - Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2); + Q_REQUIRED_RESULT Q_CORE_EXPORT static 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); + Q_REQUIRED_RESULT Q_CORE_EXPORT static QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr); #endif - Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex = nullptr); - Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex = nullptr); + Q_REQUIRED_RESULT Q_CORE_EXPORT static QVersionNumber fromString(QLatin1String string, int *suffixIndex = nullptr); + Q_REQUIRED_RESULT Q_CORE_EXPORT static QVersionNumber fromString(QStringView string, int *suffixIndex = nullptr); private: #ifndef QT_NO_DATASTREAM |