2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
27 ** A genericTable is a mapping from string keys to void * objects.
28 ** We sacrific type checking here for code reuse.
31 # include "lclintMacros.nf"
33 # include "randomNumbers.h"
35 /*@constant null ghbucket ghbucket_undefined; @*/
36 # define ghbucket_undefined 0
38 static /*@truenull@*/ bool ghbucket_isNull (/*@null@*/ ghbucket h)
40 return (h == ghbucket_undefined);
44 ghentry_create (/*@keep@*/ cstring key, /*@keep@*/ void *val)
46 ghentry h = (ghentry) dmalloc (sizeof (*h));
50 llassert (val != NULL);
57 ghbucket_isEmpty (ghbucket h)
59 return (h == ghbucket_undefined || h->size == 0);
62 int genericTable_size (genericTable h)
64 if (genericTable_isDefined (h)) {
72 ghbucket_unparse (ghbucket h)
74 cstring s = cstring_undefined;
76 if (!ghbucket_isNull (h))
80 for (i = 0; i < h->size; i++)
82 s = message ("%q %s", s, h->entries[i]->key);
89 static ghbucket ghbucket_single (/*@keep@*/ ghentry e)
91 ghbucket h = (ghbucket) dmalloc (sizeof (*h));
94 h->nspace = GHBUCKET_BASESIZE - 1;
95 h->entries = (ghentry *) dmalloc (GHBUCKET_BASESIZE * sizeof (*h->entries));
96 /*@i23@*/ h->entries[0] = e;
102 ghbucket_grow (/*@notnull@*/ ghbucket h)
107 h->nspace += GHBUCKET_BASESIZE;
109 newentries = (ghentry *)
110 dmalloc ((h->size + GHBUCKET_BASESIZE) * sizeof (*newentries));
112 for (i = 0; i < h->size; i++)
114 newentries[i] = h->entries[i];
117 /*@i32@*/ sfree (h->entries);
118 h->entries = newentries;
121 static /*@null@*/ /*@exposed@*/ void *ghbucket_lookup (ghbucket p_h, cstring p_key);
124 ** bizarre duplicate behaviour
125 ** required for duplicate entries
129 ghbucket_add (/*@notnull@*/ ghbucket h, /*@only@*/ ghentry e)
131 void *exloc = ghbucket_lookup (h, e->key);
137 if (h->nspace == 0) {
141 h->entries[h->size] = e;
147 ghbucket_ncollisions (ghbucket h)
149 if (!ghbucket_isNull (h) && (h->size > 1))
150 return (h->size - 1);
155 /*@exposed@*/ /*@null@*/ void *
156 ghbucket_lookup (ghbucket h, cstring key)
158 if (!ghbucket_isNull (h))
162 for (i = 0; i < h->size; i++)
164 if (cstring_equal (h->entries[i]->key, key))
166 return h->entries[i]->val;
175 void ghbucket_free (/*@only@*/ ghbucket h)
177 if (!ghbucket_isNull (h))
179 /*@i32@*/ sfree (h->entries);
185 genericTable_free (/*@only@*/ genericTable h)
187 if (genericTable_isDefined (h))
191 for (i = 0; i < h->size; i++)
193 ghbucket_free (h->buckets[i]);
202 genericTable_countCollisions (genericTable h)
207 llassert (genericTable_isDefined (h));
209 for (i = 0; i < h->size; i++)
211 nc += ghbucket_ncollisions (h->buckets[i]);
219 genericTable_countEmpty (genericTable h)
224 llassert (genericTable_isDefined (h));
226 for (i = 0; i < h->size; i++)
228 if (ghbucket_isEmpty (h->buckets[i]))
238 ** hash function snarfed from quake/hash.c Hash_String
239 ** by Stephen Harrison
243 genericTable_hashValue (/*@notnull@*/ genericTable h, cstring key)
246 unsigned int hash_value = 0;
248 llassert (h->size != 0);
250 for (p = cstring_toCharsSafe (key); *p != '\0'; p++)
252 hash_value = (hash_value << 1) ^ g_randomNumbers[*p % 256];
255 return (hash_value % h->size);
258 static /*@exposed@*/ ghbucket
259 genericTable_hash (/*@notnull@*/ genericTable h, cstring key)
261 return h->buckets[genericTable_hashValue (h, key)];
265 /*@only@*/ genericTable
266 genericTable_create (int size)
269 genericTable h = (genericTable) dmalloc (sizeof (*h));
274 h->buckets = (ghbucket *) dmalloc (sizeof (*h->buckets) * size);
277 for (i = 0; i < size; i++)
279 h->buckets[i] = ghbucket_undefined;
286 static /*@unused@*/ void
287 genericTable_print (genericTable h)
291 if (genericTable_isDefined (h)) {
292 for (i = 0; i < h->size; i++)
294 ghbucket hb = h->buckets[i];
298 llmsg (message ("%d. %s\n", i, ghbucket_unparse (hb)));
302 llmsg (message ("size: %d, collisions: %d, empty: %d",
304 genericTable_countCollisions (h),
305 genericTable_countEmpty (h)));
307 llmsglit ("Empty hash table.");
313 genericTable_stats (genericTable h)
315 llassert (genericTable_isDefined (h));
316 return (message ("size: %d, collisions: %d, empty: %d\n",
317 h->size, genericTable_countCollisions (h),
318 genericTable_countEmpty (h)));
322 genericTable_addEntry (/*@notnull@*/ genericTable h, /*@keep@*/ ghentry e)
324 unsigned int hindex = genericTable_hashValue (h, e->key);
327 ** ghbucket hb = h->buckets[hindex];
328 ** instead reveals a bug I don't want to deal with right now!
333 if (ghbucket_isNull (h->buckets[hindex]))
335 h->buckets[hindex] = ghbucket_single (e);
339 /*@i23@*/ ghbucket_add (h->buckets[hindex], e);
344 genericTable_insert (genericTable h, cstring key, void *value)
350 llassert (genericTable_isDefined (h));
353 ** rehashing based (loosely) on code by Steve Harrison
356 if (h->nentries * 162 > h->size * 100)
359 int oldsize = h->size;
360 int newsize = 1 + ((oldsize * 26244) / 10000); /* 26244 = 162^2 */
361 ghbucket *oldbuckets = h->buckets;
363 DPRINTF (("Rehashing..."));
366 h->buckets = (ghbucket *) dmalloc (sizeof (*h->buckets) * newsize);
369 for (i = 0; i < newsize; i++)
371 h->buckets[i] = ghbucket_undefined;
375 for (i = 0; i < oldsize; i++)
377 ghbucket bucket = oldbuckets[i];
379 oldbuckets[i] = NULL;
381 if (!ghbucket_isNull (bucket))
385 for (j = 0; j < bucket->size; j++)
387 genericTable_addEntry (h, bucket->entries[j]);
390 sfree (bucket->entries); /* evans 2001-03-24: LCLint caught this */
398 /* evans 2000-12-22: this was before the rehash! Lost an entry size! */
400 e = ghentry_create (key, value);
401 hindex = genericTable_hashValue (h, key);
402 hb = h->buckets[hindex];
404 if (ghbucket_isNull (hb))
406 /*@i23@*/ h->buckets[hindex] = ghbucket_single (e);
410 ghbucket_add (hb, e);
414 /*@null@*/ /*@exposed@*/ void *
415 genericTable_lookup (genericTable h, cstring key)
419 llassert (genericTable_isDefined (h));
421 hb = genericTable_hash (h, key);
422 res = ghbucket_lookup (hb, key);
424 /* if (res == NULL) { DPRINTF (("Lookup not found: %s", key)); } */
429 genericTable_update (genericTable h, cstring key, /*@only@*/ void *newval)
433 llassert (genericTable_isDefined (h));
435 hb = genericTable_hash (h, key);
437 if (!ghbucket_isNull (hb))
441 for (i = 0; i < hb->size; i++)
443 if (cstring_equal (hb->entries[i]->key, key))
445 llassert (newval != NULL);
446 hb->entries[i]->val = newval;
452 llbug (message ("genericTable_update: %s not found", key));
456 genericTable_remove (genericTable h, cstring key)
460 llassert (genericTable_isDefined (h));
461 hb = genericTable_hash (h, key);
463 if (!ghbucket_isNull (hb))
467 for (i = 0; i < hb->size; i++)
469 if (cstring_equal (hb->entries[i]->key, key))
471 if (i < hb->size - 1)
473 hb->entries[i] = hb->entries[hb->size - 1];
482 llbug (message ("genericTable_removeKey: %s not found", key));
485 bool genericTable_contains (genericTable h, cstring key)
487 return (genericTable_lookup (h, key) != NULL);