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