From c0791ac76ec7cfdc3945efa67a6f72ee3623413c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 12 Feb 2014 14:18:40 +0100 Subject: [PATCH] Add qHash() overloads for floating-point types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implementation is based on GCC's implementation of std::hash, but only to the extent of checking for zero before hashing the bits. The bit hasher is the Qt one; I didn't even look what GCC uses. The check against 0.0 is mandated by the requirement to have \forall x,y: x == y => qHash(x) == qHash(y) which would be violated for x = 0.0 and y = -0.0 if we only hashed the bits. Implemented out-of-line to avoid potential FP-comparison warnings, as well as to be able to use the file-static hash() functions, which gets inlined unlike qHashBits(), which cannot be. [ChangeLog][QtCore][QHash/QSet] Allowed to use float, double and long double as QHash/QSet keys. Change-Id: I38cec4afb860f17e9f8be7b67544e58b330f8fff Reviewed-by: Thiago Macieira Reviewed-by: Jędrzej Nowacki --- src/corelib/tools/qhash.cpp | 32 ++++++++++++++++++++ src/corelib/tools/qhash.h | 5 +++ tests/auto/corelib/tools/qhash/tst_qhash.cpp | 15 +++++++++ 3 files changed, 52 insertions(+) diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 18d1cee0eb..5320ea1fbf 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -737,6 +737,38 @@ void QHashData::checkSanity() Returns the hash value for the \a key, using \a seed to seed the calculation. */ +/*! \relates QHash + \since 5.3 + + Returns the hash value for the \a key, using \a seed to seed the calculation. +*/ +uint qHash(float key, uint seed) Q_DECL_NOTHROW +{ + return key != 0.0f ? hash(reinterpret_cast(&key), sizeof(key), seed) : seed ; +} + +/*! \relates QHash + \since 5.3 + + Returns the hash value for the \a key, using \a seed to seed the calculation. +*/ +uint qHash(double key, uint seed) Q_DECL_NOTHROW +{ + return key != 0.0 ? hash(reinterpret_cast(&key), sizeof(key), seed) : seed ; +} + +#ifndef Q_OS_DARWIN +/*! \relates QHash + \since 5.3 + + Returns the hash value for the \a key, using \a seed to seed the calculation. +*/ +uint qHash(long double key, uint seed) Q_DECL_NOTHROW +{ + return key != 0.0L ? hash(reinterpret_cast(&key), sizeof(key), seed) : seed ; +} +#endif + /*! \fn uint qHash(QChar key, uint seed = 0) \relates QHash \since 5.0 diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 9dd0e6144d..d4bf8df442 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -85,6 +85,11 @@ inline uint qHash(quint64 key, uint seed = 0) Q_DECL_NOTHROW } } inline uint qHash(qint64 key, uint seed = 0) Q_DECL_NOTHROW { return qHash(quint64(key), seed); } +Q_CORE_EXPORT uint qHash(float key, uint seed = 0) Q_DECL_NOTHROW; +Q_CORE_EXPORT uint qHash(double key, uint seed = 0) Q_DECL_NOTHROW; +#ifndef Q_OS_DARWIN +Q_CORE_EXPORT uint qHash(long double key, uint seed = 0) Q_DECL_NOTHROW; +#endif inline uint qHash(QChar key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.unicode(), seed); } Q_CORE_EXPORT uint qHash(const QByteArray &key, uint seed = 0) Q_DECL_NOTHROW; Q_CORE_EXPORT uint qHash(const QString &key, uint seed = 0) Q_DECL_NOTHROW; diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index af1c7aed15..ddb72a3c32 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -64,6 +64,7 @@ private slots: void rehash_isnt_quadratic(); void dont_need_default_constructor(); void qhash(); + void fp_qhash_of_zero_is_zero(); void qmultihash_specific(); void compare(); @@ -1043,6 +1044,20 @@ void tst_QHash::qhash() } } +void tst_QHash::fp_qhash_of_zero_is_zero() +{ + QCOMPARE(qHash(-0.0f), 0U); + QCOMPARE(qHash( 0.0f), 0U); + + QCOMPARE(qHash(-0.0 ), 0U); + QCOMPARE(qHash( 0.0 ), 0U); + +#ifndef Q_OS_DARWIN + QCOMPARE(qHash(-0.0L), 0U); + QCOMPARE(qHash( 0.0L), 0U); +#endif +} + void tst_QHash::qmultihash_specific() { QMultiHash hash1;