[bug] Special case check for hashing -0.0 (#605)

* Special case check for hashing 0 floating point numbers

* Update test_hash.cpp

Co-authored-by: Jesse <jli@planarmotor.com>
Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
Jesse Li 2022-10-03 11:17:00 -07:00 committed by GitHub
parent 5faf7b0dc1
commit 52b7187324
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 12 deletions

View File

@ -91,7 +91,7 @@ namespace etl
/// Primary definition of base hash class, by default is poisoned
//*************************************************************************
template<typename T, bool IsEnum=false>
struct hash_base
struct hash_base
{
private:
hash_base(); // Can't default construct
@ -363,6 +363,10 @@ namespace etl
float v;
} u;
if (v == -0.0f)
{ // -0.0 and 0.0 are represented differently at bit level
v = 0.0f;
}
u.v = v;
return u.s;
@ -393,6 +397,10 @@ namespace etl
double v;
} u;
if (v == -0.0)
{ // -0.0 and 0.0 are represented differently at bit level
v = 0.0;
}
u.v = v;
return u.s;
@ -423,6 +431,10 @@ namespace etl
long double v;
} u;
if (v == -0.0L)
{ // -0.0 and 0.0 are represented differently at bit level
v = 0.0L;
}
u.v = v;
return u.s;
@ -465,7 +477,7 @@ namespace etl
}
};
namespace private_hash
namespace private_hash
{
//*************************************************************************
/// Specialization for enums
@ -475,11 +487,11 @@ namespace etl
{
size_t operator()(T v) const
{
if (sizeof(size_t) >= sizeof(T))
if (sizeof(size_t) >= sizeof(T))
{
return static_cast<size_t>(v);
}
else
}
else
{
return ::etl::hash<unsigned long long>()(static_cast<unsigned long long>(v));
}

View File

@ -199,6 +199,30 @@ namespace
}
}
TEST(test_hash_floating_point_negative_zero)
{
if (sizeof(float) == sizeof(size_t)) {
etl::hash<float> hasher{};
size_t hash1 = hasher(0.0);
size_t hash2 = hasher(-0.0);
CHECK_EQUAL(hash1, hash2);
}
if (sizeof(double) == sizeof(size_t)) {
etl::hash<double> hasher{};
size_t hash1 = hasher(0.0);
size_t hash2 = hasher(-0.0);
CHECK_EQUAL(hash1, hash2);
}
if (sizeof(long double) == sizeof(size_t)) {
etl::hash<long double> hasher{};
size_t hash1 = hasher(0.0);
size_t hash2 = hasher(-0.0);
CHECK_EQUAL(hash1, hash2);
}
}
//*************************************************************************
TEST(test_hash_pointer)
{
@ -231,10 +255,13 @@ namespace
//*************************************************************************
TEST(test_hash_enums)
{
enum class MyEnumClass : char {
enum class MyEnumClass : char
{
OneE = 0x1E
};
enum MyEnum : char {
enum MyEnum : char
{
MyEnum_TwoF = 0x2F
};
@ -245,17 +272,23 @@ namespace
CHECK_EQUAL(0x2F, hash);
}
TEST(test_hash_big_enums) {
//*************************************************************************
TEST(test_hash_big_enums)
{
constexpr unsigned long long big_number = 0x5AA555AA3CC333CCULL;
enum class MyBigEnumClass : unsigned long long {
enum class MyBigEnumClass : unsigned long long
{
Big = big_number
};
size_t hash = etl::hash<MyBigEnumClass>()(MyBigEnumClass::Big);
size_t expectedHash = etl::hash<unsigned long long>()(big_number);
CHECK_EQUAL(expectedHash, hash);
}
TEST(test_hash_poisoned) {
//*************************************************************************
TEST(test_hash_poisoned)
{
// Unspecialized hash<> should be disabled (unusable) - see https://en.cppreference.com/w/cpp/utility/hash
class A {};
typedef etl::hash<A> general_hasher;
@ -267,8 +300,9 @@ namespace
CHECK_FALSE(std::is_move_assignable<general_hasher>::value);
}
TEST(test_hash_custom) {
//*************************************************************************
TEST(test_hash_custom)
{
typedef etl::hash<CustomType> custom_hasher;
CHECK_TRUE(std::is_default_constructible<custom_hasher>::value);