Add qHash() overloads for floating-point types

This implementation is based on GCC's implementation of std::hash<FP>, 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 <thiago.macieira@intel.com>
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
bb10
Marc Mutz 2014-02-12 14:18:40 +01:00 committed by The Qt Project
parent d24cceebf2
commit c0791ac76e
3 changed files with 52 additions and 0 deletions

View File

@ -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<const uchar *>(&key), sizeof(key), seed) : seed ;
}
/*! \relates QHash
\since 5.3
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
uint qHash(double key, uint seed) Q_DECL_NOTHROW
{
return key != 0.0 ? hash(reinterpret_cast<const uchar *>(&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<const uchar *>(&key), sizeof(key), seed) : seed ;
}
#endif
/*! \fn uint qHash(QChar key, uint seed = 0)
\relates QHash
\since 5.0

View File

@ -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;

View File

@ -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<int, int> hash1;