PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/rel-1-3-15/SWIG/Source/DOH/Doh/hash.c

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