diff options
Diffstat (limited to 'src/corelib/tools/qhash.cpp')
-rw-r--r-- | src/corelib/tools/qhash.cpp | 178 |
1 files changed, 112 insertions, 66 deletions
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 4cc9ec8ec8..e336b7e618 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -63,13 +63,9 @@ #ifndef QT_BOOTSTRAPPED #include <qcoreapplication.h> +#include <qrandom.h> #endif // QT_BOOTSTRAPPED -#ifdef Q_OS_UNIX -#include <stdio.h> -#include "private/qcore_unix_p.h" -#endif // Q_OS_UNIX - #include <limits.h> QT_BEGIN_NAMESPACE @@ -205,7 +201,7 @@ static inline uint hash(const uchar *p, size_t len, uint seed) Q_DECL_NOTHROW { uint h = seed; - if (hasFastCrc32()) + if (seed && hasFastCrc32()) return crc32(p, len, h); for (size_t i = 0; i < len; ++i) @@ -223,7 +219,7 @@ static inline uint hash(const QChar *p, size_t len, uint seed) Q_DECL_NOTHROW { uint h = seed; - if (hasFastCrc32()) + if (seed && hasFastCrc32()) return crc32(p, len, h); for (size_t i = 0; i < len; ++i) @@ -237,6 +233,7 @@ uint qHash(const QByteArray &key, uint seed) Q_DECL_NOTHROW return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed); } +#if QT_STRINGVIEW_LEVEL < 2 uint qHash(const QString &key, uint seed) Q_DECL_NOTHROW { return hash(key.unicode(), size_t(key.size()), seed); @@ -246,6 +243,12 @@ uint qHash(const QStringRef &key, uint seed) Q_DECL_NOTHROW { return hash(key.unicode(), size_t(key.size()), seed); } +#endif + +uint qHash(QStringView key, uint seed) Q_DECL_NOTHROW +{ + return hash(key.data(), key.size(), seed); +} uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW { @@ -283,42 +286,17 @@ static uint qt_create_qhash_seed() #ifndef QT_BOOTSTRAPPED QByteArray envSeed = qgetenv("QT_HASH_SEED"); - if (!envSeed.isNull()) - return envSeed.toUInt(); - -#ifdef Q_OS_UNIX - int randomfd = qt_safe_open("/dev/urandom", O_RDONLY); - if (randomfd == -1) - randomfd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK); - if (randomfd != -1) { - if (qt_safe_read(randomfd, reinterpret_cast<char *>(&seed), sizeof(seed)) == sizeof(seed)) { - qt_safe_close(randomfd); - return 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."); } - qt_safe_close(randomfd); - } -#endif // Q_OS_UNIX - -#if defined(Q_OS_WIN32) && !defined(Q_CC_GNU) - errno_t err; - err = rand_s(&seed); - if (err == 0) return seed; -#endif // Q_OS_WIN32 - - // general fallback: initialize from the current timestamp, pid, - // and address of a stack-local variable - quint64 timestamp = QDateTime::currentMSecsSinceEpoch(); - seed ^= timestamp; - seed ^= (timestamp >> 32); - - quint64 pid = QCoreApplication::applicationPid(); - seed ^= pid; - seed ^= (pid >> 32); + } - quintptr seedPtr = reinterpret_cast<quintptr>(&seed); - seed ^= seedPtr; - seed ^= (qulonglong(seedPtr) >> 32); // no-op on 32-bit platforms + seed = QRandomGenerator::get32(); #endif // QT_BOOTSTRAPPED return seed; @@ -374,14 +352,17 @@ int qGlobalQHashSeed() is needed. We discourage to do it in production code as it can make your application susceptible to \l{algorithmic complexity attacks}. + From Qt 5.10 and onwards, the only allowed values are 0 and -1. Passing the + value -1 will reinitialize the global QHash seed to a random value, while + the value of 0 is used to request a stable algorithm for C++ primitive + types types (like \c int) and string types (QString, QByteArray). + The seed is set in any newly created QHash. See \l{qHash} about how this seed is being used by QHash. If the environment variable \c QT_HASH_SEED is set, calling this function will result in a no-op. - Passing the value -1 will reinitialize the global QHash seed to a random value. - \sa qGlobalQHashSeed */ void qSetGlobalQHashSeed(int newSeed) @@ -392,6 +373,11 @@ void qSetGlobalQHashSeed(int newSeed) int x(qt_create_qhash_seed() & INT_MAX); qt_qhash_seed.store(x); } 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.store(newSeed & INT_MAX); } } @@ -407,37 +393,25 @@ void qSetGlobalQHashSeed(int newSeed) results. The qt_hash functions must *never* change their results. + + This function can hash discontiguous memory by invoking it on each chunk, + passing the previous's result in the next call's \a chained argument. */ -static uint qt_hash(const QChar *p, int n) Q_DECL_NOTHROW +uint qt_hash(QStringView key, uint chained) Q_DECL_NOTHROW { - uint h = 0; + auto n = key.size(); + auto p = key.utf16(); + + uint h = chained; while (n--) { - h = (h << 4) + (*p++).unicode(); + h = (h << 4) + *p++; h ^= (h & 0xf0000000) >> 23; h &= 0x0fffffff; } return h; } -/*! - \internal - \overload -*/ -uint qt_hash(const QString &key) Q_DECL_NOTHROW -{ - return qt_hash(key.unicode(), key.size()); -} - -/*! - \internal - \overload -*/ -uint qt_hash(const QStringRef &key) Q_DECL_NOTHROW -{ - return qt_hash(key.unicode(), key.size()); -} - /* The prime_deltas array contains the difference between a power of two and the next prime number: @@ -1035,6 +1009,13 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW Returns the hash value for the \a key, using \a seed to seed the calculation. */ +/*! \fn uint qHash(QStringView key, uint 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) \relates QHash \since 5.0 @@ -1254,9 +1235,8 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW should never depend on a particular QHash ordering, there may be situations 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. The contents of that variable, interpreted as a - decimal value, will be used as the seed for qHash(). Alternatively, you can - call the qSetGlobalQHashSeed() function. + variable \c QT_HASH_SEED to have the value 0. Alternatively, you can call + the qSetGlobalQHashSeed() function with the value 0. \sa QHashIterator, QMutableHashIterator, QMap, QSet */ @@ -1708,6 +1688,60 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW \sa keyBegin() */ +/*! \fn QHash::key_value_iterator QHash::keyValueBegin() + \since 5.10 + + Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the hash. + + \sa keyValueEnd() +*/ + +/*! \fn QHash::key_value_iterator QHash::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. + + \sa keyValueBegin() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::keyValueBegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the hash. + + \sa keyValueEnd() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::constKeyValueBegin() const + \since 5.10 + + Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry + in the hash. + + \sa keyValueBegin() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::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. + + \sa keyValueBegin() +*/ + +/*! \fn QHash::const_key_value_iterator QHash::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. + + \sa constKeyValueBegin() +*/ + /*! \fn QHash::iterator QHash::erase(const_iterator pos) \since 5.7 @@ -2443,6 +2477,18 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW Returns the underlying const_iterator this key_iterator is based on. */ +/*! \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. + + QHash::key_value_iterator is essentially the same as QHash::iterator + with the difference that operator*() returns a key/value pair instead of a + value. + + \sa QKeyValueIterator +*/ + /*! \fn QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash) \relates QHash |