summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qarraydata.cpp4
-rw-r--r--src/corelib/tools/qeasingcurve.cpp18
-rw-r--r--src/corelib/tools/qhash.cpp112
-rw-r--r--src/corelib/tools/qhash.h479
-rw-r--r--src/corelib/tools/qlist.cpp7
-rw-r--r--src/corelib/tools/qlist.h18
-rw-r--r--src/corelib/tools/qmap.cpp14
-rw-r--r--src/corelib/tools/qmap.h44
-rw-r--r--src/corelib/tools/qscopedvaluerollback.h6
-rw-r--r--src/corelib/tools/qset.h70
-rw-r--r--src/corelib/tools/qset.qdoc8
-rw-r--r--src/corelib/tools/qsimd.cpp133
12 files changed, 694 insertions, 219 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 234a44f6b6..3879b48cbb 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -143,7 +143,7 @@ qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t heade
}
result.elementCount = (bytes - unsigned(headerSize)) / unsigned(elementSize);
- result.size = bytes;
+ result.size = result.elementCount * elementSize + headerSize;
return result;
}
@@ -265,7 +265,7 @@ void QArrayData::deallocate(QArrayData *data, size_t objectSize,
return;
#endif
- Q_ASSERT_X(data == 0 || !data->ref.isStatic(), "QArrayData::deallocate",
+ Q_ASSERT_X(data == nullptr || !data->ref.isStatic(), "QArrayData::deallocate",
"Static data cannot be deleted");
::free(data);
}
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index bf2fd2e401..84430ae49a 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -443,12 +443,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; }
@@ -590,7 +590,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));
@@ -1097,7 +1097,7 @@ static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
case QEasingCurve::CosineCurve:
return &easeCosineCurve;
default:
- return 0;
+ return nullptr;
};
}
@@ -1127,7 +1127,7 @@ static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
return new QEasingCurveFunction(type, qreal(0.3), qreal(1.0), qreal(1.70158));
}
- return 0;
+ return nullptr;
}
/*!
@@ -1422,7 +1422,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) ||
@@ -1436,11 +1436,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;
}
@@ -1487,7 +1487,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;
}
/*!
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 6ec8019ba3..15f731a603 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -1120,21 +1120,6 @@ uint qHash(long double key, uint seed) noexcept
\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 only need to extract the values from a hash (not the keys),
you can also use \l{foreach}:
@@ -1435,9 +1420,8 @@ uint qHash(long double key, uint seed) noexcept
/*! \fn template <class Key, class T> int 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.
+ Returns the number of items removed which is 1 if the key exists in the hash,
+ and 0 otherwise.
\sa clear(), take(), QMultiHash::remove()
*/
@@ -1507,27 +1491,25 @@ uint qHash(long double key, uint seed) noexcept
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::uniqueKeys() const
\since 4.2
+ \obsolete
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()
+ \sa QMultiHash::uniqueKeys()
*/
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::keys() const
Returns a list containing all the keys in the hash, in an
arbitrary order. Keys that occur multiple times in the hash
- (because 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().
+ (because the method is operating on a QMultiHash) also occur
+ multiple times in the list.
The order is guaranteed to be the same as that used by values().
- \sa uniqueKeys(), values(), key()
+ \sa QMultiMap::uniqueKeys(), values(), key()
*/
/*! \fn template <class Key, class T> QList<Key> QHash<Key, T>::keys(const T &value) const
@@ -1555,7 +1537,7 @@ uint qHash(long double key, uint seed) noexcept
*/
/*! \fn template <class Key, class T> QList<T> QHash<Key, T>::values(const Key &key) const
-
+ \obsolete
\overload
Returns a list of all the values associated with the \a key,
@@ -1592,6 +1574,7 @@ uint qHash(long double key, uint seed) noexcept
*/
/*! \fn template <class Key, class T> int QHash<Key, T>::count(const Key &key) const
+ \obsolete
Returns the number of items associated with the \a key.
@@ -1803,11 +1786,22 @@ 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.
+*/
+
+/*! \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.
+
+ If a key is common to both hashes, its value will be replaced with the
+ value stored in \a other.
- \sa insertMulti()
+ \note If \a other contains multiple entries with the same key then the
+ final value of the key is undefined.
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &key, const T &value)
+ \obsolete
Inserts a new item with the \a key and a value of \a value.
@@ -1816,16 +1810,17 @@ uint qHash(long double key, uint seed) noexcept
different from insert(), which overwrites the value of an
existing item.)
+ This function is obsolete. Use QMultiHash or QMultiMap instead.
+
\sa insert(), values()
*/
/*! \fn template <class Key, class T> QHash &QHash<Key, T>::unite(const QHash &other)
+ \obsolete
Inserts all the items in the \a other hash into this hash. If a
key is common to both hashes, the resulting hash will contain the
key multiple times.
-
- \sa insertMulti()
*/
/*! \fn template <class Key, class T> bool QHash<Key, T>::empty() const
@@ -1966,10 +1961,7 @@ 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.
@@ -2036,7 +2028,7 @@ uint qHash(long double key, uint seed) noexcept
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()
*/
@@ -2198,7 +2190,7 @@ 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
@@ -2531,18 +2523,22 @@ 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
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 will allow 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
@@ -2633,7 +2629,8 @@ uint qHash(long double key, uint seed) noexcept
\sa replace()
*/
-/*! \fn template <class Key, class T> QMultiHash &QMultiHash<Key, T>::operator+=(const QMultiHash &other)
+/*! \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.
@@ -2641,6 +2638,32 @@ 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> 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> 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
@@ -2670,6 +2693,13 @@ uint qHash(long double key, uint seed) noexcept
\sa QHash::remove()
*/
+/*! \fn template <class Key, class T> int QMultiHash<Key, T>::count(const Key &key) const
+
+ Returns the number of items associated with the \a key.
+
+ \sa contains(), insert()
+*/
+
/*!
\fn template <class Key, class T> int QMultiHash<Key, T>::count(const Key &key, const T &value) const
\since 4.3
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 236e433101..0b8a0b283d 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -308,12 +308,14 @@ public:
T &operator[](const Key &key);
const T operator[](const Key &key) const;
- 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;
+#if QT_DEPRECATED_SINCE(5, 15)
+ QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList<Key> uniqueKeys() const;
+ QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QList<T> values(const Key &key) const;
+ QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") int count(const Key &key) const;
+#endif
class const_iterator;
@@ -325,7 +327,11 @@ public:
QHashData::Node *i;
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 T *pointer;
@@ -350,21 +356,25 @@ public:
i = QHashData::nextNode(i);
return r;
}
- inline iterator &operator--() {
+#if QT_DEPRECATED_SINCE(5, 15)
+ inline QT_DEPRECATED iterator &operator--()
+ {
i = QHashData::previousNode(i);
return *this;
}
- inline iterator operator--(int) {
+ inline QT_DEPRECATED iterator operator--(int)
+ {
iterator r = *this;
i = QHashData::previousNode(i);
return r;
}
- inline iterator operator+(int j) const
+ inline QT_DEPRECATED 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 QT_DEPRECATED iterator operator-(int j) const { return operator+(-j); }
+ inline QT_DEPRECATED iterator &operator+=(int j) { return *this = *this + j; }
+ inline QT_DEPRECATED iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline QT_DEPRECATED iterator operator+(int j, iterator k) { return k + j; }
+#endif
#ifndef QT_STRICT_ITERATORS
public:
@@ -380,11 +390,16 @@ public:
{
friend class iterator;
friend class QHash<Key, T>;
+ friend class QMultiHash<Key, T>;
friend class QSet<Key>;
QHashData::Node *i;
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;
@@ -416,21 +431,28 @@ public:
i = QHashData::nextNode(i);
return r;
}
- inline const_iterator &operator--() {
+#if QT_DEPRECATED_SINCE(5, 15)
+ inline QT_DEPRECATED const_iterator &operator--()
+ {
i = QHashData::previousNode(i);
return *this;
}
- inline const_iterator operator--(int) {
+ inline QT_DEPRECATED const_iterator operator--(int)
+ {
const_iterator r = *this;
i = QHashData::previousNode(i);
return r;
}
- inline const_iterator operator+(int j) const
+ inline QT_DEPRECATED 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; }
+ inline QT_DEPRECATED const_iterator operator-(int j) const { return operator+(-j); }
+ inline QT_DEPRECATED const_iterator &operator+=(int j) { return *this = *this + j; }
+ inline QT_DEPRECATED const_iterator &operator-=(int j) { return *this = *this - j; }
+ friend inline QT_DEPRECATED const_iterator operator+(int j, const_iterator k)
+ {
+ return k + j;
+ }
+#endif
// ### Qt 5: not sure this is necessary anymore
#ifdef QT_STRICT_ITERATORS
@@ -462,8 +484,14 @@ public:
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--); }
+#if QT_DEPRECATED_SINCE(5, 15)
+ inline QT_DEPRECATED key_iterator &operator--()
+ {
+ --i;
+ return *this;
+ }
+ inline QT_DEPRECATED key_iterator operator--(int) { return key_iterator(i--); }
+#endif
const_iterator base() const { return i; }
};
@@ -501,8 +529,11 @@ public:
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);
+ void insert(const QHash &hash);
+#if QT_DEPRECATED_SINCE(5, 15)
+ QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") iterator insertMulti(const Key &key, const T &value);
+ QT_DEPRECATED_X("Use QMultiHash for hashes storing multiple values with the same key.") QHash &unite(const QHash &other);
+#endif
// STL compatibility
typedef T mapped_type;
@@ -544,6 +575,7 @@ private:
#endif
}
friend class QSet<Key>;
+ friend class QMultiHash<Key, T>;
};
@@ -582,22 +614,6 @@ QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anex
}
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());
- }
- }
- return *this;
-}
-
-template <class Key, class T>
Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x)
{
x->free_helper(deleteNode2);
@@ -656,26 +672,6 @@ Q_INLINE_TEMPLATE const T QHash<Key, T>::value(const Key &akey, const T &adefaul
}
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());
- }
- }
-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;
@@ -734,32 +730,6 @@ Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values() const
}
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;
-}
-
-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;
-}
-
-template <class Key, class T>
Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const
{
return value(akey);
@@ -800,15 +770,28 @@ Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insert(const K
}
template <class Key, class T>
-Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &akey,
- const T &avalue)
+Q_INLINE_TEMPLATE void QHash<Key, T>::insert(const QHash &hash)
{
+ if (d == hash.d)
+ return;
+
detach();
- d->willGrow();
- uint h;
- Node **nextNode = findNode(akey, &h);
- return iterator(createNode(h, akey, avalue, nextNode));
+ QHashData::Node *i = hash.d->firstNode();
+ QHashData::Node *end = reinterpret_cast<QHashData::Node *>(hash.e);
+ while (i != end) {
+ Node *n = concrete(i);
+ Node **node = findNode(n->key, n->h);
+ if (*node == e) {
+ if (d->willGrow())
+ node = findNode(n->key, n->h);
+ createNode(n->h, n->key, n->value, node);
+ } else {
+ if (!std::is_same<T, QHashDummyValue>::value)
+ (*node)->value = n->value;
+ }
+ i = QHashData::nextNode(i);
+ }
}
template <class Key, class T>
@@ -1061,11 +1044,12 @@ public:
inline typename QHash<Key, T>::iterator replace(const Key &key, const T &value)
{ return QHash<Key, T>::insert(key, value); }
- inline typename QHash<Key, T>::iterator insert(const Key &key, const T &value)
- { return QHash<Key, T>::insertMulti(key, value); }
+ typename QHash<Key, T>::iterator insert(const Key &key, const T &value);
+
+ inline QMultiHash &unite(const QMultiHash &other);
inline QMultiHash &operator+=(const QMultiHash &other)
- { this->unite(other); return *this; }
+ { return unite(other); }
inline QMultiHash operator+(const QMultiHash &other) const
{ QMultiHash result = *this; result += other; return result; }
@@ -1074,13 +1058,27 @@ public:
using QHash<Key, T>::count;
using QHash<Key, T>::find;
using QHash<Key, T>::constFind;
+ using QHash<Key, T>::values;
+ using QHash<Key, T>::findNode;
+ using QHash<Key, T>::createNode;
+ using QHash<Key, T>::concrete;
+ using QHash<Key, T>::detach;
+
+ using typename QHash<Key, T>::Node;
+ using typename QHash<Key, T>::iterator;
+ using typename QHash<Key, T>::const_iterator;
bool contains(const Key &key, const T &value) const;
int remove(const Key &key, const T &value);
+ int count(const Key &key) const;
int count(const Key &key, const T &value) const;
+ QList<Key> uniqueKeys() const;
+
+ QList<T> values(const Key &akey) const;
+
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());
@@ -1109,6 +1107,50 @@ private:
};
template <class Key, class T>
+Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QMultiHash<Key, T>::insert(const Key &akey, const T &avalue)
+{
+ detach();
+ this->d->willGrow();
+
+ uint h;
+ Node **nextNode = findNode(akey, &h);
+ return iterator(createNode(h, akey, avalue, nextNode));
+}
+
+template <class Key, class T>
+Q_INLINE_TEMPLATE QMultiHash<Key, T> &QMultiHash<Key, T>::unite(const QMultiHash &other)
+{
+ if (this->d == &QHashData::shared_null) {
+ *this = other;
+ } else {
+#if QT_DEPRECATED_SINCE(5, 15)
+ QMultiHash copy(other);
+ const_iterator it = copy.constEnd();
+ while (it != copy.constBegin()) {
+ it.i = QHashData::previousNode(it.i);
+ insert(it.key(), it.value());
+ }
+#else
+ const QMultiHash copy(other);
+ const_iterator it = copy.cbegin();
+ const const_iterator end = copy.cend();
+ while (it != end) {
+ const auto rangeStart = it++;
+ while (it != end && rangeStart.key() == it.key())
+ ++it;
+ const qint64 last = std::distance(rangeStart, it) - 1;
+ for (qint64 i = last; i >= 0; --i) {
+ auto next = std::next(rangeStart, i);
+ insert(next.key(), next.value());
+ }
+ }
+#endif
+ }
+ return *this;
+}
+
+
+template <class Key, class T>
Q_INLINE_TEMPLATE bool QMultiHash<Key, T>::contains(const Key &key, const T &value) const
{
return constFind(key, value) != QHash<Key, T>::constEnd();
@@ -1145,8 +1187,257 @@ Q_INLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &key, const T &value)
return n;
}
-Q_DECLARE_ASSOCIATIVE_ITERATOR(Hash)
-Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR(Hash)
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QList<Key> QMultiHash<Key, T>::uniqueKeys() const
+{
+ QList<Key> res;
+ res.reserve(QHash<Key, T>::size()); // May be too much, but assume short lifetime
+ typename QHash<Key, T>::const_iterator i = QHash<Key, T>::begin();
+ if (i != QHash<Key, T>::end()) {
+ for (;;) {
+ const Key &aKey = i.key();
+ res.append(aKey);
+ do {
+ if (++i == QHash<Key, T>::end())
+ goto break_out_of_outer_loop;
+ } while (aKey == i.key());
+ }
+ }
+break_out_of_outer_loop:
+ return res;
+}
+
+#if QT_DEPRECATED_SINCE(5, 15)
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insertMulti(const Key &key, const T &value) {
+ return static_cast<QMultiHash<Key, T> *>(this)->insert(key, value);
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash &other) {
+ return static_cast<QMultiHash<Key, T> *>(this)->unite(other);
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QList<T> QHash<Key, T>::values(const Key &akey) const
+{
+ return static_cast<const QMultiHash<Key, T> *>(this)->values(akey);
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE int QHash<Key, T>::count(const Key &akey) const
+{
+ return static_cast<const QMultiHash<Key, T> *>(this)->count(akey);
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QList<Key> QHash<Key, T>::uniqueKeys() const
+{
+ return static_cast<const QMultiHash<Key, T> *>(this)->uniqueKeys();
+}
+#endif
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE QList<T> QMultiHash<Key, T>::values(const Key &akey) const
+{
+ QList<T> res;
+ Node *node = *findNode(akey);
+ if (node != this->e) {
+ do {
+ res.append(node->value);
+ } while ((node = node->next) != this->e && node->key == akey);
+ }
+ return res;
+}
+
+template <class Key, class T>
+Q_OUTOFLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &akey) const
+{
+ int cnt = 0;
+ Node *node = *findNode(akey);
+ if (node != this->e) {
+ do {
+ ++cnt;
+ } while ((node = node->next) != this->e && node->key == akey);
+ }
+ return cnt;
+}
+
+template <class Key, class T>
+class QHashIterator
+{
+ typedef typename QHash<Key, T>::const_iterator const_iterator;
+ typedef const_iterator Item;
+ QHash<Key, T> c;
+ const_iterator i, n;
+ inline bool item_exists() const { return n != c.constEnd(); }
+
+public:
+ inline QHashIterator(const QHash<Key, T> &container)
+ : c(container), i(c.constBegin()), n(c.constEnd())
+ {
+ }
+ inline QHashIterator &operator=(const QHash<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;
+ }
+#if QT_DEPRECATED_SINCE(5, 15)
+ inline QT_DEPRECATED bool hasPrevious() const { return i != c.constBegin(); }
+ inline QT_DEPRECATED Item previous()
+ {
+ n = --i;
+ return n;
+ }
+ inline QT_DEPRECATED Item peekPrevious() const
+ {
+ const_iterator p = i;
+ return --p;
+ }
+ inline bool QT_DEPRECATED findPrevious(const T &t)
+ {
+ while (i != c.constBegin())
+ if (*(n = --i) == t)
+ return true;
+ n = c.constEnd();
+ return false;
+ }
+#endif
+};
+
+template<class Key, class T>
+class QMutableHashIterator
+{
+ typedef typename QHash<Key, T>::iterator iterator;
+ typedef typename QHash<Key, T>::const_iterator const_iterator;
+ typedef iterator Item;
+ QHash<Key, T> *c;
+ iterator i, n;
+ inline bool item_exists() const { return const_iterator(n) != c->constEnd(); }
+
+public:
+ inline QMutableHashIterator(QHash<Key, T> &container) : c(&container)
+ {
+ i = c->begin();
+ n = c->end();
+ }
+ inline QMutableHashIterator &operator=(QHash<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;
+ }
+#if QT_DEPRECATED_SINCE(5, 15)
+ inline QT_DEPRECATED bool hasPrevious() const { return const_iterator(i) != c->constBegin(); }
+ inline QT_DEPRECATED Item previous()
+ {
+ n = --i;
+ return n;
+ }
+ inline QT_DEPRECATED Item peekPrevious() const
+ {
+ iterator p = i;
+ return --p;
+ }
+ inline QT_DEPRECATED bool findPrevious(const T &t)
+ {
+ while (const_iterator(i) != c->constBegin())
+ if (*(n = --i) == t)
+ return true;
+ n = c->end();
+ return false;
+ }
+#endif
+};
template <class Key, class T>
uint qHash(const QHash<Key, T> &key, uint seed = 0)
diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp
index 66770f6866..5d5da20752 100644
--- a/src/corelib/tools/qlist.cpp
+++ b/src/corelib/tools/qlist.cpp
@@ -847,9 +847,10 @@ void **QListData::erase(void **xi)
/*! \fn template <class T> void QList<T>::insert(int i, const T &value)
- Inserts \a value at index position \a i in the list. If \a i <= 0,
- the value is prepended to the list. If \a i >= size(), the
- value is appended to the list.
+ Inserts \a value at index position \a i in the list.
+
+ If \a i == 0, the value is prepended to the list. If \a i == size(),
+ the value is appended to the list.
Example:
\snippet code/src_corelib_tools_qlistdata.cpp 8
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 425ffa42a5..ffd470efcd 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -580,8 +580,16 @@ inline T &QList<T>::operator[](int i)
detach(); return reinterpret_cast<Node *>(p.at(i))->t(); }
template <typename T>
inline void QList<T>::removeAt(int i)
-{ if(i >= 0 && i < p.size()) { detach();
- node_destruct(reinterpret_cast<Node *>(p.at(i))); p.remove(i); } }
+{
+#if !QT_DEPRECATED_SINCE(5, 15)
+ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::removeAt", "index out of range");
+#elif !defined(QT_NO_DEBUG)
+ if (i < 0 || i >= p.size())
+ qWarning("QList::removeAt(): Index out of range.");
+#endif
+ detach();
+ node_destruct(reinterpret_cast<Node *>(p.at(i))); p.remove(i);
+}
template <typename T>
inline T QList<T>::takeAt(int i)
{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::take", "index out of range");
@@ -676,6 +684,12 @@ inline void QList<T>::prepend(const T &t)
template <typename T>
inline void QList<T>::insert(int i, const T &t)
{
+#if !QT_DEPRECATED_SINCE(5, 15)
+ Q_ASSERT_X(i >= 0 && i <= p.size(), "QList<T>::insert", "index out of range");
+#elif !defined(QT_NO_DEBUG)
+ if (i < 0 || i > p.size())
+ qWarning("QList::insert(): Index out of range.");
+#endif
if (d->ref.isShared()) {
Node *n = detach_helper_grow(i, 1);
QT_TRY {
diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp
index a0ec372f9a..970373101f 100644
--- a/src/corelib/tools/qmap.cpp
+++ b/src/corelib/tools/qmap.cpp
@@ -1150,6 +1150,20 @@ void QMapDataBase::freeData(QMapDataBase *d)
\sa insertMulti()
*/
+/*! \fn template <class Key, class T> void QMap<Key, T>::insert(const QMap<Key, T> &map)
+ \since 5.15
+
+ Inserts all the items in \a map into this map.
+
+ If a key is common to both maps, its value will be replaced with
+ the value stored in \a map.
+
+ \note If \a map contains multiple entries with the same key then the
+ final value of the key is undefined.
+
+ \sa insertMulti()
+*/
+
/*! \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.
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 18c681581f..fa736e8413 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -578,6 +578,7 @@ public:
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);
+ void insert(const QMap<Key, T> &map);
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);
@@ -789,6 +790,49 @@ typename QMap<Key, T>::iterator QMap<Key, T>::insert(const_iterator pos, const K
}
template <class Key, class T>
+Q_INLINE_TEMPLATE void QMap<Key, T>::insert(const QMap<Key, T> &map)
+{
+ if (d == map.d)
+ return;
+
+ detach();
+
+ Node *n = d->root();
+ auto it = map.cbegin();
+ const auto e = map.cend();
+ while (it != e) {
+ // Insertion here is based on insert(Key, T)
+ auto parent = d->end();
+ bool left = true;
+ Node *lastNode = nullptr;
+ while (n) {
+ parent = n;
+ if (!qMapLessThanKey(n->key, it.key())) {
+ lastNode = n;
+ n = n->leftNode();
+ left = true;
+ } else {
+ n = n->rightNode();
+ left = false;
+ }
+ }
+ if (lastNode && !qMapLessThanKey(it.key(), lastNode->key)) {
+ lastNode->value = it.value();
+ n = lastNode;
+ } else {
+ n = d->createNode(it.key(), it.value(), parent, left);
+ }
+ ++it;
+ if (it != e) {
+ // Move back up the tree until we find the next branch or node which is
+ // relevant for the next key.
+ while (n != d->root() && qMapLessThanKey(n->key, it.key()))
+ n = static_cast<Node *>(n->parent());
+ }
+ }
+}
+
+template <class Key, class T>
Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key &akey,
const T &avalue)
{
diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h
index f904b8dfcb..b8ceff6665 100644
--- a/src/corelib/tools/qscopedvaluerollback.h
+++ b/src/corelib/tools/qscopedvaluerollback.h
@@ -45,7 +45,11 @@
QT_BEGIN_NAMESPACE
template <typename T>
-class QScopedValueRollback
+class
+#if QT_HAS_CPP_ATTRIBUTE(nodiscard) && __cplusplus >= 201703L
+[[nodiscard]]
+#endif
+QScopedValueRollback
{
public:
explicit QScopedValueRollback(T &var)
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index 2e72832185..879e2176f2 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -108,7 +108,11 @@ 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;
@@ -128,13 +132,15 @@ public:
{ return i != o.i; }
inline iterator &operator++() { ++i; return *this; }
inline iterator operator++(int) { iterator r = *this; ++i; return r; }
- inline iterator &operator--() { --i; return *this; }
- inline iterator operator--(int) { iterator r = *this; --i; return r; }
- inline iterator operator+(int j) const { return i + j; }
- inline iterator operator-(int j) const { return i - j; }
- friend inline iterator operator+(int j, iterator k) { return k + j; }
- inline iterator &operator+=(int j) { i += j; return *this; }
- inline iterator &operator-=(int j) { i -= j; return *this; }
+#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
@@ -145,7 +151,11 @@ 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;
@@ -163,19 +173,18 @@ 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; }
- inline const_iterator &operator--() { --i; return *this; }
- inline const_iterator operator--(int) { const_iterator r = *this; --i; return r; }
- inline const_iterator operator+(int j) const { return i + j; }
- inline const_iterator operator-(int j) const { return i - j; }
- friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
- inline const_iterator &operator+=(int j) { i += j; return *this; }
- inline const_iterator &operator-=(int j) { i -= j; return *this; }
+#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
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
inline iterator begin() { return q_hash.begin(); }
inline const_iterator begin() const noexcept { return q_hash.begin(); }
inline const_iterator cbegin() const noexcept { return q_hash.begin(); }
@@ -185,12 +194,17 @@ public:
inline const_iterator cend() const noexcept { return q_hash.end(); }
inline const_iterator constEnd() const noexcept { return q_hash.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()); }
+#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)); }
@@ -429,17 +443,19 @@ public:
inline bool hasNext() const { return c->constEnd() != i; }
inline const T &next() { n = i++; return *n; }
inline const T &peekNext() const { return *i; }
- inline bool hasPrevious() const { return c->constBegin() != i; }
- inline const T &previous() { n = --i; return *n; }
- inline const T &peekPrevious() const { iterator p = i; return *--p; }
inline void remove()
{ if (c->constEnd() != n) { i = c->erase(n); n = c->end(); } }
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; }
- inline bool findPrevious(const T &t)
+#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
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
index 78854be0de..33a0697e12 100644
--- a/src/corelib/tools/qset.qdoc
+++ b/src/corelib/tools/qset.qdoc
@@ -906,8 +906,6 @@
Calling this function on QSet<T>::constEnd() leads to
undefined results.
-
- \sa operator--()
*/
/*!
@@ -924,6 +922,7 @@
/*!
\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.
@@ -937,6 +936,7 @@
/*!
\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
@@ -947,6 +947,7 @@
/*!
\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.)
@@ -959,6 +960,7 @@
/*!
\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.)
@@ -971,6 +973,7 @@
/*!
\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.)
@@ -983,6 +986,7 @@
/*!
\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.)
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index fb9b5996f6..75c380ee8a 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
+** Copyright (C) 2019 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -188,6 +188,8 @@ static inline quint64 detectProcessorFeatures()
# define PICreg "%%rbx"
#endif
+static bool checkRdrndWorks() noexcept;
+
static int maxBasicCpuidSupported()
{
#if defined(Q_CC_EMSCRIPTEN)
@@ -376,37 +378,8 @@ static quint64 detectProcessorFeatures()
features &= ~AllAVX512;
}
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
- /**
- * 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
- */
- if (features & CpuFeatureRDRND) {
- const qsizetype testBufferSize = 4;
- unsigned testBuffer[4] = {};
-
- const qsizetype generated = qRandomCpu(testBuffer, testBufferSize);
-
- if (Q_UNLIKELY(generated == testBufferSize &&
- testBuffer[0] == testBuffer[1] &&
- testBuffer[1] == testBuffer[2] &&
- testBuffer[2] == testBuffer[3])) {
-
- fprintf(stderr, "WARNING: CPU random generator seem to be failing, disable hardware random number generation\n");
- fprintf(stderr, "WARNING: RDRND generated: 0x%x 0x%x 0x%x 0x%x\n",
- testBuffer[0], testBuffer[1], testBuffer[2], testBuffer[3]);
-
- features &= ~CpuFeatureRDRND;
- }
- }
-#endif
+ if (features & CpuFeatureRDRND && !checkRdrndWorks())
+ features &= ~(CpuFeatureRDRND | CpuFeatureRDSEED);
return features;
}
@@ -626,16 +599,45 @@ void qDumpCPUFeatures()
# 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
-QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
+# if QT_COMPILER_SUPPORTS_HERE(RDSEED)
+static QT_FUNCTION_TARGET(RDSEED) unsigned *qt_random_rdseed(unsigned *ptr, unsigned *end) noexcept
{
- unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
- unsigned *end = ptr + count;
- int retries = 10;
+ // 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);
@@ -653,9 +655,64 @@ QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) no
}
out:
- return ptr - reinterpret_cast<unsigned *>(buffer);
+ 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;
}
-#endif
+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