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