blob: 3943c94e2a34695d79a6945dfb1854a169a60d60 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file func.c Hashmap functions
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <ctype.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_list.h>
10#include <re_hash.h>
11
12
13/**
14 * Calculate hash-value using "Jenkins One-at-a-time" hash algorithm.
15 *
16 * @param key Pointer to key
17 * @param len Key length
18 *
19 * @return Calculated hash-value
20 */
21uint32_t hash_joaat(const uint8_t *key, size_t len)
22{
23 uint32_t hash = 0;
24 size_t i;
25
26 for (i = 0; i < len; i++) {
27 hash += key[i];
28 hash += (hash << 10);
29 hash ^= (hash >> 6);
30 }
31 hash += (hash << 3);
32 hash ^= (hash >> 11);
33 hash += (hash << 15);
34
35 return hash;
36}
37
38
39/**
40 * Calculate hash-value for a case-insensitive string
41 *
42 * @param str String
43 * @param len Length of string
44 *
45 * @return Calculated hash-value
46 */
47uint32_t hash_joaat_ci(const char *str, size_t len)
48{
49 uint32_t hash = 0;
50 size_t i;
51
52 for (i = 0; i < len; i++) {
53 hash += tolower(str[i]);
54 hash += (hash << 10);
55 hash ^= (hash >> 6);
56 }
57 hash += (hash << 3);
58 hash ^= (hash >> 11);
59 hash += (hash << 15);
60
61 return hash;
62}
63
64
65/**
66 * Calculate hash-value for a NULL-terminated string
67 *
68 * @param str String
69 *
70 * @return Calculated hash-value
71 */
72uint32_t hash_joaat_str(const char *str)
73{
74 uint32_t hash = 0;
75
76 while (*str) {
77 hash += *str++;
78 hash += (hash << 10);
79 hash ^= (hash >> 6);
80 }
81 hash += (hash << 3);
82 hash ^= (hash >> 11);
83 hash += (hash << 15);
84
85 return hash;
86}
87
88
89/**
90 * Calculate hash-value for a case-insensitive NULL-terminated string
91 *
92 * @param str String
93 *
94 * @return Calculated hash-value
95 */
96uint32_t hash_joaat_str_ci(const char *str)
97{
98 uint32_t hash = 0;
99
100 while (*str) {
101 hash += tolower(*str++);
102 hash += (hash << 10);
103 hash ^= (hash >> 6);
104 }
105 hash += (hash << 3);
106 hash ^= (hash >> 11);
107 hash += (hash << 15);
108
109 return hash;
110}
111
112
113/**
114 * Calculate hash-value for a pointer-length object
115 *
116 * @param pl Pointer-length object
117 *
118 * @return Calculated hash-value
119 */
120uint32_t hash_joaat_pl(const struct pl *pl)
121{
122 return pl ? hash_joaat((const uint8_t *)pl->p, pl->l) : 0;
123}
124
125
126/**
127 * Calculate hash-value for a case-insensitive pointer-length object
128 *
129 * @param pl Pointer-length object
130 *
131 * @return Calculated hash-value
132 */
133uint32_t hash_joaat_pl_ci(const struct pl *pl)
134{
135 return pl ? hash_joaat_ci(pl->p, pl->l) : 0;
136}
137
138
139/*
140 * My best guess at if you are big-endian or little-endian. This may
141 * need adjustment.
142 */
143#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
144 __BYTE_ORDER == __LITTLE_ENDIAN) || \
145 (defined(i386) || defined(__i386__) || defined(__i486__) || \
146 defined(__i586__) || defined(__i686__) || \
147 defined(vax) || defined(MIPSEL))
148# define HASH_LITTLE_ENDIAN 1
149# define HASH_BIG_ENDIAN 0
150#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
151 __BYTE_ORDER == __BIG_ENDIAN) || \
152 (defined(sparc) || defined(POWERPC) || \
153 defined(mc68000) || defined(sel))
154# define HASH_LITTLE_ENDIAN 0
155# define HASH_BIG_ENDIAN 1
156#else
157# define HASH_LITTLE_ENDIAN 0
158# define HASH_BIG_ENDIAN 0
159#endif
160
161#define hashsize(n) ((uint32_t)1<<(n))
162#define hashmask(n) (hashsize(n)-1)
163#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
164
165#define mix(a,b,c) { \
166 a -= c; a ^= rot(c, 4); c += b; \
167 b -= a; b ^= rot(a, 6); a += c; \
168 c -= b; c ^= rot(b, 8); b += a; \
169 a -= c; a ^= rot(c,16); c += b; \
170 b -= a; b ^= rot(a,19); a += c; \
171 c -= b; c ^= rot(b, 4); b += a; \
172 }
173
174
175#define final(a,b,c) \
176 { \
177 c ^= b; c -= rot(b,14); \
178 a ^= c; a -= rot(c,11); \
179 b ^= a; b -= rot(a,25); \
180 c ^= b; c -= rot(b,16); \
181 a ^= c; a -= rot(c,4); \
182 b ^= a; b -= rot(a,14); \
183 c ^= b; c -= rot(b,24); \
184 }
185
186
187static uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
188{
189 uint32_t a,b,c;
190 union { const void *ptr; size_t i; } u;
191
192 /* Set up the internal state */
193 a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
194
195 u.ptr = key;
196 if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
197 const uint32_t *k = (const uint32_t *)key;
198
199 while (length > 12) {
200 a += k[0];
201 b += k[1];
202 c += k[2];
203 mix(a,b,c);
204 length -= 12;
205 k += 3;
206 }
207
208#ifndef VALGRIND
209 switch (length) {
210
211 case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
212 case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
213 case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
214 case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
215 case 8 : b+=k[1]; a+=k[0]; break;
216 case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
217 case 6 : b+=k[1]&0xffff; a+=k[0]; break;
218 case 5 : b+=k[1]&0xff; a+=k[0]; break;
219 case 4 : a+=k[0]; break;
220 case 3 : a+=k[0]&0xffffff; break;
221 case 2 : a+=k[0]&0xffff; break;
222 case 1 : a+=k[0]&0xff; break;
223 case 0 : return c;
224 }
225
226#else /* make valgrind happy */
227
228 const uint8_t *k8 = (const uint8_t *)k;
229 switch (length) {
230
231 case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
232 case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
233 case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
234 case 9 : c+=k8[8]; /* fall through */
235 case 8 : b+=k[1]; a+=k[0]; break;
236 case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
237 case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
238 case 5 : b+=k8[4]; /* fall through */
239 case 4 : a+=k[0]; break;
240 case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
241 case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
242 case 1 : a+=k8[0]; break;
243 case 0 : return c;
244 }
245
246#endif /* !valgrind */
247
248 }
249 else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
250 const uint16_t *k = (const uint16_t *)key;
251 const uint8_t *k8;
252
253 while (length > 12) {
254 a += k[0] + (((uint32_t)k[1])<<16);
255 b += k[2] + (((uint32_t)k[3])<<16);
256 c += k[4] + (((uint32_t)k[5])<<16);
257 mix(a,b,c);
258 length -= 12;
259 k += 6;
260 }
261
262 k8 = (const uint8_t *)k;
263
264 switch (length) {
265
266 case 12: c+=k[4]+(((uint32_t)k[5])<<16);
267 b+=k[2]+(((uint32_t)k[3])<<16);
268 a+=k[0]+(((uint32_t)k[1])<<16);
269 break;
270 case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
271 case 10: c+=k[4];
272 b+=k[2]+(((uint32_t)k[3])<<16);
273 a+=k[0]+(((uint32_t)k[1])<<16);
274 break;
275 case 9 : c+=k8[8]; /* fall through */
276 case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
277 a+=k[0]+(((uint32_t)k[1])<<16);
278 break;
279 case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
280 case 6 : b+=k[2];
281 a+=k[0]+(((uint32_t)k[1])<<16);
282 break;
283 case 5 : b+=k8[4]; /* fall through */
284 case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
285 break;
286 case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
287 case 2 : a+=k[0];
288 break;
289 case 1 : a+=k8[0];
290 break;
291 case 0 : return c;
292 }
293 }
294 else {
295 const uint8_t *k = (const uint8_t *)key;
296
297 while (length > 12) {
298 a += k[0];
299 a += ((uint32_t)k[1])<<8;
300 a += ((uint32_t)k[2])<<16;
301 a += ((uint32_t)k[3])<<24;
302 b += k[4];
303 b += ((uint32_t)k[5])<<8;
304 b += ((uint32_t)k[6])<<16;
305 b += ((uint32_t)k[7])<<24;
306 c += k[8];
307 c += ((uint32_t)k[9])<<8;
308 c += ((uint32_t)k[10])<<16;
309 c += ((uint32_t)k[11])<<24;
310 mix(a,b,c);
311 length -= 12;
312 k += 12;
313 }
314
315 /* all the case statements fall through */
316 switch (length) {
317
318 case 12: c+=((uint32_t)k[11])<<24;
319 case 11: c+=((uint32_t)k[10])<<16;
320 case 10: c+=((uint32_t)k[9])<<8;
321 case 9 : c+=k[8];
322 case 8 : b+=((uint32_t)k[7])<<24;
323 case 7 : b+=((uint32_t)k[6])<<16;
324 case 6 : b+=((uint32_t)k[5])<<8;
325 case 5 : b+=k[4];
326 case 4 : a+=((uint32_t)k[3])<<24;
327 case 3 : a+=((uint32_t)k[2])<<16;
328 case 2 : a+=((uint32_t)k[1])<<8;
329 case 1 : a+=k[0];
330 break;
331 case 0 : return c;
332 }
333 }
334
335 final(a,b,c);
336 return c;
337}
338
339
340/**
341 * Calculate hash-value using fast hash algorithm.
342 *
343 * @param k Pointer to key
344 * @param len Key length
345 *
346 * @return Calculated hash-value
347 */
348uint32_t hash_fast(const char *k, size_t len)
349{
350 static volatile int random_seed = 0x304a0012;
351
352 if (!k)
353 return 0;
354
355 return hashlittle(k, len, random_seed);
356}
357
358
359/**
360 * Calculate hash-value for a NULL-terminated string
361 *
362 * @param str String
363 *
364 * @return Calculated hash-value
365 */
366uint32_t hash_fast_str(const char *str)
367{
368 return hash_fast(str, str_len(str));
369}