From b3777110abdbd682c295fb6319cc7bdb004749f3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Apr 2026 16:12:00 +0900 Subject: [PATCH] hash.c, string.c: improve hash function quality Use FNV-1a (xor-then-multiply) instead of FNV-1 for better avalanche in byte hashing. Strengthen the hash finalizer in mrb_obj_hash_code() with multiply-xorshift to improve distribution for integer and symbol keys with power-of-two table sizes. Co-authored-by: Claude --- src/hash.c | 5 ++++- src/string.c | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hash.c b/src/hash.c index 1dba928be..060bcb3c3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -361,7 +361,10 @@ mrb_obj_hash_code(mrb_state *mrb, mrb_value key) hash_code = U32(tt) ^ U32(mrb_integer(hash_code_obj)); break; } - return hash_code ^ (hash_code << 2) ^ (hash_code >> 2); + hash_code ^= hash_code >> 16; + hash_code *= 0x45d9f3b; + hash_code ^= hash_code >> 16; + return hash_code; } static uint32_t diff --git a/src/string.c b/src/string.c index d490ec310..851a42f47 100644 --- a/src/string.c +++ b/src/string.c @@ -2014,18 +2014,18 @@ mrb_byte_hash_step(const uint8_t *s, mrb_int len, uint32_t hval) const uint8_t *send = s + len; /* - * FNV-1 hash each octet in the buffer + * FNV-1a hash each octet in the buffer */ while (s < send) { + /* xor the bottom with the current octet */ + hval ^= (uint32_t)*s++; + /* multiply by the 32-bit FNV magic prime mod 2^32 */ #if defined(NO_FNV_GCC_OPTIMIZATION) hval *= FNV_32_PRIME; #else hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); #endif - - /* xor the bottom with the current octet */ - hval ^= (uint32_t)*s++; } /* return our new hash value */