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 "cstringHash.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
);
62 static void hentry_free (/*@only@*/ hentry h
)
64 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 s
= message ("%q %s:%d", s
, h
->entries
[i
]->key
, h
->entries
[i
]->val
);
92 # endif /* DEADCODE */
95 hbucket_single (/*@only@*/ hentry e
)
97 hbucket h
= (hbucket
) dmalloc (sizeof (*h
));
100 h
->nspace
= HBUCKET_BASESIZE
- 1;
101 h
->entries
= (hentry
*) dmalloc (HBUCKET_BASESIZE
* sizeof (*h
->entries
));
108 hbucket_grow (/*@notnull@*/ hbucket h
)
113 h
->nspace
+= HBUCKET_BASESIZE
;
115 newentries
= (hentry
*)
116 dmalloc ((h
->size
+ HBUCKET_BASESIZE
) * sizeof (*newentries
));
118 for (i
= 0; i
< h
->size
; i
++)
120 newentries
[i
] = h
->entries
[i
];
124 h
->entries
= newentries
;
126 } /*@=compmempass@*/ /* Spurious warnings reported - shouldn't need this */
128 static int hbucket_lookup (hbucket p_h
, cstring p_key
);
130 static bool hbucket_contains (hbucket p_h
, cstring p_key
) /*@*/ {
131 return (hbucket_lookup (p_h
, p_key
) != HBUCKET_DNE
);
135 ** bizarre duplicate behaviour
136 ** required for duplicate entries
140 hbucket_add (/*@notnull@*/ hbucket h
, /*@only@*/ hentry e
)
142 int exloc
= hbucket_lookup (h
, e
->key
);
144 llassert (exloc
== HBUCKET_DNE
);
151 llassert (e
->val
!= HBUCKET_DNE
);
152 h
->entries
[h
->size
] = e
;
159 hbucket_ncollisions (hbucket h
)
161 if (!hbucket_isNull (h
) && (h
->size
> 1))
162 return (h
->size
- 1);
166 # endif /* DEADCODE */
169 hbucket_lookup (hbucket h
, cstring key
)
171 if (!hbucket_isNull (h
))
175 for (i
= 0; i
< h
->size
; i
++)
177 if (cstring_equal (h
->entries
[i
]->key
, key
))
179 return h
->entries
[i
]->val
;
188 void hbucket_free (/*@only@*/ hbucket h
)
190 if (!hbucket_isNull (h
))
193 /* evans 2002-07-12: added this to free entries (splint warning had been suppressed) */
194 for (i
= 0; i
< h
->size
; i
++)
196 hentry_free (h
->entries
[i
]);
205 cstringTable_free (/*@only@*/ cstringTable h
)
209 llassert (cstringTable_isDefined (h
));
211 for (i
= 0; i
< h
->size
; i
++)
213 hbucket_free (h
->buckets
[i
]);
222 cstringTable_countCollisions (cstringTable h
)
227 llassert (cstringTable_isDefined (h
));
229 for (i
= 0; i
< h
->size
; i
++)
231 nc
+= hbucket_ncollisions (h
->buckets
[i
]);
239 cstringTable_countEmpty (cstringTable h
)
244 llassert (cstringTable_isDefined (h
));
246 for (i
= 0; i
< h
->size
; i
++)
248 if (hbucket_isEmpty (h
->buckets
[i
]))
256 # endif /* DEADCODE */
259 cstringTable_hashValue (/*@notnull@*/ cstringTable h
, cstring key
)
261 return (cstring_hashValue(key
) % h
->size
);
264 static /*@exposed@*/ hbucket
265 cstringTable_hash (/*@notnull@*/ cstringTable h
, cstring key
)
267 return h
->buckets
[cstringTable_hashValue (h
, key
)];
271 /*@only@*/ cstringTable
272 cstringTable_create (unsigned long size
)
275 cstringTable h
= (cstringTable
) dmalloc (sizeof (*h
));
279 h
->buckets
= (hbucket
*) dmalloc (sizeof (*h
->buckets
) * size
);
282 for (i
= 0; i
< size
; i
++)
284 h
->buckets
[i
] = hbucket_undefined
;
291 cstring
cstringTable_unparse (cstringTable h
)
293 cstring res
= cstring_newEmpty ();
296 if (cstringTable_isDefined (h
))
298 for (i
= 0; i
< h
->size
; i
++)
300 hbucket hb
= h
->buckets
[i
];
304 res
= message ("%q%wl. %q\n", res
, i
, hbucket_unparse (hb
));
308 res
= message ("%qsize: %wl, collisions: %d, empty: %d",
311 cstringTable_countCollisions (h
),
312 cstringTable_countEmpty (h
));
317 res
= cstring_makeLiteral ("< empty cstring table >");
325 cstringTable_stats (cstringTable h
)
327 llassert (cstringTable_isDefined (h
));
328 return (message ("size: %wl, collisions: %d, empty: %d\n",
329 h
->size
, cstringTable_countCollisions (h
),
330 cstringTable_countEmpty (h
)));
332 # endif /* DEADCODE */
335 cstringTable_rehash (/*@notnull@*/ cstringTable h
)
338 ** rehashing based (loosely) on code by Steve Harrison
342 /* Fix provided by Thomas Mertz (int -> unsigned long), 21 Apr 2004 */
343 unsigned long oldsize
= h
->size
;
344 unsigned long newsize
= 1 + ((oldsize
* 26244) / 10000); /* 26244 = 162^2 */
345 hbucket
*oldbuckets
= h
->buckets
;
349 h
->buckets
= (hbucket
*) dmalloc (sizeof (*h
->buckets
) * newsize
);
352 for (i
= 0; i
< newsize
; i
++)
354 h
->buckets
[i
] = hbucket_undefined
;
358 for (i
= 0; i
< oldsize
; i
++)
360 hbucket bucket
= oldbuckets
[i
];
362 oldbuckets
[i
] = NULL
;
364 if (!hbucket_isNull (bucket
))
368 for (j
= 0; j
< bucket
->size
; j
++)
370 cstringTable_addEntry (h
, bucket
->entries
[j
]);
374 ** evans 2001-03-24: new memory leak detected by Splint
375 ** after I fixed the checkCompletelyDestroyed.
378 sfree (bucket
->entries
);
387 cstringTable_addEntry (/*@notnull@*/ cstringTable h
, /*@only@*/ hentry e
)
389 unsigned int hindex
= cstringTable_hashValue (h
, e
->key
);
393 ** hbucket hb = h->buckets[hindex];
394 ** instead reveals a bug I don't want to deal with right now!
397 if (hbucket_isNull (h
->buckets
[hindex
]))
399 h
->buckets
[hindex
] = hbucket_single (e
);
404 if (hbucket_contains (h
->buckets
[hindex
], e
->key
)) {
407 ("cstringTable: Attempt to add duplicate entry: %s "
408 "[previous value %d, new value %d]",
409 e
->key
, cstringTable_lookup (h
, e
->key
), e
->val
));
414 hbucket_add (h
->buckets
[hindex
], e
);
420 cstringTable_insert (cstringTable h
, cstring key
, int value
)
422 unsigned long hindex
;
426 llassert (cstringTable_isDefined (h
));
430 if (h
->nentries
* 162 > h
->size
* 100)
432 cstringTable_rehash (h
);
435 hindex
= cstringTable_hashValue (h
, key
);
436 e
= hentry_create (key
, value
);
438 hb
= h
->buckets
[hindex
];
440 if (hbucket_isNull (hb
))
442 h
->buckets
[hindex
] = hbucket_single (e
);
446 llassert (!hbucket_contains (hb
, e
->key
));
452 cstringTable_lookup (cstringTable h
, cstring key
)
455 llassert (cstringTable_isDefined (h
));
457 hb
= cstringTable_hash (h
, key
);
458 return (hbucket_lookup (hb
, key
));
463 cstringTable_update (cstringTable h
, cstring key
, int newval
)
467 llassert (cstringTable_isDefined (h
));
469 hb
= cstringTable_hash (h
, key
);
471 if (!hbucket_isNull (hb
))
475 for (i
= 0; i
< hb
->size
; i
++)
477 if (cstring_equal (hb
->entries
[i
]->key
, key
))
479 hb
->entries
[i
]->val
= newval
;
485 llbug (message ("cstringTable_update: %s not found", key
));
487 # endif /* DEADCODE */
490 ** This is needed if oldkey is going to be released.
494 cstringTable_replaceKey (cstringTable h
, cstring oldkey
, /*@only@*/ cstring newkey
)
497 llassert (cstringTable_isDefined (h
));
499 hb
= cstringTable_hash (h
, oldkey
);
500 llassert (cstring_equal (oldkey
, newkey
));
502 if (!hbucket_isNull (hb
))
506 for (i
= 0; i
< hb
->size
; i
++)
508 if (cstring_equal (hb
->entries
[i
]->key
, oldkey
))
510 hb
->entries
[i
]->key
= newkey
;
516 llbug (message ("cstringTable_replaceKey: %s not found", oldkey
));
520 cstringTable_remove (cstringTable h
, cstring key
)
524 llassert (cstringTable_isDefined (h
));
525 hb
= cstringTable_hash (h
, key
);
527 if (!hbucket_isNull (hb
))
531 for (i
= 0; i
< hb
->size
; i
++)
533 if (cstring_equal (hb
->entries
[i
]->key
, key
))
535 if (i
< hb
->size
- 1)
537 hb
->entries
[i
] = hb
->entries
[hb
->size
- 1];
546 llbug (message ("cstringTable_removeKey: %s not found", key
));