hashtab.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /* Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2004, 2006,
  2. * 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <alloca.h>
  23. #include <stdio.h>
  24. #include <assert.h>
  25. #include "libguile/_scm.h"
  26. #include "libguile/alist.h"
  27. #include "libguile/hash.h"
  28. #include "libguile/eval.h"
  29. #include "libguile/root.h"
  30. #include "libguile/vectors.h"
  31. #include "libguile/ports.h"
  32. #include "libguile/bdw-gc.h"
  33. #include "libguile/validate.h"
  34. #include "libguile/hashtab.h"
  35. /* A hash table is a cell containing a vector of association lists.
  36. *
  37. * Growing or shrinking, with following rehashing, is triggered when
  38. * the load factor
  39. *
  40. * L = N / S (N: number of items in table, S: bucket vector length)
  41. *
  42. * passes an upper limit of 0.9 or a lower limit of 0.25.
  43. *
  44. * The implementation stores the upper and lower number of items which
  45. * trigger a resize in the hashtable object.
  46. *
  47. * Possible hash table sizes (primes) are stored in the array
  48. * hashtable_size.
  49. */
  50. static unsigned long hashtable_size[] = {
  51. 31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363,
  52. 224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041
  53. #if SIZEOF_SCM_T_BITS > 4
  54. /* vector lengths are stored in the first word of vectors, shifted by
  55. 8 bits for the tc8, so for 32-bit we only get 2^24-1 = 16777215
  56. elements. But we allow a few more sizes for 64-bit. */
  57. , 28762081, 57524111, 115048217, 230096423, 460192829
  58. #endif
  59. };
  60. #define HASHTABLE_SIZE_N (sizeof(hashtable_size)/sizeof(unsigned long))
  61. static char *s_hashtable = "hashtable";
  62. static SCM
  63. make_hash_table (unsigned long k, const char *func_name)
  64. {
  65. SCM vector;
  66. scm_t_hashtable *t;
  67. int i = 0, n = k ? k : 31;
  68. while (i + 1 < HASHTABLE_SIZE_N && n > hashtable_size[i])
  69. ++i;
  70. n = hashtable_size[i];
  71. vector = scm_c_make_vector (n, SCM_EOL);
  72. t = scm_gc_malloc_pointerless (sizeof (*t), s_hashtable);
  73. t->min_size_index = t->size_index = i;
  74. t->n_items = 0;
  75. t->lower = 0;
  76. t->upper = 9 * n / 10;
  77. /* FIXME: we just need two words of storage, not three */
  78. return scm_double_cell (scm_tc7_hashtable, SCM_UNPACK (vector),
  79. (scm_t_bits)t, 0);
  80. }
  81. void
  82. scm_i_rehash (SCM table,
  83. scm_t_hash_fn hash_fn,
  84. void *closure,
  85. const char* func_name)
  86. {
  87. SCM buckets, new_buckets;
  88. int i;
  89. unsigned long old_size;
  90. unsigned long new_size;
  91. if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table))
  92. {
  93. /* rehashing is not triggered when i <= min_size */
  94. i = SCM_HASHTABLE (table)->size_index;
  95. do
  96. --i;
  97. while (i > SCM_HASHTABLE (table)->min_size_index
  98. && SCM_HASHTABLE_N_ITEMS (table) < hashtable_size[i] / 4);
  99. }
  100. else
  101. {
  102. i = SCM_HASHTABLE (table)->size_index + 1;
  103. if (i >= HASHTABLE_SIZE_N)
  104. /* don't rehash */
  105. return;
  106. }
  107. SCM_HASHTABLE (table)->size_index = i;
  108. new_size = hashtable_size[i];
  109. if (i <= SCM_HASHTABLE (table)->min_size_index)
  110. SCM_HASHTABLE (table)->lower = 0;
  111. else
  112. SCM_HASHTABLE (table)->lower = new_size / 4;
  113. SCM_HASHTABLE (table)->upper = 9 * new_size / 10;
  114. buckets = SCM_HASHTABLE_VECTOR (table);
  115. new_buckets = scm_c_make_vector (new_size, SCM_EOL);
  116. SCM_SET_HASHTABLE_VECTOR (table, new_buckets);
  117. SCM_SET_HASHTABLE_N_ITEMS (table, 0);
  118. old_size = SCM_SIMPLE_VECTOR_LENGTH (buckets);
  119. for (i = 0; i < old_size; ++i)
  120. {
  121. SCM ls, cell, handle;
  122. ls = SCM_SIMPLE_VECTOR_REF (buckets, i);
  123. SCM_SIMPLE_VECTOR_SET (buckets, i, SCM_EOL);
  124. while (scm_is_pair (ls))
  125. {
  126. unsigned long h;
  127. cell = ls;
  128. handle = SCM_CAR (cell);
  129. ls = SCM_CDR (ls);
  130. h = hash_fn (SCM_CAR (handle), new_size, closure);
  131. if (h >= new_size)
  132. scm_out_of_range (func_name, scm_from_ulong (h));
  133. SCM_SETCDR (cell, SCM_SIMPLE_VECTOR_REF (new_buckets, h));
  134. SCM_SIMPLE_VECTOR_SET (new_buckets, h, cell);
  135. SCM_HASHTABLE_INCREMENT (table);
  136. }
  137. }
  138. }
  139. void
  140. scm_i_hashtable_print (SCM exp, SCM port, scm_print_state *pstate)
  141. {
  142. scm_puts_unlocked ("#<hash-table ", port);
  143. scm_uintprint (SCM_UNPACK (exp), 16, port);
  144. scm_putc (' ', port);
  145. scm_uintprint (SCM_HASHTABLE_N_ITEMS (exp), 10, port);
  146. scm_putc_unlocked ('/', port);
  147. scm_uintprint (SCM_SIMPLE_VECTOR_LENGTH (SCM_HASHTABLE_VECTOR (exp)),
  148. 10, port);
  149. scm_puts_unlocked (">", port);
  150. }
  151. SCM
  152. scm_c_make_hash_table (unsigned long k)
  153. {
  154. return make_hash_table (k, "scm_c_make_hash_table");
  155. }
  156. SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
  157. (SCM n),
  158. "Make a new abstract hash table object with minimum number of buckets @var{n}\n")
  159. #define FUNC_NAME s_scm_make_hash_table
  160. {
  161. return make_hash_table (SCM_UNBNDP (n) ? 0 : scm_to_ulong (n), FUNC_NAME);
  162. }
  163. #undef FUNC_NAME
  164. #define SCM_WEAK_TABLE_P(x) (scm_is_true (scm_weak_table_p (x)))
  165. SCM_DEFINE (scm_hash_table_p, "hash-table?", 1, 0, 0,
  166. (SCM obj),
  167. "Return @code{#t} if @var{obj} is an abstract hash table object.")
  168. #define FUNC_NAME s_scm_hash_table_p
  169. {
  170. return scm_from_bool (SCM_HASHTABLE_P (obj) || SCM_WEAK_TABLE_P (obj));
  171. }
  172. #undef FUNC_NAME
  173. /* Accessing hash table entries. */
  174. SCM
  175. scm_hash_fn_get_handle (SCM table, SCM obj,
  176. scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
  177. void * closure)
  178. #define FUNC_NAME "scm_hash_fn_get_handle"
  179. {
  180. unsigned long k;
  181. SCM buckets, h;
  182. SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
  183. buckets = SCM_HASHTABLE_VECTOR (table);
  184. if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
  185. return SCM_BOOL_F;
  186. k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
  187. if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
  188. scm_out_of_range (FUNC_NAME, scm_from_ulong (k));
  189. h = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
  190. return h;
  191. }
  192. #undef FUNC_NAME
  193. SCM
  194. scm_hash_fn_create_handle_x (SCM table, SCM obj, SCM init,
  195. scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
  196. void * closure)
  197. #define FUNC_NAME "scm_hash_fn_create_handle_x"
  198. {
  199. unsigned long k;
  200. SCM buckets, it;
  201. SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
  202. buckets = SCM_HASHTABLE_VECTOR (table);
  203. if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
  204. SCM_MISC_ERROR ("void hashtable", SCM_EOL);
  205. k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
  206. if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
  207. scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k));
  208. it = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
  209. if (scm_is_pair (it))
  210. return it;
  211. else if (scm_is_true (it))
  212. scm_wrong_type_arg_msg (NULL, 0, it, "a pair");
  213. else
  214. {
  215. SCM handle, new_bucket;
  216. handle = scm_cons (obj, init);
  217. new_bucket = scm_cons (handle, SCM_EOL);
  218. if (!scm_is_eq (SCM_HASHTABLE_VECTOR (table), buckets))
  219. {
  220. buckets = SCM_HASHTABLE_VECTOR (table);
  221. k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
  222. if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
  223. scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k));
  224. }
  225. SCM_SETCDR (new_bucket, SCM_SIMPLE_VECTOR_REF (buckets, k));
  226. SCM_SIMPLE_VECTOR_SET (buckets, k, new_bucket);
  227. SCM_HASHTABLE_INCREMENT (table);
  228. /* Maybe rehash the table. */
  229. if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table)
  230. || SCM_HASHTABLE_N_ITEMS (table) > SCM_HASHTABLE_UPPER (table))
  231. scm_i_rehash (table, hash_fn, closure, FUNC_NAME);
  232. return SCM_CAR (new_bucket);
  233. }
  234. }
  235. #undef FUNC_NAME
  236. SCM
  237. scm_hash_fn_ref (SCM table, SCM obj, SCM dflt,
  238. scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
  239. void *closure)
  240. {
  241. SCM it = scm_hash_fn_get_handle (table, obj, hash_fn, assoc_fn, closure);
  242. if (scm_is_pair (it))
  243. return SCM_CDR (it);
  244. else
  245. return dflt;
  246. }
  247. SCM
  248. scm_hash_fn_set_x (SCM table, SCM obj, SCM val,
  249. scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
  250. void *closure)
  251. {
  252. SCM pair;
  253. pair = scm_hash_fn_create_handle_x (table, obj, val,
  254. hash_fn, assoc_fn, closure);
  255. if (!scm_is_eq (SCM_CDR (pair), val))
  256. SCM_SETCDR (pair, val);
  257. return val;
  258. }
  259. SCM
  260. scm_hash_fn_remove_x (SCM table, SCM obj,
  261. scm_t_hash_fn hash_fn,
  262. scm_t_assoc_fn assoc_fn,
  263. void *closure)
  264. #define FUNC_NAME "hash_fn_remove_x"
  265. {
  266. unsigned long k;
  267. SCM buckets, h;
  268. SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
  269. buckets = SCM_HASHTABLE_VECTOR (table);
  270. if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
  271. return SCM_EOL;
  272. k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
  273. if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
  274. scm_out_of_range (FUNC_NAME, scm_from_ulong (k));
  275. h = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
  276. if (scm_is_true (h))
  277. {
  278. SCM_SIMPLE_VECTOR_SET
  279. (buckets, k, scm_delq_x (h, SCM_SIMPLE_VECTOR_REF (buckets, k)));
  280. SCM_HASHTABLE_DECREMENT (table);
  281. if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table))
  282. scm_i_rehash (table, hash_fn, closure, FUNC_NAME);
  283. }
  284. return h;
  285. }
  286. #undef FUNC_NAME
  287. SCM_DEFINE (scm_hash_clear_x, "hash-clear!", 1, 0, 0,
  288. (SCM table),
  289. "Remove all items from @var{table} (without triggering a resize).")
  290. #define FUNC_NAME s_scm_hash_clear_x
  291. {
  292. if (SCM_WEAK_TABLE_P (table))
  293. {
  294. scm_weak_table_clear_x (table);
  295. return SCM_UNSPECIFIED;
  296. }
  297. SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
  298. scm_vector_fill_x (SCM_HASHTABLE_VECTOR (table), SCM_EOL);
  299. SCM_SET_HASHTABLE_N_ITEMS (table, 0);
  300. return SCM_UNSPECIFIED;
  301. }
  302. #undef FUNC_NAME
  303. SCM_DEFINE (scm_hashq_get_handle, "hashq-get-handle", 2, 0, 0,
  304. (SCM table, SCM key),
  305. "This procedure returns the @code{(key . value)} pair from the\n"
  306. "hash table @var{table}. If @var{table} does not hold an\n"
  307. "associated value for @var{key}, @code{#f} is returned.\n"
  308. "Uses @code{eq?} for equality testing.")
  309. #define FUNC_NAME s_scm_hashq_get_handle
  310. {
  311. return scm_hash_fn_get_handle (table, key,
  312. (scm_t_hash_fn) scm_ihashq,
  313. (scm_t_assoc_fn) scm_sloppy_assq,
  314. 0);
  315. }
  316. #undef FUNC_NAME
  317. SCM_DEFINE (scm_hashq_create_handle_x, "hashq-create-handle!", 3, 0, 0,
  318. (SCM table, SCM key, SCM init),
  319. "This function looks up @var{key} in @var{table} and returns its handle.\n"
  320. "If @var{key} is not already present, a new handle is created which\n"
  321. "associates @var{key} with @var{init}.")
  322. #define FUNC_NAME s_scm_hashq_create_handle_x
  323. {
  324. return scm_hash_fn_create_handle_x (table, key, init,
  325. (scm_t_hash_fn) scm_ihashq,
  326. (scm_t_assoc_fn) scm_sloppy_assq,
  327. 0);
  328. }
  329. #undef FUNC_NAME
  330. SCM_DEFINE (scm_hashq_ref, "hashq-ref", 2, 1, 0,
  331. (SCM table, SCM key, SCM dflt),
  332. "Look up @var{key} in the hash table @var{table}, and return the\n"
  333. "value (if any) associated with it. If @var{key} is not found,\n"
  334. "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
  335. "is supplied). Uses @code{eq?} for equality testing.")
  336. #define FUNC_NAME s_scm_hashq_ref
  337. {
  338. if (SCM_UNBNDP (dflt))
  339. dflt = SCM_BOOL_F;
  340. if (SCM_WEAK_TABLE_P (table))
  341. return scm_weak_table_refq (table, key, dflt);
  342. return scm_hash_fn_ref (table, key, dflt,
  343. (scm_t_hash_fn) scm_ihashq,
  344. (scm_t_assoc_fn) scm_sloppy_assq,
  345. 0);
  346. }
  347. #undef FUNC_NAME
  348. SCM_DEFINE (scm_hashq_set_x, "hashq-set!", 3, 0, 0,
  349. (SCM table, SCM key, SCM val),
  350. "Find the entry in @var{table} associated with @var{key}, and\n"
  351. "store @var{val} there. Uses @code{eq?} for equality testing.")
  352. #define FUNC_NAME s_scm_hashq_set_x
  353. {
  354. if (SCM_WEAK_TABLE_P (table))
  355. {
  356. scm_weak_table_putq_x (table, key, val);
  357. return val;
  358. }
  359. return scm_hash_fn_set_x (table, key, val,
  360. (scm_t_hash_fn) scm_ihashq,
  361. (scm_t_assoc_fn) scm_sloppy_assq,
  362. 0);
  363. }
  364. #undef FUNC_NAME
  365. SCM_DEFINE (scm_hashq_remove_x, "hashq-remove!", 2, 0, 0,
  366. (SCM table, SCM key),
  367. "Remove @var{key} (and any value associated with it) from\n"
  368. "@var{table}. Uses @code{eq?} for equality tests.")
  369. #define FUNC_NAME s_scm_hashq_remove_x
  370. {
  371. if (SCM_WEAK_TABLE_P (table))
  372. {
  373. scm_weak_table_remq_x (table, key);
  374. /* This return value is for historical compatibility with
  375. hash-remove!, which returns either the "handle" corresponding
  376. to the entry, or #f. Since weak tables don't have handles, we
  377. have to return #f. */
  378. return SCM_BOOL_F;
  379. }
  380. return scm_hash_fn_remove_x (table, key,
  381. (scm_t_hash_fn) scm_ihashq,
  382. (scm_t_assoc_fn) scm_sloppy_assq,
  383. 0);
  384. }
  385. #undef FUNC_NAME
  386. SCM_DEFINE (scm_hashv_get_handle, "hashv-get-handle", 2, 0, 0,
  387. (SCM table, SCM key),
  388. "This procedure returns the @code{(key . value)} pair from the\n"
  389. "hash table @var{table}. If @var{table} does not hold an\n"
  390. "associated value for @var{key}, @code{#f} is returned.\n"
  391. "Uses @code{eqv?} for equality testing.")
  392. #define FUNC_NAME s_scm_hashv_get_handle
  393. {
  394. return scm_hash_fn_get_handle (table, key,
  395. (scm_t_hash_fn) scm_ihashv,
  396. (scm_t_assoc_fn) scm_sloppy_assv,
  397. 0);
  398. }
  399. #undef FUNC_NAME
  400. SCM_DEFINE (scm_hashv_create_handle_x, "hashv-create-handle!", 3, 0, 0,
  401. (SCM table, SCM key, SCM init),
  402. "This function looks up @var{key} in @var{table} and returns its handle.\n"
  403. "If @var{key} is not already present, a new handle is created which\n"
  404. "associates @var{key} with @var{init}.")
  405. #define FUNC_NAME s_scm_hashv_create_handle_x
  406. {
  407. return scm_hash_fn_create_handle_x (table, key, init,
  408. (scm_t_hash_fn) scm_ihashv,
  409. (scm_t_assoc_fn) scm_sloppy_assv,
  410. 0);
  411. }
  412. #undef FUNC_NAME
  413. static int
  414. assv_predicate (SCM k, SCM v, void *closure)
  415. {
  416. return scm_is_true (scm_eqv_p (k, SCM_PACK_POINTER (closure)));
  417. }
  418. SCM_DEFINE (scm_hashv_ref, "hashv-ref", 2, 1, 0,
  419. (SCM table, SCM key, SCM dflt),
  420. "Look up @var{key} in the hash table @var{table}, and return the\n"
  421. "value (if any) associated with it. If @var{key} is not found,\n"
  422. "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
  423. "is supplied). Uses @code{eqv?} for equality testing.")
  424. #define FUNC_NAME s_scm_hashv_ref
  425. {
  426. if (SCM_UNBNDP (dflt))
  427. dflt = SCM_BOOL_F;
  428. if (SCM_WEAK_TABLE_P (table))
  429. return scm_c_weak_table_ref (table, scm_ihashv (key, -1),
  430. assv_predicate,
  431. (void *) SCM_UNPACK (key), dflt);
  432. return scm_hash_fn_ref (table, key, dflt,
  433. (scm_t_hash_fn) scm_ihashv,
  434. (scm_t_assoc_fn) scm_sloppy_assv,
  435. 0);
  436. }
  437. #undef FUNC_NAME
  438. SCM_DEFINE (scm_hashv_set_x, "hashv-set!", 3, 0, 0,
  439. (SCM table, SCM key, SCM val),
  440. "Find the entry in @var{table} associated with @var{key}, and\n"
  441. "store @var{value} there. Uses @code{eqv?} for equality testing.")
  442. #define FUNC_NAME s_scm_hashv_set_x
  443. {
  444. if (SCM_WEAK_TABLE_P (table))
  445. {
  446. scm_c_weak_table_put_x (table, scm_ihashv (key, -1),
  447. assv_predicate, (void *) SCM_UNPACK (key),
  448. key, val);
  449. return val;
  450. }
  451. return scm_hash_fn_set_x (table, key, val,
  452. (scm_t_hash_fn) scm_ihashv,
  453. (scm_t_assoc_fn) scm_sloppy_assv,
  454. 0);
  455. }
  456. #undef FUNC_NAME
  457. SCM_DEFINE (scm_hashv_remove_x, "hashv-remove!", 2, 0, 0,
  458. (SCM table, SCM key),
  459. "Remove @var{key} (and any value associated with it) from\n"
  460. "@var{table}. Uses @code{eqv?} for equality tests.")
  461. #define FUNC_NAME s_scm_hashv_remove_x
  462. {
  463. if (SCM_WEAK_TABLE_P (table))
  464. {
  465. scm_c_weak_table_remove_x (table, scm_ihashv (key, -1),
  466. assv_predicate, (void *) SCM_UNPACK (key));
  467. /* See note in hashq-remove!. */
  468. return SCM_BOOL_F;
  469. }
  470. return scm_hash_fn_remove_x (table, key,
  471. (scm_t_hash_fn) scm_ihashv,
  472. (scm_t_assoc_fn) scm_sloppy_assv,
  473. 0);
  474. }
  475. #undef FUNC_NAME
  476. SCM_DEFINE (scm_hash_get_handle, "hash-get-handle", 2, 0, 0,
  477. (SCM table, SCM key),
  478. "This procedure returns the @code{(key . value)} pair from the\n"
  479. "hash table @var{table}. If @var{table} does not hold an\n"
  480. "associated value for @var{key}, @code{#f} is returned.\n"
  481. "Uses @code{equal?} for equality testing.")
  482. #define FUNC_NAME s_scm_hash_get_handle
  483. {
  484. return scm_hash_fn_get_handle (table, key,
  485. (scm_t_hash_fn) scm_ihash,
  486. (scm_t_assoc_fn) scm_sloppy_assoc,
  487. 0);
  488. }
  489. #undef FUNC_NAME
  490. SCM_DEFINE (scm_hash_create_handle_x, "hash-create-handle!", 3, 0, 0,
  491. (SCM table, SCM key, SCM init),
  492. "This function looks up @var{key} in @var{table} and returns its handle.\n"
  493. "If @var{key} is not already present, a new handle is created which\n"
  494. "associates @var{key} with @var{init}.")
  495. #define FUNC_NAME s_scm_hash_create_handle_x
  496. {
  497. return scm_hash_fn_create_handle_x (table, key, init,
  498. (scm_t_hash_fn) scm_ihash,
  499. (scm_t_assoc_fn) scm_sloppy_assoc,
  500. 0);
  501. }
  502. #undef FUNC_NAME
  503. static int
  504. assoc_predicate (SCM k, SCM v, void *closure)
  505. {
  506. return scm_is_true (scm_equal_p (k, SCM_PACK_POINTER (closure)));
  507. }
  508. SCM_DEFINE (scm_hash_ref, "hash-ref", 2, 1, 0,
  509. (SCM table, SCM key, SCM dflt),
  510. "Look up @var{key} in the hash table @var{table}, and return the\n"
  511. "value (if any) associated with it. If @var{key} is not found,\n"
  512. "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
  513. "is supplied). Uses @code{equal?} for equality testing.")
  514. #define FUNC_NAME s_scm_hash_ref
  515. {
  516. if (SCM_UNBNDP (dflt))
  517. dflt = SCM_BOOL_F;
  518. if (SCM_WEAK_TABLE_P (table))
  519. return scm_c_weak_table_ref (table, scm_ihash (key, -1),
  520. assoc_predicate,
  521. (void *) SCM_UNPACK (key), dflt);
  522. return scm_hash_fn_ref (table, key, dflt,
  523. (scm_t_hash_fn) scm_ihash,
  524. (scm_t_assoc_fn) scm_sloppy_assoc,
  525. 0);
  526. }
  527. #undef FUNC_NAME
  528. SCM_DEFINE (scm_hash_set_x, "hash-set!", 3, 0, 0,
  529. (SCM table, SCM key, SCM val),
  530. "Find the entry in @var{table} associated with @var{key}, and\n"
  531. "store @var{val} there. Uses @code{equal?} for equality\n"
  532. "testing.")
  533. #define FUNC_NAME s_scm_hash_set_x
  534. {
  535. if (SCM_WEAK_TABLE_P (table))
  536. {
  537. scm_c_weak_table_put_x (table, scm_ihash (key, -1),
  538. assoc_predicate, (void *) SCM_UNPACK (key),
  539. key, val);
  540. return val;
  541. }
  542. return scm_hash_fn_set_x (table, key, val,
  543. (scm_t_hash_fn) scm_ihash,
  544. (scm_t_assoc_fn) scm_sloppy_assoc,
  545. 0);
  546. }
  547. #undef FUNC_NAME
  548. SCM_DEFINE (scm_hash_remove_x, "hash-remove!", 2, 0, 0,
  549. (SCM table, SCM key),
  550. "Remove @var{key} (and any value associated with it) from\n"
  551. "@var{table}. Uses @code{equal?} for equality tests.")
  552. #define FUNC_NAME s_scm_hash_remove_x
  553. {
  554. if (SCM_WEAK_TABLE_P (table))
  555. {
  556. scm_c_weak_table_remove_x (table, scm_ihash (key, -1),
  557. assoc_predicate, (void *) SCM_UNPACK (key));
  558. /* See note in hashq-remove!. */
  559. return SCM_BOOL_F;
  560. }
  561. return scm_hash_fn_remove_x (table, key,
  562. (scm_t_hash_fn) scm_ihash,
  563. (scm_t_assoc_fn) scm_sloppy_assoc,
  564. 0);
  565. }
  566. #undef FUNC_NAME
  567. typedef struct scm_t_ihashx_closure
  568. {
  569. SCM hash;
  570. SCM assoc;
  571. SCM key;
  572. } scm_t_ihashx_closure;
  573. static unsigned long
  574. scm_ihashx (SCM obj, unsigned long n, void *arg)
  575. {
  576. SCM answer;
  577. scm_t_ihashx_closure *closure = (scm_t_ihashx_closure *) arg;
  578. answer = scm_call_2 (closure->hash, obj, scm_from_ulong (n));
  579. return scm_to_ulong (answer);
  580. }
  581. static SCM
  582. scm_sloppy_assx (SCM obj, SCM alist, void *arg)
  583. {
  584. scm_t_ihashx_closure *closure = (scm_t_ihashx_closure *) arg;
  585. return scm_call_2 (closure->assoc, obj, alist);
  586. }
  587. static int
  588. assx_predicate (SCM k, SCM v, void *closure)
  589. {
  590. scm_t_ihashx_closure *c = (scm_t_ihashx_closure *) closure;
  591. /* FIXME: The hashx interface is crazy. Hash tables have nothing to
  592. do with alists in principle. Instead of getting an assoc proc,
  593. hashx functions should use an equality predicate. Perhaps we can
  594. change this before 2.2, but until then, add a terrible, terrible
  595. hack. */
  596. return scm_is_true (scm_call_2 (c->assoc, c->key, scm_acons (k, v, SCM_EOL)));
  597. }
  598. SCM_DEFINE (scm_hashx_get_handle, "hashx-get-handle", 4, 0, 0,
  599. (SCM hash, SCM assoc, SCM table, SCM key),
  600. "This behaves the same way as the corresponding\n"
  601. "@code{-get-handle} function, but uses @var{hash} as a hash\n"
  602. "function and @var{assoc} to compare keys. @code{hash} must be\n"
  603. "a function that takes two arguments, a key to be hashed and a\n"
  604. "table size. @code{assoc} must be an associator function, like\n"
  605. "@code{assoc}, @code{assq} or @code{assv}.")
  606. #define FUNC_NAME s_scm_hashx_get_handle
  607. {
  608. scm_t_ihashx_closure closure;
  609. closure.hash = hash;
  610. closure.assoc = assoc;
  611. closure.key = key;
  612. return scm_hash_fn_get_handle (table, key, scm_ihashx, scm_sloppy_assx,
  613. (void *) &closure);
  614. }
  615. #undef FUNC_NAME
  616. SCM_DEFINE (scm_hashx_create_handle_x, "hashx-create-handle!", 5, 0, 0,
  617. (SCM hash, SCM assoc, SCM table, SCM key, SCM init),
  618. "This behaves the same way as the corresponding\n"
  619. "@code{-create-handle} function, but uses @var{hash} as a hash\n"
  620. "function and @var{assoc} to compare keys. @code{hash} must be\n"
  621. "a function that takes two arguments, a key to be hashed and a\n"
  622. "table size. @code{assoc} must be an associator function, like\n"
  623. "@code{assoc}, @code{assq} or @code{assv}.")
  624. #define FUNC_NAME s_scm_hashx_create_handle_x
  625. {
  626. scm_t_ihashx_closure closure;
  627. closure.hash = hash;
  628. closure.assoc = assoc;
  629. closure.key = key;
  630. return scm_hash_fn_create_handle_x (table, key, init, scm_ihashx,
  631. scm_sloppy_assx, (void *)&closure);
  632. }
  633. #undef FUNC_NAME
  634. SCM_DEFINE (scm_hashx_ref, "hashx-ref", 4, 1, 0,
  635. (SCM hash, SCM assoc, SCM table, SCM key, SCM dflt),
  636. "This behaves the same way as the corresponding @code{ref}\n"
  637. "function, but uses @var{hash} as a hash function and\n"
  638. "@var{assoc} to compare keys. @code{hash} must be a function\n"
  639. "that takes two arguments, a key to be hashed and a table size.\n"
  640. "@code{assoc} must be an associator function, like @code{assoc},\n"
  641. "@code{assq} or @code{assv}.\n"
  642. "\n"
  643. "By way of illustration, @code{hashq-ref table key} is\n"
  644. "equivalent to @code{hashx-ref hashq assq table key}.")
  645. #define FUNC_NAME s_scm_hashx_ref
  646. {
  647. scm_t_ihashx_closure closure;
  648. if (SCM_UNBNDP (dflt))
  649. dflt = SCM_BOOL_F;
  650. closure.hash = hash;
  651. closure.assoc = assoc;
  652. closure.key = key;
  653. if (SCM_WEAK_TABLE_P (table))
  654. {
  655. unsigned long h = scm_to_ulong (scm_call_2 (hash, key,
  656. scm_from_ulong (-1)));
  657. return scm_c_weak_table_ref (table, h, assx_predicate, &closure, dflt);
  658. }
  659. return scm_hash_fn_ref (table, key, dflt, scm_ihashx, scm_sloppy_assx,
  660. (void *)&closure);
  661. }
  662. #undef FUNC_NAME
  663. SCM_DEFINE (scm_hashx_set_x, "hashx-set!", 5, 0, 0,
  664. (SCM hash, SCM assoc, SCM table, SCM key, SCM val),
  665. "This behaves the same way as the corresponding @code{set!}\n"
  666. "function, but uses @var{hash} as a hash function and\n"
  667. "@var{assoc} to compare keys. @code{hash} must be a function\n"
  668. "that takes two arguments, a key to be hashed and a table size.\n"
  669. "@code{assoc} must be an associator function, like @code{assoc},\n"
  670. "@code{assq} or @code{assv}.\n"
  671. "\n"
  672. " By way of illustration, @code{hashq-set! table key} is\n"
  673. "equivalent to @code{hashx-set! hashq assq table key}.")
  674. #define FUNC_NAME s_scm_hashx_set_x
  675. {
  676. scm_t_ihashx_closure closure;
  677. closure.hash = hash;
  678. closure.assoc = assoc;
  679. closure.key = key;
  680. if (SCM_WEAK_TABLE_P (table))
  681. {
  682. unsigned long h = scm_to_ulong (scm_call_2 (hash, key,
  683. scm_from_ulong (-1)));
  684. scm_c_weak_table_put_x (table, h, assx_predicate, &closure, key, val);
  685. return val;
  686. }
  687. return scm_hash_fn_set_x (table, key, val, scm_ihashx, scm_sloppy_assx,
  688. (void *)&closure);
  689. }
  690. #undef FUNC_NAME
  691. SCM_DEFINE (scm_hashx_remove_x, "hashx-remove!", 4, 0, 0,
  692. (SCM hash, SCM assoc, SCM table, SCM obj),
  693. "This behaves the same way as the corresponding @code{remove!}\n"
  694. "function, but uses @var{hash} as a hash function and\n"
  695. "@var{assoc} to compare keys. @code{hash} must be a function\n"
  696. "that takes two arguments, a key to be hashed and a table size.\n"
  697. "@code{assoc} must be an associator function, like @code{assoc},\n"
  698. "@code{assq} or @code{assv}.\n"
  699. "\n"
  700. " By way of illustration, @code{hashq-remove! table key} is\n"
  701. "equivalent to @code{hashx-remove! hashq assq #f table key}.")
  702. #define FUNC_NAME s_scm_hashx_remove_x
  703. {
  704. scm_t_ihashx_closure closure;
  705. closure.hash = hash;
  706. closure.assoc = assoc;
  707. closure.key = obj;
  708. if (SCM_WEAK_TABLE_P (table))
  709. {
  710. unsigned long h = scm_to_ulong (scm_call_2 (hash, obj,
  711. scm_from_ulong (-1)));
  712. scm_c_weak_table_remove_x (table, h, assx_predicate, &closure);
  713. /* See note in hashq-remove!. */
  714. return SCM_BOOL_F;
  715. }
  716. return scm_hash_fn_remove_x (table, obj, scm_ihashx, scm_sloppy_assx,
  717. (void *) &closure);
  718. }
  719. #undef FUNC_NAME
  720. /* Hash table iterators */
  721. SCM_DEFINE (scm_hash_fold, "hash-fold", 3, 0, 0,
  722. (SCM proc, SCM init, SCM table),
  723. "An iterator over hash-table elements.\n"
  724. "Accumulates and returns a result by applying PROC successively.\n"
  725. "The arguments to PROC are \"(key value prior-result)\" where key\n"
  726. "and value are successive pairs from the hash table TABLE, and\n"
  727. "prior-result is either INIT (for the first application of PROC)\n"
  728. "or the return value of the previous application of PROC.\n"
  729. "For example, @code{(hash-fold acons '() tab)} will convert a hash\n"
  730. "table into an a-list of key-value pairs.")
  731. #define FUNC_NAME s_scm_hash_fold
  732. {
  733. SCM_VALIDATE_PROC (1, proc);
  734. if (SCM_WEAK_TABLE_P (table))
  735. return scm_weak_table_fold (proc, init, table);
  736. SCM_VALIDATE_HASHTABLE (3, table);
  737. return scm_internal_hash_fold ((scm_t_hash_fold_fn) scm_call_3,
  738. (void *) SCM_UNPACK (proc), init, table);
  739. }
  740. #undef FUNC_NAME
  741. static SCM
  742. for_each_proc (void *proc, SCM handle)
  743. {
  744. return scm_call_2 (SCM_PACK (proc), SCM_CAR (handle), SCM_CDR (handle));
  745. }
  746. SCM_DEFINE (scm_hash_for_each, "hash-for-each", 2, 0, 0,
  747. (SCM proc, SCM table),
  748. "An iterator over hash-table elements.\n"
  749. "Applies PROC successively on all hash table items.\n"
  750. "The arguments to PROC are \"(key value)\" where key\n"
  751. "and value are successive pairs from the hash table TABLE.")
  752. #define FUNC_NAME s_scm_hash_for_each
  753. {
  754. SCM_VALIDATE_PROC (1, proc);
  755. if (SCM_WEAK_TABLE_P (table))
  756. {
  757. scm_weak_table_for_each (proc, table);
  758. return SCM_UNSPECIFIED;
  759. }
  760. SCM_VALIDATE_HASHTABLE (2, table);
  761. scm_internal_hash_for_each_handle (for_each_proc,
  762. (void *) SCM_UNPACK (proc),
  763. table);
  764. return SCM_UNSPECIFIED;
  765. }
  766. #undef FUNC_NAME
  767. SCM_DEFINE (scm_hash_for_each_handle, "hash-for-each-handle", 2, 0, 0,
  768. (SCM proc, SCM table),
  769. "An iterator over hash-table elements.\n"
  770. "Applies PROC successively on all hash table handles.")
  771. #define FUNC_NAME s_scm_hash_for_each_handle
  772. {
  773. SCM_ASSERT (scm_is_true (scm_procedure_p (proc)), proc, 1, FUNC_NAME);
  774. SCM_VALIDATE_HASHTABLE (2, table);
  775. scm_internal_hash_for_each_handle ((scm_t_hash_handle_fn) scm_call_1,
  776. (void *) SCM_UNPACK (proc),
  777. table);
  778. return SCM_UNSPECIFIED;
  779. }
  780. #undef FUNC_NAME
  781. static SCM
  782. map_proc (void *proc, SCM key, SCM data, SCM value)
  783. {
  784. return scm_cons (scm_call_2 (SCM_PACK (proc), key, data), value);
  785. }
  786. SCM_DEFINE (scm_hash_map_to_list, "hash-map->list", 2, 0, 0,
  787. (SCM proc, SCM table),
  788. "An iterator over hash-table elements.\n"
  789. "Accumulates and returns as a list the results of applying PROC successively.\n"
  790. "The arguments to PROC are \"(key value)\" where key\n"
  791. "and value are successive pairs from the hash table TABLE.")
  792. #define FUNC_NAME s_scm_hash_map_to_list
  793. {
  794. SCM_VALIDATE_PROC (1, proc);
  795. if (SCM_WEAK_TABLE_P (table))
  796. return scm_weak_table_map_to_list (proc, table);
  797. SCM_VALIDATE_HASHTABLE (2, table);
  798. return scm_internal_hash_fold (map_proc,
  799. (void *) SCM_UNPACK (proc),
  800. SCM_EOL,
  801. table);
  802. }
  803. #undef FUNC_NAME
  804. static SCM
  805. count_proc (void *pred, SCM key, SCM data, SCM value)
  806. {
  807. if (scm_is_false (scm_call_2 (SCM_PACK (pred), key, data)))
  808. return value;
  809. else
  810. return scm_oneplus(value);
  811. }
  812. SCM_DEFINE (scm_hash_count, "hash-count", 2, 0, 0,
  813. (SCM pred, SCM table),
  814. "Return the number of elements in the given hash TABLE that\n"
  815. "cause `(PRED KEY VALUE)' to return true. To quickly determine\n"
  816. "the total number of elements, use `(const #t)' for PRED.")
  817. #define FUNC_NAME s_scm_hash_count
  818. {
  819. SCM init;
  820. SCM_VALIDATE_PROC (1, pred);
  821. SCM_VALIDATE_HASHTABLE (2, table);
  822. init = scm_from_int (0);
  823. return scm_internal_hash_fold ((scm_t_hash_fold_fn) count_proc,
  824. (void *) SCM_UNPACK (pred), init, table);
  825. }
  826. #undef FUNC_NAME
  827. SCM
  828. scm_internal_hash_fold (scm_t_hash_fold_fn fn, void *closure,
  829. SCM init, SCM table)
  830. #define FUNC_NAME s_scm_hash_fold
  831. {
  832. long i, n;
  833. SCM buckets, result = init;
  834. if (SCM_WEAK_TABLE_P (table))
  835. return scm_c_weak_table_fold (fn, closure, init, table);
  836. SCM_VALIDATE_HASHTABLE (0, table);
  837. buckets = SCM_HASHTABLE_VECTOR (table);
  838. n = SCM_SIMPLE_VECTOR_LENGTH (buckets);
  839. for (i = 0; i < n; ++i)
  840. {
  841. SCM ls, handle;
  842. for (ls = SCM_SIMPLE_VECTOR_REF (buckets, i); !scm_is_null (ls);
  843. ls = SCM_CDR (ls))
  844. {
  845. handle = SCM_CAR (ls);
  846. result = fn (closure, SCM_CAR (handle), SCM_CDR (handle), result);
  847. }
  848. }
  849. return result;
  850. }
  851. #undef FUNC_NAME
  852. /* The following redundant code is here in order to be able to support
  853. hash-for-each-handle. An alternative would have been to replace
  854. this code and scm_internal_hash_fold above with a single
  855. scm_internal_hash_fold_handles, but we don't want to promote such
  856. an API. */
  857. void
  858. scm_internal_hash_for_each_handle (scm_t_hash_handle_fn fn, void *closure,
  859. SCM table)
  860. #define FUNC_NAME s_scm_hash_for_each
  861. {
  862. long i, n;
  863. SCM buckets;
  864. SCM_VALIDATE_HASHTABLE (0, table);
  865. buckets = SCM_HASHTABLE_VECTOR (table);
  866. n = SCM_SIMPLE_VECTOR_LENGTH (buckets);
  867. for (i = 0; i < n; ++i)
  868. {
  869. SCM ls = SCM_SIMPLE_VECTOR_REF (buckets, i), handle;
  870. while (!scm_is_null (ls))
  871. {
  872. if (!scm_is_pair (ls))
  873. SCM_WRONG_TYPE_ARG (SCM_ARG3, buckets);
  874. handle = SCM_CAR (ls);
  875. if (!scm_is_pair (handle))
  876. SCM_WRONG_TYPE_ARG (SCM_ARG3, buckets);
  877. fn (closure, handle);
  878. ls = SCM_CDR (ls);
  879. }
  880. }
  881. }
  882. #undef FUNC_NAME
  883. void
  884. scm_init_hashtab ()
  885. {
  886. #include "libguile/hashtab.x"
  887. }
  888. /*
  889. Local Variables:
  890. c-file-style: "gnu"
  891. End:
  892. */