1 /* Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2004, 2006,
2 * 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
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.
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.
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
30 #include "libguile/_scm.h"
31 #include "libguile/alist.h"
32 #include "libguile/hash.h"
33 #include "libguile/eval.h"
34 #include "libguile/root.h"
35 #include "libguile/vectors.h"
36 #include "libguile/ports.h"
37 #include "libguile/bdw-gc.h"
39 #include "libguile/validate.h"
40 #include "libguile/hashtab.h"
45 /* A hash table is a cell containing a vector of association lists.
47 * Growing or shrinking, with following rehashing, is triggered when
50 * L = N / S (N: number of items in table, S: bucket vector length)
52 * passes an upper limit of 0.9 or a lower limit of 0.25.
54 * The implementation stores the upper and lower number of items which
55 * trigger a resize in the hashtable object.
57 * Weak hash tables use weak pairs in the bucket lists rather than
60 * Possible hash table sizes (primes) are stored in the array
64 static unsigned long hashtable_size
[] = {
65 31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363,
66 224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041
67 #if SIZEOF_SCM_T_BITS > 4
68 /* vector lengths are stored in the first word of vectors, shifted by
69 8 bits for the tc8, so for 32-bit we only get 2^24-1 = 16777215
70 elements. But we allow a few more sizes for 64-bit. */
71 , 28762081, 57524111, 115048217, 230096423, 460192829
75 #define HASHTABLE_SIZE_N (sizeof(hashtable_size)/sizeof(unsigned long))
77 static char *s_hashtable
= "hashtable";
81 /* Helper functions and macros to deal with weak pairs.
83 Weak pairs need to be accessed very carefully since their components can
84 be nullified by the GC when the object they refer to becomes unreachable.
85 Hence the macros and functions below that detect such weak pairs within
86 buckets and remove them. */
89 /* Remove nullified weak pairs from ALIST such that the result contains only
90 valid pairs. Set REMOVED_ITEMS to the number of pairs that have been
93 scm_fixup_weak_alist (SCM alist
, size_t *removed_items
)
101 alist
= SCM_CDR (alist
))
103 SCM pair
= SCM_CAR (alist
);
105 if (SCM_WEAK_PAIR_DELETED_P (pair
))
107 /* Remove from ALIST weak pair PAIR whose car/cdr has been
108 nullified by the GC. */
109 if (scm_is_null (prev
))
110 result
= SCM_CDR (alist
);
112 SCM_SETCDR (prev
, SCM_CDR (alist
));
116 /* Leave PREV unchanged. */
126 vacuum_weak_hash_table (SCM table
)
128 SCM buckets
= SCM_HASHTABLE_VECTOR (table
);
129 unsigned long k
= SCM_SIMPLE_VECTOR_LENGTH (buckets
);
130 size_t len
= SCM_HASHTABLE_N_ITEMS (table
);
135 SCM alist
= SCM_SIMPLE_VECTOR_REF (buckets
, k
);
136 alist
= scm_fixup_weak_alist (alist
, &removed
);
137 assert (removed
<= len
);
139 SCM_SIMPLE_VECTOR_SET (buckets
, k
, alist
);
142 SCM_SET_HASHTABLE_N_ITEMS (table
, len
);
146 /* Packed arguments for `do_weak_bucket_fixup'. */
151 size_t removed_items
;
155 do_weak_bucket_fixup (void *data
)
157 struct t_fixup_args
*args
;
160 args
= (struct t_fixup_args
*) data
;
162 args
->bucket
= scm_fixup_weak_alist (args
->bucket
, &args
->removed_items
);
164 for (pair
= args
->bucket
, copy
= args
->bucket_copy
;
166 pair
= SCM_CDR (pair
), copy
+= 2)
168 /* At this point, all weak pairs have been removed. */
169 assert (!SCM_WEAK_PAIR_DELETED_P (SCM_CAR (pair
)));
171 /* Copy the key and value. */
172 copy
[0] = SCM_CAAR (pair
);
173 copy
[1] = SCM_CDAR (pair
);
179 /* Lookup OBJECT in weak hash table TABLE using ASSOC. OBJECT is searched
180 for in the alist that is the BUCKET_INDEXth element of BUCKETS.
181 Optionally update TABLE and rehash it. */
183 weak_bucket_assoc (SCM table
, SCM buckets
, size_t bucket_index
,
184 scm_t_hash_fn hash_fn
,
185 scm_t_assoc_fn assoc
, SCM object
, void *closure
)
188 SCM bucket
, *strong_refs
;
189 struct t_fixup_args args
;
191 bucket
= SCM_SIMPLE_VECTOR_REF (buckets
, bucket_index
);
193 /* Prepare STRONG_REFS as an array large enough to hold all the keys
194 and values in BUCKET. */
195 strong_refs
= alloca (scm_ilength (bucket
) * 2 * sizeof (SCM
));
197 args
.bucket
= bucket
;
198 args
.bucket_copy
= strong_refs
;
200 /* Fixup BUCKET. Do that with the allocation lock held to avoid
201 seeing disappearing links pointing to objects that have already
202 been reclaimed (this happens when the disappearing links that point
203 to it haven't yet been cleared.)
205 The `do_weak_bucket_fixup' call populates STRONG_REFS with a copy
206 of BUCKET's entries after it's been fixed up. Thus, all the
207 entries kept in BUCKET are still reachable when ASSOC sees
209 GC_call_with_alloc_lock (do_weak_bucket_fixup
, &args
);
211 bucket
= args
.bucket
;
212 SCM_SIMPLE_VECTOR_SET (buckets
, bucket_index
, bucket
);
214 result
= assoc (object
, bucket
, closure
);
216 /* If we got a result, it should not have NULL fields. */
217 if (scm_is_pair (result
) && SCM_WEAK_PAIR_DELETED_P (result
))
220 scm_remember_upto_here_1 (strong_refs
);
222 if (args
.removed_items
> 0)
224 /* Update TABLE's item count and optionally trigger a rehash. */
227 assert (SCM_HASHTABLE_N_ITEMS (table
) >= args
.removed_items
);
229 remaining
= SCM_HASHTABLE_N_ITEMS (table
) - args
.removed_items
;
230 SCM_SET_HASHTABLE_N_ITEMS (table
, remaining
);
232 if (remaining
< SCM_HASHTABLE_LOWER (table
))
233 scm_i_rehash (table
, hash_fn
, closure
, "weak_bucket_assoc");
240 /* Packed arguments for `weak_bucket_assoc_by_hash'. */
241 struct assoc_by_hash_data
245 scm_t_hash_predicate_fn predicate
;
249 /* See scm_hash_fn_get_handle_by_hash below. */
251 weak_bucket_assoc_by_hash (void *args
)
253 struct assoc_by_hash_data
*data
= args
;
254 SCM alist
= data
->alist
;
256 for (; scm_is_pair (alist
); alist
= SCM_CDR (alist
))
258 SCM pair
= SCM_CAR (alist
);
260 if (!SCM_WEAK_PAIR_DELETED_P (pair
)
261 && data
->predicate (SCM_CAR (pair
), data
->closure
))
273 make_hash_table (int flags
, unsigned long k
, const char *func_name
)
277 int i
= 0, n
= k
? k
: 31;
278 while (i
+ 1 < HASHTABLE_SIZE_N
&& n
> hashtable_size
[i
])
280 n
= hashtable_size
[i
];
282 /* In both cases, i.e., regardless of whether we are creating a weak hash
283 table, we return a non-weak vector. This is because the vector itself
284 is not weak in the case of a weak hash table: the alist pairs are. */
285 vector
= scm_c_make_vector (n
, SCM_EOL
);
287 t
= scm_gc_malloc_pointerless (sizeof (*t
), s_hashtable
);
288 t
->min_size_index
= t
->size_index
= i
;
291 t
->upper
= 9 * n
/ 10;
295 /* FIXME: we just need two words of storage, not three */
296 return scm_double_cell (scm_tc7_hashtable
, SCM_UNPACK (vector
),
301 scm_i_rehash (SCM table
,
302 scm_t_hash_fn hash_fn
,
304 const char* func_name
)
306 SCM buckets
, new_buckets
;
308 unsigned long old_size
;
309 unsigned long new_size
;
311 if (SCM_HASHTABLE_N_ITEMS (table
) < SCM_HASHTABLE_LOWER (table
))
313 /* rehashing is not triggered when i <= min_size */
314 i
= SCM_HASHTABLE (table
)->size_index
;
317 while (i
> SCM_HASHTABLE (table
)->min_size_index
318 && SCM_HASHTABLE_N_ITEMS (table
) < hashtable_size
[i
] / 4);
322 i
= SCM_HASHTABLE (table
)->size_index
+ 1;
323 if (i
>= HASHTABLE_SIZE_N
)
327 /* Remember HASH_FN for rehash_after_gc, but only when CLOSURE
328 is not needed since CLOSURE can not be guaranteed to be valid
329 after this function returns.
332 SCM_HASHTABLE (table
)->hash_fn
= hash_fn
;
334 SCM_HASHTABLE (table
)->size_index
= i
;
336 new_size
= hashtable_size
[i
];
337 if (i
<= SCM_HASHTABLE (table
)->min_size_index
)
338 SCM_HASHTABLE (table
)->lower
= 0;
340 SCM_HASHTABLE (table
)->lower
= new_size
/ 4;
341 SCM_HASHTABLE (table
)->upper
= 9 * new_size
/ 10;
342 buckets
= SCM_HASHTABLE_VECTOR (table
);
344 new_buckets
= scm_c_make_vector (new_size
, SCM_EOL
);
346 /* When this is a weak hashtable, running the GC might change it.
347 We need to cope with this while rehashing its elements. We do
348 this by first installing the new, empty bucket vector. Then we
349 remove the elements from the old bucket vector and insert them
353 SCM_SET_HASHTABLE_VECTOR (table
, new_buckets
);
354 SCM_SET_HASHTABLE_N_ITEMS (table
, 0);
356 old_size
= SCM_SIMPLE_VECTOR_LENGTH (buckets
);
357 for (i
= 0; i
< old_size
; ++i
)
359 SCM ls
, cell
, handle
;
361 ls
= SCM_SIMPLE_VECTOR_REF (buckets
, i
);
362 SCM_SIMPLE_VECTOR_SET (buckets
, i
, SCM_EOL
);
364 while (scm_is_pair (ls
))
369 handle
= SCM_CAR (cell
);
372 if (SCM_WEAK_PAIR_DELETED_P (handle
))
373 /* HANDLE is a nullified weak pair: skip it. */
376 h
= hash_fn (SCM_CAR (handle
), new_size
, closure
);
378 scm_out_of_range (func_name
, scm_from_ulong (h
));
379 SCM_SETCDR (cell
, SCM_SIMPLE_VECTOR_REF (new_buckets
, h
));
380 SCM_SIMPLE_VECTOR_SET (new_buckets
, h
, cell
);
381 SCM_HASHTABLE_INCREMENT (table
);
388 scm_i_hashtable_print (SCM exp
, SCM port
, scm_print_state
*pstate
)
390 scm_puts ("#<", port
);
391 if (SCM_HASHTABLE_WEAK_KEY_P (exp
))
392 scm_puts ("weak-key-", port
);
393 else if (SCM_HASHTABLE_WEAK_VALUE_P (exp
))
394 scm_puts ("weak-value-", port
);
395 else if (SCM_HASHTABLE_DOUBLY_WEAK_P (exp
))
396 scm_puts ("doubly-weak-", port
);
397 scm_puts ("hash-table ", port
);
398 scm_uintprint (SCM_UNPACK (exp
), 16, port
);
399 scm_putc (' ', port
);
400 scm_uintprint (SCM_HASHTABLE_N_ITEMS (exp
), 10, port
);
401 scm_putc ('/', port
);
402 scm_uintprint (SCM_SIMPLE_VECTOR_LENGTH (SCM_HASHTABLE_VECTOR (exp
)),
404 scm_puts (">", port
);
409 scm_c_make_hash_table (unsigned long k
)
411 return make_hash_table (0, k
, "scm_c_make_hash_table");
414 SCM_DEFINE (scm_make_hash_table
, "make-hash-table", 0, 1, 0,
416 "Make a new abstract hash table object with minimum number of buckets @var{n}\n")
417 #define FUNC_NAME s_scm_make_hash_table
420 return make_hash_table (0, 0, FUNC_NAME
);
422 return make_hash_table (0, scm_to_ulong (n
), FUNC_NAME
);
426 /* The before-gc C hook only runs if GC_set_start_callback is available,
427 so if not, fall back on a finalizer-based implementation. */
429 weak_gc_callback (void **weak
)
432 void (*callback
) (SCM
) = weak
[1];
437 callback (PTR2SCM (val
));
442 #ifdef HAVE_GC_SET_START_CALLBACK
444 weak_gc_hook (void *hook_data
, void *fn_data
, void *data
)
446 if (!weak_gc_callback (fn_data
))
447 scm_c_hook_remove (&scm_before_gc_c_hook
, weak_gc_hook
, fn_data
);
453 weak_gc_finalizer (void *ptr
, void *data
)
455 if (weak_gc_callback (ptr
))
456 GC_REGISTER_FINALIZER_NO_ORDER (ptr
, weak_gc_finalizer
, data
, NULL
, NULL
);
461 scm_c_register_weak_gc_callback (SCM obj
, void (*callback
) (SCM
))
463 void **weak
= GC_MALLOC_ATOMIC (sizeof (void*) * 2);
465 weak
[0] = SCM2PTR (obj
);
466 weak
[1] = (void*)callback
;
467 GC_GENERAL_REGISTER_DISAPPEARING_LINK (weak
, SCM2PTR (obj
));
469 #ifdef HAVE_GC_SET_START_CALLBACK
470 scm_c_hook_add (&scm_before_gc_c_hook
, weak_gc_hook
, weak
, 0);
472 GC_REGISTER_FINALIZER_NO_ORDER (weak
, weak_gc_finalizer
, NULL
, NULL
, NULL
);
476 SCM_DEFINE (scm_make_weak_key_hash_table
, "make-weak-key-hash-table", 0, 1, 0,
478 "@deffnx {Scheme Procedure} make-weak-value-hash-table size\n"
479 "@deffnx {Scheme Procedure} make-doubly-weak-hash-table size\n"
480 "Return a weak hash table with @var{size} buckets.\n"
482 "You can modify weak hash tables in exactly the same way you\n"
483 "would modify regular hash tables. (@pxref{Hash Tables})")
484 #define FUNC_NAME s_scm_make_weak_key_hash_table
489 ret
= make_hash_table (SCM_HASHTABLEF_WEAK_CAR
, 0, FUNC_NAME
);
491 ret
= make_hash_table (SCM_HASHTABLEF_WEAK_CAR
,
492 scm_to_ulong (n
), FUNC_NAME
);
494 scm_c_register_weak_gc_callback (ret
, vacuum_weak_hash_table
);
501 SCM_DEFINE (scm_make_weak_value_hash_table
, "make-weak-value-hash-table", 0, 1, 0,
503 "Return a hash table with weak values with @var{size} buckets.\n"
504 "(@pxref{Hash Tables})")
505 #define FUNC_NAME s_scm_make_weak_value_hash_table
510 ret
= make_hash_table (SCM_HASHTABLEF_WEAK_CDR
, 0, FUNC_NAME
);
512 ret
= make_hash_table (SCM_HASHTABLEF_WEAK_CDR
,
513 scm_to_ulong (n
), FUNC_NAME
);
515 scm_c_register_weak_gc_callback (ret
, vacuum_weak_hash_table
);
522 SCM_DEFINE (scm_make_doubly_weak_hash_table
, "make-doubly-weak-hash-table", 1, 0, 0,
524 "Return a hash table with weak keys and values with @var{size}\n"
525 "buckets. (@pxref{Hash Tables})")
526 #define FUNC_NAME s_scm_make_doubly_weak_hash_table
531 ret
= make_hash_table (SCM_HASHTABLEF_WEAK_CAR
| SCM_HASHTABLEF_WEAK_CDR
,
534 ret
= make_hash_table (SCM_HASHTABLEF_WEAK_CAR
| SCM_HASHTABLEF_WEAK_CDR
,
535 scm_to_ulong (n
), FUNC_NAME
);
537 scm_c_register_weak_gc_callback (ret
, vacuum_weak_hash_table
);
544 SCM_DEFINE (scm_hash_table_p
, "hash-table?", 1, 0, 0,
546 "Return @code{#t} if @var{obj} is an abstract hash table object.")
547 #define FUNC_NAME s_scm_hash_table_p
549 return scm_from_bool (SCM_HASHTABLE_P (obj
));
554 SCM_DEFINE (scm_weak_key_hash_table_p
, "weak-key-hash-table?", 1, 0, 0,
556 "@deffnx {Scheme Procedure} weak-value-hash-table? obj\n"
557 "@deffnx {Scheme Procedure} doubly-weak-hash-table? obj\n"
558 "Return @code{#t} if @var{obj} is the specified weak hash\n"
559 "table. Note that a doubly weak hash table is neither a weak key\n"
560 "nor a weak value hash table.")
561 #define FUNC_NAME s_scm_weak_key_hash_table_p
563 return scm_from_bool (SCM_HASHTABLE_P (obj
) && SCM_HASHTABLE_WEAK_KEY_P (obj
));
568 SCM_DEFINE (scm_weak_value_hash_table_p
, "weak-value-hash-table?", 1, 0, 0,
570 "Return @code{#t} if @var{obj} is a weak value hash table.")
571 #define FUNC_NAME s_scm_weak_value_hash_table_p
573 return scm_from_bool (SCM_HASHTABLE_P (obj
) && SCM_HASHTABLE_WEAK_VALUE_P (obj
));
578 SCM_DEFINE (scm_doubly_weak_hash_table_p
, "doubly-weak-hash-table?", 1, 0, 0,
580 "Return @code{#t} if @var{obj} is a doubly weak hash table.")
581 #define FUNC_NAME s_scm_doubly_weak_hash_table_p
583 return scm_from_bool (SCM_HASHTABLE_P (obj
) && SCM_HASHTABLE_DOUBLY_WEAK_P (obj
));
588 /* Accessing hash table entries. */
591 scm_hash_fn_get_handle (SCM table
, SCM obj
,
592 scm_t_hash_fn hash_fn
, scm_t_assoc_fn assoc_fn
,
594 #define FUNC_NAME "scm_hash_fn_get_handle"
599 SCM_VALIDATE_HASHTABLE (SCM_ARG1
, table
);
600 buckets
= SCM_HASHTABLE_VECTOR (table
);
602 if (SCM_SIMPLE_VECTOR_LENGTH (buckets
) == 0)
604 k
= hash_fn (obj
, SCM_SIMPLE_VECTOR_LENGTH (buckets
), closure
);
605 if (k
>= SCM_SIMPLE_VECTOR_LENGTH (buckets
))
606 scm_out_of_range (FUNC_NAME
, scm_from_ulong (k
));
608 if (SCM_HASHTABLE_WEAK_P (table
))
609 h
= weak_bucket_assoc (table
, buckets
, k
, hash_fn
,
610 assoc_fn
, obj
, closure
);
612 h
= assoc_fn (obj
, SCM_SIMPLE_VECTOR_REF (buckets
, k
), closure
);
619 /* This procedure implements three optimizations, with respect to the
622 1. For weak tables, it's assumed that calling the predicate in the
623 allocation lock is safe. In practice this means that the predicate
624 cannot call arbitrary scheme functions.
626 2. We don't check for overflow / underflow and rehash.
628 3. We don't actually have to allocate a key -- instead we get the
629 hash value directly. This is useful for, for example, looking up
630 strings in the symbol table.
633 scm_hash_fn_get_handle_by_hash (SCM table
, unsigned long raw_hash
,
634 scm_t_hash_predicate_fn predicate_fn
,
636 #define FUNC_NAME "scm_hash_fn_ref_by_hash"
639 SCM buckets
, alist
, h
= SCM_BOOL_F
;
641 SCM_VALIDATE_HASHTABLE (SCM_ARG1
, table
);
642 buckets
= SCM_HASHTABLE_VECTOR (table
);
644 if (SCM_SIMPLE_VECTOR_LENGTH (buckets
) == 0)
647 k
= raw_hash
% SCM_SIMPLE_VECTOR_LENGTH (buckets
);
648 alist
= SCM_SIMPLE_VECTOR_REF (buckets
, k
);
650 if (SCM_HASHTABLE_WEAK_P (table
))
652 struct assoc_by_hash_data args
;
655 args
.ret
= SCM_BOOL_F
;
656 args
.predicate
= predicate_fn
;
657 args
.closure
= closure
;
658 GC_call_with_alloc_lock (weak_bucket_assoc_by_hash
, &args
);
662 for (; scm_is_pair (alist
); alist
= SCM_CDR (alist
))
664 SCM pair
= SCM_CAR (alist
);
665 if (predicate_fn (SCM_CAR (pair
), closure
))
678 scm_hash_fn_create_handle_x (SCM table
, SCM obj
, SCM init
,
679 scm_t_hash_fn hash_fn
, scm_t_assoc_fn assoc_fn
,
681 #define FUNC_NAME "scm_hash_fn_create_handle_x"
686 SCM_VALIDATE_HASHTABLE (SCM_ARG1
, table
);
687 buckets
= SCM_HASHTABLE_VECTOR (table
);
689 if (SCM_SIMPLE_VECTOR_LENGTH (buckets
) == 0)
690 SCM_MISC_ERROR ("void hashtable", SCM_EOL
);
692 k
= hash_fn (obj
, SCM_SIMPLE_VECTOR_LENGTH (buckets
), closure
);
693 if (k
>= SCM_SIMPLE_VECTOR_LENGTH (buckets
))
694 scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k
));
696 if (SCM_HASHTABLE_WEAK_P (table
))
697 it
= weak_bucket_assoc (table
, buckets
, k
, hash_fn
,
698 assoc_fn
, obj
, closure
);
700 it
= assoc_fn (obj
, SCM_SIMPLE_VECTOR_REF (buckets
, k
), closure
);
702 if (scm_is_pair (it
))
704 else if (scm_is_true (it
))
705 scm_wrong_type_arg_msg (NULL
, 0, it
, "a pair");
708 /* When this is a weak hashtable, running the GC can change it.
709 Thus, we must allocate the new cells first and can only then
710 access BUCKETS. Also, we need to fetch the bucket vector
711 again since the hashtable might have been rehashed. This
712 necessitates a new hash value as well.
714 SCM handle
, new_bucket
;
716 if (SCM_HASHTABLE_WEAK_P (table
))
718 /* FIXME: We don't support weak alist vectors. */
719 /* Use a weak cell. */
720 if (SCM_HASHTABLE_DOUBLY_WEAK_P (table
))
721 handle
= scm_doubly_weak_pair (obj
, init
);
722 else if (SCM_HASHTABLE_WEAK_KEY_P (table
))
723 handle
= scm_weak_car_pair (obj
, init
);
725 handle
= scm_weak_cdr_pair (obj
, init
);
728 /* Use a regular, non-weak cell. */
729 handle
= scm_cons (obj
, init
);
731 new_bucket
= scm_cons (handle
, SCM_EOL
);
733 if (!scm_is_eq (SCM_HASHTABLE_VECTOR (table
), buckets
))
735 buckets
= SCM_HASHTABLE_VECTOR (table
);
736 k
= hash_fn (obj
, SCM_SIMPLE_VECTOR_LENGTH (buckets
), closure
);
737 if (k
>= SCM_SIMPLE_VECTOR_LENGTH (buckets
))
738 scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k
));
740 SCM_SETCDR (new_bucket
, SCM_SIMPLE_VECTOR_REF (buckets
, k
));
741 SCM_SIMPLE_VECTOR_SET (buckets
, k
, new_bucket
);
742 SCM_HASHTABLE_INCREMENT (table
);
744 /* Maybe rehash the table. */
745 if (SCM_HASHTABLE_N_ITEMS (table
) < SCM_HASHTABLE_LOWER (table
)
746 || SCM_HASHTABLE_N_ITEMS (table
) > SCM_HASHTABLE_UPPER (table
))
747 scm_i_rehash (table
, hash_fn
, closure
, FUNC_NAME
);
748 return SCM_CAR (new_bucket
);
755 scm_hash_fn_ref (SCM table
, SCM obj
, SCM dflt
,
756 scm_t_hash_fn hash_fn
, scm_t_assoc_fn assoc_fn
,
759 SCM it
= scm_hash_fn_get_handle (table
, obj
, hash_fn
, assoc_fn
, closure
);
760 if (scm_is_pair (it
))
773 get_weak_cdr (void *data
)
775 struct weak_cdr_data
*d
= data
;
777 if (SCM_WEAK_PAIR_CDR_DELETED_P (d
->pair
))
780 d
->cdr
= SCM_CDR (d
->pair
);
786 weak_pair_cdr (SCM x
)
788 struct weak_cdr_data data
;
791 GC_call_with_alloc_lock (get_weak_cdr
, &data
);
797 scm_hash_fn_set_x (SCM table
, SCM obj
, SCM val
,
798 scm_t_hash_fn hash_fn
, scm_t_assoc_fn assoc_fn
,
803 pair
= scm_hash_fn_create_handle_x (table
, obj
, val
,
804 hash_fn
, assoc_fn
, closure
);
806 if (!scm_is_eq (SCM_CDR (pair
), val
))
808 if (SCM_UNLIKELY (SCM_HASHTABLE_WEAK_VALUE_P (table
)))
810 /* If the former value was on the heap, we need to unregister
812 SCM prev
= weak_pair_cdr (pair
);
814 SCM_SETCDR (pair
, val
);
816 if (SCM_NIMP (prev
) && !SCM_NIMP (val
))
817 GC_unregister_disappearing_link ((GC_PTR
) SCM_CDRLOC (pair
));
819 SCM_I_REGISTER_DISAPPEARING_LINK ((GC_PTR
) SCM_CDRLOC (pair
),
820 (GC_PTR
) SCM2PTR (val
));
823 SCM_SETCDR (pair
, val
);
831 scm_hash_fn_remove_x (SCM table
, SCM obj
,
832 scm_t_hash_fn hash_fn
,
833 scm_t_assoc_fn assoc_fn
,
835 #define FUNC_NAME "hash_fn_remove_x"
840 SCM_VALIDATE_HASHTABLE (SCM_ARG1
, table
);
842 buckets
= SCM_HASHTABLE_VECTOR (table
);
844 if (SCM_SIMPLE_VECTOR_LENGTH (buckets
) == 0)
847 k
= hash_fn (obj
, SCM_SIMPLE_VECTOR_LENGTH (buckets
), closure
);
848 if (k
>= SCM_SIMPLE_VECTOR_LENGTH (buckets
))
849 scm_out_of_range (FUNC_NAME
, scm_from_ulong (k
));
851 if (SCM_HASHTABLE_WEAK_P (table
))
852 h
= weak_bucket_assoc (table
, buckets
, k
, hash_fn
,
853 assoc_fn
, obj
, closure
);
855 h
= assoc_fn (obj
, SCM_SIMPLE_VECTOR_REF (buckets
, k
), closure
);
859 SCM_SIMPLE_VECTOR_SET
860 (buckets
, k
, scm_delq_x (h
, SCM_SIMPLE_VECTOR_REF (buckets
, k
)));
861 SCM_HASHTABLE_DECREMENT (table
);
862 if (SCM_HASHTABLE_N_ITEMS (table
) < SCM_HASHTABLE_LOWER (table
))
863 scm_i_rehash (table
, hash_fn
, closure
, FUNC_NAME
);
869 SCM_DEFINE (scm_hash_clear_x
, "hash-clear!", 1, 0, 0,
871 "Remove all items from @var{table} (without triggering a resize).")
872 #define FUNC_NAME s_scm_hash_clear_x
874 SCM_VALIDATE_HASHTABLE (SCM_ARG1
, table
);
876 scm_vector_fill_x (SCM_HASHTABLE_VECTOR (table
), SCM_EOL
);
877 SCM_SET_HASHTABLE_N_ITEMS (table
, 0);
879 return SCM_UNSPECIFIED
;
885 SCM_DEFINE (scm_hashq_get_handle
, "hashq-get-handle", 2, 0, 0,
886 (SCM table
, SCM key
),
887 "This procedure returns the @code{(key . value)} pair from the\n"
888 "hash table @var{table}. If @var{table} does not hold an\n"
889 "associated value for @var{key}, @code{#f} is returned.\n"
890 "Uses @code{eq?} for equality testing.")
891 #define FUNC_NAME s_scm_hashq_get_handle
893 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
894 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
896 return scm_hash_fn_get_handle (table
, key
,
897 (scm_t_hash_fn
) scm_ihashq
,
898 (scm_t_assoc_fn
) scm_sloppy_assq
,
904 SCM_DEFINE (scm_hashq_create_handle_x
, "hashq-create-handle!", 3, 0, 0,
905 (SCM table
, SCM key
, SCM init
),
906 "This function looks up @var{key} in @var{table} and returns its handle.\n"
907 "If @var{key} is not already present, a new handle is created which\n"
908 "associates @var{key} with @var{init}.")
909 #define FUNC_NAME s_scm_hashq_create_handle_x
911 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
912 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
914 return scm_hash_fn_create_handle_x (table
, key
, init
,
915 (scm_t_hash_fn
) scm_ihashq
,
916 (scm_t_assoc_fn
) scm_sloppy_assq
,
922 SCM_DEFINE (scm_hashq_ref
, "hashq-ref", 2, 1, 0,
923 (SCM table
, SCM key
, SCM dflt
),
924 "Look up @var{key} in the hash table @var{table}, and return the\n"
925 "value (if any) associated with it. If @var{key} is not found,\n"
926 "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
927 "is supplied). Uses @code{eq?} for equality testing.")
928 #define FUNC_NAME s_scm_hashq_ref
930 if (SCM_UNBNDP (dflt
))
932 return scm_hash_fn_ref (table
, key
, dflt
,
933 (scm_t_hash_fn
) scm_ihashq
,
934 (scm_t_assoc_fn
) scm_sloppy_assq
,
941 SCM_DEFINE (scm_hashq_set_x
, "hashq-set!", 3, 0, 0,
942 (SCM table
, SCM key
, SCM val
),
943 "Find the entry in @var{table} associated with @var{key}, and\n"
944 "store @var{val} there. Uses @code{eq?} for equality testing.")
945 #define FUNC_NAME s_scm_hashq_set_x
947 return scm_hash_fn_set_x (table
, key
, val
,
948 (scm_t_hash_fn
) scm_ihashq
,
949 (scm_t_assoc_fn
) scm_sloppy_assq
,
956 SCM_DEFINE (scm_hashq_remove_x
, "hashq-remove!", 2, 0, 0,
957 (SCM table
, SCM key
),
958 "Remove @var{key} (and any value associated with it) from\n"
959 "@var{table}. Uses @code{eq?} for equality tests.")
960 #define FUNC_NAME s_scm_hashq_remove_x
962 return scm_hash_fn_remove_x (table
, key
,
963 (scm_t_hash_fn
) scm_ihashq
,
964 (scm_t_assoc_fn
) scm_sloppy_assq
,
972 SCM_DEFINE (scm_hashv_get_handle
, "hashv-get-handle", 2, 0, 0,
973 (SCM table
, SCM key
),
974 "This procedure returns the @code{(key . value)} pair from the\n"
975 "hash table @var{table}. If @var{table} does not hold an\n"
976 "associated value for @var{key}, @code{#f} is returned.\n"
977 "Uses @code{eqv?} for equality testing.")
978 #define FUNC_NAME s_scm_hashv_get_handle
980 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
981 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
983 return scm_hash_fn_get_handle (table
, key
,
984 (scm_t_hash_fn
) scm_ihashv
,
985 (scm_t_assoc_fn
) scm_sloppy_assv
,
991 SCM_DEFINE (scm_hashv_create_handle_x
, "hashv-create-handle!", 3, 0, 0,
992 (SCM table
, SCM key
, SCM init
),
993 "This function looks up @var{key} in @var{table} and returns its handle.\n"
994 "If @var{key} is not already present, a new handle is created which\n"
995 "associates @var{key} with @var{init}.")
996 #define FUNC_NAME s_scm_hashv_create_handle_x
998 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
999 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
1001 return scm_hash_fn_create_handle_x (table
, key
, init
,
1002 (scm_t_hash_fn
) scm_ihashv
,
1003 (scm_t_assoc_fn
) scm_sloppy_assv
,
1009 SCM_DEFINE (scm_hashv_ref
, "hashv-ref", 2, 1, 0,
1010 (SCM table
, SCM key
, SCM dflt
),
1011 "Look up @var{key} in the hash table @var{table}, and return the\n"
1012 "value (if any) associated with it. If @var{key} is not found,\n"
1013 "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
1014 "is supplied). Uses @code{eqv?} for equality testing.")
1015 #define FUNC_NAME s_scm_hashv_ref
1017 if (SCM_UNBNDP (dflt
))
1019 return scm_hash_fn_ref (table
, key
, dflt
,
1020 (scm_t_hash_fn
) scm_ihashv
,
1021 (scm_t_assoc_fn
) scm_sloppy_assv
,
1028 SCM_DEFINE (scm_hashv_set_x
, "hashv-set!", 3, 0, 0,
1029 (SCM table
, SCM key
, SCM val
),
1030 "Find the entry in @var{table} associated with @var{key}, and\n"
1031 "store @var{value} there. Uses @code{eqv?} for equality testing.")
1032 #define FUNC_NAME s_scm_hashv_set_x
1034 return scm_hash_fn_set_x (table
, key
, val
,
1035 (scm_t_hash_fn
) scm_ihashv
,
1036 (scm_t_assoc_fn
) scm_sloppy_assv
,
1042 SCM_DEFINE (scm_hashv_remove_x
, "hashv-remove!", 2, 0, 0,
1043 (SCM table
, SCM key
),
1044 "Remove @var{key} (and any value associated with it) from\n"
1045 "@var{table}. Uses @code{eqv?} for equality tests.")
1046 #define FUNC_NAME s_scm_hashv_remove_x
1048 return scm_hash_fn_remove_x (table
, key
,
1049 (scm_t_hash_fn
) scm_ihashv
,
1050 (scm_t_assoc_fn
) scm_sloppy_assv
,
1057 SCM_DEFINE (scm_hash_get_handle
, "hash-get-handle", 2, 0, 0,
1058 (SCM table
, SCM key
),
1059 "This procedure returns the @code{(key . value)} pair from the\n"
1060 "hash table @var{table}. If @var{table} does not hold an\n"
1061 "associated value for @var{key}, @code{#f} is returned.\n"
1062 "Uses @code{equal?} for equality testing.")
1063 #define FUNC_NAME s_scm_hash_get_handle
1065 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
1066 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
1068 return scm_hash_fn_get_handle (table
, key
,
1069 (scm_t_hash_fn
) scm_ihash
,
1070 (scm_t_assoc_fn
) scm_sloppy_assoc
,
1076 SCM_DEFINE (scm_hash_create_handle_x
, "hash-create-handle!", 3, 0, 0,
1077 (SCM table
, SCM key
, SCM init
),
1078 "This function looks up @var{key} in @var{table} and returns its handle.\n"
1079 "If @var{key} is not already present, a new handle is created which\n"
1080 "associates @var{key} with @var{init}.")
1081 #define FUNC_NAME s_scm_hash_create_handle_x
1083 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
1084 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
1086 return scm_hash_fn_create_handle_x (table
, key
, init
,
1087 (scm_t_hash_fn
) scm_ihash
,
1088 (scm_t_assoc_fn
) scm_sloppy_assoc
,
1094 SCM_DEFINE (scm_hash_ref
, "hash-ref", 2, 1, 0,
1095 (SCM table
, SCM key
, SCM dflt
),
1096 "Look up @var{key} in the hash table @var{table}, and return the\n"
1097 "value (if any) associated with it. If @var{key} is not found,\n"
1098 "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
1099 "is supplied). Uses @code{equal?} for equality testing.")
1100 #define FUNC_NAME s_scm_hash_ref
1102 if (SCM_UNBNDP (dflt
))
1104 return scm_hash_fn_ref (table
, key
, dflt
,
1105 (scm_t_hash_fn
) scm_ihash
,
1106 (scm_t_assoc_fn
) scm_sloppy_assoc
,
1113 SCM_DEFINE (scm_hash_set_x
, "hash-set!", 3, 0, 0,
1114 (SCM table
, SCM key
, SCM val
),
1115 "Find the entry in @var{table} associated with @var{key}, and\n"
1116 "store @var{val} there. Uses @code{equal?} for equality\n"
1118 #define FUNC_NAME s_scm_hash_set_x
1120 return scm_hash_fn_set_x (table
, key
, val
,
1121 (scm_t_hash_fn
) scm_ihash
,
1122 (scm_t_assoc_fn
) scm_sloppy_assoc
,
1129 SCM_DEFINE (scm_hash_remove_x
, "hash-remove!", 2, 0, 0,
1130 (SCM table
, SCM key
),
1131 "Remove @var{key} (and any value associated with it) from\n"
1132 "@var{table}. Uses @code{equal?} for equality tests.")
1133 #define FUNC_NAME s_scm_hash_remove_x
1135 return scm_hash_fn_remove_x (table
, key
,
1136 (scm_t_hash_fn
) scm_ihash
,
1137 (scm_t_assoc_fn
) scm_sloppy_assoc
,
1145 typedef struct scm_t_ihashx_closure
1149 } scm_t_ihashx_closure
;
1153 static unsigned long
1154 scm_ihashx (SCM obj
, unsigned long n
, void *arg
)
1157 scm_t_ihashx_closure
*closure
= (scm_t_ihashx_closure
*) arg
;
1158 answer
= scm_call_2 (closure
->hash
, obj
, scm_from_ulong (n
));
1159 return scm_to_ulong (answer
);
1165 scm_sloppy_assx (SCM obj
, SCM alist
, void *arg
)
1167 scm_t_ihashx_closure
*closure
= (scm_t_ihashx_closure
*) arg
;
1168 return scm_call_2 (closure
->assoc
, obj
, alist
);
1172 SCM_DEFINE (scm_hashx_get_handle
, "hashx-get-handle", 4, 0, 0,
1173 (SCM hash
, SCM assoc
, SCM table
, SCM key
),
1174 "This behaves the same way as the corresponding\n"
1175 "@code{-get-handle} function, but uses @var{hash} as a hash\n"
1176 "function and @var{assoc} to compare keys. @code{hash} must be\n"
1177 "a function that takes two arguments, a key to be hashed and a\n"
1178 "table size. @code{assoc} must be an associator function, like\n"
1179 "@code{assoc}, @code{assq} or @code{assv}.")
1180 #define FUNC_NAME s_scm_hashx_get_handle
1182 scm_t_ihashx_closure closure
;
1183 closure
.hash
= hash
;
1184 closure
.assoc
= assoc
;
1186 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
1187 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
1189 return scm_hash_fn_get_handle (table
, key
, scm_ihashx
, scm_sloppy_assx
,
1195 SCM_DEFINE (scm_hashx_create_handle_x
, "hashx-create-handle!", 5, 0, 0,
1196 (SCM hash
, SCM assoc
, SCM table
, SCM key
, SCM init
),
1197 "This behaves the same way as the corresponding\n"
1198 "@code{-create-handle} function, but uses @var{hash} as a hash\n"
1199 "function and @var{assoc} to compare keys. @code{hash} must be\n"
1200 "a function that takes two arguments, a key to be hashed and a\n"
1201 "table size. @code{assoc} must be an associator function, like\n"
1202 "@code{assoc}, @code{assq} or @code{assv}.")
1203 #define FUNC_NAME s_scm_hashx_create_handle_x
1205 scm_t_ihashx_closure closure
;
1206 closure
.hash
= hash
;
1207 closure
.assoc
= assoc
;
1209 if (SCM_UNLIKELY (SCM_HASHTABLE_P (table
) && SCM_HASHTABLE_WEAK_P (table
)))
1210 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
1212 return scm_hash_fn_create_handle_x (table
, key
, init
, scm_ihashx
,
1213 scm_sloppy_assx
, (void *)&closure
);
1219 SCM_DEFINE (scm_hashx_ref
, "hashx-ref", 4, 1, 0,
1220 (SCM hash
, SCM assoc
, SCM table
, SCM key
, SCM dflt
),
1221 "This behaves the same way as the corresponding @code{ref}\n"
1222 "function, but uses @var{hash} as a hash function and\n"
1223 "@var{assoc} to compare keys. @code{hash} must be a function\n"
1224 "that takes two arguments, a key to be hashed and a table size.\n"
1225 "@code{assoc} must be an associator function, like @code{assoc},\n"
1226 "@code{assq} or @code{assv}.\n"
1228 "By way of illustration, @code{hashq-ref table key} is\n"
1229 "equivalent to @code{hashx-ref hashq assq table key}.")
1230 #define FUNC_NAME s_scm_hashx_ref
1232 scm_t_ihashx_closure closure
;
1233 if (SCM_UNBNDP (dflt
))
1235 closure
.hash
= hash
;
1236 closure
.assoc
= assoc
;
1237 return scm_hash_fn_ref (table
, key
, dflt
, scm_ihashx
, scm_sloppy_assx
,
1245 SCM_DEFINE (scm_hashx_set_x
, "hashx-set!", 5, 0, 0,
1246 (SCM hash
, SCM assoc
, SCM table
, SCM key
, SCM val
),
1247 "This behaves the same way as the corresponding @code{set!}\n"
1248 "function, but uses @var{hash} as a hash function and\n"
1249 "@var{assoc} to compare keys. @code{hash} must be a function\n"
1250 "that takes two arguments, a key to be hashed and a table size.\n"
1251 "@code{assoc} must be an associator function, like @code{assoc},\n"
1252 "@code{assq} or @code{assv}.\n"
1254 " By way of illustration, @code{hashq-set! table key} is\n"
1255 "equivalent to @code{hashx-set! hashq assq table key}.")
1256 #define FUNC_NAME s_scm_hashx_set_x
1258 scm_t_ihashx_closure closure
;
1259 closure
.hash
= hash
;
1260 closure
.assoc
= assoc
;
1261 return scm_hash_fn_set_x (table
, key
, val
, scm_ihashx
, scm_sloppy_assx
,
1266 SCM_DEFINE (scm_hashx_remove_x
, "hashx-remove!", 4, 0, 0,
1267 (SCM hash
, SCM assoc
, SCM table
, SCM obj
),
1268 "This behaves the same way as the corresponding @code{remove!}\n"
1269 "function, but uses @var{hash} as a hash function and\n"
1270 "@var{assoc} to compare keys. @code{hash} must be a function\n"
1271 "that takes two arguments, a key to be hashed and a table size.\n"
1272 "@code{assoc} must be an associator function, like @code{assoc},\n"
1273 "@code{assq} or @code{assv}.\n"
1275 " By way of illustration, @code{hashq-remove! table key} is\n"
1276 "equivalent to @code{hashx-remove! hashq assq #f table key}.")
1277 #define FUNC_NAME s_scm_hashx_remove_x
1279 scm_t_ihashx_closure closure
;
1280 closure
.hash
= hash
;
1281 closure
.assoc
= assoc
;
1282 return scm_hash_fn_remove_x (table
, obj
, scm_ihashx
, scm_sloppy_assx
,
1287 /* Hash table iterators */
1289 SCM_DEFINE (scm_hash_fold
, "hash-fold", 3, 0, 0,
1290 (SCM proc
, SCM init
, SCM table
),
1291 "An iterator over hash-table elements.\n"
1292 "Accumulates and returns a result by applying PROC successively.\n"
1293 "The arguments to PROC are \"(key value prior-result)\" where key\n"
1294 "and value are successive pairs from the hash table TABLE, and\n"
1295 "prior-result is either INIT (for the first application of PROC)\n"
1296 "or the return value of the previous application of PROC.\n"
1297 "For example, @code{(hash-fold acons '() tab)} will convert a hash\n"
1298 "table into an a-list of key-value pairs.")
1299 #define FUNC_NAME s_scm_hash_fold
1301 SCM_VALIDATE_PROC (1, proc
);
1302 SCM_VALIDATE_HASHTABLE (3, table
);
1303 return scm_internal_hash_fold ((scm_t_hash_fold_fn
) scm_call_3
,
1304 (void *) SCM_UNPACK (proc
), init
, table
);
1309 for_each_proc (void *proc
, SCM handle
)
1311 return scm_call_2 (SCM_PACK (proc
), SCM_CAR (handle
), SCM_CDR (handle
));
1314 SCM_DEFINE (scm_hash_for_each
, "hash-for-each", 2, 0, 0,
1315 (SCM proc
, SCM table
),
1316 "An iterator over hash-table elements.\n"
1317 "Applies PROC successively on all hash table items.\n"
1318 "The arguments to PROC are \"(key value)\" where key\n"
1319 "and value are successive pairs from the hash table TABLE.")
1320 #define FUNC_NAME s_scm_hash_for_each
1322 SCM_VALIDATE_PROC (1, proc
);
1323 SCM_VALIDATE_HASHTABLE (2, table
);
1325 scm_internal_hash_for_each_handle (for_each_proc
,
1326 (void *) SCM_UNPACK (proc
),
1328 return SCM_UNSPECIFIED
;
1332 SCM_DEFINE (scm_hash_for_each_handle
, "hash-for-each-handle", 2, 0, 0,
1333 (SCM proc
, SCM table
),
1334 "An iterator over hash-table elements.\n"
1335 "Applies PROC successively on all hash table handles.")
1336 #define FUNC_NAME s_scm_hash_for_each_handle
1338 SCM_ASSERT (scm_is_true (scm_procedure_p (proc
)), proc
, 1, FUNC_NAME
);
1339 SCM_VALIDATE_HASHTABLE (2, table
);
1341 if (SCM_UNLIKELY (SCM_HASHTABLE_WEAK_P (table
)))
1342 SCM_MISC_ERROR ("Handle access not permitted on weak table", SCM_EOL
);
1344 scm_internal_hash_for_each_handle ((scm_t_hash_handle_fn
) scm_call_1
,
1345 (void *) SCM_UNPACK (proc
),
1347 return SCM_UNSPECIFIED
;
1352 map_proc (void *proc
, SCM key
, SCM data
, SCM value
)
1354 return scm_cons (scm_call_2 (SCM_PACK (proc
), key
, data
), value
);
1357 SCM_DEFINE (scm_hash_map_to_list
, "hash-map->list", 2, 0, 0,
1358 (SCM proc
, SCM table
),
1359 "An iterator over hash-table elements.\n"
1360 "Accumulates and returns as a list the results of applying PROC successively.\n"
1361 "The arguments to PROC are \"(key value)\" where key\n"
1362 "and value are successive pairs from the hash table TABLE.")
1363 #define FUNC_NAME s_scm_hash_map_to_list
1365 SCM_VALIDATE_PROC (1, proc
);
1366 SCM_VALIDATE_HASHTABLE (2, table
);
1367 return scm_internal_hash_fold (map_proc
,
1368 (void *) SCM_UNPACK (proc
),
1377 scm_internal_hash_fold (scm_t_hash_fold_fn fn
, void *closure
,
1378 SCM init
, SCM table
)
1379 #define FUNC_NAME s_scm_hash_fold
1382 SCM buckets
, result
= init
;
1384 SCM_VALIDATE_HASHTABLE (0, table
);
1385 buckets
= SCM_HASHTABLE_VECTOR (table
);
1387 n
= SCM_SIMPLE_VECTOR_LENGTH (buckets
);
1388 for (i
= 0; i
< n
; ++i
)
1392 for (ls
= SCM_SIMPLE_VECTOR_REF (buckets
, i
); !scm_is_null (ls
);
1395 handle
= SCM_CAR (ls
);
1397 if (SCM_HASHTABLE_WEAK_P (table
) && SCM_WEAK_PAIR_DELETED_P (handle
))
1398 /* Don't try to unlink this weak pair, as we're not within
1399 the allocation lock. Instead rely on
1400 vacuum_weak_hash_table to do its job. */
1403 result
= fn (closure
, SCM_CAR (handle
), SCM_CDR (handle
), result
);
1411 /* The following redundant code is here in order to be able to support
1412 hash-for-each-handle. An alternative would have been to replace
1413 this code and scm_internal_hash_fold above with a single
1414 scm_internal_hash_fold_handles, but we don't want to promote such
1418 scm_internal_hash_for_each_handle (scm_t_hash_handle_fn fn
, void *closure
,
1420 #define FUNC_NAME s_scm_hash_for_each
1425 SCM_VALIDATE_HASHTABLE (0, table
);
1426 buckets
= SCM_HASHTABLE_VECTOR (table
);
1427 n
= SCM_SIMPLE_VECTOR_LENGTH (buckets
);
1429 for (i
= 0; i
< n
; ++i
)
1431 SCM ls
= SCM_SIMPLE_VECTOR_REF (buckets
, i
), handle
;
1432 while (!scm_is_null (ls
))
1434 if (!scm_is_pair (ls
))
1435 SCM_WRONG_TYPE_ARG (SCM_ARG3
, buckets
);
1436 handle
= SCM_CAR (ls
);
1437 if (!scm_is_pair (handle
))
1438 SCM_WRONG_TYPE_ARG (SCM_ARG3
, buckets
);
1439 fn (closure
, handle
);
1452 #include "libguile/hashtab.x"