hash_64.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * hash_64 - 64 bit Fowler/Noll/Vo-0 hash code
  3. *
  4. * @(#) $Revision: 5.1 $
  5. * @(#) $Id: hash_64.c,v 5.1 2009/06/30 09:01:38 chongo Exp $
  6. * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64.c,v $
  7. *
  8. ***
  9. *
  10. * Fowler/Noll/Vo hash
  11. *
  12. * The basis of this hash algorithm was taken from an idea sent
  13. * as reviewer comments to the IEEE POSIX P1003.2 committee by:
  14. *
  15. * Phong Vo (http://www.research.att.com/info/kpv/)
  16. * Glenn Fowler (http://www.research.att.com/~gsf/)
  17. *
  18. * In a subsequent ballot round:
  19. *
  20. * Landon Curt Noll (http://www.isthe.com/chongo/)
  21. *
  22. * improved on their algorithm. Some people tried this hash
  23. * and found that it worked rather well. In an EMail message
  24. * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash.
  25. *
  26. * FNV hashes are designed to be fast while maintaining a low
  27. * collision rate. The FNV speed allows one to quickly hash lots
  28. * of data while maintaining a reasonable collision rate. See:
  29. *
  30. * http://www.isthe.com/chongo/tech/comp/fnv/index.html
  31. *
  32. * for more details as well as other forms of the FNV hash.
  33. *
  34. ***
  35. *
  36. * NOTE: The FNV-0 historic hash is not recommended. One should use
  37. * the FNV-1 hash instead.
  38. *
  39. * To use the 64 bit FNV-0 historic hash, pass FNV0_64_INIT as the
  40. * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str().
  41. *
  42. * To use the recommended 64 bit FNV-1 hash, pass FNV1_64_INIT as the
  43. * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str().
  44. *
  45. ***
  46. *
  47. * Please do not copyright this code. This code is in the public domain.
  48. *
  49. * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  50. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
  51. * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  52. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  53. * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  54. * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  55. * PERFORMANCE OF THIS SOFTWARE.
  56. *
  57. * By:
  58. * chongo <Landon Curt Noll> /\oo/\
  59. * http://www.isthe.com/chongo/
  60. *
  61. * Share and Enjoy! :-)
  62. */
  63. #include <stdlib.h>
  64. #include "fnv.h"
  65. /*
  66. * FNV-0 defines the initial basis to be zero
  67. */
  68. #if !defined(HAVE_64BIT_LONG_LONG)
  69. const Fnv64_t fnv0_64_init = { 0UL, 0UL };
  70. #endif /* ! HAVE_64BIT_LONG_LONG */
  71. /*
  72. * FNV-1 defines the initial basis to be non-zero
  73. */
  74. #if !defined(HAVE_64BIT_LONG_LONG)
  75. const Fnv64_t fnv1_64_init = { 0x84222325UL, 0xcbf29ce4UL };
  76. #endif /* ! HAVE_64BIT_LONG_LONG */
  77. /*
  78. * 64 bit magic FNV-0 and FNV-1 prime
  79. */
  80. #if defined(HAVE_64BIT_LONG_LONG)
  81. #define FNV_64_PRIME ((Fnv64_t)0x100000001b3ULL)
  82. #else /* HAVE_64BIT_LONG_LONG */
  83. #define FNV_64_PRIME_LOW ((unsigned long)0x1b3) /* lower bits of FNV prime */
  84. #define FNV_64_PRIME_SHIFT (8) /* top FNV prime shift above 2^32 */
  85. #endif /* HAVE_64BIT_LONG_LONG */
  86. /*
  87. * fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer
  88. *
  89. * input:
  90. * buf - start of buffer to hash
  91. * len - length of buffer in octets
  92. * hval - previous hash value or 0 if first call
  93. *
  94. * returns:
  95. * 64 bit hash as a static hash type
  96. *
  97. * NOTE: To use the 64 bit FNV-0 historic hash, use FNV0_64_INIT as the hval
  98. * argument on the first call to either fnv_64_buf() or fnv_64_str().
  99. *
  100. * NOTE: To use the recommended 64 bit FNV-1 hash, use FNV1_64_INIT as the hval
  101. * argument on the first call to either fnv_64_buf() or fnv_64_str().
  102. */
  103. Fnv64_t
  104. fnv_64_buf(void *buf, size_t len, Fnv64_t hval)
  105. {
  106. unsigned char *bp = (unsigned char *)buf; /* start of buffer */
  107. unsigned char *be = bp + len; /* beyond end of buffer */
  108. #if defined(HAVE_64BIT_LONG_LONG)
  109. /*
  110. * FNV-1 hash each octet of the buffer
  111. */
  112. while (bp < be) {
  113. /* multiply by the 64 bit FNV magic prime mod 2^64 */
  114. #if defined(NO_FNV_GCC_OPTIMIZATION)
  115. hval *= FNV_64_PRIME;
  116. #else /* NO_FNV_GCC_OPTIMIZATION */
  117. hval += (hval << 1) + (hval << 4) + (hval << 5) +
  118. (hval << 7) + (hval << 8) + (hval << 40);
  119. #endif /* NO_FNV_GCC_OPTIMIZATION */
  120. /* xor the bottom with the current octet */
  121. hval ^= (Fnv64_t)*bp++;
  122. }
  123. #else /* HAVE_64BIT_LONG_LONG */
  124. unsigned long val[4]; /* hash value in base 2^16 */
  125. unsigned long tmp[4]; /* tmp 64 bit value */
  126. /*
  127. * Convert Fnv64_t hval into a base 2^16 array
  128. */
  129. val[0] = hval.w32[0];
  130. val[1] = (val[0] >> 16);
  131. val[0] &= 0xffff;
  132. val[2] = hval.w32[1];
  133. val[3] = (val[2] >> 16);
  134. val[2] &= 0xffff;
  135. /*
  136. * FNV-1 hash each octet of the buffer
  137. */
  138. while (bp < be) {
  139. /*
  140. * multiply by the 64 bit FNV magic prime mod 2^64
  141. *
  142. * Using 0x100000001b3 we have the following digits base 2^16:
  143. *
  144. * 0x0 0x100 0x0 0x1b3
  145. *
  146. * which is the same as:
  147. *
  148. * 0x0 1<<FNV_64_PRIME_SHIFT 0x0 FNV_64_PRIME_LOW
  149. */
  150. /* multiply by the lowest order digit base 2^16 */
  151. tmp[0] = val[0] * FNV_64_PRIME_LOW;
  152. tmp[1] = val[1] * FNV_64_PRIME_LOW;
  153. tmp[2] = val[2] * FNV_64_PRIME_LOW;
  154. tmp[3] = val[3] * FNV_64_PRIME_LOW;
  155. /* multiply by the other non-zero digit */
  156. tmp[2] += val[0] << FNV_64_PRIME_SHIFT; /* tmp[2] += val[0] * 0x100 */
  157. tmp[3] += val[1] << FNV_64_PRIME_SHIFT; /* tmp[3] += val[1] * 0x100 */
  158. /* propagate carries */
  159. tmp[1] += (tmp[0] >> 16);
  160. val[0] = tmp[0] & 0xffff;
  161. tmp[2] += (tmp[1] >> 16);
  162. val[1] = tmp[1] & 0xffff;
  163. val[3] = tmp[3] + (tmp[2] >> 16);
  164. val[2] = tmp[2] & 0xffff;
  165. /*
  166. * Doing a val[3] &= 0xffff; is not really needed since it simply
  167. * removes multiples of 2^64. We can discard these excess bits
  168. * outside of the loop when we convert to Fnv64_t.
  169. */
  170. /* xor the bottom with the current octet */
  171. val[0] ^= (unsigned long)*bp++;
  172. }
  173. /*
  174. * Convert base 2^16 array back into an Fnv64_t
  175. */
  176. hval.w32[1] = ((val[3]<<16) | val[2]);
  177. hval.w32[0] = ((val[1]<<16) | val[0]);
  178. #endif /* HAVE_64BIT_LONG_LONG */
  179. /* return our new hash value */
  180. return hval;
  181. }
  182. /*
  183. * fnv_64_str - perform a 64 bit Fowler/Noll/Vo hash on a buffer
  184. *
  185. * input:
  186. * buf - start of buffer to hash
  187. * hval - previous hash value or 0 if first call
  188. *
  189. * returns:
  190. * 64 bit hash as a static hash type
  191. *
  192. * NOTE: To use the 64 bit FNV-0 historic hash, use FNV0_64_INIT as the hval
  193. * argument on the first call to either fnv_64_buf() or fnv_64_str().
  194. *
  195. * NOTE: To use the recommended 64 bit FNV-1 hash, use FNV1_64_INIT as the hval
  196. * argument on the first call to either fnv_64_buf() or fnv_64_str().
  197. */
  198. Fnv64_t
  199. fnv_64_str(char *str, Fnv64_t hval)
  200. {
  201. unsigned char *s = (unsigned char *)str; /* unsigned string */
  202. #if defined(HAVE_64BIT_LONG_LONG)
  203. /*
  204. * FNV-1 hash each octet of the string
  205. */
  206. while (*s) {
  207. /* multiply by the 64 bit FNV magic prime mod 2^64 */
  208. #if defined(NO_FNV_GCC_OPTIMIZATION)
  209. hval *= FNV_64_PRIME;
  210. #else /* NO_FNV_GCC_OPTIMIZATION */
  211. hval += (hval << 1) + (hval << 4) + (hval << 5) +
  212. (hval << 7) + (hval << 8) + (hval << 40);
  213. #endif /* NO_FNV_GCC_OPTIMIZATION */
  214. /* xor the bottom with the current octet */
  215. hval ^= (Fnv64_t)*s++;
  216. }
  217. #else /* !HAVE_64BIT_LONG_LONG */
  218. unsigned long val[4]; /* hash value in base 2^16 */
  219. unsigned long tmp[4]; /* tmp 64 bit value */
  220. /*
  221. * Convert Fnv64_t hval into a base 2^16 array
  222. */
  223. val[0] = hval.w32[0];
  224. val[1] = (val[0] >> 16);
  225. val[0] &= 0xffff;
  226. val[2] = hval.w32[1];
  227. val[3] = (val[2] >> 16);
  228. val[2] &= 0xffff;
  229. /*
  230. * FNV-1 hash each octet of the string
  231. */
  232. while (*s) {
  233. /*
  234. * multiply by the 64 bit FNV magic prime mod 2^64
  235. *
  236. * Using 1099511628211, we have the following digits base 2^16:
  237. *
  238. * 0x0 0x100 0x0 0x1b3
  239. *
  240. * which is the same as:
  241. *
  242. * 0x0 1<<FNV_64_PRIME_SHIFT 0x0 FNV_64_PRIME_LOW
  243. */
  244. /* multiply by the lowest order digit base 2^16 */
  245. tmp[0] = val[0] * FNV_64_PRIME_LOW;
  246. tmp[1] = val[1] * FNV_64_PRIME_LOW;
  247. tmp[2] = val[2] * FNV_64_PRIME_LOW;
  248. tmp[3] = val[3] * FNV_64_PRIME_LOW;
  249. /* multiply by the other non-zero digit */
  250. tmp[2] += val[0] << FNV_64_PRIME_SHIFT; /* tmp[2] += val[0] * 0x100 */
  251. tmp[3] += val[1] << FNV_64_PRIME_SHIFT; /* tmp[3] += val[1] * 0x100 */
  252. /* propagate carries */
  253. tmp[1] += (tmp[0] >> 16);
  254. val[0] = tmp[0] & 0xffff;
  255. tmp[2] += (tmp[1] >> 16);
  256. val[1] = tmp[1] & 0xffff;
  257. val[3] = tmp[3] + (tmp[2] >> 16);
  258. val[2] = tmp[2] & 0xffff;
  259. /*
  260. * Doing a val[3] &= 0xffff; is not really needed since it simply
  261. * removes multiples of 2^64. We can discard these excess bits
  262. * outside of the loop when we convert to Fnv64_t.
  263. */
  264. /* xor the bottom with the current octet */
  265. val[0] ^= (unsigned long)(*s++);
  266. }
  267. /*
  268. * Convert base 2^16 array back into an Fnv64_t
  269. */
  270. hval.w32[1] = ((val[3]<<16) | val[2]);
  271. hval.w32[0] = ((val[1]<<16) | val[0]);
  272. #endif /* !HAVE_64BIT_LONG_LONG */
  273. /* return our new hash value */
  274. return hval;
  275. }