xref: /minix3/common/lib/libc/hash/murmurhash/murmurhash.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: murmurhash.c,v 1.6 2013/10/26 21:06:38 rmind Exp $	*/
2f14fb602SLionel Sambuc 
3f14fb602SLionel Sambuc /*
4f14fb602SLionel Sambuc  * MurmurHash2 -- from the original code:
5f14fb602SLionel Sambuc  *
6f14fb602SLionel Sambuc  * "MurmurHash2 was written by Austin Appleby, and is placed in the public
7f14fb602SLionel Sambuc  * domain. The author hereby disclaims copyright to this source code."
8f14fb602SLionel Sambuc  *
9f14fb602SLionel Sambuc  * References:
10f14fb602SLionel Sambuc  *	http://code.google.com/p/smhasher/
11f14fb602SLionel Sambuc  *	https://sites.google.com/site/murmurhash/
12f14fb602SLionel Sambuc  */
13f14fb602SLionel Sambuc 
14f14fb602SLionel Sambuc #include <sys/cdefs.h>
15f14fb602SLionel Sambuc 
16f14fb602SLionel Sambuc #if defined(_KERNEL) || defined(_STANDALONE)
17*84d9c625SLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: murmurhash.c,v 1.6 2013/10/26 21:06:38 rmind Exp $");
18f14fb602SLionel Sambuc 
19f14fb602SLionel Sambuc #else
20f14fb602SLionel Sambuc 
21f14fb602SLionel Sambuc #if defined(LIBC_SCCS) && !defined(lint)
22*84d9c625SLionel Sambuc __RCSID("$NetBSD: murmurhash.c,v 1.6 2013/10/26 21:06:38 rmind Exp $");
23f14fb602SLionel Sambuc #endif /* LIBC_SCCS and not lint */
24f14fb602SLionel Sambuc 
25f14fb602SLionel Sambuc #include "namespace.h"
26f14fb602SLionel Sambuc #endif
27f14fb602SLionel Sambuc 
28f14fb602SLionel Sambuc #include <sys/types.h>
29*84d9c625SLionel Sambuc #include <sys/param.h>
30f14fb602SLionel Sambuc #include <sys/hash.h>
31f14fb602SLionel Sambuc 
32*84d9c625SLionel Sambuc #if !defined(_KERNEL) && !defined(_STANDALONE)
33f14fb602SLionel Sambuc #ifdef __weak_alias
__weak_alias(murmurhash2,_murmurhash2)34f14fb602SLionel Sambuc __weak_alias(murmurhash2,_murmurhash2)
35f14fb602SLionel Sambuc #endif
36*84d9c625SLionel Sambuc #endif
37f14fb602SLionel Sambuc 
38f14fb602SLionel Sambuc uint32_t
39f14fb602SLionel Sambuc murmurhash2(const void *key, size_t len, uint32_t seed)
40f14fb602SLionel Sambuc {
41f14fb602SLionel Sambuc 	/*
42f14fb602SLionel Sambuc 	 * Note: 'm' and 'r' are mixing constants generated offline.
43f14fb602SLionel Sambuc 	 * They're not really 'magic', they just happen to work well.
44f14fb602SLionel Sambuc 	 * Initialize the hash to a 'random' value.
45f14fb602SLionel Sambuc 	 */
46f14fb602SLionel Sambuc 	const uint32_t m = 0x5bd1e995;
47f14fb602SLionel Sambuc 	const int r = 24;
48f14fb602SLionel Sambuc 
49f14fb602SLionel Sambuc 	const uint8_t *data = key;
50f14fb602SLionel Sambuc 	uint32_t h = seed ^ (uint32_t)len;
51f14fb602SLionel Sambuc 
52*84d9c625SLionel Sambuc 	if (__predict_true(ALIGNED_POINTER(key, uint32_t))) {
53*84d9c625SLionel Sambuc 		while (len >= sizeof(uint32_t)) {
54*84d9c625SLionel Sambuc 			uint32_t k = *(const uint32_t *)data;
55*84d9c625SLionel Sambuc 
56*84d9c625SLionel Sambuc 			k *= m;
57*84d9c625SLionel Sambuc 			k ^= k >> r;
58*84d9c625SLionel Sambuc 			k *= m;
59*84d9c625SLionel Sambuc 
60*84d9c625SLionel Sambuc 			h *= m;
61*84d9c625SLionel Sambuc 			h ^= k;
62*84d9c625SLionel Sambuc 
63*84d9c625SLionel Sambuc 			data += sizeof(uint32_t);
64*84d9c625SLionel Sambuc 			len -= sizeof(uint32_t);
65*84d9c625SLionel Sambuc 		}
66*84d9c625SLionel Sambuc 	} else {
67f14fb602SLionel Sambuc 		while (len >= sizeof(uint32_t)) {
68f14fb602SLionel Sambuc 			uint32_t k;
69f14fb602SLionel Sambuc 
70f14fb602SLionel Sambuc 			k  = data[0];
71f14fb602SLionel Sambuc 			k |= data[1] << 8;
72f14fb602SLionel Sambuc 			k |= data[2] << 16;
73f14fb602SLionel Sambuc 			k |= data[3] << 24;
74f14fb602SLionel Sambuc 
75f14fb602SLionel Sambuc 			k *= m;
76f14fb602SLionel Sambuc 			k ^= k >> r;
77f14fb602SLionel Sambuc 			k *= m;
78f14fb602SLionel Sambuc 
79f14fb602SLionel Sambuc 			h *= m;
80f14fb602SLionel Sambuc 			h ^= k;
81f14fb602SLionel Sambuc 
82f14fb602SLionel Sambuc 			data += sizeof(uint32_t);
83f14fb602SLionel Sambuc 			len -= sizeof(uint32_t);
84f14fb602SLionel Sambuc 		}
85*84d9c625SLionel Sambuc 	}
86f14fb602SLionel Sambuc 
87f14fb602SLionel Sambuc 	/* Handle the last few bytes of the input array. */
88f14fb602SLionel Sambuc 	switch (len) {
89f14fb602SLionel Sambuc 	case 3:
90f14fb602SLionel Sambuc 		h ^= data[2] << 16;
91f14fb602SLionel Sambuc 		/* FALLTHROUGH */
92f14fb602SLionel Sambuc 	case 2:
93f14fb602SLionel Sambuc 		h ^= data[1] << 8;
94f14fb602SLionel Sambuc 		/* FALLTHROUGH */
95f14fb602SLionel Sambuc 	case 1:
96f14fb602SLionel Sambuc 		h ^= data[0];
97f14fb602SLionel Sambuc 		h *= m;
98f14fb602SLionel Sambuc 	}
99f14fb602SLionel Sambuc 
100f14fb602SLionel Sambuc 	/*
101f14fb602SLionel Sambuc 	 * Do a few final mixes of the hash to ensure the last few
102f14fb602SLionel Sambuc 	 * bytes are well-incorporated.
103f14fb602SLionel Sambuc 	 */
104f14fb602SLionel Sambuc 	h ^= h >> 13;
105f14fb602SLionel Sambuc 	h *= m;
106f14fb602SLionel Sambuc 	h ^= h >> 15;
107f14fb602SLionel Sambuc 
108f14fb602SLionel Sambuc 	return h;
109f14fb602SLionel Sambuc }
110