]> andersk Git - splint.git/blame - src/cstringTable.c
Fixed all /*@i...@*/ tags (except 1).
[splint.git] / src / cstringTable.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** cstringTable.c
26**
27** Since hsearch defined in <search.h> only allows one hash table,
28** I'll implement my own.
29**
30** Try to find a decent hash function, etc. later...
31**
32** cstringTable is from string -> unsigned
33**
34*/
35
1b8ae690 36# include "splintMacros.nf"
28bf4b0b 37# include "basic.h"
38# include "randomNumbers.h"
39
40/*@constant null hbucket hbucket_undefined; @*/
41# define hbucket_undefined 0
42
43static void
44cstringTable_addEntry (/*@notnull@*/ cstringTable p_h, /*@only@*/ hentry p_e)
45 /*@modifies p_h@*/ ;
46
0e41eb0e 47static /*@nullwhentrue@*/ bool hbucket_isNull (/*@null@*/ hbucket h)
28bf4b0b 48{
49 return (h == hbucket_undefined);
50}
51
6fcd0b1e 52static hentry hentry_create (/*@only@*/ cstring key, int val)
28bf4b0b 53{
54 hentry h = (hentry) dmalloc (sizeof (*h));
55
56 h->key = key;
57 h->val = val;
b73d1009 58 llassert (val != HBUCKET_DNE);
28bf4b0b 59 return (h);
60}
61
62static void hentry_free (/*@only@*/ hentry h)
63{
64 cstring_free (h->key);
65 sfree (h);
66}
67
68static bool
69hbucket_isEmpty (hbucket h)
70{
71 return (h == hbucket_undefined || h->size == 0);
72}
73
74static cstring
75hbucket_unparse (hbucket h)
76{
77 cstring s = cstring_undefined;
78
79 if (!hbucket_isNull (h))
80 {
81 int i;
82
83 for (i = 0; i < h->size; i++)
84 {
8fd556fb 85 s = message ("%q %s:%d", s, h->entries[i]->key, h->entries[i]->val);
28bf4b0b 86 }
87 }
88
89 return s;
90}
91
92static hbucket
93hbucket_single (/*@only@*/ hentry e)
94{
95 hbucket h = (hbucket) dmalloc (sizeof (*h));
96
97 h->size = 1;
98 h->nspace = HBUCKET_BASESIZE - 1;
99 h->entries = (hentry *) dmalloc (HBUCKET_BASESIZE * sizeof (*h->entries));
8fd556fb 100 h->entries[0] = e;
28bf4b0b 101
102 return (h);
103}
104
105static void
106hbucket_grow (/*@notnull@*/ hbucket h)
107{
108 int i;
109 hentry *newentries;
110
111 h->nspace += HBUCKET_BASESIZE;
112
113 newentries = (hentry *)
114 dmalloc ((h->size + HBUCKET_BASESIZE) * sizeof (*newentries));
115
116 for (i = 0; i < h->size; i++)
117 {
b73d1009 118 newentries[i] = h->entries[i];
28bf4b0b 119 }
120
b73d1009 121 sfree (h->entries);
28bf4b0b 122 h->entries = newentries;
b73d1009 123 /*@-compmempass@*/
124} /*@=compmempass@*/ /* Spurious warnings reported - shouldn't need this */
28bf4b0b 125
126static int hbucket_lookup (hbucket p_h, cstring p_key);
127
128static bool hbucket_contains (hbucket p_h, cstring p_key) /*@*/ {
129 return (hbucket_lookup (p_h, p_key) != HBUCKET_DNE);
130}
131
132/*
133** bizarre duplicate behaviour
134** required for duplicate entries
135*/
136
137static void
138hbucket_add (/*@notnull@*/ hbucket h, /*@only@*/ hentry e)
139{
140 int exloc = hbucket_lookup (h, e->key);
141
142 llassert (exloc == HBUCKET_DNE);
143
144 if (h->nspace == 0)
145 {
146 hbucket_grow (h);
147 }
148
149 llassert (e->val != HBUCKET_DNE);
8fd556fb 150 h->entries[h->size] = e;
28bf4b0b 151 h->size++;
152 h->nspace--;
153}
154
155static int
156hbucket_ncollisions (hbucket h)
157{
158 if (!hbucket_isNull (h) && (h->size > 1))
159 return (h->size - 1);
160 else
161 return 0;
162}
163
164int
165hbucket_lookup (hbucket h, cstring key)
166{
167 if (!hbucket_isNull (h))
168 {
169 int i;
170
171 for (i = 0; i < h->size; i++)
172 {
8fd556fb 173 if (cstring_equal (h->entries[i]->key, key))
28bf4b0b 174 {
175 return h->entries[i]->val;
176 }
177 }
178 }
179
180 return HBUCKET_DNE;
181}
182
183static
184void hbucket_free (/*@only@*/ hbucket h)
185{
186 if (!hbucket_isNull (h))
187 {
6fcd0b1e 188 int i;
189 /* evans 2002-07-12: added this to free entries (splint warning had been suppressed) */
190 for (i = 0; i < h->size; i++)
191 {
192 hentry_free (h->entries[i]);
193 }
194
195 sfree (h->entries);
28bf4b0b 196 sfree (h);
197 }
198}
199
200void
201cstringTable_free (/*@only@*/ cstringTable h)
202{
203 int i;
204
205 llassert (cstringTable_isDefined (h));
206
207 for (i = 0; i < h->size; i++)
208 {
8fd556fb 209 hbucket_free (h->buckets[i]);
28bf4b0b 210 }
211
212 sfree (h->buckets);
213 sfree (h);
214}
215
216static int
217cstringTable_countCollisions (cstringTable h)
218{
219 int nc = 0;
220 int i;
221
222 llassert (cstringTable_isDefined (h));
223
224 for (i = 0; i < h->size; i++)
225 {
8fd556fb 226 nc += hbucket_ncollisions (h->buckets[i]);
28bf4b0b 227 }
228
229 return (nc);
230}
231
232
233static int
234cstringTable_countEmpty (cstringTable h)
235{
236 int nc = 0;
237 int i;
238
239 llassert (cstringTable_isDefined (h));
240
241 for (i = 0; i < h->size; i++)
242 {
8fd556fb 243 if (hbucket_isEmpty (h->buckets[i]))
28bf4b0b 244 {
245 nc++;
246 }
247 }
248
249 return (nc);
250}
251
252/*
253** hash function snarfed from quake/hash.c Hash_String
254** by Stephen Harrison
255*/
256
257static unsigned int
258cstringTable_hashValue (/*@notnull@*/ cstringTable h, cstring key)
259{
260 char *p;
261 unsigned int hash_value = 0;
262
263 for (p = cstring_toCharsSafe (key); *p != '\0'; p++)
264 {
8fd556fb 265 hash_value = (hash_value << 1) ^ g_randomNumbers[*p % 256];
28bf4b0b 266 }
267
268 return (hash_value % h->size);
269}
270
271static /*@exposed@*/ hbucket
272cstringTable_hash (/*@notnull@*/ cstringTable h, cstring key)
273{
274 return h->buckets[cstringTable_hashValue (h, key)];
275}
276
277
278/*@only@*/ cstringTable
279cstringTable_create (int size)
280{
281 int i;
282 cstringTable h = (cstringTable) dmalloc (sizeof (*h));
283
284 h->size = size;
285 h->nentries = 0;
286 h->buckets = (hbucket *) dmalloc (sizeof (*h->buckets) * size);
287
288 /*@+loopexec@*/
289 for (i = 0; i < size; i++)
290 {
8fd556fb 291 h->buckets[i] = hbucket_undefined;
28bf4b0b 292 }
293 /*@-loopexec@*/
294 return h;
295}
296
297cstring cstringTable_unparse (cstringTable h)
298{
299 cstring res = cstring_newEmpty ();
300 int i;
301
302 if (cstringTable_isDefined (h))
303 {
304 for (i = 0; i < h->size; i++)
305 {
8fd556fb 306 hbucket hb = h->buckets[i];
28bf4b0b 307
308 if (hb != NULL)
309 {
310 res = message ("%q%d. %q\n", res, i, hbucket_unparse (hb));
311 }
312 }
313
314 res = message ("%qsize: %d, collisions: %d, empty: %d",
315 res,
316 h->size,
317 cstringTable_countCollisions (h),
318 cstringTable_countEmpty (h));
319 }
320 else
321 {
322 cstring_free (res);
323 res = cstring_makeLiteral ("< empty cstring table >");
324 }
325
326 return res;
327}
328
329
330/*@only@*/ cstring
331cstringTable_stats (cstringTable h)
332{
333 llassert (cstringTable_isDefined (h));
334 return (message ("size: %d, collisions: %d, empty: %d\n",
335 h->size, cstringTable_countCollisions (h),
336 cstringTable_countEmpty (h)));
337}
338
339static void
340cstringTable_rehash (/*@notnull@*/ cstringTable h)
341{
342 /*
343 ** rehashing based (loosely) on code by Steve Harrison
344 */
345
346 int i;
347 int oldsize = h->size;
348 int newsize = 1 + ((oldsize * 26244) / 10000); /* 26244 = 162^2 */
349 hbucket *oldbuckets = h->buckets;
350
351 h->size = newsize;
352 h->nentries = 0;
353 h->buckets = (hbucket *) dmalloc (sizeof (*h->buckets) * newsize);
354
355 /*@+loopexec@*/
356 for (i = 0; i < newsize; i++)
357 {
8fd556fb 358 h->buckets[i] = hbucket_undefined;
28bf4b0b 359 }
360 /*@=loopexec@*/
361
362 for (i = 0; i < oldsize; i++)
363 {
8fd556fb 364 hbucket bucket = oldbuckets[i];
28bf4b0b 365
8fd556fb 366 oldbuckets[i] = NULL;
28bf4b0b 367
368 if (!hbucket_isNull (bucket))
369 {
370 int j;
371
372 for (j = 0; j < bucket->size; j++)
373 {
8fd556fb 374 cstringTable_addEntry (h, bucket->entries[j]);
28bf4b0b 375 }
376
377 /*
11db3170 378 ** evans 2001-03-24: new memory leak detected by Splint
28bf4b0b 379 ** after I fixed the checkCompletelyDestroyed.
380 */
381
382 sfree (bucket->entries);
383 sfree (bucket);
384 }
385 }
386
387 sfree (oldbuckets);
388}
389
390static void
391cstringTable_addEntry (/*@notnull@*/ cstringTable h, /*@only@*/ hentry e)
392{
393 unsigned int hindex = cstringTable_hashValue (h, e->key);
394
395 /*
396 ** using
397 ** hbucket hb = h->buckets[hindex];
398 ** instead reveals a bug I don't want to deal with right now!
399 */
400
8fd556fb 401 if (hbucket_isNull (h->buckets[hindex]))
28bf4b0b 402 {
8fd556fb 403 h->buckets[hindex] = hbucket_single (e);
28bf4b0b 404 h->nentries++;
405 }
406 else
407 {
408 if (hbucket_contains (h->buckets[hindex], e->key)) {
409 llcontbug
410 (message
411 ("cstringTable: Attempt to add duplicate entry: %s "
412 "[previous value %d, new value %d]",
413 e->key, cstringTable_lookup (h, e->key), e->val));
414 hentry_free (e);
415 return;
416 }
417
418 hbucket_add (h->buckets[hindex], e);
419 h->nentries++;
420 }
421}
422
423void
424cstringTable_insert (cstringTable h, cstring key, int value)
425{
426 unsigned int hindex;
427 hbucket hb;
428 hentry e;
429
430 llassert (cstringTable_isDefined (h));
431
432 h->nentries++;
433
434 if (h->nentries * 162 > h->size * 100)
435 {
436 cstringTable_rehash (h);
437 }
438
28bf4b0b 439 hindex = cstringTable_hashValue (h, key);
6fcd0b1e 440 e = hentry_create (key, value);
28bf4b0b 441
8fd556fb 442 hb = h->buckets[hindex];
28bf4b0b 443
444 if (hbucket_isNull (hb))
445 {
8fd556fb 446 h->buckets[hindex] = hbucket_single (e);
28bf4b0b 447 }
448 else
449 {
450 llassert (!hbucket_contains (hb, e->key));
451 hbucket_add (hb, e);
452 }
453}
454
455int
456cstringTable_lookup (cstringTable h, cstring key)
457{
458 hbucket hb;
459 llassert (cstringTable_isDefined (h));
460
461 hb = cstringTable_hash (h, key);
462 return (hbucket_lookup (hb, key));
463}
464
465void
466cstringTable_update (cstringTable h, cstring key, int newval)
467{
468 hbucket hb;
469
470 llassert (cstringTable_isDefined (h));
471
472 hb = cstringTable_hash (h, key);
473
474 if (!hbucket_isNull (hb))
475 {
476 int i;
477
478 for (i = 0; i < hb->size; i++)
479 {
8fd556fb 480 if (cstring_equal (hb->entries[i]->key, key))
28bf4b0b 481 {
8fd556fb 482 hb->entries[i]->val = newval;
28bf4b0b 483 return;
484 }
485 }
486 }
487
488 llbug (message ("cstringTable_update: %s not found", key));
489}
490
491/*
492** This is needed if oldkey is going to be released.
493*/
494
495void
496cstringTable_replaceKey (cstringTable h, cstring oldkey, /*@only@*/ cstring newkey)
497{
498 hbucket hb;
499 llassert (cstringTable_isDefined (h));
6fcd0b1e 500
28bf4b0b 501 hb = cstringTable_hash (h, oldkey);
502 llassert (cstring_equal (oldkey, newkey));
503
504 if (!hbucket_isNull (hb))
505 {
506 int i;
507
508 for (i = 0; i < hb->size; i++)
509 {
8fd556fb 510 if (cstring_equal (hb->entries[i]->key, oldkey))
28bf4b0b 511 {
8fd556fb 512 hb->entries[i]->key = newkey;
28bf4b0b 513 return;
514 }
515 }
516 }
517
518 llbug (message ("cstringTable_replaceKey: %s not found", oldkey));
519}
520
521void
522cstringTable_remove (cstringTable h, cstring key)
523{
524 hbucket hb;
525
526 llassert (cstringTable_isDefined (h));
527 hb = cstringTable_hash (h, key);
528
529 if (!hbucket_isNull (hb))
530 {
531 int i;
532
533 for (i = 0; i < hb->size; i++)
534 {
8fd556fb 535 if (cstring_equal (hb->entries[i]->key, key))
28bf4b0b 536 {
537 if (i < hb->size - 1)
538 {
8fd556fb 539 hb->entries[i] = hb->entries[hb->size - 1];
28bf4b0b 540 }
541
542 hb->size--;
543 return;
544 }
545 }
546 }
547
548 llbug (message ("cstringTable_removeKey: %s not found", key));
549}
550
551
This page took 0.410187 seconds and 5 git commands to generate.