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