]> andersk Git - splint.git/blame - src/genericTable.c
Fixes for win32
[splint.git] / src / genericTable.c
CommitLineData
28bf4b0b 1/*
11db3170 2** Splint - annotation-assisted static program checker
c59f5181 3** Copyright (C) 1994-2003 University of Virginia,
28bf4b0b 4** Massachusetts Institute of Technology
5**
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.
10**
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.
15**
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.
19**
155af98d 20** For information on splint: info@splint.org
21** To report a bug: splint-bug@splint.org
11db3170 22** For more information: http://www.splint.org
28bf4b0b 23*/
24/*
25** genericTable.c
26**
27** A genericTable is a mapping from string keys to void * objects.
28** We sacrific type checking here for code reuse.
29*/
30
1b8ae690 31# include "splintMacros.nf"
28bf4b0b 32# include "basic.h"
33# include "randomNumbers.h"
34
35/*@constant null ghbucket ghbucket_undefined; @*/
36# define ghbucket_undefined 0
37
0e41eb0e 38static /*@nullwhentrue@*/ bool ghbucket_isNull (/*@null@*/ ghbucket h)
28bf4b0b 39{
40 return (h == ghbucket_undefined);
41}
42
43static ghentry
44ghentry_create (/*@keep@*/ cstring key, /*@keep@*/ void *val)
45{
46 ghentry h = (ghentry) dmalloc (sizeof (*h));
47
48 h->key = key;
49
50 llassert (val != NULL);
51 h->val = val;
52
53 return (h);
54}
55
b73d1009 56static void
57ghentry_free (/*@only@*/ ghentry ghe)
58{
59 cstring_free (ghe->key);
60 /* can't free val contents */
61 sfree (ghe->val);
62 sfree (ghe);
63}
64
28bf4b0b 65static bool
66ghbucket_isEmpty (ghbucket h)
67{
68 return (h == ghbucket_undefined || h->size == 0);
69}
70
71int genericTable_size (genericTable h)
72{
73 if (genericTable_isDefined (h)) {
74 return h->nentries;
75 } else {
76 return 0;
77 }
78}
79
8250fa4a 80# if 0
81static /*@unused@*/ cstring
28bf4b0b 82ghbucket_unparse (ghbucket h)
83{
84 cstring s = cstring_undefined;
85
86 if (!ghbucket_isNull (h))
87 {
88 int i;
89
90 for (i = 0; i < h->size; i++)
91 {
92 s = message ("%q %s", s, h->entries[i]->key);
93 }
94 }
95
96 return s;
97}
8250fa4a 98# endif
28bf4b0b 99
100static ghbucket ghbucket_single (/*@keep@*/ ghentry e)
101{
102 ghbucket h = (ghbucket) dmalloc (sizeof (*h));
103
104 h->size = 1;
105 h->nspace = GHBUCKET_BASESIZE - 1;
106 h->entries = (ghentry *) dmalloc (GHBUCKET_BASESIZE * sizeof (*h->entries));
b73d1009 107 h->entries[0] = e;
28bf4b0b 108
109 return (h);
110}
111
112static void
113ghbucket_grow (/*@notnull@*/ ghbucket h)
114{
115 int i;
116 ghentry *newentries;
117
118 h->nspace += GHBUCKET_BASESIZE;
119
120 newentries = (ghentry *)
121 dmalloc ((h->size + GHBUCKET_BASESIZE) * sizeof (*newentries));
122
123 for (i = 0; i < h->size; i++)
124 {
125 newentries[i] = h->entries[i];
126 }
127
b73d1009 128 sfree (h->entries);
28bf4b0b 129 h->entries = newentries;
b73d1009 130 /*@-compmempass@*/
131} /*@=compmempass*/ /* Spurious warnings reported for h->entries */
28bf4b0b 132
133static /*@null@*/ /*@exposed@*/ void *ghbucket_lookup (ghbucket p_h, cstring p_key);
134
135/*
136** bizarre duplicate behaviour
137** required for duplicate entries
138*/
139
140static void
141ghbucket_add (/*@notnull@*/ ghbucket h, /*@only@*/ ghentry e)
142{
51bc6ecc 143 void *exloc = ghbucket_lookup (h, e->key);
144
145 if (exloc != NULL) {
146 llcontbug (message ("ghbucket_add: adding duplicate entry: %s",
147 e->key));
148 ghentry_free (e);
149 return;
150 }
151
152 if (h->nspace == 0) {
153 ghbucket_grow (h);
154 }
155
156 h->entries[h->size] = e;
157 h->size++;
158 h->nspace--;
b73d1009 159}
28bf4b0b 160
161static int
162ghbucket_ncollisions (ghbucket h)
163{
164 if (!ghbucket_isNull (h) && (h->size > 1))
165 return (h->size - 1);
166 else
167 return 0;
168}
169
170/*@exposed@*/ /*@null@*/ void *
171ghbucket_lookup (ghbucket h, cstring key)
172{
173 if (!ghbucket_isNull (h))
174 {
175 int i;
176
177 for (i = 0; i < h->size; i++)
178 {
179 if (cstring_equal (h->entries[i]->key, key))
180 {
181 return h->entries[i]->val;
182 }
183 }
184 }
185
186 return NULL;
187}
188
189static
190void ghbucket_free (/*@only@*/ ghbucket h)
191{
192 if (!ghbucket_isNull (h))
193 {
b73d1009 194 int i;
195
196 for (i = 0; i < h->size; i++)
197 {
198 ghentry_free (h->entries[i]);
199 }
200
201 sfree (h->entries);
28bf4b0b 202 sfree (h);
203 }
204}
205
206void
207genericTable_free (/*@only@*/ genericTable h)
208{
209 if (genericTable_isDefined (h))
210 {
211 int i;
212
213 for (i = 0; i < h->size; i++)
214 {
215 ghbucket_free (h->buckets[i]);
216 }
217
218 sfree (h->buckets);
219 sfree (h);
220 }
221}
222
223static int
224genericTable_countCollisions (genericTable h)
225{
226 int nc = 0;
227 int i;
228
229 llassert (genericTable_isDefined (h));
230
231 for (i = 0; i < h->size; i++)
232 {
233 nc += ghbucket_ncollisions (h->buckets[i]);
234 }
235
236 return (nc);
237}
238
239
240static int
241genericTable_countEmpty (genericTable h)
242{
243 int nc = 0;
244 int i;
245
246 llassert (genericTable_isDefined (h));
247
248 for (i = 0; i < h->size; i++)
249 {
250 if (ghbucket_isEmpty (h->buckets[i]))
251 {
252 nc++;
253 }
254 }
255
256 return (nc);
257}
258
259/*
260** hash function snarfed from quake/hash.c Hash_String
261** by Stephen Harrison
262*/
263
264static unsigned int
265genericTable_hashValue (/*@notnull@*/ genericTable h, cstring key)
266{
267 char *p;
268 unsigned int hash_value = 0;
269
270 llassert (h->size != 0);
271
272 for (p = cstring_toCharsSafe (key); *p != '\0'; p++)
273 {
274 hash_value = (hash_value << 1) ^ g_randomNumbers[*p % 256];
275 }
276
277 return (hash_value % h->size);
278}
279
280static /*@exposed@*/ ghbucket
281genericTable_hash (/*@notnull@*/ genericTable h, cstring key)
282{
283 return h->buckets[genericTable_hashValue (h, key)];
284}
285
286
287/*@only@*/ genericTable
288genericTable_create (int size)
289{
290 int i;
291 genericTable h = (genericTable) dmalloc (sizeof (*h));
292
293 llassert (size > 0);
294 h->size = size;
295 h->nentries = 0;
296 h->buckets = (ghbucket *) dmalloc (sizeof (*h->buckets) * size);
297
298 /*@+loopexec@*/
299 for (i = 0; i < size; i++)
300 {
301 h->buckets[i] = ghbucket_undefined;
302 }
303 /*@-loopexec@*/
304 return h;
305}
306
8250fa4a 307# if 0
28bf4b0b 308/*@-mustfree@*/
309static /*@unused@*/ void
310genericTable_print (genericTable h)
311{
312 int i;
313
314 if (genericTable_isDefined (h)) {
315 for (i = 0; i < h->size; i++)
316 {
317 ghbucket hb = h->buckets[i];
318
319 if (hb != NULL)
320 {
321 llmsg (message ("%d. %s\n", i, ghbucket_unparse (hb)));
322 }
323 }
324
325 llmsg (message ("size: %d, collisions: %d, empty: %d",
326 h->size,
327 genericTable_countCollisions (h),
328 genericTable_countEmpty (h)));
329 } else {
330 llmsglit ("Empty hash table.");
331 }
332}
333/*@=mustfree@*/
8250fa4a 334# endif
28bf4b0b 335
336/*@only@*/ cstring
337genericTable_stats (genericTable h)
338{
339 llassert (genericTable_isDefined (h));
340 return (message ("size: %d, collisions: %d, empty: %d\n",
341 h->size, genericTable_countCollisions (h),
342 genericTable_countEmpty (h)));
343}
344
345static void
b73d1009 346genericTable_addEntry (/*@notnull@*/ genericTable h, /*@only@*/ ghentry e)
28bf4b0b 347{
348 unsigned int hindex = genericTable_hashValue (h, e->key);
349 /*
350 ** using
351 ** ghbucket hb = h->buckets[hindex];
352 ** instead reveals a bug I don't want to deal with right now!
353 */
354
355 h->nentries++;
356
357 if (ghbucket_isNull (h->buckets[hindex]))
358 {
359 h->buckets[hindex] = ghbucket_single (e);
360 }
361 else
362 {
b73d1009 363 ghbucket_add (h->buckets[hindex], e);
364 }
28bf4b0b 365}
366
367void
368genericTable_insert (genericTable h, cstring key, void *value)
369{
370 unsigned int hindex;
371 ghbucket hb;
372 ghentry e;
373
374 llassert (genericTable_isDefined (h));
375
376 /*
377 ** rehashing based (loosely) on code by Steve Harrison
378 */
379
380 if (h->nentries * 162 > h->size * 100)
381 {
382 int i;
383 int oldsize = h->size;
384 int newsize = 1 + ((oldsize * 26244) / 10000); /* 26244 = 162^2 */
385 ghbucket *oldbuckets = h->buckets;
386
387 DPRINTF (("Rehashing..."));
388 h->size = newsize;
389 h->nentries = 0;
390 h->buckets = (ghbucket *) dmalloc (sizeof (*h->buckets) * newsize);
391
392 /*@+loopexec@*/
393 for (i = 0; i < newsize; i++)
394 {
395 h->buckets[i] = ghbucket_undefined;
396 }
397 /*@=loopexec@*/
398
399 for (i = 0; i < oldsize; i++)
400 {
401 ghbucket bucket = oldbuckets[i];
402
403 oldbuckets[i] = NULL;
404
405 if (!ghbucket_isNull (bucket))
406 {
407 int j;
408
409 for (j = 0; j < bucket->size; j++)
410 {
411 genericTable_addEntry (h, bucket->entries[j]);
412 }
413
11db3170 414 sfree (bucket->entries); /* evans 2001-03-24: Splint caught this */
28bf4b0b 415 sfree (bucket);
416 }
417 }
418
419 sfree (oldbuckets);
420 }
421
422 /* evans 2000-12-22: this was before the rehash! Lost an entry size! */
423 h->nentries++;
424 e = ghentry_create (key, value);
425 hindex = genericTable_hashValue (h, key);
426 hb = h->buckets[hindex];
427
428 if (ghbucket_isNull (hb))
429 {
b73d1009 430 h->buckets[hindex] = ghbucket_single (e);
28bf4b0b 431 }
432 else
433 {
b73d1009 434 ghbucket_add (hb, e);
435 }
436}
28bf4b0b 437
438/*@null@*/ /*@exposed@*/ void *
439genericTable_lookup (genericTable h, cstring key)
440{
441 ghbucket hb;
442 void *res;
443 llassert (genericTable_isDefined (h));
444
445 hb = genericTable_hash (h, key);
446 res = ghbucket_lookup (hb, key);
447
448 /* if (res == NULL) { DPRINTF (("Lookup not found: %s", key)); } */
449 return res;
450}
451
452void
453genericTable_update (genericTable h, cstring key, /*@only@*/ void *newval)
454{
455 ghbucket hb;
456
457 llassert (genericTable_isDefined (h));
458
459 hb = genericTable_hash (h, key);
460
461 if (!ghbucket_isNull (hb))
462 {
463 int i;
464
465 for (i = 0; i < hb->size; i++)
466 {
467 if (cstring_equal (hb->entries[i]->key, key))
468 {
469 llassert (newval != NULL);
470 hb->entries[i]->val = newval;
471 return;
472 }
473 }
474 }
475
476 llbug (message ("genericTable_update: %s not found", key));
477}
478
479void
480genericTable_remove (genericTable h, cstring key)
481{
482 ghbucket hb;
483
484 llassert (genericTable_isDefined (h));
485 hb = genericTable_hash (h, key);
486
487 if (!ghbucket_isNull (hb))
488 {
489 int i;
490
491 for (i = 0; i < hb->size; i++)
492 {
493 if (cstring_equal (hb->entries[i]->key, key))
494 {
495 if (i < hb->size - 1)
496 {
497 hb->entries[i] = hb->entries[hb->size - 1];
498 }
499
500 hb->size--;
501 return;
502 }
503 }
504 }
505
506 llbug (message ("genericTable_removeKey: %s not found", key));
507}
508
509bool genericTable_contains (genericTable h, cstring key)
510{
511 return (genericTable_lookup (h, key) != NULL);
512}
This page took 0.241162 seconds and 5 git commands to generate.