]> git.ipfire.org Git - thirdparty/squid.git/blame - test-suite/hash.c
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / test-suite / hash.c
CommitLineData
14c63c25 1
2/*
262a0e14 3 * $Id$
14c63c25 4 *
5 * DEBUG: section 0 Hash Tables
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
14c63c25 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.
14c63c25 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 *
14c63c25 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 *
14c63c25 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
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
26ac0430 33 *
14c63c25 34 */
35
14c63c25 36#include <unistd.h>
37#include <stdlib.h>
38#include <stdio.h>
39#include <sys/types.h>
40#include <ctype.h>
41#include <sys/time.h>
42#include <strings.h>
e7740002 43#include <assert.h>
14c63c25 44#include "hash.h"
e7740002 45#undef free
468ae12b 46extern void my_free(char *, int, void *);
e7740002 47
48#define free(a) my_free(__FILE__, __LINE__, a)
14c63c25 49
da537f52 50extern void print_stats();
14c63c25 51/*
52 * hash_url() - Returns a well-distributed hash function for URLs.
53 * The best way is to sum up the last half of the string.
54 * Adapted from code written by Mic Bowman. -Darren
55 * Generates a standard deviation = 15.73
56 */
57unsigned int
58hash_url(const void *data, unsigned int size)
59{
60 const char *s = data;
61 unsigned int i, j, n;
62 j = strlen(s);
63 for (i = j / 2, n = 0; i < j; i++)
26ac0430 64 n ^= 271 * (unsigned) s[i];
14c63c25 65 i = n ^ (j * 271);
66 return i % size;
67}
68
69unsigned int
70hash_string(const void *data, unsigned int size)
71{
72 const char *s = data;
73 unsigned int n = 0;
74 unsigned int j = 0;
75 unsigned int i = 0;
76 while (*s) {
26ac0430
AJ
77 j++;
78 n ^= 271 * (unsigned) *s++;
14c63c25 79 }
80 i = n ^ (j * 271);
81 return i % size;
82}
83
84/* the following 4 functions were adapted from
85 * usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite */
86
87/*
88 * HASH FUNCTIONS
89 *
90 * Assume that we've already split the bucket to which this key hashes,
91 * calculate that bucket, and check that in fact we did already split it.
92 *
93 * This came from ejb's hsearch.
94 */
95
96#define PRIME1 37
97#define PRIME2 1048583
98
99/* Hash function from Chris Torek. */
100unsigned int
101hash4(const void *data, unsigned int size)
102{
103 const char *key = data;
104 size_t loop;
105 unsigned int h;
106 size_t len;
107
108#define HASH4a h = (h << 5) - h + *key++;
109#define HASH4b h = (h << 5) + h + *key++;
110#define HASH4 HASH4b
111
112 h = 0;
113 len = strlen(key);
114 loop = (len + 8 - 1) >> 3;
115 switch (len & (8 - 1)) {
116 case 0:
26ac0430
AJ
117 do {
118 HASH4;
119 /* FALLTHROUGH */
120 case 7:
121 HASH4;
122 /* FALLTHROUGH */
123 case 6:
124 HASH4;
125 /* FALLTHROUGH */
126 case 5:
127 HASH4;
128 /* FALLTHROUGH */
129 case 4:
130 HASH4;
131 /* FALLTHROUGH */
132 case 3:
133 HASH4;
134 /* FALLTHROUGH */
135 case 2:
136 HASH4;
137 /* FALLTHROUGH */
138 case 1:
139 HASH4;
140 } while (--loop);
14c63c25 141 }
142 return h % size;
143}
144
145/*
146 * hash_create - creates a new hash table, uses the cmp_func
147 * to compare keys. Returns the identification for the hash table;
148 * otherwise returns a negative number on error.
149 */
150hash_table *
151hash_create(HASHCMP * cmp_func, int hash_sz, HASHHASH * hash_func)
152{
153 hash_table *hid = calloc(1, sizeof(hash_table));
154 if (!hash_sz)
26ac0430 155 hid->size = (unsigned int) DEFAULT_HASH_SIZE;
14c63c25 156 else
26ac0430 157 hid->size = (unsigned int) hash_sz;
14c63c25 158 /* allocate and null the buckets */
159 hid->buckets = calloc(hid->size, sizeof(hash_link *));
160 hid->cmp = cmp_func;
161 hid->hash = hash_func;
162 hid->current_ptr = NULL;
163 hid->current_slot = 0;
164 return hid;
165}
166
167/*
168 * hash_insert - inserts the given item 'item' under the given key 'k'
169 * into the hash table 'hid'. Returns non-zero on error; otherwise,
170 * returns 0 and inserts the item.
171 *
172 * It does not copy any data into the hash table, only pointers.
173 */
174void
175hash_insert(hash_table * hid, const char *k, void *item)
176{
177 int i;
178 hash_link *new;
179 assert(k != NULL);
180 /* Add to the given hash table 'hid' */
181 new = calloc(1, sizeof(hash_link));
da537f52 182 if (!new) {
26ac0430
AJ
183 fprintf(stderr, "calloc failed!\n");
184 print_stats();
185 exit(1);
da537f52 186 }
14c63c25 187 new->item = item;
188 new->key = (char *) k;
189 i = hid->hash(k, hid->size);
190 new->next = hid->buckets[i];
191 hid->buckets[i] = new;
192}
193
194/*
195 * hash_join - joins a hash_link under its key lnk->key
26ac0430 196 * into the hash table 'hid'.
14c63c25 197 *
198 * It does not copy any data into the hash table, only links pointers.
199 */
200void
201hash_join(hash_table * hid, hash_link * lnk)
202{
203 int i;
204 i = hid->hash(lnk->key, hid->size);
205 lnk->next = hid->buckets[i];
206 hid->buckets[i] = lnk;
207}
208
209/*
210 * hash_lookup - locates the item under the key 'k' in the hash table
211 * 'hid'. Returns a pointer to the hash bucket on success; otherwise
212 * returns NULL.
213 */
214hash_link *
215hash_lookup(hash_table * hid, const void *k)
216{
217 hash_link *walker;
218 int b;
219 assert(k != NULL);
220 b = hid->hash(k, hid->size);
221 for (walker = hid->buckets[b]; walker != NULL; walker = walker->next) {
26ac0430
AJ
222 if ((hid->cmp) (k, walker->key) == 0)
223 return (walker);
224 assert(walker != walker->next);
14c63c25 225 }
226 return NULL;
227}
228
229/*
230 * hash_first - returns the first item in the hash table 'hid'.
231 * Otherwise, returns NULL on error.
232 */
233hash_link *
234hash_first(hash_table * hid)
235{
236 int i;
237
238 for (i = 0; i < hid->size; i++) {
26ac0430
AJ
239 hid->current_slot = i;
240 if (hid->buckets[i] != NULL)
241 return (hid->current_ptr = hid->buckets[i]);
14c63c25 242 }
243 return NULL;
244}
245
246/*
247 * hash_next - returns the next item in the hash table 'hid'.
26ac0430 248 * Otherwise, returns NULL on error or end of list.
14c63c25 249 *
250 * MUST call hash_first() before hash_next().
251 */
252hash_link *
253hash_next(hash_table * hid)
254{
255 int i;
256
257 if (hid->current_ptr != NULL) {
26ac0430
AJ
258 hid->current_ptr = hid->current_ptr->next;
259 if (hid->current_ptr != NULL)
260 return (hid->current_ptr); /* next item */
14c63c25 261 }
262 /* find next bucket */
263 for (i = hid->current_slot + 1; i < hid->size; i++) {
26ac0430
AJ
264 hid->current_slot = i;
265 if (hid->buckets[i] != NULL)
266 return (hid->current_ptr = hid->buckets[i]);
14c63c25 267 }
268 return NULL; /* end of list */
269}
270
271int
272hash_delete(hash_table * hid, const char *key)
273{
274 return hash_delete_link(hid, hash_lookup(hid, key));
275}
276
277/*
26ac0430 278 * hash_delete_link - deletes the given hash_link node from the
14c63c25 279 * hash table 'hid'. If FreeLink then free the given hash_link.
280 *
26ac0430 281 * On success, it returns 0 and deletes the link; otherwise,
14c63c25 282 * returns non-zero on error.
283 */
da537f52 284int
14c63c25 285hash_unlink(hash_table * hid, hash_link * hl, int FreeLink)
286{
287 hash_link *walker, *prev;
288 int i;
289 if (hl == NULL)
26ac0430 290 return -1;
14c63c25 291 i = hid->hash(hl->key, hid->size);
292 for (prev = NULL, walker = hid->buckets[i];
26ac0430
AJ
293 walker != NULL; prev = walker, walker = walker->next) {
294 if (walker == hl) {
295 if (prev == NULL) { /* it's the head */
296 hid->buckets[i] = walker->next;
297 } else {
298 prev->next = walker->next; /* skip it */
299 }
300 /* fix walker state if needed */
301 if (walker == hid->current_ptr)
302 hid->current_ptr = walker->next;
303 if (FreeLink) {
304 if (walker) {
305 free(walker);
306 }
307 }
308 return 0;
309 }
14c63c25 310 }
311 return 1;
312}
313
314/* take link off and free link node */
315int
316hash_delete_link(hash_table * hid, hash_link * hl)
317{
318 return (hash_unlink(hid, hl, 1));
319}
320
321/* take link off only */
322int
323hash_remove_link(hash_table * hid, hash_link * hl)
324{
325 return (hash_unlink(hid, hl, 0));
326}
327
328/*
26ac0430 329 * hash_get_bucket - returns the head item of the bucket
14c63c25 330 * in the hash table 'hid'. Otherwise, returns NULL on error.
331 */
332hash_link *
333hash_get_bucket(hash_table * hid, unsigned int bucket)
334{
335 if (bucket >= hid->size)
26ac0430 336 return NULL;
14c63c25 337 return (hid->buckets[bucket]);
338}
339
340
341void
342hashFreeMemory(hash_table * hid)
343{
468ae12b 344 if (hid->buckets);
14c63c25 345 free(hid->buckets);
468ae12b 346 if (hid)
26ac0430 347 free(hid);
14c63c25 348}
349
350
351#ifdef USE_HASH_DRIVER
352/*
353 * hash-driver - Run with a big file as stdin to insert each line into the
354 * hash table, then prints the whole hash table, then deletes a random item,
355 * and prints the table again...
356 */
357int
358main(void)
359{
360 hash_table *hid;
361 int i;
362 LOCAL_ARRAY(char, buf, BUFSIZ);
363 LOCAL_ARRAY(char, todelete, BUFSIZ);
364 hash_link *walker = NULL;
365
366 todelete[0] = '\0';
367 printf("init\n");
368
369 printf("creating hash table\n");
370 if ((hid = hash_create(strcmp, 229, hash_string)) < 0) {
26ac0430
AJ
371 printf("hash_create error.\n");
372 exit(1);
14c63c25 373 }
374 printf("done creating hash table: %d\n", hid);
375
376 while (fgets(buf, BUFSIZ, stdin)) {
26ac0430
AJ
377 buf[strlen(buf) - 1] = '\0';
378 printf("Inserting '%s' for item %p to hash table: %d\n",
379 buf, buf, hid);
380 hash_insert(hid, xstrdup(buf), (void *) 0x12345678);
381 if (random() % 17 == 0)
382 strcpy(todelete, buf);
14c63c25 383 }
384
385 printf("walking hash table...\n");
386 for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
26ac0430
AJ
387 printf("item %5d: key: '%s' item: %p\n", i++, walker->key,
388 walker->item);
14c63c25 389 }
390 printf("done walking hash table...\n");
391
392 if (todelete[0]) {
26ac0430
AJ
393 printf("deleting %s from %d\n", todelete, hid);
394 if (hash_delete(hid, todelete))
395 printf("hash_delete error\n");
14c63c25 396 }
397 printf("walking hash table...\n");
398 for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
26ac0430
AJ
399 printf("item %5d: key: '%s' item: %p\n", i++, walker->key,
400 walker->item);
14c63c25 401 }
402 printf("done walking hash table...\n");
403
404
405 printf("driver finished.\n");
406 exit(0);
407}
408#endif