1 /* -----------------------------------------------------------------------------
2 * hash.c
3 *
4 * Implements a simple hash table object.
5 *
6 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
7 *
8 * Copyright (C) 1999-2000. The University of Chicago
9 * See the file LICENSE for information on usage and redistribution.
10 * ----------------------------------------------------------------------------- */
11
12 static char cvsroot[] = "$Header: /home/pastacvs/cvs-rep/vermicelli/tot/src/SWILL-0.1/Source/Objects/hash.c,v 1.1 2005/01/27 08:46:25 dillema Exp $";
13
14 #include "dohint.h"
15
16 extern DohObjInfo DohHashType;
17
18 /* Hash node */
19 typedef struct HashNode {
20 DOH *key;
21 DOH *object;
22 struct HashNode *next;
23 } HashNode;
24
25 /* Hash object */
26 typedef struct Hash {
27 DOH *file;
28 int line;
29 HashNode **hashtable;
30 int hashsize;
31 int currentindex;
32 int nitems;
33 HashNode *current;
34 } Hash;
35
36 /* Key interning structure */
37 typedef struct KeyValue {
38 char *cstr;
39 DOH *sstr;
40 struct KeyValue *left;
41 struct KeyValue *right;
42 } KeyValue;
43
44 static KeyValue *root = 0;
45
46 /* Find or create a key in the interned key table */
find_key(DOH * doh_c)47 static DOH *find_key (DOH *doh_c) {
48 char *c = (char *) doh_c;
49 KeyValue *r, *s;
50 int d = 0;
51 /* OK, sure, we use a binary tree for maintaining interned
52 symbols. Then we use their hash values for accessing secondary
53 hash tables. */
54 r = root;
55 s = 0;
56 while (r) {
57 s = r;
58 d = strcmp(r->cstr,c);
59 if (d == 0) return r->sstr;
60 if (d < 0) r = r->left;
61 else r = r->right;
62 }
63 /* fprintf(stderr,"Interning '%s'\n", c);*/
64 r = (KeyValue *) DohMalloc(sizeof(KeyValue));
65 r->cstr = (char *) DohMalloc(strlen(c)+1);
66 strcpy(r->cstr,c);
67 r->sstr = NewString(c);
68 DohIntern(r->sstr);
69 r->left = 0;
70 r->right = 0;
71 if (!s) { root = r; }
72 else {
73 if (d < 0) s->left = r;
74 else s->right = r;
75 }
76 return r->sstr;
77 }
78
79 #define HASH_INIT_SIZE 7
80
81 /* Create a new hash node */
NewNode(DOH * k,void * obj)82 static HashNode *NewNode(DOH *k, void *obj) {
83 HashNode *hn = (HashNode *) DohMalloc(sizeof(HashNode));
84 hn->key = k;
85 Incref(hn->key);
86 hn->object = obj;
87 Incref(obj);
88 hn->next = 0;
89 return hn;
90 }
91
92 /* Delete a hash node */
DelNode(HashNode * hn)93 static void DelNode(HashNode *hn) {
94 Delete(hn->key);
95 Delete(hn->object);
96 DohFree(hn);
97 }
98
99 /* -----------------------------------------------------------------------------
100 * DelHash()
101 *
102 * Delete a hash table.
103 * ----------------------------------------------------------------------------- */
104
105 static void
DelHash(DOH * ho)106 DelHash(DOH *ho) {
107 Hash *h = (Hash *) ObjData(ho);
108 HashNode *n,*next;
109 int i;
110
111 for (i = 0; i < h->hashsize; i++) {
112 if ((n = h->hashtable[i])) {
113 while (n) {
114 next = n->next;
115 DelNode(n);
116 n = next;
117 }
118 }
119 }
120 DohFree(h->hashtable);
121 h->hashtable = 0;
122 h->hashsize = 0;
123 DohFree(h);
124 }
125
126 /* -----------------------------------------------------------------------------
127 * Hash_clear()
128 *
129 * Clear all of the entries in the hash table.
130 * ----------------------------------------------------------------------------- */
131
132 static void
Hash_clear(DOH * ho)133 Hash_clear(DOH *ho) {
134 Hash *h = (Hash *) ObjData(ho);
135 HashNode *n,*next;
136 int i;
137
138 for (i = 0; i < h->hashsize; i++) {
139 if ((n = h->hashtable[i])) {
140 while (n) {
141 next = n->next;
142 DelNode(n);
143 n = next;
144 }
145 }
146 h->hashtable[i] = 0;
147 }
148 h->nitems = 0;
149 }
150
151 /* resize the hash table */
resize(Hash * h)152 static void resize(Hash *h) {
153 HashNode *n, *next, **table;
154 int oldsize, newsize;
155 int i, p, hv;
156
157 if (h->nitems < 2*h->hashsize) return;
158
159 /* Too big. We have to rescale everything now */
160 oldsize = h->hashsize;
161
162 /* Calculate a new size */
163 newsize = 2*oldsize+1;
164 p = 3;
165 while (p < (newsize >> 1)) {
166 if (((newsize/p)*p) == newsize) {
167 newsize+=2;
168 p = 3;
169 continue;
170 }
171 p = p + 2;
172 }
173
174 table = (HashNode **) DohMalloc(newsize*sizeof(HashNode *));
175 for (i = 0; i < newsize; i++ ) {
176 table[i] = 0;
177 }
178
179 /* Walk down the old set of nodes and re-place */
180 h->hashsize = newsize;
181 for (i = 0; i < oldsize; i++) {
182 n = h->hashtable[i];
183 while (n) {
184 hv = Hashval(n->key) % newsize;
185 next = n->next;
186 n->next = table[hv];
187 table[hv] = n;
188 n = next;
189 }
190 }
191 DohFree(h->hashtable);
192 h->hashtable = table;
193 }
194
195 /* -----------------------------------------------------------------------------
196 * Hash_setattr()
197 *
198 * Set an attribute in the hash table. Deletes the existing entry if it already
199 * exists.
200 * ----------------------------------------------------------------------------- */
201
202 static int
Hash_setattr(DOH * ho,DOH * k,DOH * obj)203 Hash_setattr(DOH *ho, DOH *k, DOH *obj) {
204 int hv;
205 HashNode *n, *prev;
206 Hash *h = (Hash *) ObjData(ho);
207
208 if (!obj) {
209 return DohDelattr(ho,k);
210 }
211 if (!DohCheck(k)) k = find_key(k);
212 if (!DohCheck(obj)) {
213 obj = NewString((char *) obj);
214 Decref(obj);
215 }
216 hv = (Hashval(k)) % h->hashsize;
217 n = h->hashtable[hv];
218 prev = 0;
219 while (n) {
220 if (Cmp(n->key,k) == 0) {
221 /* Node already exists. Just replace its contents */
222 if (n->object == obj) {
223 /* Whoa. Same object. Do nothing */
224 return 1;
225 }
226 Delete(n->object);
227 n->object = obj;
228 Incref(obj);
229 return 1; /* Return 1 to indicate a replacement */
230 } else {
231 prev = n;
232 n = n->next;
233 }
234 }
235 /* Add this to the table */
236 n = NewNode(k,obj);
237 if (prev) prev->next = n;
238 else h->hashtable[hv] = n;
239 h->nitems++;
240 resize(h);
241 return 0;
242 }
243
244 /* -----------------------------------------------------------------------------
245 * Hash_getattr()
246 *
247 * Get an attribute from the hash table. Returns 0 if it doesn't exist.
248 * ----------------------------------------------------------------------------- */
249
250 static DOH *
Hash_getattr(DOH * ho,DOH * k)251 Hash_getattr(DOH *ho, DOH *k) {
252 int hv;
253 HashNode *n;
254 Hash *h = (Hash *) ObjData(ho);
255
256 if (!DohCheck(k)) k = find_key(k);
257 hv = Hashval(k) % h->hashsize;
258 n = h->hashtable[hv];
259 while (n) {
260 if (Cmp(n->key, k) == 0) return n->object;
261 n = n->next;
262 }
263 return 0;
264 }
265
266 /* -----------------------------------------------------------------------------
267 * Hash_delattr()
268 *
269 * Delete an object from the hash table.
270 * ----------------------------------------------------------------------------- */
271
272 static int
Hash_delattr(DOH * ho,DOH * k)273 Hash_delattr(DOH *ho, DOH *k) {
274 HashNode *n, *prev;
275 int hv;
276 Hash *h = (Hash *) ObjData(ho);
277
278 if (!DohCheck(k)) k = find_key(k);
279 hv = Hashval(k) % h->hashsize;
280 n = h->hashtable[hv];
281 prev = 0;
282 while (n) {
283 if (Cmp(n->key, k) == 0) {
284 /* Found it, kill it */
285
286 if (prev) {
287 prev->next = n->next;
288 } else {
289 h->hashtable[hv] = n->next;
290 }
291 /* Need to check for iterator location */
292 if (n == h->current) {
293 h->current = prev; /* Move back to previous node. When next is called, will move to next node */
294 if (!h->current) h->currentindex--; /* No previous node. Move back one slot */
295 }
296 DelNode(n);
297 h->nitems--;
298 return 1;
299 }
300 prev = n;
301 n = n->next;
302 }
303 return 0;
304 }
305
306 /* General purpose iterators */
307 static HashNode *
hash_first(DOH * ho)308 hash_first(DOH *ho) {
309 Hash *h = (Hash *) ObjData(ho);
310 h->currentindex = 0;
311 h->current = 0;
312 while ((h->currentindex < h->hashsize) && !h->hashtable[h->currentindex])
313 h->currentindex++;
314 if (h->currentindex >= h->hashsize) return 0;
315 h->current = h->hashtable[h->currentindex];
316 return h->current;
317 }
318
319 static HashNode *
hash_next(DOH * ho)320 hash_next(DOH *ho) {
321 Hash *h = (Hash *) ObjData(ho);
322 if (h->currentindex < 0) return hash_first(ho);
323
324 /* Try to move to the next entry */
325 if (h->current) {
326 h->current = h->current->next;
327 }
328 if (h->current) {
329 return h->current;
330 }
331 h->currentindex++;
332 while ((h->currentindex < h->hashsize) && !h->hashtable[h->currentindex])
333 h->currentindex++;
334 if (h->currentindex >= h->hashsize) return 0;
335 h->current = h->hashtable[h->currentindex];
336 return h->current;
337 }
338
339 /* -----------------------------------------------------------------------------
340 * Hash_firstkey()
341 *
342 * Return first hash-table key.
343 * ----------------------------------------------------------------------------- */
344
345 static DOH *
Hash_firstkey(DOH * ho)346 Hash_firstkey(DOH *ho) {
347 HashNode *hn = hash_first(ho);
348 if (hn) return hn->key;
349 return 0;
350 }
351
352 /* -----------------------------------------------------------------------------
353 * Hash_nextkey()
354 *
355 * Return next hash table key.
356 * ----------------------------------------------------------------------------- */
357
358 static DOH *
Hash_nextkey(DOH * ho)359 Hash_nextkey(DOH *ho) {
360 HashNode *hn = hash_next(ho);
361 if (hn) return hn->key;
362 return 0;
363 }
364
365 /* -----------------------------------------------------------------------------
366 * Hash_keys(DOH *)
367 *
368 * Return a list of keys
369 * ----------------------------------------------------------------------------- */
370
371 static DOH *
Hash_keys(DOH * so)372 Hash_keys(DOH *so) {
373 DOH *keys;
374 DOH *k;
375
376 keys = NewList();
377 k = Firstkey(so);
378 while (k) {
379 Append(keys,k);
380 k = Nextkey(so);
381 }
382 return keys;
383 }
384
385 /* -----------------------------------------------------------------------------
386 * Hash_str()
387 *
388 * Create a string representation of a hash table (mainly for debugging).
389 * ----------------------------------------------------------------------------- */
390
391 static DOH *
Hash_str(DOH * ho)392 Hash_str(DOH *ho) {
393 int i,j;
394 HashNode *n;
395 DOH *s;
396 static int indent = 4;
397 Hash *h = (Hash *) ObjData(ho);
398
399 s = NewString("");
400 if (ObjGetMark(ho)) {
401 Printf(s,"Hash(0x%x)",ho);
402 return s;
403 }
404 ObjSetMark(ho,1);
405 Printf(s,"Hash {\n");
406 for (i = 0; i < h->hashsize; i++) {
407 n = h->hashtable[i];
408 while (n) {
409 for (j = 0; j < indent; j++) Putc(' ',s);
410 indent+=4;
411 Printf(s,"'%s' : %s, \n", n->key, n->object);
412 indent-=4;
413 n = n->next;
414 }
415 }
416 for (j = 0; j < (indent-4); j++) Putc(' ',s);
417 Printf(s,"}\n");
418 ObjSetMark(ho,0);
419 return s;
420 }
421
422 /* -----------------------------------------------------------------------------
423 * Hash_len()
424 *
425 * Return number of entries in the hash table.
426 * ----------------------------------------------------------------------------- */
427
428 static int
Hash_len(DOH * ho)429 Hash_len(DOH *ho) {
430 Hash *h = (Hash *) ObjData(ho);
431 return h->nitems;
432 }
433
434 /* -----------------------------------------------------------------------------
435 * CopyHash()
436 *
437 * Make a copy of a hash table. Note: this is a shallow copy.
438 * ----------------------------------------------------------------------------- */
439
440 static DOH *
CopyHash(DOH * ho)441 CopyHash(DOH *ho) {
442 Hash *h, *nh;
443 HashNode *n;
444 DOH *nho;
445
446 int i;
447 h = (Hash *) ObjData(ho);
448 nh = (Hash *) DohMalloc(sizeof(Hash));
449 nh->hashsize = h->hashsize;
450 nh->hashtable = (HashNode **) DohMalloc(nh->hashsize*sizeof(HashNode *));
451 for (i = 0; i < nh->hashsize; i++) {
452 nh->hashtable[i] = 0;
453 }
454 nh->currentindex = -1;
455 nh->current = 0;
456 nh->nitems = 0;
457 nh->line = h->line;
458 nh->file = h->file;
459 if (nh->file) Incref(nh->file);
460
461 nho = DohObjMalloc(&DohHashType, nh);
462 for (i = 0; i < h->hashsize; i++) {
463 if ((n = h->hashtable[i])) {
464 while (n) {
465 Hash_setattr(nho, n->key, n->object);
466 n = n->next;
467 }
468 }
469 }
470 return nho;
471 }
472
473
474
475 static void
Hash_setfile(DOH * ho,DOH * file)476 Hash_setfile(DOH *ho, DOH *file) {
477 DOH *fo;
478 Hash *h = (Hash *) ObjData(ho);
479
480 if (!DohCheck(file)) {
481 fo = NewString(file);
482 Decref(fo);
483 } else fo = file;
484 Incref(fo);
485 Delete(h->file);
486 h->file = fo;
487 }
488
489 static DOH *
Hash_getfile(DOH * ho)490 Hash_getfile(DOH *ho) {
491 Hash *h = (Hash *) ObjData(ho);
492 return h->file;
493 }
494
495 static void
Hash_setline(DOH * ho,int line)496 Hash_setline(DOH *ho, int line) {
497 Hash *h = (Hash *) ObjData(ho);
498 h->line = line;
499 }
500
501 static int
Hash_getline(DOH * ho)502 Hash_getline(DOH *ho) {
503 Hash *h = (Hash *) ObjData(ho);
504 return h->line;
505 }
506
507 /* -----------------------------------------------------------------------------
508 * type information
509 * ----------------------------------------------------------------------------- */
510
511 static DohHashMethods HashHashMethods = {
512 Hash_getattr,
513 Hash_setattr,
514 Hash_delattr,
515 Hash_firstkey,
516 Hash_nextkey,
517 Hash_keys,
518 };
519
520 DohObjInfo DohHashType = {
521 "Hash", /* objname */
522 DelHash, /* doh_del */
523 CopyHash, /* doh_copy */
524 Hash_clear, /* doh_clear */
525 Hash_str, /* doh_str */
526 0, /* doh_data */
527 0, /* doh_dump */
528 Hash_len, /* doh_len */
529 0, /* doh_hash */
530 0, /* doh_cmp */
531 Hash_setfile, /* doh_setfile */
532 Hash_getfile, /* doh_getfile */
533 Hash_setline, /* doh_setline */
534 Hash_getline, /* doh_getline */
535 &HashHashMethods, /* doh_mapping */
536 0, /* doh_sequence */
537 0, /* doh_file */
538 0, /* doh_string */
539 0, /* doh_positional */
540 0,
541 };
542
543 /* -----------------------------------------------------------------------------
544 * NewHash()
545 *
546 * Create a new hash table.
547 * ----------------------------------------------------------------------------- */
548
549 DOH *
DohNewHash()550 DohNewHash() {
551 Hash *h;
552 int i;
553 static int init = 0;
554 h = (Hash *) DohMalloc(sizeof(Hash));
555 h->hashsize = HASH_INIT_SIZE;
556 h->hashtable = (HashNode **) DohMalloc(h->hashsize*sizeof(HashNode *));
557 for (i = 0; i < h->hashsize; i++) {
558 h->hashtable[i] = 0;
559 }
560 h->currentindex = -1;
561 h->current = 0;
562 h->nitems = 0;
563 h->file = 0;
564 h->line = 0;
565 return DohObjMalloc(&DohHashType,h);
566 }
567