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