You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1065 lines
28 KiB

  1. /**CFile***********************************************************************
  2. FileName [st.c]
  3. PackageName [st]
  4. Synopsis [Symbol table package.]
  5. Description [The st library provides functions to create, maintain,
  6. and query symbol tables.]
  7. SeeAlso []
  8. Author []
  9. Copyright []
  10. ******************************************************************************/
  11. #include "util.h"
  12. #include "st.h"
  13. /*---------------------------------------------------------------------------*/
  14. /* Constant declarations */
  15. /*---------------------------------------------------------------------------*/
  16. /*---------------------------------------------------------------------------*/
  17. /* Stucture declarations */
  18. /*---------------------------------------------------------------------------*/
  19. /*---------------------------------------------------------------------------*/
  20. /* Type declarations */
  21. /*---------------------------------------------------------------------------*/
  22. /*---------------------------------------------------------------------------*/
  23. /* Variable declarations */
  24. /*---------------------------------------------------------------------------*/
  25. #ifndef lint
  26. static char rcsid[] UTIL_UNUSED = " $Id: st.c,v 1.12 2010/04/22 19:00:55 fabio Exp fabio $";
  27. #endif
  28. /*---------------------------------------------------------------------------*/
  29. /* Macro declarations */
  30. /*---------------------------------------------------------------------------*/
  31. #define ST_NUMCMP(x,y) ((x) != (y))
  32. #define ST_NUMHASH(x,size) ((unsigned long)(x)%(size))
  33. #if SIZEOF_VOID_P == 8
  34. #define st_shift 3
  35. #else
  36. #define st_shift 2
  37. #endif
  38. #define ST_PTRHASH(x,size) ((unsigned int)((unsigned long)(x)>>st_shift)%size)
  39. #define EQUAL(func, x, y) \
  40. ((((func) == st_numcmp) || ((func) == st_ptrcmp)) ?\
  41. (ST_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0))
  42. #define do_hash(key, table)\
  43. ((int)((table->hash == st_ptrhash) ? ST_PTRHASH((char *)(key),(table)->num_bins) :\
  44. (table->hash == st_numhash) ? ST_NUMHASH((char *)(key), (table)->num_bins) :\
  45. (*table->hash)((char *)(key), (table)->num_bins)))
  46. #define PTR_NOT_EQUAL(table, ptr, user_key)\
  47. (ptr != NIL(st_table_entry) && !EQUAL(table->compare, (char *)user_key, (ptr)->key))
  48. #define FIND_ENTRY(table, hash_val, key, ptr, last) \
  49. (last) = &(table)->bins[hash_val];\
  50. (ptr) = *(last);\
  51. while (PTR_NOT_EQUAL((table), (ptr), (key))) {\
  52. (last) = &(ptr)->next; (ptr) = *(last);\
  53. }\
  54. if ((ptr) != NIL(st_table_entry) && (table)->reorder_flag) {\
  55. *(last) = (ptr)->next;\
  56. (ptr)->next = (table)->bins[hash_val];\
  57. (table)->bins[hash_val] = (ptr);\
  58. }
  59. /* This macro does not check if memory allocation fails. Use at you own risk */
  60. #define ADD_DIRECT(table, key, value, hash_val, newt)\
  61. {\
  62. if (table->num_entries/table->num_bins >= table->max_density) {\
  63. rehash(table);\
  64. hash_val = do_hash(key,table);\
  65. }\
  66. \
  67. newt = ALLOC(st_table_entry, 1);\
  68. \
  69. newt->key = (char *)key;\
  70. newt->record = value;\
  71. newt->next = table->bins[hash_val];\
  72. table->bins[hash_val] = newt;\
  73. table->num_entries++;\
  74. }
  75. /**AutomaticStart*************************************************************/
  76. /*---------------------------------------------------------------------------*/
  77. /* Static function prototypes */
  78. /*---------------------------------------------------------------------------*/
  79. static int rehash (st_table *);
  80. /**AutomaticEnd***************************************************************/
  81. /*---------------------------------------------------------------------------*/
  82. /* Definition of exported functions */
  83. /*---------------------------------------------------------------------------*/
  84. /**Function********************************************************************
  85. Synopsis [Create and initialize a table.]
  86. Description [Create and initialize a table with the comparison function
  87. compare_fn and hash function hash_fn. compare_fn is
  88. <pre>
  89. int compare_fn(const char *key1, const char *key2)
  90. </pre>
  91. It returns <,=,> 0 depending on whether key1 <,=,> key2 by some measure.<p>
  92. hash_fn is
  93. <pre>
  94. int hash_fn(char *key, int modulus)
  95. </pre>
  96. It returns a integer between 0 and modulus-1 such that if
  97. compare_fn(key1,key2) == 0 then hash_fn(key1) == hash_fn(key2).<p>
  98. There are five predefined hash and comparison functions in st.
  99. For keys as numbers:
  100. <pre>
  101. st_numhash(key, modulus) { return (unsigned int) key % modulus; }
  102. </pre>
  103. <pre>
  104. st_numcmp(x,y) { return (int) x - (int) y; }
  105. </pre>
  106. For keys as pointers:
  107. <pre>
  108. st_ptrhash(key, modulus) { return ((unsigned int) key/4) % modulus }
  109. </pre>
  110. <pre>
  111. st_ptrcmp(x,y) { return (int) x - (int) y; }
  112. </pre>
  113. For keys as strings:
  114. <pre>
  115. st_strhash(x,y) - a reasonable hashing function for strings
  116. </pre>
  117. <pre>
  118. strcmp(x,y) - the standard library function
  119. </pre>
  120. It is recommended to use these particular functions if they fit your
  121. needs, since st will recognize certain of them and run more quickly
  122. because of it.]
  123. SideEffects [None]
  124. SeeAlso [st_init_table_with_params st_free_table]
  125. ******************************************************************************/
  126. st_table *
  127. st_init_table(ST_PFICPCP compare, ST_PFICPI hash)
  128. {
  129. return st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE,
  130. ST_DEFAULT_MAX_DENSITY,
  131. ST_DEFAULT_GROW_FACTOR,
  132. ST_DEFAULT_REORDER_FLAG);
  133. } /* st_init_table */
  134. /**Function********************************************************************
  135. Synopsis [Create a table with given parameters.]
  136. Description [The full blown table initializer. compare and hash are
  137. the same as in st_init_table. density is the largest the average
  138. number of entries per hash bin there should be before the table is
  139. grown. grow_factor is the factor the table is grown by when it
  140. becomes too full. size is the initial number of bins to be allocated
  141. for the hash table. If reorder_flag is non-zero, then every time an
  142. entry is found, it is moved to the top of the chain.<p>
  143. st_init_table(compare, hash) is equivelent to
  144. <pre>
  145. st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE,
  146. ST_DEFAULT_MAX_DENSITY,
  147. ST_DEFAULT_GROW_FACTOR,
  148. ST_DEFAULT_REORDER_FLAG);
  149. </pre>
  150. ]
  151. SideEffects [None]
  152. SeeAlso [st_init_table st_free_table]
  153. ******************************************************************************/
  154. st_table *
  155. st_init_table_with_params(
  156. ST_PFICPCP compare,
  157. ST_PFICPI hash,
  158. int size,
  159. int density,
  160. double grow_factor,
  161. int reorder_flag)
  162. {
  163. int i;
  164. st_table *newt;
  165. newt = ALLOC(st_table, 1);
  166. if (newt == NIL(st_table)) {
  167. return NIL(st_table);
  168. }
  169. newt->compare = compare;
  170. newt->hash = hash;
  171. newt->num_entries = 0;
  172. newt->max_density = density;
  173. newt->grow_factor = grow_factor;
  174. newt->reorder_flag = reorder_flag;
  175. if (size <= 0) {
  176. size = 1;
  177. }
  178. newt->num_bins = size;
  179. newt->bins = ALLOC(st_table_entry *, size);
  180. if (newt->bins == NIL(st_table_entry *)) {
  181. FREE(newt);
  182. return NIL(st_table);
  183. }
  184. for(i = 0; i < size; i++) {
  185. newt->bins[i] = 0;
  186. }
  187. return newt;
  188. } /* st_init_table_with_params */
  189. /**Function********************************************************************
  190. Synopsis [Free a table.]
  191. Description [Any internal storage associated with table is freed.
  192. It is the user's responsibility to free any storage associated
  193. with the pointers he placed in the table (by perhaps using
  194. st_foreach).]
  195. SideEffects [None]
  196. SeeAlso [st_init_table st_init_table_with_params]
  197. ******************************************************************************/
  198. void
  199. st_free_table(st_table *table)
  200. {
  201. st_table_entry *ptr, *next;
  202. int i;
  203. for(i = 0; i < table->num_bins ; i++) {
  204. ptr = table->bins[i];
  205. while (ptr != NIL(st_table_entry)) {
  206. next = ptr->next;
  207. FREE(ptr);
  208. ptr = next;
  209. }
  210. }
  211. FREE(table->bins);
  212. FREE(table);
  213. } /* st_free_table */
  214. /**Function********************************************************************
  215. Synopsis [Lookup up `key' in `table'.]
  216. Description [Lookup up `key' in `table'. If an entry is found, 1 is
  217. returned and if `value' is not nil, the variable it points to is set
  218. to the associated value. If an entry is not found, 0 is returned
  219. and the variable pointed by value is unchanged.]
  220. SideEffects [None]
  221. SeeAlso [st_lookup_int]
  222. ******************************************************************************/
  223. int
  224. st_lookup(st_table *table, void *key, void *value)
  225. {
  226. int hash_val;
  227. st_table_entry *ptr, **last;
  228. hash_val = do_hash(key, table);
  229. FIND_ENTRY(table, hash_val, key, ptr, last);
  230. if (ptr == NIL(st_table_entry)) {
  231. return 0;
  232. } else {
  233. if (value != NIL(void)) {
  234. *(char **)value = ptr->record;
  235. }
  236. return 1;
  237. }
  238. } /* st_lookup */
  239. /**Function********************************************************************
  240. Synopsis [Lookup up `key' in `table'.]
  241. Description [Lookup up `key' in `table'. If an entry is found, 1 is
  242. returned and if `value' is not nil, the variable it points to is
  243. set to the associated integer value. If an entry is not found, 0 is
  244. return and the variable pointed by `value' is unchanged.]
  245. SideEffects [None]
  246. SeeAlso [st_lookup]
  247. ******************************************************************************/
  248. int
  249. st_lookup_int(st_table *table, void *key, int *value)
  250. {
  251. int hash_val;
  252. st_table_entry *ptr, **last;
  253. hash_val = do_hash(key, table);
  254. FIND_ENTRY(table, hash_val, key, ptr, last);
  255. if (ptr == NIL(st_table_entry)) {
  256. return 0;
  257. } else {
  258. if (value != NIL(int)) {
  259. *value = (int) (long) ptr->record;
  260. }
  261. return 1;
  262. }
  263. } /* st_lookup_int */
  264. /**Function********************************************************************
  265. Synopsis [Insert value in table under the key 'key'.]
  266. Description [Insert value in table under the key 'key'. Returns 1
  267. if there was an entry already under the key; 0 if there was no entry
  268. under the key and insertion was successful; ST_OUT_OF_MEM otherwise.
  269. In either of the first two cases the new value is added.]
  270. SideEffects [None]
  271. SeeAlso []
  272. ******************************************************************************/
  273. int
  274. st_insert(st_table *table, void *key, void *value)
  275. {
  276. int hash_val;
  277. st_table_entry *newt;
  278. st_table_entry *ptr, **last;
  279. hash_val = do_hash(key, table);
  280. FIND_ENTRY(table, hash_val, key, ptr, last);
  281. if (ptr == NIL(st_table_entry)) {
  282. if (table->num_entries/table->num_bins >= table->max_density) {
  283. if (rehash(table) == ST_OUT_OF_MEM) {
  284. return ST_OUT_OF_MEM;
  285. }
  286. hash_val = do_hash(key, table);
  287. }
  288. newt = ALLOC(st_table_entry, 1);
  289. if (newt == NIL(st_table_entry)) {
  290. return ST_OUT_OF_MEM;
  291. }
  292. newt->key = (char *)key;
  293. newt->record = (char *)value;
  294. newt->next = table->bins[hash_val];
  295. table->bins[hash_val] = newt;
  296. table->num_entries++;
  297. return 0;
  298. } else {
  299. ptr->record = (char *)value;
  300. return 1;
  301. }
  302. } /* st_insert */
  303. /**Function********************************************************************
  304. Synopsis [Place 'value' in 'table' under the key 'key'.]
  305. Description [Place 'value' in 'table' under the key 'key'. This is
  306. done without checking if 'key' is in 'table' already. This should
  307. only be used if you are sure there is not already an entry for
  308. 'key', since it is undefined which entry you would later get from
  309. st_lookup or st_find_or_add. Returns 1 if successful; ST_OUT_OF_MEM
  310. otherwise.]
  311. SideEffects [None]
  312. SeeAlso []
  313. ******************************************************************************/
  314. int
  315. st_add_direct(st_table *table, void *key, void *value)
  316. {
  317. int hash_val;
  318. st_table_entry *newt;
  319. hash_val = do_hash(key, table);
  320. if (table->num_entries / table->num_bins >= table->max_density) {
  321. if (rehash(table) == ST_OUT_OF_MEM) {
  322. return ST_OUT_OF_MEM;
  323. }
  324. }
  325. hash_val = do_hash(key, table);
  326. newt = ALLOC(st_table_entry, 1);
  327. if (newt == NIL(st_table_entry)) {
  328. return ST_OUT_OF_MEM;
  329. }
  330. newt->key = (char *)key;
  331. newt->record = (char *)value;
  332. newt->next = table->bins[hash_val];
  333. table->bins[hash_val] = newt;
  334. table->num_entries++;
  335. return 1;
  336. } /* st_add_direct */
  337. /**Function********************************************************************
  338. Synopsis [Lookup `key' in `table'.]
  339. Description [Lookup `key' in `table'. If not found, create an
  340. entry. In either case set slot to point to the field in the entry
  341. where the value is stored. The value associated with `key' may then
  342. be changed by accessing directly through slot. Returns 1 if an
  343. entry already existed, 0 if it did not exist and creation was
  344. successful; ST_OUT_OF_MEM otherwise. As an example:
  345. <pre>
  346. char **slot;
  347. </pre>
  348. <pre>
  349. char *key;
  350. </pre>
  351. <pre>
  352. char *value = (char *) item_ptr <-- ptr to a malloc'd structure
  353. </pre>
  354. <pre>
  355. if (st_find_or_add(table, key, &slot) == 1) {
  356. </pre>
  357. <pre>
  358. FREE(*slot); <-- free the old value of the record
  359. </pre>
  360. <pre>
  361. }
  362. </pre>
  363. <pre>
  364. *slot = value; <-- attach the new value to the record
  365. </pre>
  366. This replaces the equivelent code:
  367. <pre>
  368. if (st_lookup(table, key, &ovalue) == 1) {
  369. </pre>
  370. <pre>
  371. FREE(ovalue);
  372. </pre>
  373. <pre>
  374. }
  375. </pre>
  376. <pre>
  377. st_insert(table, key, value);
  378. </pre>
  379. ]
  380. SideEffects [None]
  381. SeeAlso [st_find]
  382. ******************************************************************************/
  383. int
  384. st_find_or_add(st_table *table, void *key, void *slot)
  385. {
  386. int hash_val;
  387. st_table_entry *newt, *ptr, **last;
  388. hash_val = do_hash(key, table);
  389. FIND_ENTRY(table, hash_val, key, ptr, last);
  390. if (ptr == NIL(st_table_entry)) {
  391. if (table->num_entries / table->num_bins >= table->max_density) {
  392. if (rehash(table) == ST_OUT_OF_MEM) {
  393. return ST_OUT_OF_MEM;
  394. }
  395. hash_val = do_hash(key, table);
  396. }
  397. newt = ALLOC(st_table_entry, 1);
  398. if (newt == NIL(st_table_entry)) {
  399. return ST_OUT_OF_MEM;
  400. }
  401. newt->key = (char *)key;
  402. newt->record = (char *) 0;
  403. newt->next = table->bins[hash_val];
  404. table->bins[hash_val] = newt;
  405. table->num_entries++;
  406. if (slot != NIL(void)) *(char ***)slot = &newt->record;
  407. return 0;
  408. } else {
  409. if (slot != NIL(void)) *(char ***)slot = &ptr->record;
  410. return 1;
  411. }
  412. } /* st_find_or_add */
  413. /**Function********************************************************************
  414. Synopsis [Lookup `key' in `table'.]
  415. Description [Like st_find_or_add, but does not create an entry if
  416. one is not found.]
  417. SideEffects [None]
  418. SeeAlso [st_find_or_add]
  419. ******************************************************************************/
  420. int
  421. st_find(st_table *table, void *key, void *slot)
  422. {
  423. int hash_val;
  424. st_table_entry *ptr, **last;
  425. hash_val = do_hash(key, table);
  426. FIND_ENTRY(table, hash_val, key, ptr, last);
  427. if (ptr == NIL(st_table_entry)) {
  428. return 0;
  429. } else {
  430. if (slot != NIL(void)) {
  431. *(char ***)slot = &ptr->record;
  432. }
  433. return 1;
  434. }
  435. } /* st_find */
  436. /**Function********************************************************************
  437. Synopsis [Return a copy of old_table and all its members.]
  438. Description [Return a copy of old_table and all its members.
  439. (st_table *) 0 is returned if there was insufficient memory to do
  440. the copy.]
  441. SideEffects [None]
  442. SeeAlso []
  443. ******************************************************************************/
  444. st_table *
  445. st_copy(st_table *old_table)
  446. {
  447. st_table *new_table;
  448. st_table_entry *ptr, *newptr, *next, *newt;
  449. int i, j, num_bins = old_table->num_bins;
  450. new_table = ALLOC(st_table, 1);
  451. if (new_table == NIL(st_table)) {
  452. return NIL(st_table);
  453. }
  454. *new_table = *old_table;
  455. new_table->bins = ALLOC(st_table_entry *, num_bins);
  456. if (new_table->bins == NIL(st_table_entry *)) {
  457. FREE(new_table);
  458. return NIL(st_table);
  459. }
  460. for(i = 0; i < num_bins ; i++) {
  461. new_table->bins[i] = NIL(st_table_entry);
  462. ptr = old_table->bins[i];
  463. while (ptr != NIL(st_table_entry)) {
  464. newt = ALLOC(st_table_entry, 1);
  465. if (newt == NIL(st_table_entry)) {
  466. for (j = 0; j <= i; j++) {
  467. newptr = new_table->bins[j];
  468. while (newptr != NIL(st_table_entry)) {
  469. next = newptr->next;
  470. FREE(newptr);
  471. newptr = next;
  472. }
  473. }
  474. FREE(new_table->bins);
  475. FREE(new_table);
  476. return NIL(st_table);
  477. }
  478. *newt = *ptr;
  479. newt->next = new_table->bins[i];
  480. new_table->bins[i] = newt;
  481. ptr = ptr->next;
  482. }
  483. }
  484. return new_table;
  485. } /* st_copy */
  486. /**Function********************************************************************
  487. Synopsis [Delete the entry with the key pointed to by `keyp'.]
  488. Description [Delete the entry with the key pointed to by `keyp'. If
  489. the entry is found, 1 is returned, the variable pointed by `keyp' is
  490. set to the actual key and the variable pointed by `value' is set to
  491. the corresponding entry. (This allows the freeing of the associated
  492. storage.) If the entry is not found, then 0 is returned and nothing
  493. is changed.]
  494. SideEffects [None]
  495. SeeAlso [st_delete_int]
  496. ******************************************************************************/
  497. int
  498. st_delete(st_table *table, void *keyp, void *value)
  499. {
  500. int hash_val;
  501. char *key = *(char **)keyp;
  502. st_table_entry *ptr, **last;
  503. hash_val = do_hash(key, table);
  504. FIND_ENTRY(table, hash_val, key, ptr ,last);
  505. if (ptr == NIL(st_table_entry)) {
  506. return 0;
  507. }
  508. *last = ptr->next;
  509. if (value != NIL(void)) *(char **)value = ptr->record;
  510. *(char **)keyp = ptr->key;
  511. FREE(ptr);
  512. table->num_entries--;
  513. return 1;
  514. } /* st_delete */
  515. /**Function********************************************************************
  516. Synopsis [Delete the entry with the key pointed to by `keyp'.]
  517. Description [Delete the entry with the key pointed to by `keyp'.
  518. `value' must be a pointer to an integer. If the entry is found, 1
  519. is returned, the variable pointed by `keyp' is set to the actual key
  520. and the variable pointed by `value' is set to the corresponding
  521. entry. (This allows the freeing of the associated storage.) If the
  522. entry is not found, then 0 is returned and nothing is changed.]
  523. SideEffects [None]
  524. SeeAlso [st_delete]
  525. ******************************************************************************/
  526. int
  527. st_delete_int(st_table *table, void *keyp, int *value)
  528. {
  529. int hash_val;
  530. char *key = *(char **)keyp;
  531. st_table_entry *ptr, **last;
  532. hash_val = do_hash(key, table);
  533. FIND_ENTRY(table, hash_val, key, ptr ,last);
  534. if (ptr == NIL(st_table_entry)) {
  535. return 0;
  536. }
  537. *last = ptr->next;
  538. if (value != NIL(int)) *value = (int) (long) ptr->record;
  539. *(char **)keyp = ptr->key;
  540. FREE(ptr);
  541. table->num_entries--;
  542. return 1;
  543. } /* st_delete_int */
  544. /**Function********************************************************************
  545. Synopsis [Iterates over the elements of a table.]
  546. Description [For each (key, value) record in `table', st_foreach
  547. call func with the arguments
  548. <pre>
  549. (*func)(key, value, arg)
  550. </pre>
  551. If func returns ST_CONTINUE, st_foreach continues processing
  552. entries. If func returns ST_STOP, st_foreach stops processing and
  553. returns immediately. If func returns ST_DELETE, then the entry is
  554. deleted from the symbol table and st_foreach continues. In the case
  555. of ST_DELETE, it is func's responsibility to free the key and value,
  556. if necessary.<p>
  557. The routine returns 1 if all items in the table were generated and 0
  558. if the generation sequence was aborted using ST_STOP. The order in
  559. which the records are visited will be seemingly random.]
  560. SideEffects [None]
  561. SeeAlso [st_foreach_item st_foreach_item_int]
  562. ******************************************************************************/
  563. int
  564. st_foreach(st_table *table, ST_PFSR func, char *arg)
  565. {
  566. st_table_entry *ptr, **last;
  567. enum st_retval retval;
  568. int i;
  569. for(i = 0; i < table->num_bins; i++) {
  570. last = &table->bins[i]; ptr = *last;
  571. while (ptr != NIL(st_table_entry)) {
  572. retval = (*func)(ptr->key, ptr->record, arg);
  573. switch (retval) {
  574. case ST_CONTINUE:
  575. last = &ptr->next; ptr = *last;
  576. break;
  577. case ST_STOP:
  578. return 0;
  579. case ST_DELETE:
  580. *last = ptr->next;
  581. table->num_entries--; /* cstevens@ic */
  582. FREE(ptr);
  583. ptr = *last;
  584. }
  585. }
  586. }
  587. return 1;
  588. } /* st_foreach */
  589. /**Function********************************************************************
  590. Synopsis [String hash function.]
  591. Description [String hash function.]
  592. SideEffects [None]
  593. SeeAlso [st_init_table]
  594. ******************************************************************************/
  595. int
  596. st_strhash(char *string, int modulus)
  597. {
  598. int val = 0;
  599. int c;
  600. while ((c = *string++) != '\0') {
  601. val = val*997 + c;
  602. }
  603. return ((val < 0) ? -val : val)%modulus;
  604. } /* st_strhash */
  605. /**Function********************************************************************
  606. Synopsis [Number hash function.]
  607. Description [Integer number hash function.]
  608. SideEffects [None]
  609. SeeAlso [st_init_table st_numcmp]
  610. ******************************************************************************/
  611. int
  612. st_numhash(char *x, int size)
  613. {
  614. return ST_NUMHASH(x, size);
  615. } /* st_numhash */
  616. /**Function********************************************************************
  617. Synopsis [Pointer hash function.]
  618. Description [Pointer hash function.]
  619. SideEffects [None]
  620. SeeAlso [st_init_table st_ptrcmp]
  621. ******************************************************************************/
  622. int
  623. st_ptrhash(char *x, int size)
  624. {
  625. return ST_PTRHASH(x, size);
  626. } /* st_ptrhash */
  627. /**Function********************************************************************
  628. Synopsis [Number comparison function.]
  629. Description [integer number comparison function.]
  630. SideEffects [None]
  631. SeeAlso [st_init_table st_numhash]
  632. ******************************************************************************/
  633. int
  634. st_numcmp(const char *x, const char *y)
  635. {
  636. return ST_NUMCMP(x, y);
  637. } /* st_numcmp */
  638. /**Function********************************************************************
  639. Synopsis [Pointer comparison function.]
  640. Description [Pointer comparison function.]
  641. SideEffects [None]
  642. SeeAlso [st_init_table st_ptrhash]
  643. ******************************************************************************/
  644. int
  645. st_ptrcmp(const char *x, const char *y)
  646. {
  647. return ST_NUMCMP(x, y);
  648. } /* st_ptrcmp */
  649. /**Function********************************************************************
  650. Synopsis [Initializes a generator.]
  651. Description [Returns a generator handle which when used with
  652. st_gen() will progressively return each (key, value) record in
  653. `table'.]
  654. SideEffects [None]
  655. SeeAlso [st_free_gen]
  656. ******************************************************************************/
  657. st_generator *
  658. st_init_gen(st_table *table)
  659. {
  660. st_generator *gen;
  661. gen = ALLOC(st_generator, 1);
  662. if (gen == NIL(st_generator)) {
  663. return NIL(st_generator);
  664. }
  665. gen->table = table;
  666. gen->entry = NIL(st_table_entry);
  667. gen->index = 0;
  668. return gen;
  669. } /* st_init_gen */
  670. /**Function********************************************************************
  671. Synopsis [returns the next (key, value) pair in the generation
  672. sequence. ]
  673. Description [Given a generator returned by st_init_gen(), this
  674. routine returns the next (key, value) pair in the generation
  675. sequence. The pointer `value_p' can be zero which means no value
  676. will be returned. When there are no more items in the generation
  677. sequence, the routine returns 0.
  678. While using a generation sequence, deleting any (key, value) pair
  679. other than the one just generated may cause a fatal error when
  680. st_gen() is called later in the sequence and is therefore not
  681. recommended.]
  682. SideEffects [None]
  683. SeeAlso [st_gen_int]
  684. ******************************************************************************/
  685. int
  686. st_gen(st_generator *gen, void *key_p, void *value_p)
  687. {
  688. int i;
  689. if (gen->entry == NIL(st_table_entry)) {
  690. /* try to find next entry */
  691. for(i = gen->index; i < gen->table->num_bins; i++) {
  692. if (gen->table->bins[i] != NIL(st_table_entry)) {
  693. gen->index = i+1;
  694. gen->entry = gen->table->bins[i];
  695. break;
  696. }
  697. }
  698. if (gen->entry == NIL(st_table_entry)) {
  699. return 0; /* that's all folks ! */
  700. }
  701. }
  702. *(char **)key_p = gen->entry->key;
  703. if (value_p != NIL(void)) {
  704. *(char **)value_p = gen->entry->record;
  705. }
  706. gen->entry = gen->entry->next;
  707. return 1;
  708. } /* st_gen */
  709. /**Function********************************************************************
  710. Synopsis [Returns the next (key, value) pair in the generation
  711. sequence.]
  712. Description [Given a generator returned by st_init_gen(), this
  713. routine returns the next (key, value) pair in the generation
  714. sequence. `value_p' must be a pointer to an integer. The pointer
  715. `value_p' can be zero which means no value will be returned. When
  716. there are no more items in the generation sequence, the routine
  717. returns 0.]
  718. SideEffects [None]
  719. SeeAlso [st_gen]
  720. ******************************************************************************/
  721. int
  722. st_gen_int(st_generator *gen, void *key_p, int *value_p)
  723. {
  724. int i;
  725. if (gen->entry == NIL(st_table_entry)) {
  726. /* try to find next entry */
  727. for(i = gen->index; i < gen->table->num_bins; i++) {
  728. if (gen->table->bins[i] != NIL(st_table_entry)) {
  729. gen->index = i+1;
  730. gen->entry = gen->table->bins[i];
  731. break;
  732. }
  733. }
  734. if (gen->entry == NIL(st_table_entry)) {
  735. return 0; /* that's all folks ! */
  736. }
  737. }
  738. *(char **)key_p = gen->entry->key;
  739. if (value_p != NIL(int)) {
  740. *value_p = (int) (long) gen->entry->record;
  741. }
  742. gen->entry = gen->entry->next;
  743. return 1;
  744. } /* st_gen_int */
  745. /**Function********************************************************************
  746. Synopsis [Reclaims the resources associated with `gen'.]
  747. Description [After generating all items in a generation sequence,
  748. this routine must be called to reclaim the resources associated with
  749. `gen'.]
  750. SideEffects [None]
  751. SeeAlso [st_init_gen]
  752. ******************************************************************************/
  753. void
  754. st_free_gen(st_generator *gen)
  755. {
  756. FREE(gen);
  757. } /* st_free_gen */
  758. /*---------------------------------------------------------------------------*/
  759. /* Definition of internal functions */
  760. /*---------------------------------------------------------------------------*/
  761. /*---------------------------------------------------------------------------*/
  762. /* Definition of static functions */
  763. /*---------------------------------------------------------------------------*/
  764. /**Function********************************************************************
  765. Synopsis [Rehashes a symbol table.]
  766. Description [Rehashes a symbol table.]
  767. SideEffects [None]
  768. SeeAlso [st_insert]
  769. ******************************************************************************/
  770. static int
  771. rehash(st_table *table)
  772. {
  773. st_table_entry *ptr, *next, **old_bins;
  774. int i, old_num_bins, hash_val, old_num_entries;
  775. /* save old values */
  776. old_bins = table->bins;
  777. old_num_bins = table->num_bins;
  778. old_num_entries = table->num_entries;
  779. /* rehash */
  780. table->num_bins = (int) (table->grow_factor * old_num_bins);
  781. if (table->num_bins % 2 == 0) {
  782. table->num_bins += 1;
  783. }
  784. table->num_entries = 0;
  785. table->bins = ALLOC(st_table_entry *, table->num_bins);
  786. if (table->bins == NIL(st_table_entry *)) {
  787. table->bins = old_bins;
  788. table->num_bins = old_num_bins;
  789. table->num_entries = old_num_entries;
  790. return ST_OUT_OF_MEM;
  791. }
  792. /* initialize */
  793. for (i = 0; i < table->num_bins; i++) {
  794. table->bins[i] = 0;
  795. }
  796. /* copy data over */
  797. for (i = 0; i < old_num_bins; i++) {
  798. ptr = old_bins[i];
  799. while (ptr != NIL(st_table_entry)) {
  800. next = ptr->next;
  801. hash_val = do_hash(ptr->key, table);
  802. ptr->next = table->bins[hash_val];
  803. table->bins[hash_val] = ptr;
  804. table->num_entries++;
  805. ptr = next;
  806. }
  807. }
  808. FREE(old_bins);
  809. return 1;
  810. } /* rehash */