mirror of
https://github.com/ETLCPP/etl.git
synced 2026-11-09 14:49:53 +08:00
[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:
parent
5faf7b0dc1
commit
52b7187324
@ -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));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user