]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/hash.c
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / lib / hash.c
CommitLineData
f52a7d75 1
2/*
262a0e14 3 * $Id$
f52a7d75 4 *
5 * DEBUG: section 0 Hash Tables
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
f52a7d75 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
f52a7d75 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
26ac0430 24 *
f52a7d75 25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
26ac0430 29 *
f52a7d75 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36#include "config.h"
37
38#if HAVE_STDIO_H
39#include <stdio.h>
40#endif
41#if HAVE_STDLIB_H
42#include <stdlib.h>
43#endif
44#if HAVE_STRING_H
45#include <string.h>
46#endif
47#if HAVE_UNISTD_H
48#include <unistd.h>
49#endif
50#if HAVE_GNUMALLLOC_H
51#include <gnumalloc.h>
482aa790 52#elif HAVE_MALLOC_H
f52a7d75 53#include <malloc.h>
54#endif
55#if HAVE_ASSERT_H
56#include <assert.h>
57#endif
e880cefa 58#if HAVE_MATH_H
59#include <math.h>
60#endif
f52a7d75 61
62#include "hash.h"
63#include "util.h"
88bfe092 64#include "profiling.h"
f52a7d75 65
66static void hash_next_bucket(hash_table * hid);
67
68unsigned int
69hash_string(const void *data, unsigned int size)
70{
71 const char *s = data;
72 unsigned int n = 0;
73 unsigned int j = 0;
74 unsigned int i = 0;
75 while (*s) {
26ac0430
AJ
76 j++;
77 n ^= 271 * (unsigned) *s++;
f52a7d75 78 }
79 i = n ^ (j * 271);
80 return i % size;
81}
82
83/* the following function(s) were adapted from
84 * usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite */
85
86/* Hash function from Chris Torek. */
87unsigned int
88hash4(const void *data, unsigned int size)
89{
90 const char *key = data;
91 size_t loop;
92 unsigned int h;
93 size_t len;
94
95#define HASH4a h = (h << 5) - h + *key++;
96#define HASH4b h = (h << 5) + h + *key++;
97#define HASH4 HASH4b
98
99 h = 0;
100 len = strlen(key);
101 loop = len >> 3;
102 switch (len & (8 - 1)) {
103 case 0:
26ac0430 104 break;
f52a7d75 105 case 7:
26ac0430
AJ
106 HASH4;
107 /* FALLTHROUGH */
f52a7d75 108 case 6:
26ac0430
AJ
109 HASH4;
110 /* FALLTHROUGH */
f52a7d75 111 case 5:
26ac0430
AJ
112 HASH4;
113 /* FALLTHROUGH */
f52a7d75 114 case 4:
26ac0430
AJ
115 HASH4;
116 /* FALLTHROUGH */
f52a7d75 117 case 3:
26ac0430
AJ
118 HASH4;
119 /* FALLTHROUGH */
f52a7d75 120 case 2:
26ac0430
AJ
121 HASH4;
122 /* FALLTHROUGH */
f52a7d75 123 case 1:
26ac0430 124 HASH4;
f52a7d75 125 }
126 while (loop--) {
26ac0430
AJ
127 HASH4;
128 HASH4;
129 HASH4;
130 HASH4;
131 HASH4;
132 HASH4;
133 HASH4;
134 HASH4;
f52a7d75 135 }
136 return h % size;
137}
138
139/*
140 * hash_create - creates a new hash table, uses the cmp_func
141 * to compare keys. Returns the identification for the hash table;
142 * otherwise returns a negative number on error.
143 */
144hash_table *
145hash_create(HASHCMP * cmp_func, int hash_sz, HASHHASH * hash_func)
146{
147 hash_table *hid = xcalloc(1, sizeof(hash_table));
148 if (!hash_sz)
26ac0430 149 hid->size = (unsigned int) DEFAULT_HASH_SIZE;
f52a7d75 150 else
26ac0430 151 hid->size = (unsigned int) hash_sz;
f52a7d75 152 /* allocate and null the buckets */
153 hid->buckets = xcalloc(hid->size, sizeof(hash_link *));
154 hid->cmp = cmp_func;
155 hid->hash = hash_func;
156 hid->next = NULL;
157 hid->current_slot = 0;
158 return hid;
159}
160
161/*
162 * hash_join - joins a hash_link under its key lnk->key
26ac0430 163 * into the hash table 'hid'.
f52a7d75 164 *
165 * It does not copy any data into the hash table, only links pointers.
166 */
167void
168hash_join(hash_table * hid, hash_link * lnk)
169{
170 int i;
171 i = hid->hash(lnk->key, hid->size);
172 lnk->next = hid->buckets[i];
173 hid->buckets[i] = lnk;
174 hid->count++;
175}
176
177/*
178 * hash_lookup - locates the item under the key 'k' in the hash table
179 * 'hid'. Returns a pointer to the hash bucket on success; otherwise
180 * returns NULL.
181 */
4a8b20e8 182hash_link *
f52a7d75 183hash_lookup(hash_table * hid, const void *k)
184{
185 hash_link *walker;
186 int b;
88bfe092 187 PROF_start(hash_lookup);
f52a7d75 188 assert(k != NULL);
189 b = hid->hash(k, hid->size);
190 for (walker = hid->buckets[b]; walker != NULL; walker = walker->next) {
26ac0430
AJ
191 if ((hid->cmp) (k, walker->key) == 0) {
192 PROF_stop(hash_lookup);
193 return (walker);
194 }
195 assert(walker != walker->next);
f52a7d75 196 }
88bfe092 197 PROF_stop(hash_lookup);
f52a7d75 198 return NULL;
199}
200
201static void
202hash_next_bucket(hash_table * hid)
203{
204 while (hid->next == NULL && ++hid->current_slot < hid->size)
26ac0430 205 hid->next = hid->buckets[hid->current_slot];
f52a7d75 206}
207
208/*
209 * hash_first - initializes the hash table for the hash_next()
210 * function.
211 */
212void
213hash_first(hash_table * hid)
214{
215 assert(NULL == hid->next);
216 hid->current_slot = 0;
217 hid->next = hid->buckets[hid->current_slot];
218 if (NULL == hid->next)
26ac0430 219 hash_next_bucket(hid);
f52a7d75 220}
221
222/*
223 * hash_next - returns the next item in the hash table 'hid'.
26ac0430 224 * Otherwise, returns NULL on error or end of list.
f52a7d75 225 *
226 * MUST call hash_first() before hash_next().
227 */
4a8b20e8 228hash_link *
f52a7d75 229hash_next(hash_table * hid)
230{
231 hash_link *this = hid->next;
232 if (NULL == this)
26ac0430 233 return NULL;
f52a7d75 234 hid->next = this->next;
235 if (NULL == hid->next)
26ac0430 236 hash_next_bucket(hid);
f52a7d75 237 return this;
238}
239
2c4f7ab2 240/*
241 * hash_last - resets hash traversal state to NULL
242 *
243 */
244void
ab96e65c 245hash_last(hash_table * hid)
2c4f7ab2 246{
137a13ea 247 assert(hid != NULL);
2c4f7ab2 248 hid->next = NULL;
249 hid->current_slot = 0;
250}
251
f52a7d75 252/*
26ac0430 253 * hash_remove_link - deletes the given hash_link node from the
f52a7d75 254 * hash table 'hid'. Does not free the item, only removes it
255 * from the list.
256 *
4fba1a24 257 * An assertion is triggered if the hash_link is not found in the
258 * list.
f52a7d75 259 */
260void
261hash_remove_link(hash_table * hid, hash_link * hl)
262{
263 hash_link **P;
264 int i;
265 assert(hl != NULL);
266 i = hid->hash(hl->key, hid->size);
267 for (P = &hid->buckets[i]; *P; P = &(*P)->next) {
26ac0430
AJ
268 if (*P != hl)
269 continue;
270 *P = hl->next;
271 if (hid->next == hl) {
272 hid->next = hl->next;
273 if (NULL == hid->next)
274 hash_next_bucket(hid);
275 }
276 hid->count--;
277 return;
f52a7d75 278 }
e530de6c 279 assert(0);
f52a7d75 280}
281
282/*
26ac0430 283 * hash_get_bucket - returns the head item of the bucket
f52a7d75 284 * in the hash table 'hid'. Otherwise, returns NULL on error.
285 */
286hash_link *
287hash_get_bucket(hash_table * hid, unsigned int bucket)
288{
289 if (bucket >= hid->size)
26ac0430 290 return NULL;
f52a7d75 291 return (hid->buckets[bucket]);
292}
293
294void
295hashFreeItems(hash_table * hid, HASHFREE * free_func)
296{
297 hash_link *l;
298 hash_link **list;
299 int i = 0;
300 int j;
301 list = xcalloc(hid->count, sizeof(hash_link *));
302 hash_first(hid);
303 while ((l = hash_next(hid)) && i < hid->count) {
26ac0430
AJ
304 *(list + i) = l;
305 i++;
f52a7d75 306 }
307 for (j = 0; j < i; j++)
26ac0430 308 free_func(*(list + j));
f52a7d75 309 xfree(list);
310}
311
312void
313hashFreeMemory(hash_table * hid)
314{
137a13ea 315 assert(hid != NULL);
efacbef0 316 if (hid->buckets)
26ac0430 317 xfree(hid->buckets);
f52a7d75 318 xfree(hid);
319}
320
26ac0430 321static int hash_primes[] = {
f52a7d75 322 103,
323 229,
324 467,
325 977,
326 1979,
327 4019,
328 6037,
329 7951,
330 12149,
331 16231,
332 33493,
333 65357
334};
335
336int
337hashPrime(int n)
338{
339 int I = sizeof(hash_primes) / sizeof(int);
340 int i;
341 int best_prime = hash_primes[0];
d87ebd78 342 double min = fabs(log((double) n) - log((double) hash_primes[0]));
f52a7d75 343 double d;
344 for (i = 0; i < I; i++) {
26ac0430
AJ
345 d = fabs(log((double) n) - log((double) hash_primes[i]));
346 if (d > min)
347 continue;
348 min = d;
349 best_prime = hash_primes[i];
f52a7d75 350 }
351 return best_prime;
352}
353
186477c1 354/*
355 * return the key of a hash_link as a const string
356 */
357const char *
358hashKeyStr(hash_link * hl)
359{
360 return (const char *) hl->key;
361}
362
f52a7d75 363
364#ifdef USE_HASH_DRIVER
365/*
366 * hash-driver - Run with a big file as stdin to insert each line into the
367 * hash table, then prints the whole hash table, then deletes a random item,
368 * and prints the table again...
369 */
370int
371main(void)
372{
373 hash_table *hid;
374 int i;
375 LOCAL_ARRAY(char, buf, BUFSIZ);
376 LOCAL_ARRAY(char, todelete, BUFSIZ);
377 hash_link *walker = NULL;
378
379 todelete[0] = '\0';
380 printf("init\n");
381
382 printf("creating hash table\n");
383 if ((hid = hash_create((HASHCMP *) strcmp, 229, hash4)) < 0) {
26ac0430
AJ
384 printf("hash_create error.\n");
385 exit(1);
f52a7d75 386 }
387 printf("done creating hash table: %d\n", hid);
388
389 while (fgets(buf, BUFSIZ, stdin)) {
26ac0430
AJ
390 buf[strlen(buf) - 1] = '\0';
391 printf("Inserting '%s' for item %p to hash table: %d\n",
392 buf, buf, hid);
393 hash_insert(hid, xstrdup(buf), (void *) 0x12345678);
394 if (random() % 17 == 0)
395 strcpy(todelete, buf);
f52a7d75 396 }
397
398 printf("walking hash table...\n");
399 for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
26ac0430
AJ
400 printf("item %5d: key: '%s' item: %p\n", i++, walker->key,
401 walker->item);
f52a7d75 402 }
403 printf("done walking hash table...\n");
404
405 if (todelete[0]) {
26ac0430
AJ
406 printf("deleting %s from %d\n", todelete, hid);
407 if (hash_delete(hid, todelete))
408 printf("hash_delete error\n");
f52a7d75 409 }
410 printf("walking hash table...\n");
411 for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
26ac0430
AJ
412 printf("item %5d: key: '%s' item: %p\n", i++, walker->key,
413 walker->item);
f52a7d75 414 }
415 printf("done walking hash table...\n");
416
417
418 printf("driver finished.\n");
419 exit(0);
420}
421#endif