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.

1198 lines
29 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup st
  4. @brief Symbol table package.
  5. @details The st library provides functions to create, maintain,
  6. and query symbol tables.
  7. @copyright@parblock
  8. Copyright (c) 1994-1998 The Regents of the Univ. of California.
  9. All rights reserved.
  10. Permission is hereby granted, without written agreement and without license
  11. or royalty fees, to use, copy, modify, and distribute this software and its
  12. documentation for any purpose, provided that the above copyright notice and
  13. the following two paragraphs appear in all copies of this software.
  14. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  15. DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  16. OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  17. CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  18. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  19. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20. FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
  21. "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
  22. MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23. @endparblock
  24. @copyright@parblock
  25. Copyright (c) 1999-2015, Regents of the University of Colorado
  26. All rights reserved.
  27. Redistribution and use in source and binary forms, with or without
  28. modification, are permitted provided that the following conditions
  29. are met:
  30. Redistributions of source code must retain the above copyright
  31. notice, this list of conditions and the following disclaimer.
  32. Redistributions in binary form must reproduce the above copyright
  33. notice, this list of conditions and the following disclaimer in the
  34. documentation and/or other materials provided with the distribution.
  35. Neither the name of the University of Colorado nor the names of its
  36. contributors may be used to endorse or promote products derived from
  37. this software without specific prior written permission.
  38. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  39. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  40. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  41. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  42. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  43. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  44. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  45. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  46. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  47. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  48. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  49. POSSIBILITY OF SUCH DAMAGE.
  50. @endparblock
  51. */
  52. #include "util.h"
  53. #include "st.h"
  54. /*---------------------------------------------------------------------------*/
  55. /* Constant declarations */
  56. /*---------------------------------------------------------------------------*/
  57. /*---------------------------------------------------------------------------*/
  58. /* Type declarations */
  59. /*---------------------------------------------------------------------------*/
  60. /**
  61. * @brief Type of symbol table entries.
  62. */
  63. typedef struct st_table_entry st_table_entry;
  64. /*---------------------------------------------------------------------------*/
  65. /* Stucture declarations */
  66. /*---------------------------------------------------------------------------*/
  67. /**
  68. * @brief Symbol table entry.
  69. */
  70. struct st_table_entry {
  71. void *key;
  72. void *record;
  73. st_table_entry *next;
  74. };
  75. /**
  76. * @brief Symbol table header.
  77. */
  78. struct st_table {
  79. st_compare_t compare;
  80. st_hash_t hash;
  81. st_compare_arg_t compare_arg;
  82. st_hash_arg_t hash_arg;
  83. void const * arg;
  84. int num_bins;
  85. int num_entries;
  86. int max_density;
  87. int reorder_flag;
  88. double grow_factor;
  89. st_table_entry **bins;
  90. };
  91. /**
  92. * @brief Symbol table generator.
  93. */
  94. struct st_generator {
  95. st_table const *table;
  96. st_table_entry const *entry;
  97. int index;
  98. };
  99. /*---------------------------------------------------------------------------*/
  100. /* Variable declarations */
  101. /*---------------------------------------------------------------------------*/
  102. /*---------------------------------------------------------------------------*/
  103. /* Macro declarations */
  104. /*---------------------------------------------------------------------------*/
  105. /**
  106. * @brief Compares two numbers or two pointers.
  107. *
  108. * @details Used by the default comparison functions.
  109. */
  110. #define ST_NUMCMP(x,y) ((x) != (y))
  111. /**
  112. * @brief Hash function for numbers.
  113. */
  114. #define ST_NUMHASH(x,size) ((int)((uintptr_t)(x)%(uintptr_t)(size)))
  115. /**
  116. * @brief Amount by which pointers should be shifted right when hashing.
  117. *
  118. * @details This is to discard bits that are (likely to be) 0 due to
  119. * alignment constraints.
  120. */
  121. #if SIZEOF_VOID_P == 8
  122. #define st_shift 3
  123. #else
  124. #define st_shift 2
  125. #endif
  126. /**
  127. * @brief Hash function for pointers.
  128. */
  129. #define ST_PTRHASH(x,size) ((int)(((uintptr_t)(x)>>st_shift)%(uintptr_t)(size)))
  130. /**
  131. * @brief Compares two entries.
  132. */
  133. #define EQUAL(table, x, y) \
  134. ((((table)->compare == st_numcmp) || ((table)->compare == st_ptrcmp)) ?\
  135. (ST_NUMCMP((x),(y)) == 0) : ((table)->compare) ?\
  136. ((*(table)->compare)((x), (y)) == 0) :\
  137. ((*(table)->compare_arg)((x), (y), (table)->arg) == 0))
  138. /**
  139. * @brief Computes the hash of one entry.
  140. */
  141. #define do_hash(key, table)\
  142. (((table)->hash == st_ptrhash) ? ST_PTRHASH((key), (table)->num_bins) : \
  143. ((table)->hash == st_numhash) ? ST_NUMHASH((key), (table)->num_bins) : \
  144. ((table)->hash) ? (*(table)->hash)((key), (table)->num_bins) : \
  145. (*(table)->hash_arg)((key), (table)->num_bins, (table)->arg))
  146. /**
  147. * @brief Compares the new key to one in a collision list.
  148. */
  149. #define PTR_NOT_EQUAL(table, ptr, user_key)\
  150. ((ptr) != NIL(st_table_entry) && \
  151. !EQUAL((table), (user_key), (ptr)->key))
  152. /**
  153. * @brief Looks up an entry in a collision list.
  154. *
  155. * @details If the entry is found and the reorder flag is set, the found
  156. * entry is brought to the fore of the collision list.
  157. */
  158. #define FIND_ENTRY(table, hash_val, key, ptr, last) \
  159. (last) = &(table)->bins[hash_val];\
  160. (ptr) = *(last);\
  161. while (PTR_NOT_EQUAL((table), (ptr), (key))) {\
  162. (last) = &(ptr)->next; (ptr) = *(last);\
  163. }\
  164. if ((ptr) != NIL(st_table_entry) && (table)->reorder_flag) {\
  165. *(last) = (ptr)->next;\
  166. (ptr)->next = (table)->bins[hash_val];\
  167. (table)->bins[hash_val] = (ptr);\
  168. }
  169. /**
  170. * @brief Adds an entry to a table.
  171. *
  172. * @deprecated This macro does not check if memory allocation fails.
  173. * Use at your own risk.
  174. */
  175. #define ADD_DIRECT(table, key, value, hash_val, newt)\
  176. {\
  177. if (table->num_entries/table->num_bins >= table->max_density) {\
  178. rehash(table);\
  179. hash_val = do_hash(key,table);\
  180. }\
  181. \
  182. newt = ALLOC(st_table_entry, 1);\
  183. \
  184. newt->key = key;\
  185. newt->record = value;\
  186. newt->next = table->bins[hash_val];\
  187. table->bins[hash_val] = newt;\
  188. table->num_entries++;\
  189. }
  190. /** \cond */
  191. /*---------------------------------------------------------------------------*/
  192. /* Static function prototypes */
  193. /*---------------------------------------------------------------------------*/
  194. static int rehash (st_table *);
  195. /** \endcond */
  196. /*---------------------------------------------------------------------------*/
  197. /* Definition of exported functions */
  198. /*---------------------------------------------------------------------------*/
  199. /**
  200. @brief Creates and initializes a table.
  201. @details Creates and initializes a table with the comparison function
  202. compare_fn and hash function hash_fn. compare_fn is
  203. int compare_fn(const void *key1, const void *key2)
  204. It returns `<,=,> 0` depending on whether `key1 <,=,> key2` by some
  205. measure.<p>
  206. hash_fn is
  207. int hash_fn(void *key, int modulus)
  208. It returns an integer between `0` and `modulus-1` such that if
  209. `compare_fn(key1,key2) == 0` then `hash_fn(key1) == hash_fn(key2)`.<p>
  210. There are five predefined hash and comparison functions in st.
  211. For keys as numbers:
  212. st_numhash(key, modulus) { return (unsigned int) key % modulus; }
  213. st_numcmp(x,y) { return (int) x - (int) y; }
  214. For keys as pointers:
  215. st_ptrhash(key, modulus) { return ((unsigned int) key/4) % modulus }
  216. st_ptrcmp(x,y) { return (int) x - (int) y; }
  217. For keys as strings:
  218. st_strhash(x,y) - a reasonable hashing function for strings
  219. strcmp(x,y) - the standard library function
  220. It is recommended to use these particular functions if they fit your
  221. needs, since st will recognize certain of them and run more quickly
  222. because of it.
  223. @sideeffect None
  224. @see st_init_table_with_params st_free_table
  225. */
  226. st_table *
  227. st_init_table(st_compare_t compare, st_hash_t hash)
  228. {
  229. return st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE,
  230. ST_DEFAULT_MAX_DENSITY,
  231. ST_DEFAULT_GROW_FACTOR,
  232. ST_DEFAULT_REORDER_FLAG);
  233. } /* st_init_table */
  234. /**
  235. @brief Create a table with given parameters.
  236. @details The full blown table initializer. compare and hash are
  237. the same as in st_init_table. density is the largest the average
  238. number of entries per hash bin there should be before the table is
  239. grown. grow_factor is the factor the table is grown by when it
  240. becomes too full. size is the initial number of bins to be allocated
  241. for the hash table. If reorder_flag is non-zero, then every time an
  242. entry is found, it is moved to the top of the chain.<p>
  243. st_init_table(compare, hash) is equivelent to
  244. st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE,
  245. ST_DEFAULT_MAX_DENSITY, ST_DEFAULT_GROW_FACTOR,
  246. ST_DEFAULT_REORDER_FLAG);
  247. @sideeffect None
  248. @see st_init_table st_free_table
  249. */
  250. st_table *
  251. st_init_table_with_params(
  252. st_compare_t compare,
  253. st_hash_t hash,
  254. int size,
  255. int density,
  256. double grow_factor,
  257. int reorder_flag)
  258. {
  259. int i;
  260. st_table *newt;
  261. newt = ALLOC(st_table, 1);
  262. if (newt == NIL(st_table)) {
  263. return NIL(st_table);
  264. }
  265. newt->compare = compare;
  266. newt->hash = hash;
  267. newt->compare_arg = (st_compare_arg_t) 0;
  268. newt->hash_arg = (st_hash_arg_t) 0;
  269. newt->arg = NIL(void);
  270. newt->num_entries = 0;
  271. newt->max_density = density;
  272. newt->grow_factor = grow_factor;
  273. newt->reorder_flag = reorder_flag;
  274. if (size <= 0) {
  275. size = 1;
  276. }
  277. newt->num_bins = size;
  278. newt->bins = ALLOC(st_table_entry *, size);
  279. if (newt->bins == NIL(st_table_entry *)) {
  280. FREE(newt);
  281. return NIL(st_table);
  282. }
  283. for(i = 0; i < size; i++) {
  284. newt->bins[i] = 0;
  285. }
  286. return newt;
  287. } /* st_init_table_with_params */
  288. /**
  289. @brief Creates and initializes a table.
  290. @details Like st_init_table_with_params, but the comparison and
  291. hash functions are passed an extra parameter `arg` that is
  292. registered in the table at initialization.
  293. @see st_init_table_with_params
  294. */
  295. st_table *
  296. st_init_table_with_params_and_arg(
  297. st_compare_arg_t compare,
  298. st_hash_arg_t hash,
  299. void const * arg,
  300. int size,
  301. int density,
  302. double growth_factor,
  303. int reorder_flag)
  304. {
  305. st_table *table;
  306. table = st_init_table_with_params((st_compare_t) 0, (st_hash_t) 0, size,
  307. density, growth_factor, reorder_flag);
  308. if (table == NIL(st_table))
  309. return NIL(st_table);
  310. table->compare_arg = compare;
  311. table->hash_arg = hash;
  312. table->arg = arg;
  313. return table;
  314. } /* st_init_table_with_params_and_arg */
  315. /**
  316. @brief Creates and initializes a table.
  317. @details Like st_init_table, but the comparison and hash functions are
  318. passed an extra parameter `arg` that is registered in the table at
  319. initialization.
  320. @see st_init_table st_init_table_with_params_and_arg
  321. */
  322. st_table *
  323. st_init_table_with_arg(
  324. st_compare_arg_t compare,
  325. st_hash_arg_t hash,
  326. void const * arg)
  327. {
  328. return st_init_table_with_params_and_arg(compare, hash, arg,
  329. ST_DEFAULT_INIT_TABLE_SIZE,
  330. ST_DEFAULT_MAX_DENSITY,
  331. ST_DEFAULT_GROW_FACTOR,
  332. ST_DEFAULT_REORDER_FLAG);
  333. } /* st_init_table_with_arg */
  334. /**
  335. @brief Free a table.
  336. @details Any internal storage associated with table is freed. It is
  337. the user's responsibility to free any storage associated with the
  338. pointers he placed in the table (by perhaps using st_foreach).
  339. @sideeffect None
  340. @see st_init_table st_init_table_with_params
  341. */
  342. void
  343. st_free_table(st_table *table)
  344. {
  345. st_table_entry *ptr, *next;
  346. int i;
  347. for(i = 0; i < table->num_bins ; i++) {
  348. ptr = table->bins[i];
  349. while (ptr != NIL(st_table_entry)) {
  350. next = ptr->next;
  351. FREE(ptr);
  352. ptr = next;
  353. }
  354. }
  355. FREE(table->bins);
  356. FREE(table);
  357. } /* st_free_table */
  358. /**
  359. @brief Lookup up `key` in `table`.
  360. @details If an entry is found, 1 is returned and if `value` is not
  361. nil, the variable it points to is set to the associated value. If
  362. an entry is not found, 0 is returned and the variable pointed by
  363. value is unchanged.
  364. @sideeffect The location pointed by value is modified.
  365. @see st_lookup_int
  366. */
  367. int
  368. st_lookup(st_table *table, void const *key, void **value)
  369. {
  370. int hash_val;
  371. st_table_entry *ptr, **last;
  372. hash_val = do_hash(key, table);
  373. FIND_ENTRY(table, hash_val, key, ptr, last);
  374. if (ptr == NIL(st_table_entry)) {
  375. return 0;
  376. } else {
  377. if (value != NIL(void *)) {
  378. *value = ptr->record;
  379. }
  380. return 1;
  381. }
  382. } /* st_lookup */
  383. /**
  384. @brief Lookup up `key` in `table`.
  385. @details If an entry is found, 1 is returned and if `value` is not
  386. nil, the variable it points to is set to the associated integer
  387. value. If an entry is not found, 0 is return and the variable
  388. pointed by `value` is unchanged.
  389. @sideeffect The location pointed by value is modified.
  390. @see st_lookup
  391. */
  392. int
  393. st_lookup_int(st_table *table, void const *key, int *value)
  394. {
  395. int hash_val;
  396. st_table_entry *ptr, **last;
  397. hash_val = do_hash(key, table);
  398. FIND_ENTRY(table, hash_val, key, ptr, last);
  399. if (ptr == NIL(st_table_entry)) {
  400. return 0;
  401. } else {
  402. if (value != NIL(int)) {
  403. *value = (int) (intptr_t) ptr->record;
  404. }
  405. return 1;
  406. }
  407. } /* st_lookup_int */
  408. /**
  409. @brief Insert value in `table` under the key `key`.
  410. @return 1 if there was an entry already under the key; 0 if there
  411. was no entry under the key and insertion was successful;
  412. ST_OUT_OF_MEM otherwise. In either of the first two cases the new
  413. value is added.
  414. @sideeffect None
  415. */
  416. int
  417. st_insert(st_table *table, void *key, void *value)
  418. {
  419. int hash_val;
  420. st_table_entry *newt;
  421. st_table_entry *ptr, **last;
  422. hash_val = do_hash(key, table);
  423. FIND_ENTRY(table, hash_val, key, ptr, last);
  424. if (ptr == NIL(st_table_entry)) {
  425. if (table->num_entries/table->num_bins >= table->max_density) {
  426. if (rehash(table) == ST_OUT_OF_MEM) {
  427. return ST_OUT_OF_MEM;
  428. }
  429. hash_val = do_hash(key, table);
  430. }
  431. newt = ALLOC(st_table_entry, 1);
  432. if (newt == NIL(st_table_entry)) {
  433. return ST_OUT_OF_MEM;
  434. }
  435. newt->key = key;
  436. newt->record = value;
  437. newt->next = table->bins[hash_val];
  438. table->bins[hash_val] = newt;
  439. table->num_entries++;
  440. return 0;
  441. } else {
  442. ptr->record = value;
  443. return 1;
  444. }
  445. } /* st_insert */
  446. /**
  447. @brief Place 'value' in 'table' under the key 'key'.
  448. @details This is done without checking if 'key' is in 'table'
  449. already. This should only be used if you are sure there is not
  450. already an entry for 'key', since it is undefined which entry you
  451. would later get from st_lookup or st_find_or_add.
  452. @return 1 if successful; ST_OUT_OF_MEM otherwise.
  453. @sideeffect None
  454. @see st_lookup st_find_or_add
  455. */
  456. int
  457. st_add_direct(st_table *table, void *key, void *value)
  458. {
  459. int hash_val;
  460. st_table_entry *newt;
  461. if (table->num_entries / table->num_bins >= table->max_density) {
  462. if (rehash(table) == ST_OUT_OF_MEM) {
  463. return ST_OUT_OF_MEM;
  464. }
  465. }
  466. hash_val = do_hash(key, table);
  467. newt = ALLOC(st_table_entry, 1);
  468. if (newt == NIL(st_table_entry)) {
  469. return ST_OUT_OF_MEM;
  470. }
  471. newt->key = key;
  472. newt->record = value;
  473. newt->next = table->bins[hash_val];
  474. table->bins[hash_val] = newt;
  475. table->num_entries++;
  476. return 1;
  477. } /* st_add_direct */
  478. /**
  479. @brief Lookup `key` in `table`; if not found, create an entry.
  480. @details In either case set slot to point to the field in the entry
  481. where the value is stored. The value associated with `key` may then
  482. be changed by accessing directly through slot. As an example:
  483. void **slot;
  484. void *key;
  485. void *value = item_ptr // ptr to a malloc'd structure
  486. if (st_find_or_add(table, key, &slot) == 1) {
  487. FREE(*slot); // free the old value of the record
  488. }
  489. *slot = value; // attach the new value to the record
  490. This replaces the equivelent code:
  491. if (st_lookup(table, key, &ovalue) == 1) {
  492. FREE(ovalue);
  493. }
  494. st_insert(table, key, value);
  495. @return 1 if an entry already existed, 0 if it did not exist and
  496. creation was successful; ST_OUT_OF_MEM otherwise.
  497. @sideeffect The location pointed by slot is modified.
  498. @see st_find
  499. */
  500. int
  501. st_find_or_add(st_table *table, void *key, void ***slot)
  502. {
  503. int hash_val;
  504. st_table_entry *newt, *ptr, **last;
  505. hash_val = do_hash(key, table);
  506. FIND_ENTRY(table, hash_val, key, ptr, last);
  507. if (ptr == NIL(st_table_entry)) {
  508. if (table->num_entries / table->num_bins >= table->max_density) {
  509. if (rehash(table) == ST_OUT_OF_MEM) {
  510. return ST_OUT_OF_MEM;
  511. }
  512. hash_val = do_hash(key, table);
  513. }
  514. newt = ALLOC(st_table_entry, 1);
  515. if (newt == NIL(st_table_entry)) {
  516. return ST_OUT_OF_MEM;
  517. }
  518. newt->key = key;
  519. newt->record = NIL(void);
  520. newt->next = table->bins[hash_val];
  521. table->bins[hash_val] = newt;
  522. table->num_entries++;
  523. if (slot != NIL(void **)) *slot = &newt->record;
  524. return 0;
  525. } else {
  526. if (slot != NIL(void **)) *slot = &ptr->record;
  527. return 1;
  528. }
  529. } /* st_find_or_add */
  530. /**
  531. @brief Lookup `key` in `table`.
  532. @details Like st_find_or_add, but does not create an entry if one is
  533. not found.
  534. @sideeffect The location pointed by slot is modified.
  535. @see st_find_or_add
  536. */
  537. int
  538. st_find(st_table *table, void const *key, void ***slot)
  539. {
  540. int hash_val;
  541. st_table_entry *ptr, **last;
  542. hash_val = do_hash(key, table);
  543. FIND_ENTRY(table, hash_val, key, ptr, last);
  544. if (ptr == NIL(st_table_entry)) {
  545. return 0;
  546. } else {
  547. if (slot != NIL(void **)) {
  548. *slot = &ptr->record;
  549. }
  550. return 1;
  551. }
  552. } /* st_find */
  553. /**
  554. @brief Returns a copy of old_table and all its members.
  555. @details (st_table *) 0 is returned if there was insufficient memory
  556. to do the copy.
  557. @sideeffect None
  558. */
  559. st_table *
  560. st_copy
  561. (st_table const *old_table)
  562. {
  563. st_table *new_table;
  564. st_table_entry *ptr, *newptr, *next, *newt;
  565. int i, j, num_bins = old_table->num_bins;
  566. new_table = ALLOC(st_table, 1);
  567. if (new_table == NIL(st_table)) {
  568. return NIL(st_table);
  569. }
  570. *new_table = *old_table;
  571. new_table->bins = ALLOC(st_table_entry *, num_bins);
  572. if (new_table->bins == NIL(st_table_entry *)) {
  573. FREE(new_table);
  574. return NIL(st_table);
  575. }
  576. for(i = 0; i < num_bins ; i++) {
  577. new_table->bins[i] = NIL(st_table_entry);
  578. ptr = old_table->bins[i];
  579. while (ptr != NIL(st_table_entry)) {
  580. newt = ALLOC(st_table_entry, 1);
  581. if (newt == NIL(st_table_entry)) {
  582. for (j = 0; j <= i; j++) {
  583. newptr = new_table->bins[j];
  584. while (newptr != NIL(st_table_entry)) {
  585. next = newptr->next;
  586. FREE(newptr);
  587. newptr = next;
  588. }
  589. }
  590. FREE(new_table->bins);
  591. FREE(new_table);
  592. return NIL(st_table);
  593. }
  594. *newt = *ptr;
  595. newt->next = new_table->bins[i];
  596. new_table->bins[i] = newt;
  597. ptr = ptr->next;
  598. }
  599. }
  600. return new_table;
  601. } /* st_copy */
  602. /**
  603. @brief Deletes the entry with the key pointed to by `keyp`.
  604. @details If the entry is found, 1 is returned, the variable pointed
  605. by `keyp` is set to the actual key and the variable pointed by
  606. `value` is set to the corresponding entry. (This allows the freeing
  607. of the associated storage.) If the entry is not found, then 0 is
  608. returned and nothing is changed.
  609. @sideeffect The locations pointed by keyp and value are modified.
  610. @see st_delete_int
  611. */
  612. int
  613. st_delete(st_table *table, void **keyp, void **value)
  614. {
  615. int hash_val;
  616. void *key = *keyp;
  617. st_table_entry *ptr, **last;
  618. hash_val = do_hash(key, table);
  619. FIND_ENTRY(table, hash_val, key, ptr ,last);
  620. if (ptr == NIL(st_table_entry)) {
  621. return 0;
  622. }
  623. *last = ptr->next;
  624. if (value != NIL(void *)) *value = ptr->record;
  625. *keyp = ptr->key;
  626. FREE(ptr);
  627. table->num_entries--;
  628. return 1;
  629. } /* st_delete */
  630. /**
  631. @brief Deletes the entry with the key pointed to by `keyp`.
  632. @details `value` must be a pointer to an integer. If the entry is
  633. found, 1 is returned, the variable pointed by `keyp` is set to the
  634. actual key and the variable pointed by `value` is set to the
  635. corresponding entry. (This allows the freeing of the associated
  636. storage.) If the entry is not found, then 0 is returned and nothing
  637. is changed.
  638. @sideeffect The locations pointed by keyp and value are modified.
  639. @see st_delete
  640. */
  641. int
  642. st_delete_int(st_table *table, void **keyp, int *value)
  643. {
  644. int hash_val;
  645. void *key = *keyp;
  646. st_table_entry *ptr, **last;
  647. hash_val = do_hash(key, table);
  648. FIND_ENTRY(table, hash_val, key, ptr ,last);
  649. if (ptr == NIL(st_table_entry)) {
  650. return 0;
  651. }
  652. *last = ptr->next;
  653. if (value != NIL(int)) *value = (int) (intptr_t) ptr->record;
  654. *keyp = ptr->key;
  655. FREE(ptr);
  656. table->num_entries--;
  657. return 1;
  658. } /* st_delete_int */
  659. /**
  660. @brief Returns the number of entries in the table `table`.
  661. @sideeffect None
  662. */
  663. int st_count(st_table const *table)
  664. {
  665. return table->num_entries;
  666. }
  667. /**
  668. @brief Iterates over the elements of a table.
  669. @details
  670. For each (key, value) record in `table`, st_foreach
  671. calls func with the arguments
  672. (*func)(key, value, arg)
  673. If func returns ST_CONTINUE, st_foreach continues
  674. processing entries. If func returns ST_STOP, st_foreach stops
  675. processing and returns immediately. If func returns ST_DELETE, then
  676. the entry is deleted from the symbol table and st_foreach continues.
  677. In the case of ST_DELETE, it is func's responsibility to free the
  678. key and value, if necessary. The order in which the records are
  679. visited will be seemingly random.
  680. @return 1 if all items in the table were generated and 0 if the
  681. generation sequence was aborted using ST_STOP.
  682. @sideeffect None
  683. @see st_foreach_item st_foreach_item_int
  684. */
  685. int
  686. st_foreach(st_table *table, st_foreach_t func, void *arg)
  687. {
  688. st_table_entry *ptr, **last;
  689. enum st_retval retval;
  690. int i;
  691. for(i = 0; i < table->num_bins; i++) {
  692. last = &table->bins[i]; ptr = *last;
  693. while (ptr != NIL(st_table_entry)) {
  694. retval = (*func)(ptr->key, ptr->record, arg);
  695. switch (retval) {
  696. case ST_CONTINUE:
  697. last = &ptr->next; ptr = *last;
  698. break;
  699. case ST_STOP:
  700. return 0;
  701. case ST_DELETE:
  702. *last = ptr->next;
  703. table->num_entries--; /* cstevens@ic */
  704. FREE(ptr);
  705. ptr = *last;
  706. }
  707. }
  708. }
  709. return 1;
  710. } /* st_foreach */
  711. /**
  712. @brief String hash function.
  713. @sideeffect None
  714. @see st_init_table
  715. */
  716. int
  717. st_strhash(void const *string, int modulus)
  718. {
  719. int val = 0;
  720. int c;
  721. char const * s = (char const *) string;
  722. while ((c = *s++) != '\0') {
  723. val = val*997 + c;
  724. }
  725. return ((val < 0) ? -val : val)%modulus;
  726. } /* st_strhash */
  727. /**
  728. @brief Integral number hash function.
  729. @sideeffect None
  730. @see st_init_table st_numcmp
  731. */
  732. int
  733. st_numhash(void const *x, int size)
  734. {
  735. return ST_NUMHASH(x, size);
  736. } /* st_numhash */
  737. /**
  738. @brief Pointer hash function.
  739. @sideeffect None
  740. @see st_init_table st_ptrcmp
  741. */
  742. int
  743. st_ptrhash(void const *x, int size)
  744. {
  745. return ST_PTRHASH(x, size);
  746. } /* st_ptrhash */
  747. /**
  748. @brief Integral number comparison function.
  749. @sideeffect None
  750. @see st_init_table st_numhash
  751. */
  752. int
  753. st_numcmp(void const *x, void const *y)
  754. {
  755. return ST_NUMCMP(x, y);
  756. } /* st_numcmp */
  757. /**
  758. @brief Pointer comparison function.
  759. @sideeffect None
  760. @see st_init_table st_ptrhash
  761. */
  762. int
  763. st_ptrcmp(void const *x, void const *y)
  764. {
  765. return ST_NUMCMP(x, y);
  766. } /* st_ptrcmp */
  767. /**
  768. @brief Initializes a generator.
  769. @details Returns a generator handle which when used with
  770. st_gen() will progressively return each (key, value) record in
  771. `table`.
  772. @sideeffect None
  773. @see st_free_gen
  774. */
  775. st_generator *
  776. st_init_gen(st_table const *table)
  777. {
  778. st_generator *gen;
  779. gen = ALLOC(st_generator, 1);
  780. if (gen == NIL(st_generator)) {
  781. return NIL(st_generator);
  782. }
  783. gen->table = table;
  784. gen->entry = NIL(st_table_entry);
  785. gen->index = 0;
  786. return gen;
  787. } /* st_init_gen */
  788. /**
  789. @brief Returns the next (key, value) pair in the generation sequence.
  790. @details@parblock
  791. Given a generator returned by st_init_gen(), this
  792. routine returns the next (key, value) pair in the generation
  793. sequence. The pointer `value_p` can be zero which means no value
  794. will be returned. When there are no more items in the generation
  795. sequence, the routine returns 0.
  796. While using a generation sequence, deleting any (key, value) pair
  797. other than the one just generated may cause a fatal error when
  798. st_gen() is called later in the sequence and is therefore not
  799. recommended.
  800. @endparblock
  801. @sideeffect The locations pointed by key_p and value_p are modified.
  802. @see st_gen_int
  803. */
  804. int
  805. st_gen(st_generator *gen, void **key_p, void **value_p)
  806. {
  807. int i;
  808. if (gen->entry == NIL(st_table_entry)) {
  809. /* try to find next entry */
  810. for(i = gen->index; i < gen->table->num_bins; i++) {
  811. if (gen->table->bins[i] != NIL(st_table_entry)) {
  812. gen->index = i+1;
  813. gen->entry = gen->table->bins[i];
  814. break;
  815. }
  816. }
  817. if (gen->entry == NIL(st_table_entry)) {
  818. return 0; /* that's all folks ! */
  819. }
  820. }
  821. *key_p = gen->entry->key;
  822. if (value_p != NIL(void *)) {
  823. *value_p = gen->entry->record;
  824. }
  825. gen->entry = gen->entry->next;
  826. return 1;
  827. } /* st_gen */
  828. /**
  829. @brief Returns the next (key, value) pair in the generation
  830. sequence.
  831. @details Given a generator returned by st_init_gen(), this
  832. routine returns the next (key, value) pair in the generation
  833. sequence. `value_p` must be a pointer to an integer. The pointer
  834. `value_p` can be zero which means no value will be returned. When
  835. there are no more items in the generation sequence, the routine
  836. returns 0.
  837. @sideeffect The locations pointed by key_p and value_p are modified.
  838. @see st_gen
  839. */
  840. int
  841. st_gen_int(st_generator *gen, void **key_p, int *value_p)
  842. {
  843. int i;
  844. if (gen->entry == NIL(st_table_entry)) {
  845. /* try to find next entry */
  846. for(i = gen->index; i < gen->table->num_bins; i++) {
  847. if (gen->table->bins[i] != NIL(st_table_entry)) {
  848. gen->index = i+1;
  849. gen->entry = gen->table->bins[i];
  850. break;
  851. }
  852. }
  853. if (gen->entry == NIL(st_table_entry)) {
  854. return 0; /* that's all folks ! */
  855. }
  856. }
  857. *key_p = gen->entry->key;
  858. if (value_p != NIL(int)) {
  859. *value_p = (int) (intptr_t) gen->entry->record;
  860. }
  861. gen->entry = gen->entry->next;
  862. return 1;
  863. } /* st_gen_int */
  864. /**
  865. @brief Reclaims the resources associated with `gen`.
  866. @details After generating all items in a generation sequence,
  867. this routine must be called to reclaim the resources associated with
  868. `gen`.
  869. @sideeffect None
  870. @see st_init_gen
  871. */
  872. void
  873. st_free_gen(st_generator *gen)
  874. {
  875. FREE(gen);
  876. } /* st_free_gen */
  877. /*---------------------------------------------------------------------------*/
  878. /* Definition of internal functions */
  879. /*---------------------------------------------------------------------------*/
  880. /*---------------------------------------------------------------------------*/
  881. /* Definition of static functions */
  882. /*---------------------------------------------------------------------------*/
  883. /**
  884. @brief Rehashes a symbol table.
  885. @sideeffect None
  886. @see st_insert
  887. */
  888. static int
  889. rehash(st_table *table)
  890. {
  891. st_table_entry *ptr, *next, **old_bins;
  892. int i, old_num_bins, hash_val, old_num_entries;
  893. /* save old values */
  894. old_bins = table->bins;
  895. old_num_bins = table->num_bins;
  896. old_num_entries = table->num_entries;
  897. /* rehash */
  898. table->num_bins = (int) (table->grow_factor * old_num_bins);
  899. if (table->num_bins % 2 == 0) {
  900. table->num_bins += 1;
  901. }
  902. table->num_entries = 0;
  903. table->bins = ALLOC(st_table_entry *, table->num_bins);
  904. if (table->bins == NIL(st_table_entry *)) {
  905. table->bins = old_bins;
  906. table->num_bins = old_num_bins;
  907. table->num_entries = old_num_entries;
  908. return ST_OUT_OF_MEM;
  909. }
  910. /* initialize */
  911. for (i = 0; i < table->num_bins; i++) {
  912. table->bins[i] = 0;
  913. }
  914. /* copy data over */
  915. for (i = 0; i < old_num_bins; i++) {
  916. ptr = old_bins[i];
  917. while (ptr != NIL(st_table_entry)) {
  918. next = ptr->next;
  919. hash_val = do_hash(ptr->key, table);
  920. ptr->next = table->bins[hash_val];
  921. table->bins[hash_val] = ptr;
  922. table->num_entries++;
  923. ptr = next;
  924. }
  925. }
  926. FREE(old_bins);
  927. return 1;
  928. } /* rehash */