hash.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright 2010-2015 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #ifndef BX_HASH_H_HEADER_GUARD
  6. #define BX_HASH_H_HEADER_GUARD
  7. #include "bx.h"
  8. namespace bx
  9. {
  10. // MurmurHash2 was written by Austin Appleby, and is placed in the public
  11. // domain. The author hereby disclaims copyright to this source code.
  12. #define MURMUR_M 0x5bd1e995
  13. #define MURMUR_R 24
  14. #define mmix(_h, _k) { _k *= MURMUR_M; _k ^= _k >> MURMUR_R; _k *= MURMUR_M; _h *= MURMUR_M; _h ^= _k; }
  15. class HashMurmur2A
  16. {
  17. public:
  18. void begin(uint32_t _seed = 0)
  19. {
  20. m_hash = _seed;
  21. m_tail = 0;
  22. m_count = 0;
  23. m_size = 0;
  24. }
  25. void add(const void* _data, int _len)
  26. {
  27. if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN)
  28. && BX_UNLIKELY(!isPtrAligned(_data, 4) ) )
  29. {
  30. addUnaligned(_data, _len);
  31. return;
  32. }
  33. addAligned(_data, _len);
  34. }
  35. void addAligned(const void* _data, int _len)
  36. {
  37. const uint8_t* data = (const uint8_t*)_data;
  38. m_size += _len;
  39. mixTail(data, _len);
  40. while(_len >= 4)
  41. {
  42. uint32_t kk = *(uint32_t*)data;
  43. mmix(m_hash, kk);
  44. data += 4;
  45. _len -= 4;
  46. }
  47. mixTail(data, _len);
  48. }
  49. void addUnaligned(const void* _data, int _len)
  50. {
  51. const uint8_t* data = (const uint8_t*)_data;
  52. m_size += _len;
  53. mixTail(data, _len);
  54. while(_len >= 4)
  55. {
  56. uint32_t kk;
  57. readUnaligned(data, kk);
  58. mmix(m_hash, kk);
  59. data += 4;
  60. _len -= 4;
  61. }
  62. mixTail(data, _len);
  63. }
  64. template<typename Ty>
  65. void add(Ty _value)
  66. {
  67. add(&_value, sizeof(Ty) );
  68. }
  69. uint32_t end()
  70. {
  71. mmix(m_hash, m_tail);
  72. mmix(m_hash, m_size);
  73. m_hash ^= m_hash >> 13;
  74. m_hash *= MURMUR_M;
  75. m_hash ^= m_hash >> 15;
  76. return m_hash;
  77. }
  78. private:
  79. static void readUnaligned(const void* _data, uint32_t& _out)
  80. {
  81. const uint8_t* data = (const uint8_t*)_data;
  82. if (BX_ENABLED(BX_CPU_ENDIAN_LITTLE) )
  83. {
  84. _out = 0
  85. | data[0]<<24
  86. | data[1]<<16
  87. | data[2]<<8
  88. | data[3]
  89. ;
  90. }
  91. else
  92. {
  93. _out = 0
  94. | data[0]
  95. | data[1]<<8
  96. | data[2]<<16
  97. | data[3]<<24
  98. ;
  99. }
  100. }
  101. void mixTail(const uint8_t*& _data, int& _len)
  102. {
  103. while( _len && ((_len<4) || m_count) )
  104. {
  105. m_tail |= (*_data++) << (m_count * 8);
  106. m_count++;
  107. _len--;
  108. if(m_count == 4)
  109. {
  110. mmix(m_hash, m_tail);
  111. m_tail = 0;
  112. m_count = 0;
  113. }
  114. }
  115. }
  116. uint32_t m_hash;
  117. uint32_t m_tail;
  118. uint32_t m_count;
  119. uint32_t m_size;
  120. };
  121. #undef MURMUR_M
  122. #undef MURMUR_R
  123. #undef mmix
  124. inline uint32_t hashMurmur2A(const void* _data, uint32_t _size)
  125. {
  126. HashMurmur2A murmur;
  127. murmur.begin();
  128. murmur.add(_data, (int)_size);
  129. return murmur.end();
  130. }
  131. template <typename Ty>
  132. inline uint32_t hashMurmur2A(const Ty& _data)
  133. {
  134. return hashMurmur2A(&_data, sizeof(Ty) );
  135. }
  136. } // namespace bx
  137. #endif // BX_HASH_H_HEADER_GUARD