Added Murmur3_64. (#364)

This commit is contained in:
Branimir Karadžić
2026-01-22 21:24:41 -08:00
committed by GitHub
parent d8d7d13c85
commit ef9c17cf3d
4 changed files with 312 additions and 34 deletions

View File

@@ -147,18 +147,37 @@ void HashCrc32::add(const void* _data, int32_t _len)
m_hash = hash;
}
BX_FORCE_INLINE uint32_t readAligned(const uint8_t* _data)
BX_FORCE_INLINE uint32_t readAligned32(const uint8_t* _data)
{
return *(uint32_t*)_data;
}
BX_FORCE_INLINE uint32_t readUnaligned(const uint8_t* _data)
BX_FORCE_INLINE uint32_t readUnaligned32(const uint8_t* _data)
{
return 0
| _data[3]<<24
| _data[2]<<16
| _data[1]<<8
| _data[0]
| uint32_t(_data[3])<<24
| uint32_t(_data[2])<<16
| uint32_t(_data[1])<<8
| uint32_t(_data[0])
;
}
BX_FORCE_INLINE uint64_t readAligned64(const uint8_t* _data)
{
return *(uint64_t*)_data;
}
BX_FORCE_INLINE uint64_t readUnaligned64(const uint8_t* _data)
{
return 0
| uint64_t(_data[7])<<56
| uint64_t(_data[6])<<48
| uint64_t(_data[5])<<40
| uint64_t(_data[4])<<32
| uint64_t(_data[3])<<24
| uint64_t(_data[2])<<16
| uint64_t(_data[1])<<8
| uint64_t(_data[0])
;
}
@@ -166,7 +185,7 @@ namespace
{
template<typename Ty>
void mixTail(Ty& _self, const uint8_t*& _data, int32_t& _len)
void mixTail32(Ty& _self, const uint8_t*& _data, int32_t& _len)
{
while (0 != _len
&& (0 < _self.m_count || 4 > _len) )
@@ -183,10 +202,10 @@ void mixTail(Ty& _self, const uint8_t*& _data, int32_t& _len)
}
}
typedef uint32_t (*ReadDataFn)(const uint8_t* _data);
typedef uint32_t (*ReadData32Fn)(const uint8_t* _data);
template<typename Ty, ReadDataFn FnT>
void addData(Ty& _self, const uint8_t* _data, int32_t _len)
template<typename Ty, ReadData32Fn FnT>
void addData32(Ty& _self, const uint8_t* _data, int32_t _len)
{
while (_len >= 4)
{
@@ -198,35 +217,83 @@ void addData(Ty& _self, const uint8_t* _data, int32_t _len)
_len -= 4;
}
mixTail(_self, _data, _len);
mixTail32(_self, _data, _len);
}
template<typename SelfT, typename ThisT>
void addData(ThisT* _this, const void* _data, int32_t _len)
void addData32(ThisT* _this, const void* _data, int32_t _len)
{
SelfT& self = *(SelfT*)_this;
const uint8_t* data = (const uint8_t*)_data;
self.m_size += _len;
mixTail(self, data, _len);
mixTail32(self, data, _len);
if (BX_UNLIKELY(!isAligned(data, 4) ) )
{
addData<SelfT, readUnaligned>(self, data, _len);
addData32<SelfT, readUnaligned32>(self, data, _len);
return;
}
addData<SelfT, readAligned>(self, data, _len);
addData32<SelfT, readAligned32>(self, data, _len);
}
template<typename Ty>
void mixTail128(Ty& _self, const uint8_t*& _data, int32_t& _len)
{
while (0 != _len
&& (0 < _self.m_count || 16 > _len) )
{
_self.m_tail[_self.m_count++] = *_data++;
_len--;
if (16 == _self.m_count)
{
const uint64_t kk1 = *( (uint64_t*)&_self.m_tail[0]);
const uint64_t kk2 = *( (uint64_t*)&_self.m_tail[8]);
_self.mix(kk1, kk2);
_self.m_count = 0;
}
}
}
typedef uint64_t (*ReadData64Fn)(const uint8_t* _data);
template<typename Ty, ReadData64Fn FnT>
void addData128(Ty& _self, const uint8_t* _data, int32_t _len)
{
while (_len >= 16)
{
uint64_t kk1 = FnT(_data);
uint64_t kk2 = FnT(_data + 8);
_self.mix(kk1, kk2);
_data += 16;
_len -= 16;
}
mixTail128(_self, _data, _len);
}
template<typename SelfT, typename ThisT>
uint32_t finalize(ThisT* _this)
void addData128(ThisT* _this, const void* _data, int32_t _len)
{
SelfT& self = *(SelfT*)_this;
self.finalize();
return self.m_hash;
const uint8_t* data = (const uint8_t*)_data;
self.m_size += _len;
mixTail128(self, data, _len);
if (BX_UNLIKELY(!isAligned(data, 8) ) )
{
addData128<SelfT, readUnaligned64>(self, data, _len);
return;
}
addData128<SelfT, readAligned64>(self, data, _len);
}
} // namespace
@@ -274,12 +341,14 @@ static_assert(sizeof(HashMurmur2A) == sizeof(HashMurmur2APod) );
void HashMurmur2A::add(const void* _data, int32_t _len)
{
addData<HashMurmur2APod>(this, _data, _len);
addData32<HashMurmur2APod>(this, _data, _len);
}
uint32_t HashMurmur2A::end()
{
return finalize<HashMurmur2APod>(this);
HashMurmur2APod& hash = *(HashMurmur2APod*)this;
hash.finalize();
return hash.m_hash;
}
struct HashMurmur3Pod
@@ -312,6 +381,17 @@ struct HashMurmur3Pod
m_hash = m_hash*5 + kMurmur3Add;
}
static BX_FORCE_INLINE uint32_t fmix32(uint32_t _hash)
{
_hash ^= _hash >> 16;
_hash *= kMurmur3Mul3;
_hash ^= _hash >> 13;
_hash *= kMurmur3Mul4;
_hash ^= _hash >> 16;
return _hash;
}
void finalize()
{
uint32_t kk = 0;
@@ -327,23 +407,135 @@ struct HashMurmur3Pod
m_hash ^= m_size;
m_hash ^= m_hash >> 16;
m_hash *= kMurmur3Mul3;
m_hash ^= m_hash >> 13;
m_hash *= kMurmur3Mul4;
m_hash ^= m_hash >> 16;
m_hash = fmix32(m_hash);
}
};
static_assert(sizeof(HashMurmur3) == sizeof(HashMurmur3Pod) );
void HashMurmur3::add(const void* _data, int32_t _len)
{
addData<HashMurmur3Pod>(this, _data, _len);
addData32<HashMurmur3Pod>(this, _data, _len);
}
uint32_t HashMurmur3::end()
{
return finalize<HashMurmur3Pod>(this);
HashMurmur3Pod& hash = *(HashMurmur3Pod*)this;
hash.finalize();
return hash.m_hash;
}
struct HashMurmur3_64Pod
{
uint64_t m_hash[2];
uint32_t m_size;
uint8_t m_tail[16];
uint8_t m_count;
static constexpr uint64_t kMurmur3Mul1 = 0x87c37b91114253d5ull;
static constexpr uint64_t kMurmur3Mul2 = 0x4cf5ad432745937full;
static constexpr uint64_t kMurmur3Mul3 = 0xff51afd7ed558ccdull;
static constexpr uint64_t kMurmur3Mul4 = 0xc4ceb9fe1a85ec53ull;
static constexpr uint64_t kMurmur3Add1 = 0x52dce729ull;
static constexpr uint64_t kMurmur3Add2 = 0x38495ab5ull;
BX_FORCE_INLINE void mix1(uint64_t _k)
{
_k *= kMurmur3Mul1;
_k = uint64_rol(_k, 31);
_k *= kMurmur3Mul2;
m_hash[0] ^= _k;
}
BX_FORCE_INLINE void mix2(uint64_t _k)
{
_k *= kMurmur3Mul2;
_k = uint64_rol(_k, 33);
_k *= kMurmur3Mul1;
m_hash[1] ^= _k;
}
BX_FORCE_INLINE void mix(uint64_t _k1, uint64_t _k2)
{
mix1(_k1);
m_hash[0] = uint64_rol(m_hash[0], 27);
m_hash[0] += m_hash[1];
m_hash[0] = m_hash[0]*5 + kMurmur3Add1;
mix2(_k2);
m_hash[1] = uint64_rol(m_hash[1], 31);
m_hash[1] += m_hash[0];
m_hash[1] = m_hash[1]*5 + kMurmur3Add2;
}
static BX_FORCE_INLINE uint64_t fmix64(uint64_t _hash)
{
_hash ^= _hash >> 33;
_hash *= kMurmur3Mul3;
_hash ^= _hash >> 33;
_hash *= kMurmur3Mul4;
_hash ^= _hash >> 33;
return _hash;
}
void finalize()
{
uint64_t kk[2] = { 0, 0 };
switch (m_count)
{
case 15: kk[1] ^= uint64_t(m_tail[14]) << 48; [[fallthrough]];
case 14: kk[1] ^= uint64_t(m_tail[13]) << 40; [[fallthrough]];
case 13: kk[1] ^= uint64_t(m_tail[12]) << 32; [[fallthrough]];
case 12: kk[1] ^= uint64_t(m_tail[11]) << 24; [[fallthrough]];
case 11: kk[1] ^= uint64_t(m_tail[10]) << 16; [[fallthrough]];
case 10: kk[1] ^= uint64_t(m_tail[ 9]) << 8; [[fallthrough]];
case 9: kk[1] ^= uint64_t(m_tail[ 8]); mix2(kk[1]);
[[fallthrough]];
case 8: kk[0] ^= uint64_t(m_tail[ 7]) << 56; [[fallthrough]];
case 7: kk[0] ^= uint64_t(m_tail[ 6]) << 48; [[fallthrough]];
case 6: kk[0] ^= uint64_t(m_tail[ 5]) << 40; [[fallthrough]];
case 5: kk[0] ^= uint64_t(m_tail[ 4]) << 32; [[fallthrough]];
case 4: kk[0] ^= uint64_t(m_tail[ 3]) << 24; [[fallthrough]];
case 3: kk[0] ^= uint64_t(m_tail[ 2]) << 16; [[fallthrough]];
case 2: kk[0] ^= uint64_t(m_tail[ 1]) << 8; [[fallthrough]];
case 1: kk[0] ^= uint64_t(m_tail[ 0]); mix1(kk[0]);
break;
case 0: break;
default: BX_ASSERT(false, "Bug, m_count can't be %d (expected < 16).", m_count); BX_UNREACHABLE;
}
m_hash[0] ^= m_size;
m_hash[1] ^= m_size;
m_hash[0] += m_hash[1];
m_hash[1] += m_hash[0];
m_hash[0] = fmix64(m_hash[0]);
m_hash[1] = fmix64(m_hash[1]);
m_hash[0] += m_hash[1];
m_hash[1] += m_hash[0];
}
};
static_assert(sizeof(HashMurmur3_64) == sizeof(HashMurmur3_64Pod) );
void HashMurmur3_64::add(const void* _data, int32_t _len)
{
addData128<HashMurmur3_64Pod>(this, _data, _len);
}
uint64_t HashMurmur3_64::end()
{
HashMurmur3_64Pod& hash = *(HashMurmur3_64Pod*)this;
hash.finalize();
return hash.m_hash[0];
}
} // namespace bx