murmurhash3.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (c) 2022, smartmx <smartmx@qq.com>
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-04-03 smartmx the first version
  9. *
  10. */
  11. /*
  12. * @Note:
  13. * This is murmur3 hash algorithm: https://github.com/aappleby/smhasher.
  14. * But coded with c instead.
  15. * This repository only accomplish 32bit hash algorithm.
  16. */
  17. #include "murmurhash3.h"
  18. #define ROTL32(x,y) ((x << y) | (x >> (32 - y)))
  19. /**
  20. * calculate hash_code.
  21. *
  22. * @param hash_key the hash_key start address.
  23. * @param len the length of the hash_key.
  24. *
  25. * @return type uint32_t, the result of calculated value.
  26. */
  27. uint32_t murmurhash3_caculate32(const void *hash_key, uint32_t len)
  28. {
  29. const uint8_t *hash_key_ptr = (const uint8_t *)hash_key;
  30. int nblocks = len / 4;
  31. uint32_t hash = MURMURHASH3_SEED_VALUE;
  32. uint32_t data;
  33. /* body */
  34. while (nblocks > 0)
  35. {
  36. /* get 32bit data */
  37. data = (hash_key_ptr[0] << 24) | (hash_key_ptr[1] << 16) | (hash_key_ptr[2] << 8) | (hash_key_ptr[3]);
  38. data *= MURMURHASH3_C1_VALUE;
  39. data = ROTL32(data, MURMURHASH3_R1_VALUE);
  40. data *= MURMURHASH3_C2_VALUE;
  41. hash ^= data;
  42. hash = ROTL32(hash, MURMURHASH3_R2_VALUE);
  43. hash = hash * MURMURHASH3_M_VALUE + MURMURHASH3_N_VALUE;
  44. hash_key_ptr += 4;
  45. nblocks--;
  46. }
  47. /* tail */
  48. data = 0;
  49. switch (len & 3)
  50. {
  51. case 3:
  52. data ^= (hash_key_ptr[2] << 16);/* @suppress("No break at end of case") */
  53. case 2:
  54. data ^= (hash_key_ptr[1] << 8); /* @suppress("No break at end of case") */
  55. case 1:
  56. data ^= hash_key_ptr[0];
  57. data *= MURMURHASH3_C1_VALUE;
  58. data = ROTL32(data, MURMURHASH3_R1_VALUE);
  59. data *= MURMURHASH3_C2_VALUE;
  60. hash ^= data;
  61. }
  62. /* finalization */
  63. hash ^= len;
  64. /* Finalization mix - force all bits of a hash block to avalanche */
  65. hash ^= hash >> 16;
  66. hash *= 0x85ebca6b;
  67. hash ^= hash >> 13;
  68. hash *= 0xc2b2ae35;
  69. hash ^= hash >> 16;
  70. return hash;
  71. }
  72. /**
  73. * upper all lower letters in hash key and calculate the hash_code.
  74. *
  75. * @param c the char value.
  76. *
  77. * @return type uint8_t, the upper char value.
  78. */
  79. static uint8_t murmurhash3_lower_char_upper(uint8_t c)
  80. {
  81. if ((c >= 'a') && (c <= 'z'))
  82. return c + ('A' - 'a');
  83. return c;
  84. }
  85. /**
  86. * upper all lower letters in hash key and calculate the hash_code.
  87. *
  88. * @param c the char value.
  89. *
  90. * @return type uint8_t, the upper char value.
  91. */
  92. uint8_t murmurhash3_lower_char_upper_memcmp(const void *src1, const void *src2, uint32_t len)
  93. {
  94. uint8_t *src1_char = (uint8_t *)src1;
  95. uint8_t *src2_char = (uint8_t *)src2;
  96. uint32_t all_len = len;
  97. while (all_len)
  98. {
  99. if (murmurhash3_lower_char_upper(*src1_char) == murmurhash3_lower_char_upper(*src2_char))
  100. {
  101. src1_char++;
  102. src2_char++;
  103. all_len--;
  104. }
  105. else
  106. {
  107. return (len - all_len);
  108. }
  109. }
  110. return 0;
  111. }
  112. /**
  113. * upper all lower letters in hash key and calculate the hash_code.
  114. *
  115. * @param hash_key the hash_key start address.
  116. * @param len the length of the hash_key.
  117. *
  118. * @return type uint32_t, the result of calculated value.
  119. */
  120. uint32_t murmurhash3_upper_caculate32(const void *hash_key, uint32_t len)
  121. {
  122. const uint8_t *hash_key_ptr = (const uint8_t *)hash_key;
  123. int nblocks = len / 4;
  124. uint32_t hash = MURMURHASH3_SEED_VALUE;
  125. uint32_t data;
  126. /* body */
  127. while (nblocks > 0)
  128. {
  129. /* get 32bit data */
  130. data = (murmurhash3_lower_char_upper(hash_key_ptr[0]) << 24) | \
  131. (murmurhash3_lower_char_upper(hash_key_ptr[1]) << 16) | \
  132. (murmurhash3_lower_char_upper(hash_key_ptr[2]) << 8) | \
  133. (murmurhash3_lower_char_upper(hash_key_ptr[3]));
  134. data *= MURMURHASH3_C1_VALUE;
  135. data = ROTL32(data, MURMURHASH3_R1_VALUE);
  136. data *= MURMURHASH3_C2_VALUE;
  137. hash ^= data;
  138. hash = ROTL32(hash, MURMURHASH3_R2_VALUE);
  139. hash = hash * MURMURHASH3_M_VALUE + MURMURHASH3_N_VALUE;
  140. hash_key_ptr += 4;
  141. nblocks--;
  142. }
  143. /* tail */
  144. data = 0;
  145. switch (len & 3)
  146. {
  147. case 3:
  148. data ^= (murmurhash3_lower_char_upper(hash_key_ptr[2]) << 16);/* @suppress("No break at end of case") */
  149. case 2:
  150. data ^= (murmurhash3_lower_char_upper(hash_key_ptr[1]) << 8); /* @suppress("No break at end of case") */
  151. case 1:
  152. data ^= murmurhash3_lower_char_upper(hash_key_ptr[0]);
  153. data *= MURMURHASH3_C1_VALUE;
  154. data = ROTL32(data, MURMURHASH3_R1_VALUE);
  155. data *= MURMURHASH3_C2_VALUE;
  156. hash ^= data;
  157. }
  158. /* finalization */
  159. hash ^= len;
  160. /* Finalization mix - force all bits of a hash block to avalanche */
  161. hash ^= hash >> 16;
  162. hash *= 0x85ebca6b;
  163. hash ^= hash >> 13;
  164. hash *= 0xc2b2ae35;
  165. hash ^= hash >> 16;
  166. return hash;
  167. }