Skip to content

Commit e1f7e51

Browse files
authored
Add 32-bit Jenkins Lookup3 hash
1 parent e5dad3f commit e1f7e51

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

hash/hash_lookup3.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* @addtogroup hash Hash algorithms
3+
* @{
4+
* @file hash_lookup3.c
5+
* @author [cptr0](https://github.com/cptr0)
6+
* @brief 32-bit [Jenkins hash](https://en.wikipedia.org/wiki/Jenkins_hash_function) algorithm
7+
*/
8+
9+
#include <assert.h>
10+
#include <inttypes.h>
11+
#include <string.h>
12+
#include <stdio.h>
13+
14+
// Rotate x left by k bits
15+
#define rot(x,k) (((x) << (k)) | ((x) >> (32-(k))))
16+
17+
/**
18+
* @brief 32-bit Jenkins Lookup3 algorithm implementation
19+
*
20+
* @param s NULL terminated ASCII string to hash
21+
* @return 32-bit hash result
22+
*/
23+
24+
uint32_t lookup3_32(const char *key, uint32_t seed) {
25+
uint32_t a, b, c;
26+
a = b = 0x9e3779b9;
27+
c = seed;
28+
29+
size_t i = 0;
30+
31+
size_t length = strlen(key);
32+
33+
while (length - i >= 12) {
34+
a += (uint32_t)key[i] | ((uint32_t)key[i+1] << 8) |
35+
((uint32_t)key[i+2] << 16) | ((uint32_t)key[i+3] << 24);
36+
b += (uint32_t)key[i+4] | ((uint32_t)key[i+5] << 8) |
37+
((uint32_t)key[i+6] << 16) | ((uint32_t)key[i+7] << 24);
38+
c += (uint32_t)key[i+8] | ((uint32_t)key[i+9] << 8) |
39+
((uint32_t)key[i+10] << 16) | ((uint32_t)key[i+11] << 24);
40+
41+
a -= c; a ^= rot(c,4); c += b;
42+
b -= a; b ^= rot(a,6); a += c;
43+
c -= b; c ^= rot(b,8); b += a;
44+
a -= c; a ^= rot(c,16); c += b;
45+
b -= a; b ^= rot(a,19); a += c;
46+
c -= b; c ^= rot(b,4); b += a;
47+
48+
i += 12;
49+
}
50+
51+
uint32_t remainingA = 0, remainingB = 0, remainingC = 0;
52+
switch (length - i) {
53+
case 11: remainingC += ((uint32_t)key[i+10]) << 16;
54+
case 10: remainingC += ((uint32_t)key[i+9]) << 8;
55+
case 9: remainingC += (uint32_t)key[i+8];
56+
case 8: remainingB += ((uint32_t)key[i+7]) << 24;
57+
case 7: remainingB += ((uint32_t)key[i+6]) << 16;
58+
case 6: remainingB += ((uint32_t)key[i+5]) << 8;
59+
case 5: remainingB += (uint32_t)key[i+4];
60+
case 4: remainingA += ((uint32_t)key[i+3]) << 24;
61+
case 3: remainingA += ((uint32_t)key[i+2]) << 16;
62+
case 2: remainingA += ((uint32_t)key[i+1]) << 8;
63+
case 1: remainingA += (uint32_t)key[i];
64+
a += remainingA;
65+
b += remainingB;
66+
c += remainingC;
67+
}
68+
69+
c ^= b; c -= rot(b,14);
70+
a ^= c; a -= rot(c,11);
71+
b ^= a; b -= rot(a,25);
72+
c ^= b; c -= rot(b,16);
73+
a ^= c; a -= rot(c,4);
74+
b ^= a; b -= rot(a,14);
75+
c ^= b; c -= rot(b,24);
76+
77+
return c;
78+
}
79+
/**
80+
* @brief Test function for lookup3_32 function
81+
*
82+
* @returns None
83+
*/
84+
void test_lookup3_32()
85+
{
86+
assert(lookup3_32("Hello, Jenkins!", 0) == 2484708164);
87+
assert(lookup3_32("Hello Jenkinss", 0) == 850494015);
88+
assert(lookup3_32("Hello, Jenkins", 0) == 3393305742);
89+
assert(lookup3_32("hello, jenkins!", 0) == 3521406038);
90+
91+
printf("%s", "Test passed.\n");
92+
}
93+
94+
/**
95+
* @brief Main function
96+
*
97+
* @returns 0 on successful program exit
98+
*/
99+
int main()
100+
{
101+
test_lookup3_32();
102+
return 0;
103+
}

0 commit comments

Comments
 (0)