SDDSlib
Loading...
Searching...
No Matches
hashtab.c File Reference

Implements a hash table. More...

#include "standard.h"
#include "lookupa.h"
#include "hashtab.h"
#include "recycle.h"

Go to the source code of this file.

Functions

static void hgrow (htab *t)
 
htab * hcreate (word logsize)
 Create a hash table.
 
void hdestroy (htab *t)
 Destroy the hash table and free all its memory.
 
word hfind (htab *t, ub1 *key, ub4 keyl)
 Find an item with a given key in the hash table.
 
word hadd (htab *t, ub1 *key, ub4 keyl, void *stuff)
 Add an item to the hash table.
 
word hdel (htab *t)
 
word hfirst (htab *t)
 Position the hash table on the first element.
 
word hnbucket (htab *t)
 
void hstat (htab *t)
 

Detailed Description

Implements a hash table.

Author
Bob Jenkins
Date
1996

Keys are unique. Adding an item fails if the key is already there. Keys and items are pointed at, not copied. If you change the value of the key after it is inserted then hfind() will not be able to find it. The hash table maintains a position that can be set and queried. The table length doubles dynamically and never shrinks. The insert that causes table doubling may take a long time. The table length splits when the table length equals the number of items. Comparisons usually take 7 instructions. Computing a hash value takes 35+6n instructions for an n-byte key.

Functions provided:

  • hcreate() - create a hash table
  • hdestroy() - destroy a hash table
  • hcount() - the number of items in the hash table
  • hkey() - key at the current position
  • hkeyl() - key length at the current position
  • hstuff() - stuff at the current position
  • hfind() - find an item in the table
  • hadd() - insert an item into the table
  • hdel() - delete an item from the table
  • hstat() - print statistics about the table
  • hfirst() - position at the first item in the table
  • hnext() - move the position to the next item in the table

Definition in file hashtab.c.

Function Documentation

◆ hadd()

word hadd ( htab * t,
ub1 * key,
ub4 keyl,
void * stuff )

Add an item to the hash table.

Inserts an item into the hash table with the given key and associated data.

Parameters
tPointer to the hash table.
keyKey to add to the hash table.
keylLength of the key.
stuffData to associate with the key.
Returns
TRUE if the item was added successfully, FALSE if the key is already in the table.

Definition at line 207 of file hashtab.c.

212{
213 register hitem *h, **hp;
214 register ub4 y, x = lookup(key, keyl, 0);
215 /* make sure the key is not already there */
216 for (h = t->table[(y = (x & t->mask))]; h; h = h->next) {
217 if ((x == h->hval) && (keyl == h->keyl) && !memcmp(key, h->key, keyl)) {
218 t->apos = y;
219 t->ipos = h;
220 return FALSE;
221 }
222 }
223
224 /* find space for a new item */
225 h = (hitem *)renew(t->space);
226
227 /* make the hash table bigger if it is getting full */
228 if (++t->count > (ub4)1 << (t->logsize)) {
229 hgrow(t);
230 y = (x & t->mask);
231 }
232
233 /* add the new key to the table */
234
235 h->key = (ub1 *)malloc(keyl); /* dumb use of malloc */
236 memcpy(h->key, key, keyl); /* copy key into h->key */
237 h->keyl = keyl;
238 h->stuff = stuff;
239 h->hval = x;
240 hp = &t->table[y];
241 h->next = *hp;
242 *hp = h;
243 t->ipos = h;
244 t->apos = y;
245
246#ifdef HSANITY
247 hsanity(t);
248#endif /* HSANITY */
249
250 return TRUE;
251}

◆ hcreate()

htab * hcreate ( word logsize)

Create a hash table.

Initializes a hash table with an initial size of 2 raised to the power of logsize.

Parameters
logsizeLog base 2 of the initial size of the hash table.
Returns
Pointer to the newly created hash table.

Definition at line 124 of file hashtab.c.

126{
127 ub4 i, len;
128 htab *t = (htab *)malloc(sizeof(htab));
129
130 len = ((ub4)1 << logsize);
131 t->table = (hitem **)malloc(sizeof(hitem *) * (ub4)len);
132 for (i = 0; i < len; ++i)
133 t->table[i] = (hitem *)0;
134 t->logsize = logsize;
135 t->mask = len - 1;
136 t->count = 0;
137 t->apos = (ub4)0;
138 t->ipos = (hitem *)0;
139 t->space = remkroot(sizeof(hitem));
140 t->bcount = 0;
141 return t;
142}

◆ hdel()

word hdel ( htab * t)

Definition at line 254 of file hashtab.c.

256{
257 hitem *h; /* item being deleted */
258 hitem **ip; /* a counter */
259
260 /* check for item not existing */
261 if (!(h = t->ipos))
262 return FALSE;
263
264 /* remove item from its list */
265 for (ip = &t->table[t->apos]; *ip != h; ip = &(*ip)->next)
266 ;
267 *ip = (*ip)->next;
268 --(t->count);
269
270 /* adjust position to something that exists */
271 if (!(t->ipos = h->next))
272 hnbucket(t);
273
274 /* recycle the deleted hitem node */
275 redel(t->space, h);
276
277#ifdef HSANITY
278 hsanity(t);
279#endif /* HSANITY */
280
281 return TRUE;
282}

◆ hdestroy()

void hdestroy ( htab * t)

Destroy the hash table and free all its memory.

Parameters
tPointer to the hash table to destroy.

Definition at line 149 of file hashtab.c.

151{
152 while (hcount(t)) /* while the table is not empty */
153 {
154 if (hkey(t))
155 free(hkey(t)); /* free memory for the line */
156 hdel(t); /* delete from hash table */
157 }
158 refree(t->space);
159 free((char *)t->table);
160 free((char *)t);
161}

◆ hfind()

word hfind ( htab * t,
ub1 * key,
ub4 keyl )

Find an item with a given key in the hash table.

Searches for an item with the specified key in the hash table.

Parameters
tPointer to the hash table.
keyKey to find.
keylLength of the key.
Returns
TRUE if the item is found, FALSE otherwise.

Definition at line 178 of file hashtab.c.

182{
183 hitem *h;
184 ub4 x = lookup(key, keyl, 0);
185 ub4 y;
186 for (h = t->table[y = (x & t->mask)]; h; h = h->next) {
187 if ((x == h->hval) && (keyl == h->keyl) && !memcmp(key, h->key, keyl)) {
188 t->apos = y;
189 t->ipos = h;
190 return TRUE;
191 }
192 }
193 return FALSE;
194}

◆ hfirst()

word hfirst ( htab * t)

Position the hash table on the first element.

Sets the current position to the first item in the hash table.

Parameters
tPointer to the hash table.
Returns
TRUE if the first element exists, FALSE otherwise.

Definition at line 292 of file hashtab.c.

294{
295 t->apos = t->mask;
296 (void)hnbucket(t);
297 return (t->ipos != (hitem *)0);
298}

◆ hgrow()

static void hgrow ( htab * t)
static

Definition at line 82 of file hashtab.c.

84{
85 register ub4 newsize = (ub4)1 << (++t->logsize);
86 register ub4 newmask = newsize - 1;
87 register ub4 i;
88 register hitem **oldtab = t->table;
89 register hitem **newtab = (hitem **)malloc(newsize * sizeof(hitem *));
90
91 /* make sure newtab is cleared */
92 for (i = 0; i < newsize; ++i)
93 newtab[i] = (hitem *)0;
94 t->table = newtab;
95 t->mask = newmask;
96
97 /* Walk through old table putting entries in new table */
98 for (i = newsize >> 1; i--;) {
99 register hitem *this, *that, **newplace;
100 for (this = oldtab[i]; this;) {
101 that = this;
102 this = this->next;
103 newplace = &newtab[(that->hval & newmask)];
104 that->next = *newplace;
105 *newplace = that;
106 }
107 }
108
109 /* position the hash table on some existing item */
110 hfirst(t);
111
112 /* free the old array */
113 free((char *)oldtab);
114}
word hfirst(htab *t)
Position the hash table on the first element.
Definition hashtab.c:292

◆ hnbucket()

word hnbucket ( htab * t)

Definition at line 306 of file hashtab.c.

308{
309 ub4 oldapos = t->apos;
310 ub4 end = (ub4)1 << (t->logsize);
311 ub4 i;
312
313 /* see if the element can be found without wrapping around */
314 for (i = oldapos + 1; i < end; ++i) {
315 if (t->table[i & t->mask]) {
316 t->apos = i;
317 t->ipos = t->table[i];
318 return TRUE;
319 }
320 }
321
322 /* must have to wrap around to find the last element */
323 for (i = 0; i <= oldapos; ++i) {
324 if (t->table[i]) {
325 t->apos = i;
326 t->ipos = t->table[i];
327 return FALSE;
328 }
329 }
330
331 return FALSE;
332}

◆ hstat()

void hstat ( htab * t)

Definition at line 334 of file hashtab.c.

336{
337 ub4 i, j;
338 double total = 0.0;
339 hitem *h;
340 hitem *walk, *walk2, *stat = (hitem *)0;
341
342 /* in stat, keyl will store length of list, hval the number of buckets */
343 for (i = 0; i <= t->mask; ++i) {
344 for (h = t->table[i], j = 0; h; ++j, h = h->next)
345 ;
346 for (walk = stat; walk && (walk->keyl != j); walk = walk->next)
347 ;
348 if (walk) {
349 ++(walk->hval);
350 } else {
351 walk = (hitem *)renew(t->space);
352 walk->keyl = j;
353 walk->hval = 1;
354 if (!stat || stat->keyl > j) {
355 walk->next = stat;
356 stat = walk;
357 } else {
358 for (walk2 = stat; walk2->next && (walk2->next->keyl < j); walk2 = walk2->next)
359 ;
360 walk->next = walk2->next;
361 walk2->next = walk;
362 }
363 }
364 }
365
366 /* figure out average list length for existing elements */
367 for (walk = stat; walk; walk = walk->next) {
368 total += (double)walk->hval * (double)walk->keyl * (double)walk->keyl;
369 }
370 if (t->count)
371 total /= (double)t->count;
372 else
373 total = (double)0;
374
375 /* print statistics */
376 printf("\n");
377 for (walk = stat; walk; walk = walk->next) {
378 printf("items %ld: %ld buckets\n", walk->keyl, walk->hval);
379 }
380 printf("\nbuckets: %ld items: %ld existing: %g\n\n", ((ub4)1 << t->logsize), t->count, total);
381
382 /* clean up */
383 while (stat) {
384 walk = stat->next;
385 redel(t->space, stat);
386 stat = walk;
387 }
388}