Annotation of embedaddon/trafshow/hashtab.c, revision 1.1.1.1
1.1 misho 1: /*
2: --------------------------------------------------------------------
3: By Bob Jenkins, 1996. hashtab.c. Public Domain.
4:
5: This implements a hash table.
6: * Keys are unique. Adding an item fails if the key is already there.
7: * Keys and items are pointed at, not copied. If you change the value
8: of the key after it is inserted then hfind will not be able to find it.
9: * The hash table maintains a position that can be set and queried.
10: * The table length doubles dynamically and never shrinks. The insert
11: that causes table doubling may take a long time.
12: * The table length splits when the table length equals the number of items
13: Comparisons usually take 7 instructions.
14: Computing a hash value takes 35+6n instructions for an n-byte key.
15:
16: hcreate - create a hash table
17: hdestroy - destroy a hash table
18: hcount - The number of items in the hash table
19: hkey - key at the current position
20: hkeyl - key length at the current position
21: hstuff - stuff at the current position
22: hfind - find an item in the table
23: hadd - insert an item into the table
24: hdel - delete an item from the table
25: hstat - print statistics about the table
26: hfirst - position at the first item in the table
27: hnext - move the position to the next item in the table
28: --------------------------------------------------------------------
29: */
30:
31: #include <stdlib.h>
32: #include <string.h>
33:
34: #ifndef STANDARD
35: #include "standard.h"
36: #endif
37: #ifndef LOOKUPA
38: #include "lookupa.h"
39: #endif
40: #ifndef HASHTAB
41: #include "hashtab.h"
42: #endif
43: #ifndef RECYCLE
44: #include "recycle.h"
45: #endif
46:
47: #ifdef DEBUG
48: /* sanity check -- make sure ipos, apos, and count make sense */
49: static void hsanity(t)
50: htab *t;
51: {
52: ub4 i, end, counter;
53: hitem *h;
54:
55: /* test that apos makes sense */
56: end = (ub4)1<<(t->logsize);
57: if (end < t->apos)
58: fprintf(stderr, "hsanity: end %ld, apos %ld\n", end, t->apos);
59:
60: /* test that ipos is in bucket apos */
61: if (t->ipos)
62: {
63: for (h=t->table[t->apos]; h && h != t->ipos; h = h->next)
64: ;
65: if (h != t->ipos)
66: fprintf(stderr, "hsanity: ipos not in apos, apos is %ld\n", t->apos);
67: }
68:
69: /* test that t->count is the number of elements in the table */
70: counter=0;
71: for (counter=0, i=0; i<end; ++i)
72: for (h=t->table[i]; h; h=h->next)
73: ++counter;
74: if (counter != t->count)
75: fprintf(stderr, "hsanity: counter %ld, t->count %ld\n", counter, t->count);
76: }
77: #endif /* DEBUG */
78:
79:
80: /*
81: * hgrow - Double the size of a hash table.
82: * Allocate a new, 2x bigger array,
83: * move everything from the old array to the new array,
84: * then free the old array.
85: */
86: static void hgrow( t)
87: htab *t; /* table */
88: {
89: register ub4 newsize = (ub4)1<<(++t->logsize);
90: register ub4 newmask = newsize-1;
91: register ub4 i;
92: register hitem **oldtab = t->table;
93: register hitem **newtab = (hitem **)malloc(newsize*sizeof(hitem *));
94: if (!newtab) return;
95:
96: /* make sure newtab is cleared */
97: for (i=0; i<newsize; ++i) newtab[i] = (hitem *)0;
98: t->table = newtab;
99: t->mask = newmask;
100:
101: /* Walk through old table putting entries in new table */
102: for (i=newsize>>1; i--;)
103: {
104: register hitem *this, *that, **newplace;
105: for (this = oldtab[i]; this;)
106: {
107: that = this;
108: this = this->next;
109: newplace = &newtab[(that->hval & newmask)];
110: that->next = *newplace;
111: *newplace = that;
112: }
113: }
114:
115: /* position the hash table on some existing item */
116: hfirst(t);
117:
118: /* free the old array */
119: free((char *)oldtab);
120:
121: }
122:
123: /* hcreate - create a hash table initially of size power(2,logsize) */
124: htab *hcreate(logsize)
125: word logsize; /* log base 2 of the size of the hash table */
126: {
127: ub4 i,len;
128: htab *t = (htab *)malloc(sizeof(htab));
129: if (!t) return 0;
130:
131: len = ((ub4)1<<logsize);
132: t->table = (hitem **)malloc(sizeof(hitem *)*(ub4)len);
133: if (!t->table) return 0;
134: for (i=0; i<len; ++i) t->table[i] = (hitem *)0;
135: t->logsize = logsize;
136: t->mask = len-1;
137: t->count = 0;
138: t->apos = (ub4)0;
139: t->ipos = (hitem *)0;
140: t->space = remkroot(sizeof(hitem));
141: if (!t->space) return 0;
142: t->bcount = 0;
143: return t;
144: }
145:
146: /* hdestroy - destroy the hash table and free all its memory */
147: void hdestroy( t)
148: htab *t; /* the table */
149: {
150: refree(t->space);
151: free((char *)t->table);
152: free((char *)t);
153: }
154:
155: /* hcount() is a macro, see hashtab.h */
156: /* hkey() is a macro, see hashtab.h */
157: /* hkeyl() is a macro, see hashtab.h */
158: /* hstuff() is a macro, see hashtab.h */
159:
160: /* hfind - find an item with a given key in a hash table */
161: word hfind( t, key, keyl )
162: htab *t; /* table */
163: ub1 *key; /* key to find */
164: ub4 keyl; /* key length */
165: {
166: hitem *h;
167: ub4 x = lookup(key,keyl,0);
168: ub4 y;
169: for (h = t->table[y=(x&t->mask)]; h; h = h->next)
170: {
171: if ((x == h->hval) &&
172: (keyl == h->keyl) &&
173: !memcmp(key, h->key, keyl))
174: {
175: t->apos = y;
176: t->ipos = h;
177: return TRUE;
178: }
179: }
180: return FALSE;
181: }
182:
183: /*
184: * hadd - add an item to a hash table.
185: * return FALSE if the key is already there, otherwise TRUE.
186: */
187: word hadd( t, key, keyl, stuff)
188: htab *t; /* table */
189: ub1 *key; /* key to add to hash table */
190: ub4 keyl; /* key length */
191: void *stuff; /* stuff to associate with this key */
192: {
193: register hitem *h,**hp;
194: register ub4 y, x = lookup(key,keyl,0);
195:
196: /* make sure the key is not already there */
197: for (h = t->table[(y=(x&t->mask))]; h; h = h->next)
198: {
199: if ((x == h->hval) &&
200: (keyl == h->keyl) &&
201: !memcmp(key, h->key, keyl))
202: {
203: t->apos = y;
204: t->ipos = h;
205: return FALSE;
206: }
207: }
208:
209: /* find space for a new item */
210: h = (hitem *)renew(t->space);
211: if (!h) return -1;
212:
213: /* make the hash table bigger if it is getting full */
214: if (++t->count > (ub4)1<<(t->logsize))
215: {
216: hgrow(t);
217: y = (x&t->mask);
218: }
219:
220: /* add the new key to the table */
221: h->key = key;
222: h->keyl = keyl;
223: h->stuff = stuff;
224: h->hval = x;
225: hp = &t->table[y];
226: h->next = *hp;
227: *hp = h;
228: t->ipos = h;
229: t->apos = y;
230:
231: #ifdef DEBUG
232: hsanity(t);
233: #endif /* DEBUG */
234:
235: return TRUE;
236: }
237:
238: /* hdel - delete the item at the current position */
239: word hdel(t)
240: htab *t; /* the hash table */
241: {
242: hitem *h; /* item being deleted */
243: hitem **ip; /* a counter */
244:
245: /* check for item not existing */
246: if (!(h = t->ipos)) return FALSE;
247:
248: /* remove item from its list */
249: for (ip = &t->table[t->apos]; *ip != h; ip = &(*ip)->next)
250: ;
251: *ip = (*ip)->next;
252: --(t->count);
253:
254: /* adjust position to something that exists */
255: if (!(t->ipos = h->next)) hnbucket(t);
256:
257: /* recycle the deleted hitem node */
258: redel(t->space, h);
259:
260: #ifdef DEBUG
261: hsanity(t);
262: #endif /* DEBUG */
263:
264: return TRUE;
265: }
266:
267: /* hfirst - position on the first element in the table */
268: word hfirst(t)
269: htab *t; /* the hash table */
270: {
271: t->apos = t->mask;
272: (void)hnbucket(t);
273: return (t->ipos != (hitem *)0);
274: }
275:
276: /* hnext() is a macro, see hashtab.h */
277:
278: /*
279: * hnbucket - Move position to the first item in the next bucket.
280: * Return TRUE if we did not wrap around to the beginning of the table
281: */
282: word hnbucket(t)
283: htab *t;
284: {
285: ub4 oldapos = t->apos;
286: ub4 end = (ub4)1<<(t->logsize);
287: ub4 i;
288:
289: /* see if the element can be found without wrapping around */
290: for (i=oldapos+1; i<end; ++i)
291: {
292: if (t->table[i&t->mask])
293: {
294: t->apos = i;
295: t->ipos = t->table[i];
296: return TRUE;
297: }
298: }
299:
300: /* must have to wrap around to find the last element */
301: for (i=0; i<=oldapos; ++i)
302: {
303: if (t->table[i])
304: {
305: t->apos = i;
306: t->ipos = t->table[i];
307: return FALSE;
308: }
309: }
310:
311: return FALSE;
312: }
313:
314: void hstat(fp, t)
315: FILE *fp;
316: htab *t;
317: {
318: ub4 i,j;
319: double total = 0.0;
320: hitem *h;
321: hitem *walk, *walk2, *stat = (hitem *)0;
322:
323: /* in stat, keyl will store length of list, hval the number of buckets */
324: for (i=0; i<=t->mask; ++i)
325: {
326: for (h=t->table[i], j=0; h; ++j, h=h->next)
327: ;
328: for (walk=stat; walk && (walk->keyl != j); walk=walk->next)
329: ;
330: if (walk)
331: {
332: ++(walk->hval);
333: }
334: else
335: {
336: walk = (hitem *)renew(t->space);
337: if (!walk) {
338: fprintf(fp, "renew: Can't allocate memory?\n");
339: return;
340: }
341: walk->keyl = j;
342: walk->hval = 1;
343: if (!stat || stat->keyl > j) {walk->next=stat; stat=walk;}
344: else
345: {
346: for (walk2=stat;
347: walk2->next && (walk2->next->keyl<j);
348: walk2=walk2->next)
349: ;
350: walk->next = walk2->next;
351: walk2->next = walk;
352: }
353: }
354: }
355:
356: /* figure out average list length for existing elements */
357: for (walk=stat; walk; walk=walk->next)
358: {
359: total+=(double)walk->hval*(double)walk->keyl*(double)walk->keyl;
360: }
361: if (t->count) total /= (double)t->count;
362: else total = (double)0;
363:
364: /* print statistics */
365: fprintf(fp, "\n");
366: for (walk=stat; walk; walk=walk->next)
367: {
368: fprintf(fp, "items %ld: %ld buckets\n", walk->keyl, walk->hval);
369: }
370: fprintf(fp, "\nbuckets: %ld items: %ld existing: %g\n\n",
371: ((ub4)1<<t->logsize), t->count, total);
372:
373: /* clean up */
374: while (stat)
375: {
376: walk = stat->next;
377: redel(t->space, stat);
378: stat = walk;
379: }
380: }
381:
382:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>