172 lines
2.8 KiB
C++
172 lines
2.8 KiB
C++
/*
|
|
* Copyright 2010-2016 Branimir Karadzic. All rights reserved.
|
|
* License: https://github.com/bkaradzic/bx#license-bsd-2-clause
|
|
*/
|
|
|
|
#ifndef BX_HASH_H_HEADER_GUARD
|
|
#define BX_HASH_H_HEADER_GUARD
|
|
|
|
#include "bx.h"
|
|
|
|
namespace bx
|
|
{
|
|
// MurmurHash2 was written by Austin Appleby, and is placed in the public
|
|
// domain. The author hereby disclaims copyright to this source code.
|
|
|
|
#define MURMUR_M 0x5bd1e995
|
|
#define MURMUR_R 24
|
|
#define mmix(_h, _k) { _k *= MURMUR_M; _k ^= _k >> MURMUR_R; _k *= MURMUR_M; _h *= MURMUR_M; _h ^= _k; }
|
|
|
|
class HashMurmur2A
|
|
{
|
|
public:
|
|
void begin(uint32_t _seed = 0)
|
|
{
|
|
m_hash = _seed;
|
|
m_tail = 0;
|
|
m_count = 0;
|
|
m_size = 0;
|
|
}
|
|
|
|
void add(const void* _data, int _len)
|
|
{
|
|
if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN)
|
|
&& BX_UNLIKELY(!isPtrAligned(_data, 4) ) )
|
|
{
|
|
addUnaligned(_data, _len);
|
|
return;
|
|
}
|
|
|
|
addAligned(_data, _len);
|
|
}
|
|
|
|
void addAligned(const void* _data, int _len)
|
|
{
|
|
const uint8_t* data = (const uint8_t*)_data;
|
|
m_size += _len;
|
|
|
|
mixTail(data, _len);
|
|
|
|
while(_len >= 4)
|
|
{
|
|
uint32_t kk = *(uint32_t*)data;
|
|
|
|
mmix(m_hash, kk);
|
|
|
|
data += 4;
|
|
_len -= 4;
|
|
}
|
|
|
|
mixTail(data, _len);
|
|
}
|
|
|
|
void addUnaligned(const void* _data, int _len)
|
|
{
|
|
const uint8_t* data = (const uint8_t*)_data;
|
|
m_size += _len;
|
|
|
|
mixTail(data, _len);
|
|
|
|
while(_len >= 4)
|
|
{
|
|
uint32_t kk;
|
|
readUnaligned(data, kk);
|
|
|
|
mmix(m_hash, kk);
|
|
|
|
data += 4;
|
|
_len -= 4;
|
|
}
|
|
|
|
mixTail(data, _len);
|
|
}
|
|
|
|
template<typename Ty>
|
|
void add(Ty _value)
|
|
{
|
|
add(&_value, sizeof(Ty) );
|
|
}
|
|
|
|
uint32_t end()
|
|
{
|
|
mmix(m_hash, m_tail);
|
|
mmix(m_hash, m_size);
|
|
|
|
m_hash ^= m_hash >> 13;
|
|
m_hash *= MURMUR_M;
|
|
m_hash ^= m_hash >> 15;
|
|
|
|
return m_hash;
|
|
}
|
|
|
|
private:
|
|
static void readUnaligned(const void* _data, uint32_t& _out)
|
|
{
|
|
const uint8_t* data = (const uint8_t*)_data;
|
|
if (BX_ENABLED(BX_CPU_ENDIAN_BIG) )
|
|
{
|
|
_out = 0
|
|
| data[0]<<24
|
|
| data[1]<<16
|
|
| data[2]<<8
|
|
| data[3]
|
|
;
|
|
}
|
|
else
|
|
{
|
|
_out = 0
|
|
| data[0]
|
|
| data[1]<<8
|
|
| data[2]<<16
|
|
| data[3]<<24
|
|
;
|
|
}
|
|
}
|
|
|
|
void mixTail(const uint8_t*& _data, int& _len)
|
|
{
|
|
while( _len && ((_len<4) || m_count) )
|
|
{
|
|
m_tail |= (*_data++) << (m_count * 8);
|
|
|
|
m_count++;
|
|
_len--;
|
|
|
|
if(m_count == 4)
|
|
{
|
|
mmix(m_hash, m_tail);
|
|
m_tail = 0;
|
|
m_count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t m_hash;
|
|
uint32_t m_tail;
|
|
uint32_t m_count;
|
|
uint32_t m_size;
|
|
};
|
|
|
|
#undef MURMUR_M
|
|
#undef MURMUR_R
|
|
#undef mmix
|
|
|
|
inline uint32_t hashMurmur2A(const void* _data, uint32_t _size)
|
|
{
|
|
HashMurmur2A murmur;
|
|
murmur.begin();
|
|
murmur.add(_data, (int)_size);
|
|
return murmur.end();
|
|
}
|
|
|
|
template <typename Ty>
|
|
inline uint32_t hashMurmur2A(const Ty& _data)
|
|
{
|
|
BX_STATIC_ASSERT(BX_TYPE_IS_POD(Ty) );
|
|
return hashMurmur2A(&_data, sizeof(Ty) );
|
|
}
|
|
|
|
} // namespace bx
|
|
|
|
#endif // BX_HASH_H_HEADER_GUARD
|