Fix `module-reverse-lookup'.
[bpt/guile.git] / libguile / hashtab.c
1 /* Copyright (C) 1995,1996,1998,1999,2000,2001, 2003, 2004, 2006, 2008, 2009 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19
20 \f
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <assert.h>
27
28 #include "libguile/_scm.h"
29 #include "libguile/alist.h"
30 #include "libguile/hash.h"
31 #include "libguile/eval.h"
32 #include "libguile/root.h"
33 #include "libguile/vectors.h"
34 #include "libguile/ports.h"
35
36 #include "libguile/validate.h"
37 #include "libguile/hashtab.h"
38
39
40 \f
41
42 /* NOTES
43 *
44 * 1. The current hash table implementation uses weak alist vectors
45 * (implementation in weaks.c) internally, but we do the scanning
46 * ourselves (in scan_weak_hashtables) because we need to update the
47 * hash table structure when items are dropped during GC.
48 *
49 * 2. All hash table operations still work on alist vectors.
50 *
51 */
52
53 /* A hash table is a cell containing a vector of association lists.
54 *
55 * Growing or shrinking, with following rehashing, is triggered when
56 * the load factor
57 *
58 * L = N / S (N: number of items in table, S: bucket vector length)
59 *
60 * passes an upper limit of 0.9 or a lower limit of 0.25.
61 *
62 * The implementation stores the upper and lower number of items which
63 * trigger a resize in the hashtable object.
64 *
65 * Possible hash table sizes (primes) are stored in the array
66 * hashtable_size.
67 */
68
69 static unsigned long hashtable_size[] = {
70 31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363,
71 224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041
72 #if 0
73 /* vectors are currently restricted to 2^24-1 = 16777215 elements. */
74 28762081, 57524111, 115048217, 230096423, 460192829
75 /* larger values can't be represented as INUMs */
76 #endif
77 };
78
79 #define HASHTABLE_SIZE_N (sizeof(hashtable_size)/sizeof(unsigned long))
80
81 static char *s_hashtable = "hashtable";
82
83
84 \f
85 /* Helper functions and macros to deal with weak pairs.
86
87 Weak pairs need to be accessed very carefully since their components can
88 be nullified by the GC when the object they refer to becomes unreachable.
89 Hence the macros and functions below that detect such weak pairs within
90 buckets and remove them. */
91
92
93 /* Remove nullified weak pairs from ALIST such that the result contains only
94 valid pairs. Set REMOVED_ITEMS to the number of pairs that have been
95 deleted. */
96 static SCM
97 scm_fixup_weak_alist (SCM alist, size_t *removed_items)
98 {
99 SCM result;
100 SCM prev = SCM_EOL;
101
102 *removed_items = 0;
103 for (result = alist;
104 scm_is_pair (alist);
105 prev = alist, alist = SCM_CDR (alist))
106 {
107 SCM pair = SCM_CAR (alist);
108
109 if (scm_is_pair (pair))
110 {
111 if (SCM_WEAK_PAIR_DELETED_P (pair))
112 {
113 /* Remove from ALIST weak pair PAIR whose car/cdr has been
114 nullified by the GC. */
115 if (prev == SCM_EOL)
116 result = SCM_CDR (alist);
117 else
118 SCM_SETCDR (prev, SCM_CDR (alist));
119
120 (*removed_items)++;
121 continue;
122 }
123 }
124 }
125
126 return result;
127 }
128
129
130 /* Return true if OBJ is either a weak hash table or a weak alist vector (as
131 defined in `weaks.[ch]').
132 FIXME: We should eventually keep only weah hash tables. Actually, the
133 procs in `weaks.c' already no longer return vectors. */
134 /* XXX: We assume that if OBJ is a vector, then it's a _weak_ alist vector. */
135 #define IS_WEAK_THING(_obj) \
136 ((SCM_HASHTABLE_P (table) && (SCM_HASHTABLE_WEAK_P (table))) \
137 || (SCM_I_IS_VECTOR (table)))
138
139
140 /* Packed arguments for `do_weak_bucket_assoc ()'. */
141 struct t_assoc_args
142 {
143 /* Input arguments. */
144 SCM object;
145 SCM buckets;
146 size_t bucket_index;
147 scm_t_assoc_fn assoc_fn;
148 void *closure;
149
150 /* Output arguments. */
151 SCM result;
152 size_t removed_items;
153 };
154
155 static void *
156 do_weak_bucket_assoc (void *data)
157 {
158 struct t_assoc_args *args;
159 size_t removed;
160 SCM bucket, result;
161
162 args = (struct t_assoc_args *) data;
163
164 bucket = SCM_SIMPLE_VECTOR_REF (args->buckets, args->bucket_index);
165 bucket = scm_fixup_weak_alist (bucket, &removed);
166
167 SCM_SIMPLE_VECTOR_SET (args->buckets, args->bucket_index, bucket);
168
169 /* Run ASSOC_FN on the now clean BUCKET. */
170 result = args->assoc_fn (args->object, bucket, args->closure);
171
172 args->result = result;
173 args->removed_items = removed;
174
175 return args;
176 }
177
178 /* Lookup OBJECT in weak hash table TABLE using ASSOC. OBJECT is searched
179 for in the alist that is the BUCKET_INDEXth element of BUCKETS.
180 Optionally update TABLE and rehash it. */
181 static SCM
182 weak_bucket_assoc (SCM table, SCM buckets, size_t bucket_index,
183 scm_t_hash_fn hash_fn,
184 scm_t_assoc_fn assoc, SCM object, void *closure)
185 {
186 SCM result;
187 struct t_assoc_args args;
188
189 args.object = object;
190 args.buckets = buckets;
191 args.bucket_index = bucket_index;
192 args.assoc_fn = assoc;
193 args.closure = closure;
194
195 /* Fixup the bucket and pass the clean bucket to ASSOC. Do that with the
196 allocation lock held to avoid seeing disappearing links pointing to
197 objects that have already been reclaimed (this happens when the
198 disappearing links that point to it haven't yet been cleared.)
199 Thus, ASSOC must not take long, and it must not make any non-local
200 exit. */
201 GC_call_with_alloc_lock (do_weak_bucket_assoc, &args);
202
203 result = args.result;
204 assert (!scm_is_pair (result) ||
205 !SCM_WEAK_PAIR_DELETED_P (GC_is_visible (result)));
206
207 if (args.removed_items > 0 && SCM_HASHTABLE_P (table))
208 {
209 /* Update TABLE's item count and optionally trigger a rehash. */
210 size_t remaining;
211
212 assert (SCM_HASHTABLE_N_ITEMS (table) >= args.removed_items);
213
214 remaining = SCM_HASHTABLE_N_ITEMS (table) - args.removed_items;
215 SCM_SET_HASHTABLE_N_ITEMS (table, remaining);
216
217 scm_i_rehash (table, hash_fn, closure, "weak_bucket_assoc");
218 }
219
220 return result;
221 }
222
223
224 \f
225 static SCM
226 make_hash_table (int flags, unsigned long k, const char *func_name)
227 {
228 SCM vector;
229 scm_t_hashtable *t;
230 int i = 0, n = k ? k : 31;
231 while (i < HASHTABLE_SIZE_N && n > hashtable_size[i])
232 ++i;
233 n = hashtable_size[i];
234
235 /* In both cases, i.e., regardless of whether we are creating a weak hash
236 table, we return a non-weak vector. This is because the vector itself
237 is not weak in the case of a weak hash table: the alist pairs are. */
238 vector = scm_c_make_vector (n, SCM_EOL);
239
240 t = scm_gc_malloc_pointerless (sizeof (*t), s_hashtable);
241 t->min_size_index = t->size_index = i;
242 t->n_items = 0;
243 t->lower = 0;
244 t->upper = 9 * n / 10;
245 t->flags = flags;
246 t->hash_fn = NULL;
247
248 /* FIXME: we just need two words of storage, not three */
249 return scm_double_cell (scm_tc7_hashtable, SCM_UNPACK (vector),
250 (scm_t_bits)t, 0);
251 }
252
253 void
254 scm_i_rehash (SCM table,
255 scm_t_hash_fn hash_fn,
256 void *closure,
257 const char* func_name)
258 {
259 SCM buckets, new_buckets;
260 int i;
261 unsigned long old_size;
262 unsigned long new_size;
263
264 if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table))
265 {
266 /* rehashing is not triggered when i <= min_size */
267 i = SCM_HASHTABLE (table)->size_index;
268 do
269 --i;
270 while (i > SCM_HASHTABLE (table)->min_size_index
271 && SCM_HASHTABLE_N_ITEMS (table) < hashtable_size[i] / 4);
272 }
273 else
274 {
275 i = SCM_HASHTABLE (table)->size_index + 1;
276 if (i >= HASHTABLE_SIZE_N)
277 /* don't rehash */
278 return;
279
280 /* Remember HASH_FN for rehash_after_gc, but only when CLOSURE
281 is not needed since CLOSURE can not be guaranteed to be valid
282 after this function returns.
283 */
284 if (closure == NULL)
285 SCM_HASHTABLE (table)->hash_fn = hash_fn;
286 }
287 SCM_HASHTABLE (table)->size_index = i;
288
289 new_size = hashtable_size[i];
290 if (i <= SCM_HASHTABLE (table)->min_size_index)
291 SCM_HASHTABLE (table)->lower = 0;
292 else
293 SCM_HASHTABLE (table)->lower = new_size / 4;
294 SCM_HASHTABLE (table)->upper = 9 * new_size / 10;
295 buckets = SCM_HASHTABLE_VECTOR (table);
296
297 new_buckets = scm_c_make_vector (new_size, SCM_EOL);
298
299 /* When this is a weak hashtable, running the GC might change it.
300 We need to cope with this while rehashing its elements. We do
301 this by first installing the new, empty bucket vector. Then we
302 remove the elements from the old bucket vector and insert them
303 into the new one.
304 */
305
306 SCM_SET_HASHTABLE_VECTOR (table, new_buckets);
307 SCM_SET_HASHTABLE_N_ITEMS (table, 0);
308
309 old_size = SCM_SIMPLE_VECTOR_LENGTH (buckets);
310 for (i = 0; i < old_size; ++i)
311 {
312 SCM ls, cell, handle;
313
314 ls = SCM_SIMPLE_VECTOR_REF (buckets, i);
315 SCM_SIMPLE_VECTOR_SET (buckets, i, SCM_EOL);
316
317 while (scm_is_pair (ls))
318 {
319 unsigned long h;
320
321 cell = ls;
322 handle = SCM_CAR (cell);
323 ls = SCM_CDR (ls);
324
325 if (SCM_WEAK_PAIR_DELETED_P (handle))
326 /* HANDLE is a nullified weak pair: skip it. */
327 continue;
328
329 h = hash_fn (SCM_CAR (handle), new_size, closure);
330 if (h >= new_size)
331 scm_out_of_range (func_name, scm_from_ulong (h));
332 SCM_SETCDR (cell, SCM_SIMPLE_VECTOR_REF (new_buckets, h));
333 SCM_SIMPLE_VECTOR_SET (new_buckets, h, cell);
334 SCM_HASHTABLE_INCREMENT (table);
335 }
336 }
337 }
338
339
340 void
341 scm_i_hashtable_print (SCM exp, SCM port, scm_print_state *pstate)
342 {
343 scm_puts ("#<", port);
344 if (SCM_HASHTABLE_WEAK_KEY_P (exp))
345 scm_puts ("weak-key-", port);
346 else if (SCM_HASHTABLE_WEAK_VALUE_P (exp))
347 scm_puts ("weak-value-", port);
348 else if (SCM_HASHTABLE_DOUBLY_WEAK_P (exp))
349 scm_puts ("doubly-weak-", port);
350 scm_puts ("hash-table ", port);
351 scm_uintprint (SCM_HASHTABLE_N_ITEMS (exp), 10, port);
352 scm_putc ('/', port);
353 scm_uintprint (SCM_SIMPLE_VECTOR_LENGTH (SCM_HASHTABLE_VECTOR (exp)),
354 10, port);
355 scm_puts (">", port);
356 }
357
358
359 SCM
360 scm_c_make_hash_table (unsigned long k)
361 {
362 return make_hash_table (0, k, "scm_c_make_hash_table");
363 }
364
365 SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
366 (SCM n),
367 "Make a new abstract hash table object with minimum number of buckets @var{n}\n")
368 #define FUNC_NAME s_scm_make_hash_table
369 {
370 if (SCM_UNBNDP (n))
371 return make_hash_table (0, 0, FUNC_NAME);
372 else
373 return make_hash_table (0, scm_to_ulong (n), FUNC_NAME);
374 }
375 #undef FUNC_NAME
376
377 SCM_DEFINE (scm_make_weak_key_hash_table, "make-weak-key-hash-table", 0, 1, 0,
378 (SCM n),
379 "@deffnx {Scheme Procedure} make-weak-value-hash-table size\n"
380 "@deffnx {Scheme Procedure} make-doubly-weak-hash-table size\n"
381 "Return a weak hash table with @var{size} buckets.\n"
382 "\n"
383 "You can modify weak hash tables in exactly the same way you\n"
384 "would modify regular hash tables. (@pxref{Hash Tables})")
385 #define FUNC_NAME s_scm_make_weak_key_hash_table
386 {
387 if (SCM_UNBNDP (n))
388 return make_hash_table (SCM_HASHTABLEF_WEAK_CAR, 0, FUNC_NAME);
389 else
390 return make_hash_table (SCM_HASHTABLEF_WEAK_CAR,
391 scm_to_ulong (n), FUNC_NAME);
392 }
393 #undef FUNC_NAME
394
395
396 SCM_DEFINE (scm_make_weak_value_hash_table, "make-weak-value-hash-table", 0, 1, 0,
397 (SCM n),
398 "Return a hash table with weak values with @var{size} buckets.\n"
399 "(@pxref{Hash Tables})")
400 #define FUNC_NAME s_scm_make_weak_value_hash_table
401 {
402 if (SCM_UNBNDP (n))
403 return make_hash_table (SCM_HASHTABLEF_WEAK_CDR, 0, FUNC_NAME);
404 else
405 {
406 return make_hash_table (SCM_HASHTABLEF_WEAK_CDR,
407 scm_to_ulong (n), FUNC_NAME);
408 }
409 }
410 #undef FUNC_NAME
411
412
413 SCM_DEFINE (scm_make_doubly_weak_hash_table, "make-doubly-weak-hash-table", 1, 0, 0,
414 (SCM n),
415 "Return a hash table with weak keys and values with @var{size}\n"
416 "buckets. (@pxref{Hash Tables})")
417 #define FUNC_NAME s_scm_make_doubly_weak_hash_table
418 {
419 if (SCM_UNBNDP (n))
420 return make_hash_table (SCM_HASHTABLEF_WEAK_CAR | SCM_HASHTABLEF_WEAK_CDR,
421 0,
422 FUNC_NAME);
423 else
424 {
425 return make_hash_table (SCM_HASHTABLEF_WEAK_CAR | SCM_HASHTABLEF_WEAK_CDR,
426 scm_to_ulong (n),
427 FUNC_NAME);
428 }
429 }
430 #undef FUNC_NAME
431
432
433 SCM_DEFINE (scm_hash_table_p, "hash-table?", 1, 0, 0,
434 (SCM obj),
435 "Return @code{#t} if @var{obj} is an abstract hash table object.")
436 #define FUNC_NAME s_scm_hash_table_p
437 {
438 return scm_from_bool (SCM_HASHTABLE_P (obj));
439 }
440 #undef FUNC_NAME
441
442
443 SCM_DEFINE (scm_weak_key_hash_table_p, "weak-key-hash-table?", 1, 0, 0,
444 (SCM obj),
445 "@deffnx {Scheme Procedure} weak-value-hash-table? obj\n"
446 "@deffnx {Scheme Procedure} doubly-weak-hash-table? obj\n"
447 "Return @code{#t} if @var{obj} is the specified weak hash\n"
448 "table. Note that a doubly weak hash table is neither a weak key\n"
449 "nor a weak value hash table.")
450 #define FUNC_NAME s_scm_weak_key_hash_table_p
451 {
452 return scm_from_bool (SCM_HASHTABLE_P (obj) && SCM_HASHTABLE_WEAK_KEY_P (obj));
453 }
454 #undef FUNC_NAME
455
456
457 SCM_DEFINE (scm_weak_value_hash_table_p, "weak-value-hash-table?", 1, 0, 0,
458 (SCM obj),
459 "Return @code{#t} if @var{obj} is a weak value hash table.")
460 #define FUNC_NAME s_scm_weak_value_hash_table_p
461 {
462 return scm_from_bool (SCM_HASHTABLE_P (obj) && SCM_HASHTABLE_WEAK_VALUE_P (obj));
463 }
464 #undef FUNC_NAME
465
466
467 SCM_DEFINE (scm_doubly_weak_hash_table_p, "doubly-weak-hash-table?", 1, 0, 0,
468 (SCM obj),
469 "Return @code{#t} if @var{obj} is a doubly weak hash table.")
470 #define FUNC_NAME s_scm_doubly_weak_hash_table_p
471 {
472 return scm_from_bool (SCM_HASHTABLE_P (obj) && SCM_HASHTABLE_DOUBLY_WEAK_P (obj));
473 }
474 #undef FUNC_NAME
475
476 \f
477 /* Accessing hash table entries. */
478
479 SCM
480 scm_hash_fn_get_handle (SCM table, SCM obj,
481 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
482 void * closure)
483 #define FUNC_NAME "scm_hash_fn_get_handle"
484 {
485 unsigned long k;
486 SCM buckets, h;
487
488 if (SCM_HASHTABLE_P (table))
489 buckets = SCM_HASHTABLE_VECTOR (table);
490 else
491 {
492 SCM_VALIDATE_VECTOR (1, table);
493 buckets = table;
494 }
495
496 if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
497 return SCM_BOOL_F;
498 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
499 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
500 scm_out_of_range ("hash_fn_get_handle", scm_from_ulong (k));
501
502 if (IS_WEAK_THING (table))
503 h = weak_bucket_assoc (table, buckets, k, hash_fn,
504 assoc_fn, obj, closure);
505 else
506 h = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
507
508 return h;
509 }
510 #undef FUNC_NAME
511
512
513 SCM
514 scm_hash_fn_create_handle_x (SCM table, SCM obj, SCM init,
515 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
516 void * closure)
517 #define FUNC_NAME "scm_hash_fn_create_handle_x"
518 {
519 unsigned long k;
520 SCM buckets, it;
521
522 if (SCM_HASHTABLE_P (table))
523 buckets = SCM_HASHTABLE_VECTOR (table);
524 else
525 {
526 SCM_ASSERT (scm_is_simple_vector (table),
527 table, SCM_ARG1, "hash_fn_create_handle_x");
528 buckets = table;
529 }
530 if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
531 SCM_MISC_ERROR ("void hashtable", SCM_EOL);
532
533 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
534 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
535 scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k));
536
537 if (IS_WEAK_THING (table))
538 it = weak_bucket_assoc (table, buckets, k, hash_fn,
539 assoc_fn, obj, closure);
540 else
541 it = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
542
543 if (scm_is_pair (it))
544 return it;
545 else if (scm_is_true (it))
546 scm_wrong_type_arg_msg (NULL, 0, it, "a pair");
547 else
548 {
549 /* When this is a weak hashtable, running the GC can change it.
550 Thus, we must allocate the new cells first and can only then
551 access BUCKETS. Also, we need to fetch the bucket vector
552 again since the hashtable might have been rehashed. This
553 necessitates a new hash value as well.
554 */
555 SCM handle, new_bucket;
556
557 if ((SCM_HASHTABLE_P (table)) && (SCM_HASHTABLE_WEAK_P (table)))
558 {
559 /* FIXME: We don't support weak alist vectors. */
560 /* Use a weak cell. */
561 if (SCM_HASHTABLE_DOUBLY_WEAK_P (table))
562 handle = scm_doubly_weak_pair (obj, init);
563 else if (SCM_HASHTABLE_WEAK_KEY_P (table))
564 handle = scm_weak_car_pair (obj, init);
565 else
566 handle = scm_weak_cdr_pair (obj, init);
567 }
568 else
569 /* Use a regular, non-weak cell. */
570 handle = scm_cons (obj, init);
571
572 new_bucket = scm_cons (handle, SCM_EOL);
573
574 if (!scm_is_eq (table, buckets)
575 && !scm_is_eq (SCM_HASHTABLE_VECTOR (table), buckets))
576 {
577 buckets = SCM_HASHTABLE_VECTOR (table);
578 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
579 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
580 scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k));
581 }
582 SCM_SETCDR (new_bucket, SCM_SIMPLE_VECTOR_REF (buckets, k));
583 SCM_SIMPLE_VECTOR_SET (buckets, k, new_bucket);
584 if (!scm_is_eq (table, buckets))
585 {
586 /* Update element count and maybe rehash the table. The
587 table might have too few entries here since weak hash
588 tables used with the hashx_* functions can not be
589 rehashed after GC.
590 */
591 SCM_HASHTABLE_INCREMENT (table);
592 if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table)
593 || SCM_HASHTABLE_N_ITEMS (table) > SCM_HASHTABLE_UPPER (table))
594 scm_i_rehash (table, hash_fn, closure, FUNC_NAME);
595 }
596 return SCM_CAR (new_bucket);
597 }
598 }
599 #undef FUNC_NAME
600
601
602 SCM
603 scm_hash_fn_ref (SCM table, SCM obj, SCM dflt,
604 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
605 void *closure)
606 {
607 SCM it = scm_hash_fn_get_handle (table, obj, hash_fn, assoc_fn, closure);
608 if (scm_is_pair (it))
609 return SCM_CDR (it);
610 else
611 return dflt;
612 }
613
614
615
616
617 SCM
618 scm_hash_fn_set_x (SCM table, SCM obj, SCM val,
619 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
620 void *closure)
621 {
622 SCM it;
623
624 it = scm_hash_fn_create_handle_x (table, obj, SCM_BOOL_F, hash_fn, assoc_fn, closure);
625 SCM_SETCDR (it, val);
626 return val;
627 }
628
629
630 SCM
631 scm_hash_fn_remove_x (SCM table, SCM obj,
632 scm_t_hash_fn hash_fn,
633 scm_t_assoc_fn assoc_fn,
634 void *closure)
635 {
636 unsigned long k;
637 SCM buckets, h;
638
639 if (SCM_HASHTABLE_P (table))
640 buckets = SCM_HASHTABLE_VECTOR (table);
641 else
642 {
643 SCM_ASSERT (scm_is_simple_vector (table), table,
644 SCM_ARG1, "hash_fn_remove_x");
645 buckets = table;
646 }
647 if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
648 return SCM_EOL;
649
650 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
651 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
652 scm_out_of_range ("hash_fn_remove_x", scm_from_ulong (k));
653
654 if (IS_WEAK_THING (table))
655 h = weak_bucket_assoc (table, buckets, k, hash_fn,
656 assoc_fn, obj, closure);
657 else
658 h = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
659
660 if (scm_is_true (h))
661 {
662 SCM_SIMPLE_VECTOR_SET
663 (buckets, k, scm_delq_x (h, SCM_SIMPLE_VECTOR_REF (buckets, k)));
664 if (!scm_is_eq (table, buckets))
665 {
666 SCM_HASHTABLE_DECREMENT (table);
667 if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table))
668 scm_i_rehash (table, hash_fn, closure, "scm_hash_fn_remove_x");
669 }
670 }
671 return h;
672 }
673
674 SCM_DEFINE (scm_hash_clear_x, "hash-clear!", 1, 0, 0,
675 (SCM table),
676 "Remove all items from @var{table} (without triggering a resize).")
677 #define FUNC_NAME s_scm_hash_clear_x
678 {
679 if (SCM_HASHTABLE_P (table))
680 {
681 scm_vector_fill_x (SCM_HASHTABLE_VECTOR (table), SCM_EOL);
682 SCM_SET_HASHTABLE_N_ITEMS (table, 0);
683 }
684 else
685 scm_vector_fill_x (table, SCM_EOL);
686 return SCM_UNSPECIFIED;
687 }
688 #undef FUNC_NAME
689
690 \f
691
692 SCM_DEFINE (scm_hashq_get_handle, "hashq-get-handle", 2, 0, 0,
693 (SCM table, SCM key),
694 "This procedure returns the @code{(key . value)} pair from the\n"
695 "hash table @var{table}. If @var{table} does not hold an\n"
696 "associated value for @var{key}, @code{#f} is returned.\n"
697 "Uses @code{eq?} for equality testing.")
698 #define FUNC_NAME s_scm_hashq_get_handle
699 {
700 return scm_hash_fn_get_handle (table, key,
701 (scm_t_hash_fn) scm_ihashq,
702 (scm_t_assoc_fn) scm_sloppy_assq,
703 0);
704 }
705 #undef FUNC_NAME
706
707
708 SCM_DEFINE (scm_hashq_create_handle_x, "hashq-create-handle!", 3, 0, 0,
709 (SCM table, SCM key, SCM init),
710 "This function looks up @var{key} in @var{table} and returns its handle.\n"
711 "If @var{key} is not already present, a new handle is created which\n"
712 "associates @var{key} with @var{init}.")
713 #define FUNC_NAME s_scm_hashq_create_handle_x
714 {
715 return scm_hash_fn_create_handle_x (table, key, init,
716 (scm_t_hash_fn) scm_ihashq,
717 (scm_t_assoc_fn) scm_sloppy_assq,
718 0);
719 }
720 #undef FUNC_NAME
721
722
723 SCM_DEFINE (scm_hashq_ref, "hashq-ref", 2, 1, 0,
724 (SCM table, SCM key, SCM dflt),
725 "Look up @var{key} in the hash table @var{table}, and return the\n"
726 "value (if any) associated with it. If @var{key} is not found,\n"
727 "return @var{default} (or @code{#f} if no @var{default} argument\n"
728 "is supplied). Uses @code{eq?} for equality testing.")
729 #define FUNC_NAME s_scm_hashq_ref
730 {
731 if (SCM_UNBNDP (dflt))
732 dflt = SCM_BOOL_F;
733 return scm_hash_fn_ref (table, key, dflt,
734 (scm_t_hash_fn) scm_ihashq,
735 (scm_t_assoc_fn) scm_sloppy_assq,
736 0);
737 }
738 #undef FUNC_NAME
739
740
741
742 SCM_DEFINE (scm_hashq_set_x, "hashq-set!", 3, 0, 0,
743 (SCM table, SCM key, SCM val),
744 "Find the entry in @var{table} associated with @var{key}, and\n"
745 "store @var{value} there. Uses @code{eq?} for equality testing.")
746 #define FUNC_NAME s_scm_hashq_set_x
747 {
748 return scm_hash_fn_set_x (table, key, val,
749 (scm_t_hash_fn) scm_ihashq,
750 (scm_t_assoc_fn) scm_sloppy_assq,
751 0);
752 }
753 #undef FUNC_NAME
754
755
756
757 SCM_DEFINE (scm_hashq_remove_x, "hashq-remove!", 2, 0, 0,
758 (SCM table, SCM key),
759 "Remove @var{key} (and any value associated with it) from\n"
760 "@var{table}. Uses @code{eq?} for equality tests.")
761 #define FUNC_NAME s_scm_hashq_remove_x
762 {
763 return scm_hash_fn_remove_x (table, key,
764 (scm_t_hash_fn) scm_ihashq,
765 (scm_t_assoc_fn) scm_sloppy_assq,
766 0);
767 }
768 #undef FUNC_NAME
769
770
771 \f
772
773 SCM_DEFINE (scm_hashv_get_handle, "hashv-get-handle", 2, 0, 0,
774 (SCM table, SCM key),
775 "This procedure returns the @code{(key . value)} pair from the\n"
776 "hash table @var{table}. If @var{table} does not hold an\n"
777 "associated value for @var{key}, @code{#f} is returned.\n"
778 "Uses @code{eqv?} for equality testing.")
779 #define FUNC_NAME s_scm_hashv_get_handle
780 {
781 return scm_hash_fn_get_handle (table, key,
782 (scm_t_hash_fn) scm_ihashv,
783 (scm_t_assoc_fn) scm_sloppy_assv,
784 0);
785 }
786 #undef FUNC_NAME
787
788
789 SCM_DEFINE (scm_hashv_create_handle_x, "hashv-create-handle!", 3, 0, 0,
790 (SCM table, SCM key, SCM init),
791 "This function looks up @var{key} in @var{table} and returns its handle.\n"
792 "If @var{key} is not already present, a new handle is created which\n"
793 "associates @var{key} with @var{init}.")
794 #define FUNC_NAME s_scm_hashv_create_handle_x
795 {
796 return scm_hash_fn_create_handle_x (table, key, init,
797 (scm_t_hash_fn) scm_ihashv,
798 (scm_t_assoc_fn) scm_sloppy_assv,
799 0);
800 }
801 #undef FUNC_NAME
802
803
804 SCM_DEFINE (scm_hashv_ref, "hashv-ref", 2, 1, 0,
805 (SCM table, SCM key, SCM dflt),
806 "Look up @var{key} in the hash table @var{table}, and return the\n"
807 "value (if any) associated with it. If @var{key} is not found,\n"
808 "return @var{default} (or @code{#f} if no @var{default} argument\n"
809 "is supplied). Uses @code{eqv?} for equality testing.")
810 #define FUNC_NAME s_scm_hashv_ref
811 {
812 if (SCM_UNBNDP (dflt))
813 dflt = SCM_BOOL_F;
814 return scm_hash_fn_ref (table, key, dflt,
815 (scm_t_hash_fn) scm_ihashv,
816 (scm_t_assoc_fn) scm_sloppy_assv,
817 0);
818 }
819 #undef FUNC_NAME
820
821
822
823 SCM_DEFINE (scm_hashv_set_x, "hashv-set!", 3, 0, 0,
824 (SCM table, SCM key, SCM val),
825 "Find the entry in @var{table} associated with @var{key}, and\n"
826 "store @var{value} there. Uses @code{eqv?} for equality testing.")
827 #define FUNC_NAME s_scm_hashv_set_x
828 {
829 return scm_hash_fn_set_x (table, key, val,
830 (scm_t_hash_fn) scm_ihashv,
831 (scm_t_assoc_fn) scm_sloppy_assv,
832 0);
833 }
834 #undef FUNC_NAME
835
836
837 SCM_DEFINE (scm_hashv_remove_x, "hashv-remove!", 2, 0, 0,
838 (SCM table, SCM key),
839 "Remove @var{key} (and any value associated with it) from\n"
840 "@var{table}. Uses @code{eqv?} for equality tests.")
841 #define FUNC_NAME s_scm_hashv_remove_x
842 {
843 return scm_hash_fn_remove_x (table, key,
844 (scm_t_hash_fn) scm_ihashv,
845 (scm_t_assoc_fn) scm_sloppy_assv,
846 0);
847 }
848 #undef FUNC_NAME
849
850 \f
851
852 SCM_DEFINE (scm_hash_get_handle, "hash-get-handle", 2, 0, 0,
853 (SCM table, SCM key),
854 "This procedure returns the @code{(key . value)} pair from the\n"
855 "hash table @var{table}. If @var{table} does not hold an\n"
856 "associated value for @var{key}, @code{#f} is returned.\n"
857 "Uses @code{equal?} for equality testing.")
858 #define FUNC_NAME s_scm_hash_get_handle
859 {
860 return scm_hash_fn_get_handle (table, key,
861 (scm_t_hash_fn) scm_ihash,
862 (scm_t_assoc_fn) scm_sloppy_assoc,
863 0);
864 }
865 #undef FUNC_NAME
866
867
868 SCM_DEFINE (scm_hash_create_handle_x, "hash-create-handle!", 3, 0, 0,
869 (SCM table, SCM key, SCM init),
870 "This function looks up @var{key} in @var{table} and returns its handle.\n"
871 "If @var{key} is not already present, a new handle is created which\n"
872 "associates @var{key} with @var{init}.")
873 #define FUNC_NAME s_scm_hash_create_handle_x
874 {
875 return scm_hash_fn_create_handle_x (table, key, init,
876 (scm_t_hash_fn) scm_ihash,
877 (scm_t_assoc_fn) scm_sloppy_assoc,
878 0);
879 }
880 #undef FUNC_NAME
881
882
883 SCM_DEFINE (scm_hash_ref, "hash-ref", 2, 1, 0,
884 (SCM table, SCM key, SCM dflt),
885 "Look up @var{key} in the hash table @var{table}, and return the\n"
886 "value (if any) associated with it. If @var{key} is not found,\n"
887 "return @var{default} (or @code{#f} if no @var{default} argument\n"
888 "is supplied). Uses @code{equal?} for equality testing.")
889 #define FUNC_NAME s_scm_hash_ref
890 {
891 if (SCM_UNBNDP (dflt))
892 dflt = SCM_BOOL_F;
893 return scm_hash_fn_ref (table, key, dflt,
894 (scm_t_hash_fn) scm_ihash,
895 (scm_t_assoc_fn) scm_sloppy_assoc,
896 0);
897 }
898 #undef FUNC_NAME
899
900
901
902 SCM_DEFINE (scm_hash_set_x, "hash-set!", 3, 0, 0,
903 (SCM table, SCM key, SCM val),
904 "Find the entry in @var{table} associated with @var{key}, and\n"
905 "store @var{value} there. Uses @code{equal?} for equality\n"
906 "testing.")
907 #define FUNC_NAME s_scm_hash_set_x
908 {
909 return scm_hash_fn_set_x (table, key, val,
910 (scm_t_hash_fn) scm_ihash,
911 (scm_t_assoc_fn) scm_sloppy_assoc,
912 0);
913 }
914 #undef FUNC_NAME
915
916
917
918 SCM_DEFINE (scm_hash_remove_x, "hash-remove!", 2, 0, 0,
919 (SCM table, SCM key),
920 "Remove @var{key} (and any value associated with it) from\n"
921 "@var{table}. Uses @code{equal?} for equality tests.")
922 #define FUNC_NAME s_scm_hash_remove_x
923 {
924 return scm_hash_fn_remove_x (table, key,
925 (scm_t_hash_fn) scm_ihash,
926 (scm_t_assoc_fn) scm_sloppy_assoc,
927 0);
928 }
929 #undef FUNC_NAME
930
931 \f
932
933
934 typedef struct scm_t_ihashx_closure
935 {
936 SCM hash;
937 SCM assoc;
938 } scm_t_ihashx_closure;
939
940
941
942 static unsigned long
943 scm_ihashx (SCM obj, unsigned long n, void *arg)
944 {
945 SCM answer;
946 scm_t_ihashx_closure *closure = (scm_t_ihashx_closure *) arg;
947 answer = scm_call_2 (closure->hash, obj, scm_from_ulong (n));
948 return scm_to_ulong (answer);
949 }
950
951
952
953 static SCM
954 scm_sloppy_assx (SCM obj, SCM alist, void *arg)
955 {
956 scm_t_ihashx_closure *closure = (scm_t_ihashx_closure *) arg;
957 return scm_call_2 (closure->assoc, obj, alist);
958 }
959
960
961 SCM_DEFINE (scm_hashx_get_handle, "hashx-get-handle", 4, 0, 0,
962 (SCM hash, SCM assoc, SCM table, SCM key),
963 "This behaves the same way as the corresponding\n"
964 "@code{-get-handle} function, but uses @var{hash} as a hash\n"
965 "function and @var{assoc} to compare keys. @code{hash} must be\n"
966 "a function that takes two arguments, a key to be hashed and a\n"
967 "table size. @code{assoc} must be an associator function, like\n"
968 "@code{assoc}, @code{assq} or @code{assv}.")
969 #define FUNC_NAME s_scm_hashx_get_handle
970 {
971 scm_t_ihashx_closure closure;
972 closure.hash = hash;
973 closure.assoc = assoc;
974 return scm_hash_fn_get_handle (table, key, scm_ihashx, scm_sloppy_assx,
975 (void *) &closure);
976 }
977 #undef FUNC_NAME
978
979
980 SCM_DEFINE (scm_hashx_create_handle_x, "hashx-create-handle!", 5, 0, 0,
981 (SCM hash, SCM assoc, SCM table, SCM key, SCM init),
982 "This behaves the same way as the corresponding\n"
983 "@code{-create-handle} function, but uses @var{hash} as a hash\n"
984 "function and @var{assoc} to compare keys. @code{hash} must be\n"
985 "a function that takes two arguments, a key to be hashed and a\n"
986 "table size. @code{assoc} must be an associator function, like\n"
987 "@code{assoc}, @code{assq} or @code{assv}.")
988 #define FUNC_NAME s_scm_hashx_create_handle_x
989 {
990 scm_t_ihashx_closure closure;
991 closure.hash = hash;
992 closure.assoc = assoc;
993 return scm_hash_fn_create_handle_x (table, key, init, scm_ihashx,
994 scm_sloppy_assx, (void *)&closure);
995 }
996 #undef FUNC_NAME
997
998
999
1000 SCM_DEFINE (scm_hashx_ref, "hashx-ref", 4, 1, 0,
1001 (SCM hash, SCM assoc, SCM table, SCM key, SCM dflt),
1002 "This behaves the same way as the corresponding @code{ref}\n"
1003 "function, but uses @var{hash} as a hash function and\n"
1004 "@var{assoc} to compare keys. @code{hash} must be a function\n"
1005 "that takes two arguments, a key to be hashed and a table size.\n"
1006 "@code{assoc} must be an associator function, like @code{assoc},\n"
1007 "@code{assq} or @code{assv}.\n"
1008 "\n"
1009 "By way of illustration, @code{hashq-ref table key} is\n"
1010 "equivalent to @code{hashx-ref hashq assq table key}.")
1011 #define FUNC_NAME s_scm_hashx_ref
1012 {
1013 scm_t_ihashx_closure closure;
1014 if (SCM_UNBNDP (dflt))
1015 dflt = SCM_BOOL_F;
1016 closure.hash = hash;
1017 closure.assoc = assoc;
1018 return scm_hash_fn_ref (table, key, dflt, scm_ihashx, scm_sloppy_assx,
1019 (void *)&closure);
1020 }
1021 #undef FUNC_NAME
1022
1023
1024
1025
1026 SCM_DEFINE (scm_hashx_set_x, "hashx-set!", 5, 0, 0,
1027 (SCM hash, SCM assoc, SCM table, SCM key, SCM val),
1028 "This behaves the same way as the corresponding @code{set!}\n"
1029 "function, but uses @var{hash} as a hash function and\n"
1030 "@var{assoc} to compare keys. @code{hash} must be a function\n"
1031 "that takes two arguments, a key to be hashed and a table size.\n"
1032 "@code{assoc} must be an associator function, like @code{assoc},\n"
1033 "@code{assq} or @code{assv}.\n"
1034 "\n"
1035 " By way of illustration, @code{hashq-set! table key} is\n"
1036 "equivalent to @code{hashx-set! hashq assq table key}.")
1037 #define FUNC_NAME s_scm_hashx_set_x
1038 {
1039 scm_t_ihashx_closure closure;
1040 closure.hash = hash;
1041 closure.assoc = assoc;
1042 return scm_hash_fn_set_x (table, key, val, scm_ihashx, scm_sloppy_assx,
1043 (void *)&closure);
1044 }
1045 #undef FUNC_NAME
1046
1047 SCM_DEFINE (scm_hashx_remove_x, "hashx-remove!", 4, 0, 0,
1048 (SCM hash, SCM assoc, SCM table, SCM obj),
1049 "This behaves the same way as the corresponding @code{remove!}\n"
1050 "function, but uses @var{hash} as a hash function and\n"
1051 "@var{assoc} to compare keys. @code{hash} must be a function\n"
1052 "that takes two arguments, a key to be hashed and a table size.\n"
1053 "@code{assoc} must be an associator function, like @code{assoc},\n"
1054 "@code{assq} or @code{assv}.\n"
1055 "\n"
1056 " By way of illustration, @code{hashq-remove! table key} is\n"
1057 "equivalent to @code{hashx-remove! hashq assq #f table key}.")
1058 #define FUNC_NAME s_scm_hashx_remove_x
1059 {
1060 scm_t_ihashx_closure closure;
1061 closure.hash = hash;
1062 closure.assoc = assoc;
1063 return scm_hash_fn_remove_x (table, obj, scm_ihashx, scm_sloppy_assx,
1064 (void *) &closure);
1065 }
1066 #undef FUNC_NAME
1067
1068 /* Hash table iterators */
1069
1070 static const char s_scm_hash_fold[];
1071
1072 SCM
1073 scm_internal_hash_fold (scm_t_hash_fold_fn fn, void *closure,
1074 SCM init, SCM table)
1075 {
1076 long i, n;
1077 SCM buckets, result = init;
1078
1079 if (SCM_HASHTABLE_P (table))
1080 buckets = SCM_HASHTABLE_VECTOR (table);
1081 else
1082 /* Weak alist vector. */
1083 buckets = table;
1084
1085 n = SCM_SIMPLE_VECTOR_LENGTH (buckets);
1086 for (i = 0; i < n; ++i)
1087 {
1088 SCM prev, ls;
1089
1090 for (prev = SCM_BOOL_F, ls = SCM_SIMPLE_VECTOR_REF (buckets, i);
1091 !scm_is_null (ls);
1092 prev = ls, ls = SCM_CDR (ls))
1093 {
1094 SCM handle;
1095
1096 if (!scm_is_pair (ls))
1097 scm_wrong_type_arg (s_scm_hash_fold, SCM_ARG3, buckets);
1098
1099 handle = SCM_CAR (ls);
1100 if (!scm_is_pair (handle))
1101 scm_wrong_type_arg (s_scm_hash_fold, SCM_ARG3, buckets);
1102
1103 if (IS_WEAK_THING (table))
1104 {
1105 if (SCM_WEAK_PAIR_DELETED_P (handle))
1106 {
1107 /* We hit a weak pair whose car/cdr has become
1108 unreachable: unlink it from the bucket. */
1109 if (prev != SCM_BOOL_F)
1110 SCM_SETCDR (prev, SCM_CDR (ls));
1111 else
1112 SCM_SIMPLE_VECTOR_SET (buckets, i, SCM_CDR (ls));
1113
1114 if (SCM_HASHTABLE_P (table))
1115 /* Update the item count. */
1116 SCM_HASHTABLE_DECREMENT (table);
1117
1118 continue;
1119 }
1120 }
1121
1122 result = fn (closure, SCM_CAR (handle), SCM_CDR (handle), result);
1123 }
1124 }
1125
1126 return result;
1127 }
1128
1129 /* The following redundant code is here in order to be able to support
1130 hash-for-each-handle. An alternative would have been to replace
1131 this code and scm_internal_hash_fold above with a single
1132 scm_internal_hash_fold_handles, but we don't want to promote such
1133 an API. */
1134
1135 static const char s_scm_hash_for_each[];
1136
1137 void
1138 scm_internal_hash_for_each_handle (scm_t_hash_handle_fn fn, void *closure,
1139 SCM table)
1140 {
1141 long i, n;
1142 SCM buckets;
1143
1144 if (SCM_HASHTABLE_P (table))
1145 buckets = SCM_HASHTABLE_VECTOR (table);
1146 else
1147 buckets = table;
1148
1149 n = SCM_SIMPLE_VECTOR_LENGTH (buckets);
1150 for (i = 0; i < n; ++i)
1151 {
1152 SCM ls = SCM_SIMPLE_VECTOR_REF (buckets, i), handle;
1153 while (!scm_is_null (ls))
1154 {
1155 if (!scm_is_pair (ls))
1156 scm_wrong_type_arg (s_scm_hash_for_each, SCM_ARG3, buckets);
1157 handle = SCM_CAR (ls);
1158 if (!scm_is_pair (handle))
1159 scm_wrong_type_arg (s_scm_hash_for_each, SCM_ARG3, buckets);
1160 fn (closure, handle);
1161 ls = SCM_CDR (ls);
1162 }
1163 }
1164 }
1165
1166 SCM_DEFINE (scm_hash_fold, "hash-fold", 3, 0, 0,
1167 (SCM proc, SCM init, SCM table),
1168 "An iterator over hash-table elements.\n"
1169 "Accumulates and returns a result by applying PROC successively.\n"
1170 "The arguments to PROC are \"(key value prior-result)\" where key\n"
1171 "and value are successive pairs from the hash table TABLE, and\n"
1172 "prior-result is either INIT (for the first application of PROC)\n"
1173 "or the return value of the previous application of PROC.\n"
1174 "For example, @code{(hash-fold acons '() tab)} will convert a hash\n"
1175 "table into an a-list of key-value pairs.")
1176 #define FUNC_NAME s_scm_hash_fold
1177 {
1178 SCM_VALIDATE_PROC (1, proc);
1179 if (!SCM_HASHTABLE_P (table))
1180 SCM_VALIDATE_VECTOR (3, table);
1181 return scm_internal_hash_fold ((scm_t_hash_fold_fn) scm_call_3,
1182 (void *) SCM_UNPACK (proc), init, table);
1183 }
1184 #undef FUNC_NAME
1185
1186 static SCM
1187 for_each_proc (void *proc, SCM handle)
1188 {
1189 return scm_call_2 (SCM_PACK (proc), SCM_CAR (handle), SCM_CDR (handle));
1190 }
1191
1192 SCM_DEFINE (scm_hash_for_each, "hash-for-each", 2, 0, 0,
1193 (SCM proc, SCM table),
1194 "An iterator over hash-table elements.\n"
1195 "Applies PROC successively on all hash table items.\n"
1196 "The arguments to PROC are \"(key value)\" where key\n"
1197 "and value are successive pairs from the hash table TABLE.")
1198 #define FUNC_NAME s_scm_hash_for_each
1199 {
1200 SCM_VALIDATE_PROC (1, proc);
1201 if (!SCM_HASHTABLE_P (table))
1202 SCM_VALIDATE_VECTOR (2, table);
1203
1204 scm_internal_hash_for_each_handle (for_each_proc,
1205 (void *) SCM_UNPACK (proc),
1206 table);
1207 return SCM_UNSPECIFIED;
1208 }
1209 #undef FUNC_NAME
1210
1211 SCM_DEFINE (scm_hash_for_each_handle, "hash-for-each-handle", 2, 0, 0,
1212 (SCM proc, SCM table),
1213 "An iterator over hash-table elements.\n"
1214 "Applies PROC successively on all hash table handles.")
1215 #define FUNC_NAME s_scm_hash_for_each_handle
1216 {
1217 SCM_ASSERT (scm_is_true (scm_procedure_p (proc)), proc, 1, FUNC_NAME);
1218 if (!SCM_HASHTABLE_P (table))
1219 SCM_VALIDATE_VECTOR (2, table);
1220
1221 scm_internal_hash_for_each_handle ((scm_t_hash_handle_fn) scm_call_1,
1222 (void *) SCM_UNPACK (proc),
1223 table);
1224 return SCM_UNSPECIFIED;
1225 }
1226 #undef FUNC_NAME
1227
1228 static SCM
1229 map_proc (void *proc, SCM key, SCM data, SCM value)
1230 {
1231 return scm_cons (scm_call_2 (SCM_PACK (proc), key, data), value);
1232 }
1233
1234 SCM_DEFINE (scm_hash_map_to_list, "hash-map->list", 2, 0, 0,
1235 (SCM proc, SCM table),
1236 "An iterator over hash-table elements.\n"
1237 "Accumulates and returns as a list the results of applying PROC successively.\n"
1238 "The arguments to PROC are \"(key value)\" where key\n"
1239 "and value are successive pairs from the hash table TABLE.")
1240 #define FUNC_NAME s_scm_hash_map_to_list
1241 {
1242 SCM_VALIDATE_PROC (1, proc);
1243 if (!SCM_HASHTABLE_P (table))
1244 SCM_VALIDATE_VECTOR (2, table);
1245 return scm_internal_hash_fold (map_proc,
1246 (void *) SCM_UNPACK (proc),
1247 SCM_EOL,
1248 table);
1249 }
1250 #undef FUNC_NAME
1251
1252 \f
1253
1254
1255 void
1256 scm_init_hashtab ()
1257 {
1258 #include "libguile/hashtab.x"
1259 }
1260
1261 /*
1262 Local Variables:
1263 c-file-style: "gnu"
1264 End:
1265 */