1
/* -----------------------------------------------------------------------------
4
* Implements a simple hash table object.
6
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
8
* Copyright (C) 1999-2000. The University of Chicago
9
* See the file LICENSE for information on usage and redistribution.
10
* ----------------------------------------------------------------------------- */
12
static char cvsroot[] = "$Header: /cvs/projects/SWIG/Source/DOH/Doh/hash.c,v 1.31.4.6 2001/12/03 15:39:33 beazley Exp $";
17
typedef struct HashNode {
20
struct HashNode *next;
34
/* Key interning structure */
35
typedef struct KeyValue {
38
struct KeyValue *left;
39
struct KeyValue *right;
42
static KeyValue *root = 0;
44
/* Find or create a key in the interned key table */
45
static DOH *find_key (DOH *doh_c) {
46
char *c = (char *) doh_c;
49
/* OK, sure, we use a binary tree for maintaining interned
50
symbols. Then we use their hash values for accessing secondary
56
d = strcmp(r->cstr,c);
57
if (d == 0) return r->sstr;
58
if (d < 0) r = r->left;
61
/* fprintf(stderr,"Interning '%s'\n", c);*/
62
r = (KeyValue *) DohMalloc(sizeof(KeyValue));
63
r->cstr = (char *) DohMalloc(strlen(c)+1);
65
r->sstr = NewString(c);
71
if (d < 0) s->left = r;
77
#define HASH_INIT_SIZE 7
79
/* Create a new hash node */
80
static HashNode *NewNode(DOH *k, void *obj) {
81
HashNode *hn = (HashNode *) DohMalloc(sizeof(HashNode));
90
/* Delete a hash node */
91
static void DelNode(HashNode *hn) {
97
/* -----------------------------------------------------------------------------
100
* Delete a hash table.
101
* ----------------------------------------------------------------------------- */
105
Hash *h = (Hash *) ObjData(ho);
109
for (i = 0; i < h->hashsize; i++) {
110
if ((n = h->hashtable[i])) {
118
DohFree(h->hashtable);
124
/* -----------------------------------------------------------------------------
127
* Clear all of the entries in the hash table.
128
* ----------------------------------------------------------------------------- */
131
Hash_clear(DOH *ho) {
132
Hash *h = (Hash *) ObjData(ho);
136
for (i = 0; i < h->hashsize; i++) {
137
if ((n = h->hashtable[i])) {
149
/* resize the hash table */
150
static void resize(Hash *h) {
151
HashNode *n, *next, **table;
152
int oldsize, newsize;
155
if (h->nitems < 2*h->hashsize) return;
157
/* Too big. We have to rescale everything now */
158
oldsize = h->hashsize;
160
/* Calculate a new size */
161
newsize = 2*oldsize+1;
163
while (p < (newsize >> 1)) {
164
if (((newsize/p)*p) == newsize) {
172
table = (HashNode **) DohMalloc(newsize*sizeof(HashNode *));
173
for (i = 0; i < newsize; i++ ) {
177
/* Walk down the old set of nodes and re-place */
178
h->hashsize = newsize;
179
for (i = 0; i < oldsize; i++) {
182
hv = Hashval(n->key) % newsize;
189
DohFree(h->hashtable);
190
h->hashtable = table;
193
/* -----------------------------------------------------------------------------
196
* Set an attribute in the hash table. Deletes the existing entry if it already
198
* ----------------------------------------------------------------------------- */
201
Hash_setattr(DOH *ho, DOH *k, DOH *obj) {
204
Hash *h = (Hash *) ObjData(ho);
207
return DohDelattr(ho,k);
209
if (!DohCheck(k)) k = find_key(k);
210
if (!DohCheck(obj)) {
211
obj = NewString((char *) obj);
214
hv = (Hashval(k)) % h->hashsize;
215
n = h->hashtable[hv];
218
if (Cmp(n->key,k) == 0) {
219
/* Node already exists. Just replace its contents */
220
if (n->object == obj) {
221
/* Whoa. Same object. Do nothing */
227
return 1; /* Return 1 to indicate a replacement */
233
/* Add this to the table */
235
if (prev) prev->next = n;
236
else h->hashtable[hv] = n;
242
/* -----------------------------------------------------------------------------
245
* Get an attribute from the hash table. Returns 0 if it doesn't exist.
246
* ----------------------------------------------------------------------------- */
249
Hash_getattr(DOH *ho, DOH *k) {
252
Hash *h = (Hash *) ObjData(ho);
254
if (!DohCheck(k)) k = find_key(k);
255
hv = Hashval(k) % h->hashsize;
256
n = h->hashtable[hv];
258
if (Cmp(n->key, k) == 0) return n->object;
264
/* -----------------------------------------------------------------------------
267
* Delete an object from the hash table.
268
* ----------------------------------------------------------------------------- */
271
Hash_delattr(DOH *ho, DOH *k) {
274
Hash *h = (Hash *) ObjData(ho);
276
if (!DohCheck(k)) k = find_key(k);
277
hv = Hashval(k) % h->hashsize;
278
n = h->hashtable[hv];
281
if (Cmp(n->key, k) == 0) {
282
/* Found it, kill it */
285
prev->next = n->next;
287
h->hashtable[hv] = n->next;
289
/* Need to check for iterator location */
290
if (n == h->current) {
291
h->current = prev; /* Move back to previous node. When next is called, will move to next node */
292
if (!h->current) h->currentindex--; /* No previous node. Move back one slot */
304
/* General purpose iterators */
306
hash_first(DOH *ho) {
307
Hash *h = (Hash *) ObjData(ho);
310
while ((h->currentindex < h->hashsize) && !h->hashtable[h->currentindex])
312
if (h->currentindex >= h->hashsize) return 0;
313
h->current = h->hashtable[h->currentindex];
319
Hash *h = (Hash *) ObjData(ho);
320
if (h->currentindex < 0) return hash_first(ho);
322
/* Try to move to the next entry */
324
h->current = h->current->next;
330
while ((h->currentindex < h->hashsize) && !h->hashtable[h->currentindex])
332
if (h->currentindex >= h->hashsize) return 0;
333
h->current = h->hashtable[h->currentindex];
337
/* -----------------------------------------------------------------------------
340
* Return first hash-table key.
341
* ----------------------------------------------------------------------------- */
344
Hash_firstkey(DOH *ho) {
345
HashNode *hn = hash_first(ho);
346
if (hn) return hn->key;
350
/* -----------------------------------------------------------------------------
353
* Return next hash table key.
354
* ----------------------------------------------------------------------------- */
357
Hash_nextkey(DOH *ho) {
358
HashNode *hn = hash_next(ho);
359
if (hn) return hn->key;
363
/* -----------------------------------------------------------------------------
366
* Create a string representation of a hash table (mainly for debugging).
367
* ----------------------------------------------------------------------------- */
374
static int indent = 4;
375
Hash *h = (Hash *) ObjData(ho);
378
if (ObjGetMark(ho)) {
379
Printf(s,"Hash(0x%x)",ho);
383
Printf(s,"Hash {\n");
384
for (i = 0; i < h->hashsize; i++) {
387
for (j = 0; j < indent; j++) Putc(' ',s);
389
Printf(s,"'%s' : %s, \n", n->key, n->object);
394
for (j = 0; j < (indent-4); j++) Putc(' ',s);
400
/* -----------------------------------------------------------------------------
403
* Return number of entries in the hash table.
404
* ----------------------------------------------------------------------------- */
408
Hash *h = (Hash *) ObjData(ho);
412
/* -----------------------------------------------------------------------------
415
* Return a list of keys
416
* ----------------------------------------------------------------------------- */
428
/* List_sort(keys); */
432
/* -----------------------------------------------------------------------------
435
* Make a copy of a hash table. Note: this is a shallow copy.
436
* ----------------------------------------------------------------------------- */
445
h = (Hash *) ObjData(ho);
446
nh = (Hash *) DohMalloc(sizeof(Hash));
447
nh->hashsize = h->hashsize;
448
nh->hashtable = (HashNode **) DohMalloc(nh->hashsize*sizeof(HashNode *));
449
for (i = 0; i < nh->hashsize; i++) {
450
nh->hashtable[i] = 0;
452
nh->currentindex = -1;
457
if (nh->file) Incref(nh->file);
459
nho = DohObjMalloc(DOHTYPE_HASH, nh);
460
for (i = 0; i < h->hashsize; i++) {
461
if ((n = h->hashtable[i])) {
463
Hash_setattr(nho, n->key, n->object);
473
void Hash_setfile(DOH *ho, DOH *file) {
475
Hash *h = (Hash *) ObjData(ho);
477
if (!DohCheck(file)) {
478
fo = NewString(file);
486
DOH *Hash_getfile(DOH *ho) {
487
Hash *h = (Hash *) ObjData(ho);
491
void Hash_setline(DOH *ho, int line) {
492
Hash *h = (Hash *) ObjData(ho);
496
int Hash_getline(DOH *ho) {
497
Hash *h = (Hash *) ObjData(ho);
501
/* -----------------------------------------------------------------------------
503
* ----------------------------------------------------------------------------- */
505
static DohHashMethods HashHashMethods = {
513
static DohObjInfo HashType = {
514
"Hash", /* objname */
515
DelHash, /* doh_del */
516
CopyHash, /* doh_copy */
517
Hash_clear, /* doh_clear */
518
Hash_str, /* doh_str */
521
Hash_len, /* doh_len */
524
Hash_setfile, /* doh_setfile */
525
Hash_getfile, /* doh_getfile */
526
Hash_setline, /* doh_setline */
527
Hash_getline, /* doh_getline */
528
&HashHashMethods, /* doh_mapping */
529
0, /* doh_sequence */
532
0, /* doh_positional */
536
/* -----------------------------------------------------------------------------
539
* Create a new hash table.
540
* ----------------------------------------------------------------------------- */
548
DohRegisterType(DOHTYPE_HASH, &HashType);
551
h = (Hash *) DohMalloc(sizeof(Hash));
552
h->hashsize = HASH_INIT_SIZE;
553
h->hashtable = (HashNode **) DohMalloc(h->hashsize*sizeof(HashNode *));
554
for (i = 0; i < h->hashsize; i++) {
557
h->currentindex = -1;
562
return DohObjMalloc(DOHTYPE_HASH,h);