2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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 splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
27 ** Since hsearch defined in <search.h> only allows one hash table,
28 ** I'll implement my own.
30 ** Try to find a decent hash function, etc. later...
32 ** cstringTable is from string -> unsigned
36 # include "splintMacros.nf"
38 # include "randomNumbers.h"
40 /*@constant null hbucket hbucket_undefined; @*/
41 # define hbucket_undefined 0
44 cstringTable_addEntry (/*@notnull@*/ cstringTable p_h, /*@only@*/ hentry p_e)
47 static /*@nullwhentrue@*/ bool hbucket_isNull (/*@null@*/ hbucket h)
49 return (h == hbucket_undefined);
52 static hentry hentry_create (/*@only@*/ cstring key, int val)
54 hentry h = (hentry) dmalloc (sizeof (*h));
58 llassert (val != HBUCKET_DNE); /*@i523 way bogus! */
63 static void hentry_free (/*@only@*/ hentry h)
65 cstring_free (h->key);
70 hbucket_isEmpty (hbucket h)
72 return (h == hbucket_undefined || h->size == 0);
76 hbucket_unparse (hbucket h)
78 cstring s = cstring_undefined;
80 if (!hbucket_isNull (h))
84 for (i = 0; i < h->size; i++)
86 /*drl bee: si*/ s = message ("%q %s:%d", s, h->entries[i]->key, h->entries[i]->val);
94 hbucket_single (/*@only@*/ hentry e)
96 hbucket h = (hbucket) dmalloc (sizeof (*h));
99 h->nspace = HBUCKET_BASESIZE - 1;
100 h->entries = (hentry *) dmalloc (HBUCKET_BASESIZE * sizeof (*h->entries));
101 /*drl bee: dm*/ h->entries[0] = e;
107 hbucket_grow (/*@notnull@*/ hbucket h)
112 h->nspace += HBUCKET_BASESIZE;
114 newentries = (hentry *)
115 dmalloc ((h->size + HBUCKET_BASESIZE) * sizeof (*newentries));
117 for (i = 0; i < h->size; i++)
120 /*drl bee: si*/ newentries[i] = h->entries[i];
123 /*@i32@*/ sfree (h->entries);
124 h->entries = newentries;
127 static int hbucket_lookup (hbucket p_h, cstring p_key);
129 static bool hbucket_contains (hbucket p_h, cstring p_key) /*@*/ {
130 return (hbucket_lookup (p_h, p_key) != HBUCKET_DNE);
134 ** bizarre duplicate behaviour
135 ** required for duplicate entries
139 hbucket_add (/*@notnull@*/ hbucket h, /*@only@*/ hentry e)
141 int exloc = hbucket_lookup (h, e->key);
143 llassert (exloc == HBUCKET_DNE);
150 llassert (e->val != HBUCKET_DNE);
151 /*drl bee: si*/ h->entries[h->size] = e;
157 hbucket_ncollisions (hbucket h)
159 if (!hbucket_isNull (h) && (h->size > 1))
160 return (h->size - 1);
166 hbucket_lookup (hbucket h, cstring key)
168 if (!hbucket_isNull (h))
172 for (i = 0; i < h->size; i++)
174 /*drl bee: si*/ if (cstring_equal (h->entries[i]->key, key))
176 return h->entries[i]->val;
185 void hbucket_free (/*@only@*/ hbucket h)
187 if (!hbucket_isNull (h))
190 /* evans 2002-07-12: added this to free entries (splint warning had been suppressed) */
191 for (i = 0; i < h->size; i++)
193 hentry_free (h->entries[i]);
202 cstringTable_free (/*@only@*/ cstringTable h)
206 llassert (cstringTable_isDefined (h));
208 for (i = 0; i < h->size; i++)
210 /*drl bee: si*/ hbucket_free (h->buckets[i]);
218 cstringTable_countCollisions (cstringTable h)
223 llassert (cstringTable_isDefined (h));
225 for (i = 0; i < h->size; i++)
227 /*drl bee: si*/ nc += hbucket_ncollisions (h->buckets[i]);
235 cstringTable_countEmpty (cstringTable h)
240 llassert (cstringTable_isDefined (h));
242 for (i = 0; i < h->size; i++)
244 /*drl bee: si*/ if (hbucket_isEmpty (h->buckets[i]))
254 ** hash function snarfed from quake/hash.c Hash_String
255 ** by Stephen Harrison
259 cstringTable_hashValue (/*@notnull@*/ cstringTable h, cstring key)
262 unsigned int hash_value = 0;
264 for (p = cstring_toCharsSafe (key); *p != '\0'; p++)
266 /*drl bee: nm*/ hash_value = (hash_value << 1) ^ g_randomNumbers[*p % 256];
269 return (hash_value % h->size);
272 static /*@exposed@*/ hbucket
273 cstringTable_hash (/*@notnull@*/ cstringTable h, cstring key)
275 return h->buckets[cstringTable_hashValue (h, key)];
279 /*@only@*/ cstringTable
280 cstringTable_create (int size)
283 cstringTable h = (cstringTable) dmalloc (sizeof (*h));
287 h->buckets = (hbucket *) dmalloc (sizeof (*h->buckets) * size);
290 for (i = 0; i < size; i++)
292 /*drl bee: dm*/ h->buckets[i] = hbucket_undefined;
298 cstring cstringTable_unparse (cstringTable h)
300 cstring res = cstring_newEmpty ();
303 if (cstringTable_isDefined (h))
305 for (i = 0; i < h->size; i++)
307 /*drl bee: si*/ hbucket hb = h->buckets[i];
311 res = message ("%q%d. %q\n", res, i, hbucket_unparse (hb));
315 res = message ("%qsize: %d, collisions: %d, empty: %d",
318 cstringTable_countCollisions (h),
319 cstringTable_countEmpty (h));
324 res = cstring_makeLiteral ("< empty cstring table >");
332 cstringTable_stats (cstringTable h)
334 llassert (cstringTable_isDefined (h));
335 return (message ("size: %d, collisions: %d, empty: %d\n",
336 h->size, cstringTable_countCollisions (h),
337 cstringTable_countEmpty (h)));
341 cstringTable_rehash (/*@notnull@*/ cstringTable h)
344 ** rehashing based (loosely) on code by Steve Harrison
348 int oldsize = h->size;
349 int newsize = 1 + ((oldsize * 26244) / 10000); /* 26244 = 162^2 */
350 hbucket *oldbuckets = h->buckets;
354 h->buckets = (hbucket *) dmalloc (sizeof (*h->buckets) * newsize);
357 for (i = 0; i < newsize; i++)
359 /*drl bee: dm*/ h->buckets[i] = hbucket_undefined;
363 for (i = 0; i < oldsize; i++)
365 /*drl bee: dm*/ hbucket bucket = oldbuckets[i];
367 /*drl bee: dm*/ oldbuckets[i] = NULL;
369 if (!hbucket_isNull (bucket))
373 for (j = 0; j < bucket->size; j++)
375 /*drl bee: si*/ cstringTable_addEntry (h, bucket->entries[j]);
379 ** evans 2001-03-24: new memory leak detected by Splint
380 ** after I fixed the checkCompletelyDestroyed.
383 sfree (bucket->entries);
392 cstringTable_addEntry (/*@notnull@*/ cstringTable h, /*@only@*/ hentry e)
394 unsigned int hindex = cstringTable_hashValue (h, e->key);
398 ** hbucket hb = h->buckets[hindex];
399 ** instead reveals a bug I don't want to deal with right now!
402 /*drl bee: si*/ if (hbucket_isNull (h->buckets[hindex]))
404 /*drl bee: si*/ h->buckets[hindex] = hbucket_single (e);
409 if (hbucket_contains (h->buckets[hindex], e->key)) {
412 ("cstringTable: Attempt to add duplicate entry: %s "
413 "[previous value %d, new value %d]",
414 e->key, cstringTable_lookup (h, e->key), e->val));
419 hbucket_add (h->buckets[hindex], e);
425 cstringTable_insert (cstringTable h, cstring key, int value)
431 llassert (cstringTable_isDefined (h));
435 if (h->nentries * 162 > h->size * 100)
437 cstringTable_rehash (h);
440 hindex = cstringTable_hashValue (h, key);
441 e = hentry_create (key, value);
443 /*drl bee: si*/ hb = h->buckets[hindex];
445 if (hbucket_isNull (hb))
447 /*drl bee: si*/ h->buckets[hindex] = hbucket_single (e);
451 llassert (!hbucket_contains (hb, e->key));
457 cstringTable_lookup (cstringTable h, cstring key)
460 llassert (cstringTable_isDefined (h));
462 hb = cstringTable_hash (h, key);
463 return (hbucket_lookup (hb, key));
467 cstringTable_update (cstringTable h, cstring key, int newval)
471 llassert (cstringTable_isDefined (h));
473 hb = cstringTable_hash (h, key);
475 if (!hbucket_isNull (hb))
479 for (i = 0; i < hb->size; i++)
481 /*drl bee: si*/ if (cstring_equal (hb->entries[i]->key, key))
483 /*drl bee: si*/ hb->entries[i]->val = newval;
489 llbug (message ("cstringTable_update: %s not found", key));
493 ** This is needed if oldkey is going to be released.
497 cstringTable_replaceKey (cstringTable h, cstring oldkey, /*@only@*/ cstring newkey)
500 llassert (cstringTable_isDefined (h));
502 hb = cstringTable_hash (h, oldkey);
503 llassert (cstring_equal (oldkey, newkey));
505 if (!hbucket_isNull (hb))
509 for (i = 0; i < hb->size; i++)
511 /*drl bee: si*/ if (cstring_equal (hb->entries[i]->key, oldkey))
513 /*drl bee: si*/ hb->entries[i]->key = newkey;
519 llbug (message ("cstringTable_replaceKey: %s not found", oldkey));
523 cstringTable_remove (cstringTable h, cstring key)
527 llassert (cstringTable_isDefined (h));
528 hb = cstringTable_hash (h, key);
530 if (!hbucket_isNull (hb))
534 for (i = 0; i < hb->size; i++)
536 /*drl bee: si*/ if (cstring_equal (hb->entries[i]->key, key))
538 if (i < hb->size - 1)
541 hb->entries[i] = hb->entries[hb->size - 1];
550 llbug (message ("cstringTable_removeKey: %s not found", key));