hash.odin 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. package hash
  2. import "core:mem"
  3. import "base:intrinsics"
  4. @(optimization_mode="speed")
  5. adler32 :: proc(data: []byte, seed := u32(1)) -> u32 #no_bounds_check {
  6. ADLER_CONST :: 65521
  7. buffer := raw_data(data)
  8. a, b: u64 = u64(seed) & 0xFFFF, u64(seed) >> 16
  9. buf := data[:]
  10. for len(buf) != 0 && uintptr(buffer) & 7 != 0 {
  11. a = (a + u64(buf[0]))
  12. b = (b + a)
  13. buffer = buffer[1:]
  14. buf = buf[1:]
  15. }
  16. for len(buf) > 7 {
  17. count := min(len(buf), 5552)
  18. for count > 7 {
  19. a += u64(buf[0]); b += a
  20. a += u64(buf[1]); b += a
  21. a += u64(buf[2]); b += a
  22. a += u64(buf[3]); b += a
  23. a += u64(buf[4]); b += a
  24. a += u64(buf[5]); b += a
  25. a += u64(buf[6]); b += a
  26. a += u64(buf[7]); b += a
  27. buf = buf[8:]
  28. count -= 8
  29. }
  30. a %= ADLER_CONST
  31. b %= ADLER_CONST
  32. }
  33. for len(buf) != 0 {
  34. a = (a + u64(buf[0])) % ADLER_CONST
  35. b = (b + a) % ADLER_CONST
  36. buf = buf[1:]
  37. }
  38. return (u32(b) << 16) | u32(a)
  39. }
  40. @(optimization_mode="speed")
  41. djb2 :: proc(data: []byte, seed := u32(5381)) -> u32 {
  42. hash: u32 = seed
  43. for b in data {
  44. hash = (hash << 5) + hash + u32(b) // hash * 33 + u32(b)
  45. }
  46. return hash
  47. }
  48. djbx33a :: proc(data: []byte, seed := u32(5381)) -> (result: [16]byte) #no_bounds_check {
  49. state := [4]u32{seed, seed, seed, seed}
  50. s: u32 = 0
  51. for p in data {
  52. state[s] = (state[s] << 5) + state[s] + u32(p) // hash * 33 + u32(b)
  53. s = (s + 1) & 3
  54. }
  55. (^u32le)(&result[0])^ = u32le(state[0])
  56. (^u32le)(&result[4])^ = u32le(state[1])
  57. (^u32le)(&result[8])^ = u32le(state[2])
  58. (^u32le)(&result[12])^ = u32le(state[3])
  59. return
  60. }
  61. // If you have a choice, prefer fnv32a
  62. @(optimization_mode="speed")
  63. fnv32_no_a :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
  64. h: u32 = seed
  65. for b in data {
  66. h = (h * 0x01000193) ~ u32(b)
  67. }
  68. return h
  69. }
  70. fnv32 :: fnv32_no_a // NOTE(bill): Not a fan of these aliases but seems necessary
  71. fnv64 :: fnv64_no_a // NOTE(bill): Not a fan of these aliases but seems necessary
  72. // If you have a choice, prefer fnv64a
  73. @(optimization_mode="speed")
  74. fnv64_no_a :: proc(data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 {
  75. h: u64 = seed
  76. for b in data {
  77. h = (h * 0x100000001b3) ~ u64(b)
  78. }
  79. return h
  80. }
  81. @(optimization_mode="speed")
  82. fnv32a :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
  83. h: u32 = seed
  84. for b in data {
  85. h = (h ~ u32(b)) * 0x01000193
  86. }
  87. return h
  88. }
  89. @(optimization_mode="speed")
  90. fnv64a :: proc(data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 {
  91. h: u64 = seed
  92. for b in data {
  93. h = (h ~ u64(b)) * 0x100000001b3
  94. }
  95. return h
  96. }
  97. @(optimization_mode="speed")
  98. jenkins :: proc(data: []byte, seed := u32(0)) -> u32 {
  99. hash: u32 = seed
  100. for b in data {
  101. hash += u32(b)
  102. hash += hash << 10
  103. hash ~= hash >> 6
  104. }
  105. hash += hash << 3
  106. hash ~= hash >> 11
  107. hash += hash << 15
  108. return hash
  109. }
  110. @(optimization_mode="speed")
  111. murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
  112. c1_32: u32 : 0xcc9e2d51
  113. c2_32: u32 : 0x1b873593
  114. h1: u32 = seed
  115. nblocks := len(data)/4
  116. p := raw_data(data)
  117. p1 := p[4*nblocks:]
  118. for ; p < p1; p = p[4:] {
  119. k1 := (cast(^u32)p)^
  120. k1 *= c1_32
  121. k1 = (k1 << 15) | (k1 >> 17)
  122. k1 *= c2_32
  123. h1 ~= k1
  124. h1 = (h1 << 13) | (h1 >> 19)
  125. h1 = h1*5 + 0xe6546b64
  126. }
  127. tail := data[nblocks*4:]
  128. k1: u32
  129. switch len(tail)&3 {
  130. case 3:
  131. k1 ~= u32(tail[2]) << 16
  132. fallthrough
  133. case 2:
  134. k1 ~= u32(tail[1]) << 8
  135. fallthrough
  136. case 1:
  137. k1 ~= u32(tail[0])
  138. k1 *= c1_32
  139. k1 = (k1 << 15) | (k1 >> 17)
  140. k1 *= c2_32
  141. h1 ~= k1
  142. }
  143. h1 ~= u32(len(data))
  144. h1 ~= h1 >> 16
  145. h1 *= 0x85ebca6b
  146. h1 ~= h1 >> 13
  147. h1 *= 0xc2b2ae35
  148. h1 ~= h1 >> 16
  149. return h1
  150. }
  151. // See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L96
  152. @(optimization_mode="speed")
  153. murmur64a :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
  154. m :: 0xc6a4a7935bd1e995
  155. r :: 47
  156. h: u64 = seed ~ (u64(len(data)) * m)
  157. data64 := mem.slice_data_cast([]u64, data)
  158. for _, i in data64 {
  159. k := data64[i]
  160. k *= m
  161. k ~= k>>r
  162. k *= m
  163. h ~= k
  164. h *= m
  165. }
  166. offset := len(data64) * size_of(u64)
  167. switch len(data)&7 {
  168. case 7: h ~= u64(data[offset + 6]) << 48; fallthrough
  169. case 6: h ~= u64(data[offset + 5]) << 40; fallthrough
  170. case 5: h ~= u64(data[offset + 4]) << 32; fallthrough
  171. case 4: h ~= u64(data[offset + 3]) << 24; fallthrough
  172. case 3: h ~= u64(data[offset + 2]) << 16; fallthrough
  173. case 2: h ~= u64(data[offset + 1]) << 8; fallthrough
  174. case 1:
  175. h ~= u64(data[offset + 0])
  176. h *= m
  177. }
  178. h ~= h>>r
  179. h *= m
  180. h ~= h>>r
  181. return h
  182. }
  183. // See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L140
  184. @(optimization_mode="speed")
  185. murmur64b :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
  186. m :: 0x5bd1e995
  187. r :: 24
  188. h1 := u32(seed) ~ u32(len(data))
  189. h2 := u32(seed) >> 32
  190. data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
  191. len := len(data)
  192. i := 0
  193. for len >= 8 {
  194. k1, k2: u32
  195. k1 = data32[i]; i += 1
  196. k1 *= m
  197. k1 ~= k1>>r
  198. k1 *= m
  199. h1 *= m
  200. h1 ~= k1
  201. len -= 4
  202. k2 = data32[i]; i += 1
  203. k2 *= m
  204. k2 ~= k2>>r
  205. k2 *= m
  206. h2 *= m
  207. h2 ~= k2
  208. len -= 4
  209. }
  210. if len >= 4 {
  211. k1: u32
  212. k1 = data32[i]; i += 1
  213. k1 *= m
  214. k1 ~= k1>>r
  215. k1 *= m
  216. h1 *= m
  217. h1 ~= k1
  218. len -= 4
  219. }
  220. // TODO(bill): Fix this
  221. #no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
  222. switch len {
  223. case 3:
  224. h2 ~= u32(data8[2]) << 16
  225. fallthrough
  226. case 2:
  227. h2 ~= u32(data8[1]) << 8
  228. fallthrough
  229. case 1:
  230. h2 ~= u32(data8[0])
  231. h2 *= m
  232. }
  233. h1 ~= h2>>18
  234. h1 *= m
  235. h2 ~= h1>>22
  236. h2 *= m
  237. h1 ~= h2>>17
  238. h1 *= m
  239. h2 ~= h1>>19
  240. h2 *= m
  241. return u64(h1)<<32 | u64(h2)
  242. }
  243. @(optimization_mode="speed")
  244. sdbm :: proc(data: []byte, seed := u32(0)) -> u32 {
  245. hash: u32 = seed
  246. for b in data {
  247. hash = u32(b) + (hash<<6) + (hash<<16) - hash
  248. }
  249. return hash
  250. }