diff --git a/src/core/json/include/sourcemeta/core/json_hash.h b/src/core/json/include/sourcemeta/core/json_hash.h index 14bfe9b35..5231b3512 100644 --- a/src/core/json/include/sourcemeta/core/json_hash.h +++ b/src/core/json/include/sourcemeta/core/json_hash.h @@ -49,7 +49,6 @@ template struct PropertyHashJSON { -> hash_type { hash_type result; assert(!value.empty()); - assert(value.size() <= 31); // Copy starting a byte 2 std::memcpy(reinterpret_cast(&result) + 1, value.data(), size); return result; @@ -126,18 +125,20 @@ template struct PropertyHashJSON { // This case is specifically designed to be constant with regards to // string length, and to exploit the fact that most JSON objects don't // have a lot of entries, so hash collision is not as common - return {1 + - (size + static_cast(value.front()) + + auto hash = this->perfect(value, 31); + hash.a |= + 1 + (size + static_cast(value.front()) + static_cast(value.back())) % // Make sure the property hash can never exceed 8 bits - 255}; + 255; + return hash; } } inline auto is_perfect(const hash_type &hash) const noexcept -> bool { // If there is anything written past the first byte, // then it is a perfect hash - return hash.a > 255; + return (hash.a & 255) == 0; } }; diff --git a/test/json/json_hash_test.cc b/test/json/json_hash_test.cc index 1f3094c1c..03bc3aa5b 100644 --- a/test/json/json_hash_test.cc +++ b/test/json/json_hash_test.cc @@ -7,7 +7,7 @@ TEST(JSON_key_hash, hash_empty) { hasher; const sourcemeta::core::JSON::String value{""}; const auto hash{hasher(value)}; - EXPECT_FALSE(hasher.is_perfect(hash)); + EXPECT_TRUE(hasher.is_perfect(hash)); #if defined(__SIZEOF_INT128__) EXPECT_EQ(hash.a, (__uint128_t{0x0000000000000000} << 64) | 0x0000000000000000); @@ -619,15 +619,15 @@ TEST(JSON_key_hash, hash_fooooooooooooooooooooooooooooooo) { EXPECT_FALSE(hasher.is_perfect(hash)); #if defined(__SIZEOF_INT128__) EXPECT_EQ(hash.a, - (__uint128_t{0x0000000000000000} << 64) | 0x00000000000000f6); + (__uint128_t{0x6f6f6f6f6f6f6f6f} << 64) | 0x6f6f6f6f6f6f66f6); EXPECT_EQ(hash.b, - (__uint128_t{0x0000000000000000} << 64) | 0x0000000000000000); + (__uint128_t{0x6f6f6f6f6f6f6f6f} << 64) | 0x6f6f6f6f6f6f6f6f); #else // 0x20 (length) + 0x66 (f) + 0x6f (o) - EXPECT_EQ(hash.a, 0x00000000000000f6); - EXPECT_EQ(hash.b, 0x0000000000000000); - EXPECT_EQ(hash.c, 0x0000000000000000); - EXPECT_EQ(hash.d, 0x0000000000000000); + EXPECT_EQ(hash.a, 0x6f6f6f6f6f6f66f6); + EXPECT_EQ(hash.b, 0x6f6f6f6f6f6f6f6f); + EXPECT_EQ(hash.c, 0x6f6f6f6f6f6f6f6f); + EXPECT_EQ(hash.d, 0x6f6f6f6f6f6f6f6f); #endif } @@ -643,14 +643,14 @@ TEST(JSON_key_hash, hash_no_collision) { EXPECT_FALSE(hasher.is_perfect(hash)); #if defined(__SIZEOF_INT128__) EXPECT_EQ(hash.a, - (__uint128_t{0x0000000000000000} << 64) | 0x0000000000000003); + (__uint128_t{0x6161616161616161} << 64) | 0x6161616161617A03); EXPECT_EQ(hash.b, - (__uint128_t{0x0000000000000000} << 64) | 0x0000000000000000); + (__uint128_t{0x6161616161616161} << 64) | 0x6161616161616161); #else // 0x10C (length) + 0x7A (z) + 0x7A (z) - EXPECT_EQ(hash.a, 0x0000000000000003); - EXPECT_EQ(hash.b, 0x0000000000000000); - EXPECT_EQ(hash.c, 0x0000000000000000); - EXPECT_EQ(hash.d, 0x0000000000000000); + EXPECT_EQ(hash.a, 0x6161616161617A03); + EXPECT_EQ(hash.b, 0x6161616161616161); + EXPECT_EQ(hash.c, 0x6161616161616161); + EXPECT_EQ(hash.d, 0x6161616161616161); #endif }