Adapt ecmascript compiler to recent tree-il changes for prompts.
[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
3330f00f 208
d587c9e8
LC
209\f
210/* Accessing hash table entries. */
22a52da1 211
0f2d19dd 212SCM
d587c9e8
LC
213scm_hash_fn_get_handle (SCM table, SCM obj,
214 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
215 void * closure)
22a52da1 216#define FUNC_NAME "scm_hash_fn_get_handle"
0f2d19dd 217{
c014a02e 218 unsigned long k;
63229905 219 SCM buckets, h;
0f2d19dd 220
f0554ee7
AW
221 SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
222 buckets = SCM_HASHTABLE_VECTOR (table);
d9c82e20
LC
223
224 if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
22a52da1 225 return SCM_BOOL_F;
d9c82e20
LC
226 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
227 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
f0554ee7 228 scm_out_of_range (FUNC_NAME, scm_from_ulong (k));
3a2de079 229
54a9b981 230 h = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
6efbc280
AW
231
232 return h;
233}
234#undef FUNC_NAME
235
236
0f2d19dd 237SCM
f044da55
LC
238scm_hash_fn_create_handle_x (SCM table, SCM obj, SCM init,
239 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
240 void * closure)
cbaadf02 241#define FUNC_NAME "scm_hash_fn_create_handle_x"
0f2d19dd 242{
c014a02e 243 unsigned long k;
63229905 244 SCM buckets, it;
0f2d19dd 245
f0554ee7
AW
246 SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
247 buckets = SCM_HASHTABLE_VECTOR (table);
248
3ebc1832 249 if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
cbaadf02
DH
250 SCM_MISC_ERROR ("void hashtable", SCM_EOL);
251
3ebc1832
MV
252 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
253 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
b9bd8526 254 scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k));
3a2de079 255
54a9b981 256 it = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
e4d21e6b 257
0306509b 258 if (scm_is_pair (it))
0a4c1355 259 return it;
15bd90ea
NJ
260 else if (scm_is_true (it))
261 scm_wrong_type_arg_msg (NULL, 0, it, "a pair");
ee083ac2
DH
262 else
263 {
3a2de079
LC
264 SCM handle, new_bucket;
265
54a9b981 266 handle = scm_cons (obj, init);
3a2de079
LC
267 new_bucket = scm_cons (handle, SCM_EOL);
268
f0554ee7 269 if (!scm_is_eq (SCM_HASHTABLE_VECTOR (table), buckets))
5b582466
MV
270 {
271 buckets = SCM_HASHTABLE_VECTOR (table);
272 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
273 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
274 scm_out_of_range ("hash_fn_create_handle_x", scm_from_ulong (k));
275 }
bc6580eb 276 SCM_SETCDR (new_bucket, SCM_SIMPLE_VECTOR_REF (buckets, k));
3ebc1832 277 SCM_SIMPLE_VECTOR_SET (buckets, k, new_bucket);
f0554ee7 278 SCM_HASHTABLE_INCREMENT (table);
40d2a007 279
62c290e9 280 /* Maybe rehash the table. */
f0554ee7
AW
281 if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table)
282 || SCM_HASHTABLE_N_ITEMS (table) > SCM_HASHTABLE_UPPER (table))
283 scm_i_rehash (table, hash_fn, closure, FUNC_NAME);
ee083ac2
DH
284 return SCM_CAR (new_bucket);
285 }
0f2d19dd 286}
cbaadf02 287#undef FUNC_NAME
0f2d19dd 288
1cc91f1b 289
f044da55
LC
290SCM
291scm_hash_fn_ref (SCM table, SCM obj, SCM dflt,
292 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
293 void *closure)
0f2d19dd 294{
22a52da1 295 SCM it = scm_hash_fn_get_handle (table, obj, hash_fn, assoc_fn, closure);
d2e53ed6 296 if (scm_is_pair (it))
0f2d19dd 297 return SCM_CDR (it);
22a52da1
DH
298 else
299 return dflt;
0f2d19dd
JB
300}
301
f044da55
LC
302SCM
303scm_hash_fn_set_x (SCM table, SCM obj, SCM val,
304 scm_t_hash_fn hash_fn, scm_t_assoc_fn assoc_fn,
305 void *closure)
0f2d19dd 306{
ecc9d1b5 307 SCM pair;
0f2d19dd 308
ecc9d1b5
AW
309 pair = scm_hash_fn_create_handle_x (table, obj, val,
310 hash_fn, assoc_fn, closure);
5a99a574 311
636c99d4 312 if (!scm_is_eq (SCM_CDR (pair), val))
54a9b981 313 SCM_SETCDR (pair, val);
ecc9d1b5 314
0f2d19dd
JB
315 return val;
316}
317
318
d9c82e20 319SCM
a9cf5c71 320scm_hash_fn_remove_x (SCM table, SCM obj,
f044da55
LC
321 scm_t_hash_fn hash_fn,
322 scm_t_assoc_fn assoc_fn,
a9cf5c71 323 void *closure)
f0554ee7 324#define FUNC_NAME "hash_fn_remove_x"
0f2d19dd 325{
c014a02e 326 unsigned long k;
63229905 327 SCM buckets, h;
0f2d19dd 328
f0554ee7
AW
329 SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
330
331 buckets = SCM_HASHTABLE_VECTOR (table);
332
c99de5aa 333 if (SCM_SIMPLE_VECTOR_LENGTH (buckets) == 0)
0f2d19dd 334 return SCM_EOL;
87ca11ff 335
3ebc1832
MV
336 k = hash_fn (obj, SCM_SIMPLE_VECTOR_LENGTH (buckets), closure);
337 if (k >= SCM_SIMPLE_VECTOR_LENGTH (buckets))
f0554ee7 338 scm_out_of_range (FUNC_NAME, scm_from_ulong (k));
3a2de079 339
54a9b981 340 h = assoc_fn (obj, SCM_SIMPLE_VECTOR_REF (buckets, k), closure);
e4d21e6b 341
7888309b 342 if (scm_is_true (h))
87ca11ff 343 {
3ebc1832 344 SCM_SIMPLE_VECTOR_SET
a9cf5c71 345 (buckets, k, scm_delq_x (h, SCM_SIMPLE_VECTOR_REF (buckets, k)));
f0554ee7
AW
346 SCM_HASHTABLE_DECREMENT (table);
347 if (SCM_HASHTABLE_N_ITEMS (table) < SCM_HASHTABLE_LOWER (table))
348 scm_i_rehash (table, hash_fn, closure, FUNC_NAME);
87ca11ff 349 }
0f2d19dd
JB
350 return h;
351}
f0554ee7 352#undef FUNC_NAME
0f2d19dd 353
c35738c1
MD
354SCM_DEFINE (scm_hash_clear_x, "hash-clear!", 1, 0, 0,
355 (SCM table),
a9cf5c71 356 "Remove all items from @var{table} (without triggering a resize).")
c35738c1
MD
357#define FUNC_NAME s_scm_hash_clear_x
358{
54a9b981 359 if (SCM_WEAK_TABLE_P (table))
07e69928
AW
360 {
361 scm_weak_table_clear_x (table);
362 return SCM_UNSPECIFIED;
363 }
54a9b981 364
f0554ee7
AW
365 SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
366
367 scm_vector_fill_x (SCM_HASHTABLE_VECTOR (table), SCM_EOL);
368 SCM_SET_HASHTABLE_N_ITEMS (table, 0);
369
c35738c1
MD
370 return SCM_UNSPECIFIED;
371}
372#undef FUNC_NAME
0f2d19dd
JB
373
374\f
375
a1ec6916 376SCM_DEFINE (scm_hashq_get_handle, "hashq-get-handle", 2, 0, 0,
22a52da1
DH
377 (SCM table, SCM key),
378 "This procedure returns the @code{(key . value)} pair from the\n"
379 "hash table @var{table}. If @var{table} does not hold an\n"
380 "associated value for @var{key}, @code{#f} is returned.\n"
381 "Uses @code{eq?} for equality testing.")
1bbd0b84 382#define FUNC_NAME s_scm_hashq_get_handle
0f2d19dd 383{
d587c9e8
LC
384 return scm_hash_fn_get_handle (table, key,
385 (scm_t_hash_fn) scm_ihashq,
386 (scm_t_assoc_fn) scm_sloppy_assq,
387 0);
0f2d19dd 388}
1bbd0b84 389#undef FUNC_NAME
0f2d19dd
JB
390
391
a1ec6916 392SCM_DEFINE (scm_hashq_create_handle_x, "hashq-create-handle!", 3, 0, 0,
d550d22a
GB
393 (SCM table, SCM key, SCM init),
394 "This function looks up @var{key} in @var{table} and returns its handle.\n"
b380b885
MD
395 "If @var{key} is not already present, a new handle is created which\n"
396 "associates @var{key} with @var{init}.")
1bbd0b84 397#define FUNC_NAME s_scm_hashq_create_handle_x
0f2d19dd 398{
d587c9e8
LC
399 return scm_hash_fn_create_handle_x (table, key, init,
400 (scm_t_hash_fn) scm_ihashq,
401 (scm_t_assoc_fn) scm_sloppy_assq,
402 0);
0f2d19dd 403}
1bbd0b84 404#undef FUNC_NAME
0f2d19dd
JB
405
406
a1ec6916 407SCM_DEFINE (scm_hashq_ref, "hashq-ref", 2, 1, 0,
1e6808ea 408 (SCM table, SCM key, SCM dflt),
b380b885
MD
409 "Look up @var{key} in the hash table @var{table}, and return the\n"
410 "value (if any) associated with it. If @var{key} is not found,\n"
b7e64f8b 411 "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
5352393c 412 "is supplied). Uses @code{eq?} for equality testing.")
1bbd0b84 413#define FUNC_NAME s_scm_hashq_ref
0f2d19dd 414{
54778cd3 415 if (SCM_UNBNDP (dflt))
0f2d19dd 416 dflt = SCM_BOOL_F;
54a9b981
AW
417
418 if (SCM_WEAK_TABLE_P (table))
419 return scm_weak_table_refq (table, key, dflt);
420
d587c9e8
LC
421 return scm_hash_fn_ref (table, key, dflt,
422 (scm_t_hash_fn) scm_ihashq,
423 (scm_t_assoc_fn) scm_sloppy_assq,
424 0);
0f2d19dd 425}
1bbd0b84 426#undef FUNC_NAME
0f2d19dd
JB
427
428
429
a1ec6916 430SCM_DEFINE (scm_hashq_set_x, "hashq-set!", 3, 0, 0,
1e6808ea 431 (SCM table, SCM key, SCM val),
5352393c 432 "Find the entry in @var{table} associated with @var{key}, and\n"
b7e64f8b 433 "store @var{val} there. Uses @code{eq?} for equality testing.")
1bbd0b84 434#define FUNC_NAME s_scm_hashq_set_x
0f2d19dd 435{
54a9b981 436 if (SCM_WEAK_TABLE_P (table))
07e69928
AW
437 {
438 scm_weak_table_putq_x (table, key, val);
439 return val;
440 }
54a9b981 441
d587c9e8
LC
442 return scm_hash_fn_set_x (table, key, val,
443 (scm_t_hash_fn) scm_ihashq,
444 (scm_t_assoc_fn) scm_sloppy_assq,
445 0);
0f2d19dd 446}
1bbd0b84 447#undef FUNC_NAME
0f2d19dd
JB
448
449
450
a1ec6916 451SCM_DEFINE (scm_hashq_remove_x, "hashq-remove!", 2, 0, 0,
1e6808ea 452 (SCM table, SCM key),
5352393c
MG
453 "Remove @var{key} (and any value associated with it) from\n"
454 "@var{table}. Uses @code{eq?} for equality tests.")
1bbd0b84 455#define FUNC_NAME s_scm_hashq_remove_x
0f2d19dd 456{
54a9b981 457 if (SCM_WEAK_TABLE_P (table))
07e69928
AW
458 {
459 scm_weak_table_remq_x (table, key);
460 /* This return value is for historical compatibility with
461 hash-remove!, which returns either the "handle" corresponding
462 to the entry, or #f. Since weak tables don't have handles, we
463 have to return #f. */
464 return SCM_BOOL_F;
465 }
54a9b981 466
d587c9e8
LC
467 return scm_hash_fn_remove_x (table, key,
468 (scm_t_hash_fn) scm_ihashq,
469 (scm_t_assoc_fn) scm_sloppy_assq,
470 0);
0f2d19dd 471}
1bbd0b84 472#undef FUNC_NAME
0f2d19dd
JB
473
474
475\f
476
a1ec6916 477SCM_DEFINE (scm_hashv_get_handle, "hashv-get-handle", 2, 0, 0,
22a52da1
DH
478 (SCM table, SCM key),
479 "This procedure returns the @code{(key . value)} pair from the\n"
480 "hash table @var{table}. If @var{table} does not hold an\n"
481 "associated value for @var{key}, @code{#f} is returned.\n"
482 "Uses @code{eqv?} for equality testing.")
1bbd0b84 483#define FUNC_NAME s_scm_hashv_get_handle
0f2d19dd 484{
d587c9e8
LC
485 return scm_hash_fn_get_handle (table, key,
486 (scm_t_hash_fn) scm_ihashv,
487 (scm_t_assoc_fn) scm_sloppy_assv,
488 0);
0f2d19dd 489}
1bbd0b84 490#undef FUNC_NAME
0f2d19dd
JB
491
492
a1ec6916 493SCM_DEFINE (scm_hashv_create_handle_x, "hashv-create-handle!", 3, 0, 0,
d550d22a
GB
494 (SCM table, SCM key, SCM init),
495 "This function looks up @var{key} in @var{table} and returns its handle.\n"
496 "If @var{key} is not already present, a new handle is created which\n"
497 "associates @var{key} with @var{init}.")
1bbd0b84 498#define FUNC_NAME s_scm_hashv_create_handle_x
0f2d19dd 499{
d587c9e8
LC
500 return scm_hash_fn_create_handle_x (table, key, init,
501 (scm_t_hash_fn) scm_ihashv,
502 (scm_t_assoc_fn) scm_sloppy_assv,
503 0);
0f2d19dd 504}
1bbd0b84 505#undef FUNC_NAME
0f2d19dd
JB
506
507
54a9b981
AW
508static int
509assv_predicate (SCM k, SCM v, void *closure)
510{
21041372 511 return scm_is_true (scm_eqv_p (k, SCM_PACK_POINTER (closure)));
54a9b981
AW
512}
513
a1ec6916 514SCM_DEFINE (scm_hashv_ref, "hashv-ref", 2, 1, 0,
1e6808ea 515 (SCM table, SCM key, SCM dflt),
d550d22a
GB
516 "Look up @var{key} in the hash table @var{table}, and return the\n"
517 "value (if any) associated with it. If @var{key} is not found,\n"
b7e64f8b 518 "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
5352393c 519 "is supplied). Uses @code{eqv?} for equality testing.")
1bbd0b84 520#define FUNC_NAME s_scm_hashv_ref
0f2d19dd 521{
54778cd3 522 if (SCM_UNBNDP (dflt))
0f2d19dd 523 dflt = SCM_BOOL_F;
54a9b981
AW
524
525 if (SCM_WEAK_TABLE_P (table))
526 return scm_c_weak_table_ref (table, scm_ihashv (key, -1),
527 assv_predicate, SCM_PACK (key), dflt);
528
d587c9e8
LC
529 return scm_hash_fn_ref (table, key, dflt,
530 (scm_t_hash_fn) scm_ihashv,
531 (scm_t_assoc_fn) scm_sloppy_assv,
532 0);
0f2d19dd 533}
1bbd0b84 534#undef FUNC_NAME
0f2d19dd
JB
535
536
537
a1ec6916 538SCM_DEFINE (scm_hashv_set_x, "hashv-set!", 3, 0, 0,
1e6808ea 539 (SCM table, SCM key, SCM val),
5352393c
MG
540 "Find the entry in @var{table} associated with @var{key}, and\n"
541 "store @var{value} there. Uses @code{eqv?} for equality testing.")
1bbd0b84 542#define FUNC_NAME s_scm_hashv_set_x
0f2d19dd 543{
54a9b981
AW
544 if (SCM_WEAK_TABLE_P (table))
545 {
546 scm_c_weak_table_put_x (table, scm_ihashv (key, -1),
547 assv_predicate, SCM_PACK (key),
548 key, val);
07e69928 549 return val;
54a9b981
AW
550 }
551
d587c9e8
LC
552 return scm_hash_fn_set_x (table, key, val,
553 (scm_t_hash_fn) scm_ihashv,
554 (scm_t_assoc_fn) scm_sloppy_assv,
555 0);
0f2d19dd 556}
1bbd0b84 557#undef FUNC_NAME
0f2d19dd
JB
558
559
a1ec6916 560SCM_DEFINE (scm_hashv_remove_x, "hashv-remove!", 2, 0, 0,
1e6808ea 561 (SCM table, SCM key),
5352393c
MG
562 "Remove @var{key} (and any value associated with it) from\n"
563 "@var{table}. Uses @code{eqv?} for equality tests.")
1bbd0b84 564#define FUNC_NAME s_scm_hashv_remove_x
0f2d19dd 565{
54a9b981
AW
566 if (SCM_WEAK_TABLE_P (table))
567 {
568 scm_c_weak_table_remove_x (table, scm_ihashv (key, -1),
569 assv_predicate, SCM_PACK (key));
07e69928
AW
570 /* See note in hashq-remove!. */
571 return SCM_BOOL_F;
54a9b981
AW
572 }
573
d587c9e8
LC
574 return scm_hash_fn_remove_x (table, key,
575 (scm_t_hash_fn) scm_ihashv,
576 (scm_t_assoc_fn) scm_sloppy_assv,
577 0);
0f2d19dd 578}
1bbd0b84 579#undef FUNC_NAME
0f2d19dd
JB
580
581\f
582
a1ec6916 583SCM_DEFINE (scm_hash_get_handle, "hash-get-handle", 2, 0, 0,
22a52da1
DH
584 (SCM table, SCM key),
585 "This procedure returns the @code{(key . value)} pair from the\n"
586 "hash table @var{table}. If @var{table} does not hold an\n"
587 "associated value for @var{key}, @code{#f} is returned.\n"
588 "Uses @code{equal?} for equality testing.")
1bbd0b84 589#define FUNC_NAME s_scm_hash_get_handle
0f2d19dd 590{
d587c9e8
LC
591 return scm_hash_fn_get_handle (table, key,
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
a1ec6916 599SCM_DEFINE (scm_hash_create_handle_x, "hash-create-handle!", 3, 0, 0,
d550d22a
GB
600 (SCM table, SCM key, SCM init),
601 "This function looks up @var{key} in @var{table} and returns its handle.\n"
602 "If @var{key} is not already present, a new handle is created which\n"
603 "associates @var{key} with @var{init}.")
1bbd0b84 604#define FUNC_NAME s_scm_hash_create_handle_x
0f2d19dd 605{
d587c9e8
LC
606 return scm_hash_fn_create_handle_x (table, key, init,
607 (scm_t_hash_fn) scm_ihash,
608 (scm_t_assoc_fn) scm_sloppy_assoc,
609 0);
0f2d19dd 610}
1bbd0b84 611#undef FUNC_NAME
0f2d19dd
JB
612
613
54a9b981
AW
614static int
615assoc_predicate (SCM k, SCM v, void *closure)
616{
21041372 617 return scm_is_true (scm_equal_p (k, SCM_PACK_POINTER (closure)));
54a9b981
AW
618}
619
a1ec6916 620SCM_DEFINE (scm_hash_ref, "hash-ref", 2, 1, 0,
1e6808ea 621 (SCM table, SCM key, SCM dflt),
d550d22a
GB
622 "Look up @var{key} in the hash table @var{table}, and return the\n"
623 "value (if any) associated with it. If @var{key} is not found,\n"
b7e64f8b 624 "return @var{dflt} (or @code{#f} if no @var{dflt} argument\n"
5352393c 625 "is supplied). Uses @code{equal?} for equality testing.")
1bbd0b84 626#define FUNC_NAME s_scm_hash_ref
0f2d19dd 627{
54778cd3 628 if (SCM_UNBNDP (dflt))
0f2d19dd 629 dflt = SCM_BOOL_F;
54a9b981
AW
630
631 if (SCM_WEAK_TABLE_P (table))
632 return scm_c_weak_table_ref (table, scm_ihash (key, -1),
633 assoc_predicate, SCM_PACK (key), dflt);
634
d587c9e8
LC
635 return scm_hash_fn_ref (table, key, dflt,
636 (scm_t_hash_fn) scm_ihash,
637 (scm_t_assoc_fn) scm_sloppy_assoc,
638 0);
0f2d19dd 639}
1bbd0b84 640#undef FUNC_NAME
0f2d19dd
JB
641
642
643
a1ec6916 644SCM_DEFINE (scm_hash_set_x, "hash-set!", 3, 0, 0,
1e6808ea 645 (SCM table, SCM key, SCM val),
5352393c 646 "Find the entry in @var{table} associated with @var{key}, and\n"
b7e64f8b 647 "store @var{val} there. Uses @code{equal?} for equality\n"
5352393c 648 "testing.")
1bbd0b84 649#define FUNC_NAME s_scm_hash_set_x
0f2d19dd 650{
54a9b981
AW
651 if (SCM_WEAK_TABLE_P (table))
652 {
653 scm_c_weak_table_put_x (table, scm_ihash (key, -1),
654 assoc_predicate, SCM_PACK (key),
655 key, val);
07e69928 656 return val;
54a9b981
AW
657 }
658
d587c9e8
LC
659 return scm_hash_fn_set_x (table, key, val,
660 (scm_t_hash_fn) scm_ihash,
661 (scm_t_assoc_fn) scm_sloppy_assoc,
662 0);
0f2d19dd 663}
1bbd0b84 664#undef FUNC_NAME
0f2d19dd
JB
665
666
667
a1ec6916 668SCM_DEFINE (scm_hash_remove_x, "hash-remove!", 2, 0, 0,
1e6808ea 669 (SCM table, SCM key),
5352393c
MG
670 "Remove @var{key} (and any value associated with it) from\n"
671 "@var{table}. Uses @code{equal?} for equality tests.")
1bbd0b84 672#define FUNC_NAME s_scm_hash_remove_x
0f2d19dd 673{
54a9b981
AW
674 if (SCM_WEAK_TABLE_P (table))
675 {
676 scm_c_weak_table_remove_x (table, scm_ihash (key, -1),
677 assoc_predicate, SCM_PACK (key));
07e69928
AW
678 /* See note in hashq-remove!. */
679 return SCM_BOOL_F;
54a9b981
AW
680 }
681
d587c9e8
LC
682 return scm_hash_fn_remove_x (table, key,
683 (scm_t_hash_fn) scm_ihash,
684 (scm_t_assoc_fn) scm_sloppy_assoc,
685 0);
0f2d19dd 686}
1bbd0b84 687#undef FUNC_NAME
0f2d19dd
JB
688
689\f
690
691
92c2555f 692typedef struct scm_t_ihashx_closure
0f2d19dd
JB
693{
694 SCM hash;
695 SCM assoc;
54a9b981 696 SCM key;
92c2555f 697} scm_t_ihashx_closure;
0f2d19dd 698
c014a02e 699static unsigned long
d587c9e8 700scm_ihashx (SCM obj, unsigned long n, void *arg)
0f2d19dd 701{
d587c9e8
LC
702 SCM answer;
703 scm_t_ihashx_closure *closure = (scm_t_ihashx_closure *) arg;
704 answer = scm_call_2 (closure->hash, obj, scm_from_ulong (n));
a55c2b68 705 return scm_to_ulong (answer);
0f2d19dd
JB
706}
707
0f2d19dd 708static SCM
d587c9e8 709scm_sloppy_assx (SCM obj, SCM alist, void *arg)
0f2d19dd 710{
d587c9e8 711 scm_t_ihashx_closure *closure = (scm_t_ihashx_closure *) arg;
87ca11ff 712 return scm_call_2 (closure->assoc, obj, alist);
0f2d19dd
JB
713}
714
54a9b981
AW
715static int
716assx_predicate (SCM k, SCM v, void *closure)
717{
718 scm_t_ihashx_closure *c = (scm_t_ihashx_closure *) closure;
719
720 /* FIXME: The hashx interface is crazy. Hash tables have nothing to
721 do with alists in principle. Instead of getting an assoc proc,
722 hashx functions should use an equality predicate. Perhaps we can
723 change this before 2.2, but until then, add a terrible, terrible
724 hack. */
725
726 return scm_is_true (scm_call_2 (c->assoc, c->key, scm_acons (k, v, SCM_EOL)));
727}
728
0f2d19dd 729
a1ec6916 730SCM_DEFINE (scm_hashx_get_handle, "hashx-get-handle", 4, 0, 0,
1e6808ea
MG
731 (SCM hash, SCM assoc, SCM table, SCM key),
732 "This behaves the same way as the corresponding\n"
733 "@code{-get-handle} function, but uses @var{hash} as a hash\n"
734 "function and @var{assoc} to compare keys. @code{hash} must be\n"
735 "a function that takes two arguments, a key to be hashed and a\n"
d550d22a
GB
736 "table size. @code{assoc} must be an associator function, like\n"
737 "@code{assoc}, @code{assq} or @code{assv}.")
1bbd0b84 738#define FUNC_NAME s_scm_hashx_get_handle
0f2d19dd 739{
92c2555f 740 scm_t_ihashx_closure closure;
0f2d19dd
JB
741 closure.hash = hash;
742 closure.assoc = assoc;
54a9b981 743 closure.key = key;
1d9c2e62 744
1e6808ea 745 return scm_hash_fn_get_handle (table, key, scm_ihashx, scm_sloppy_assx,
87ca11ff 746 (void *) &closure);
0f2d19dd 747}
1bbd0b84 748#undef FUNC_NAME
0f2d19dd
JB
749
750
a1ec6916 751SCM_DEFINE (scm_hashx_create_handle_x, "hashx-create-handle!", 5, 0, 0,
1e6808ea
MG
752 (SCM hash, SCM assoc, SCM table, SCM key, SCM init),
753 "This behaves the same way as the corresponding\n"
754 "@code{-create-handle} function, but uses @var{hash} as a hash\n"
755 "function and @var{assoc} to compare keys. @code{hash} must be\n"
756 "a function that takes two arguments, a key to be hashed and a\n"
d550d22a
GB
757 "table size. @code{assoc} must be an associator function, like\n"
758 "@code{assoc}, @code{assq} or @code{assv}.")
1bbd0b84 759#define FUNC_NAME s_scm_hashx_create_handle_x
0f2d19dd 760{
92c2555f 761 scm_t_ihashx_closure closure;
0f2d19dd
JB
762 closure.hash = hash;
763 closure.assoc = assoc;
54a9b981 764 closure.key = key;
1d9c2e62 765
1e6808ea
MG
766 return scm_hash_fn_create_handle_x (table, key, init, scm_ihashx,
767 scm_sloppy_assx, (void *)&closure);
0f2d19dd 768}
1bbd0b84 769#undef FUNC_NAME
0f2d19dd
JB
770
771
772
a1ec6916 773SCM_DEFINE (scm_hashx_ref, "hashx-ref", 4, 1, 0,
1e6808ea 774 (SCM hash, SCM assoc, SCM table, SCM key, SCM dflt),
d550d22a 775 "This behaves the same way as the corresponding @code{ref}\n"
1e6808ea
MG
776 "function, but uses @var{hash} as a hash function and\n"
777 "@var{assoc} to compare keys. @code{hash} must be a function\n"
778 "that takes two arguments, a key to be hashed and a table size.\n"
779 "@code{assoc} must be an associator function, like @code{assoc},\n"
780 "@code{assq} or @code{assv}.\n"
781 "\n"
782 "By way of illustration, @code{hashq-ref table key} is\n"
783 "equivalent to @code{hashx-ref hashq assq table key}.")
1bbd0b84 784#define FUNC_NAME s_scm_hashx_ref
0f2d19dd 785{
92c2555f 786 scm_t_ihashx_closure closure;
54778cd3 787 if (SCM_UNBNDP (dflt))
0f2d19dd
JB
788 dflt = SCM_BOOL_F;
789 closure.hash = hash;
790 closure.assoc = assoc;
54a9b981
AW
791 closure.key = key;
792
793 if (SCM_WEAK_TABLE_P (table))
794 {
795 unsigned long h = scm_to_ulong (scm_call_2 (hash, key,
796 scm_from_ulong (-1)));
797 return scm_c_weak_table_ref (table, h, assx_predicate, &closure, dflt);
798 }
799
1e6808ea
MG
800 return scm_hash_fn_ref (table, key, dflt, scm_ihashx, scm_sloppy_assx,
801 (void *)&closure);
0f2d19dd 802}
1bbd0b84 803#undef FUNC_NAME
0f2d19dd
JB
804
805
806
807
a1ec6916 808SCM_DEFINE (scm_hashx_set_x, "hashx-set!", 5, 0, 0,
1e6808ea 809 (SCM hash, SCM assoc, SCM table, SCM key, SCM val),
d550d22a 810 "This behaves the same way as the corresponding @code{set!}\n"
1e6808ea
MG
811 "function, but uses @var{hash} as a hash function and\n"
812 "@var{assoc} to compare keys. @code{hash} must be a function\n"
813 "that takes two arguments, a key to be hashed and a table size.\n"
814 "@code{assoc} must be an associator function, like @code{assoc},\n"
815 "@code{assq} or @code{assv}.\n"
816 "\n"
817 " By way of illustration, @code{hashq-set! table key} is\n"
818 "equivalent to @code{hashx-set! hashq assq table key}.")
1bbd0b84 819#define FUNC_NAME s_scm_hashx_set_x
0f2d19dd 820{
92c2555f 821 scm_t_ihashx_closure closure;
0f2d19dd
JB
822 closure.hash = hash;
823 closure.assoc = assoc;
54a9b981
AW
824 closure.key = key;
825
826 if (SCM_WEAK_TABLE_P (table))
827 {
828 unsigned long h = scm_to_ulong (scm_call_2 (hash, key,
829 scm_from_ulong (-1)));
830 scm_c_weak_table_put_x (table, h, assx_predicate, &closure, key, val);
07e69928 831 return val;
54a9b981
AW
832 }
833
1e6808ea
MG
834 return scm_hash_fn_set_x (table, key, val, scm_ihashx, scm_sloppy_assx,
835 (void *)&closure);
0f2d19dd 836}
1bbd0b84 837#undef FUNC_NAME
0f2d19dd 838
a9cf5c71
MV
839SCM_DEFINE (scm_hashx_remove_x, "hashx-remove!", 4, 0, 0,
840 (SCM hash, SCM assoc, SCM table, SCM obj),
841 "This behaves the same way as the corresponding @code{remove!}\n"
842 "function, but uses @var{hash} as a hash function and\n"
843 "@var{assoc} to compare keys. @code{hash} must be a function\n"
844 "that takes two arguments, a key to be hashed and a table size.\n"
845 "@code{assoc} must be an associator function, like @code{assoc},\n"
846 "@code{assq} or @code{assv}.\n"
847 "\n"
848 " By way of illustration, @code{hashq-remove! table key} is\n"
849 "equivalent to @code{hashx-remove! hashq assq #f table key}.")
850#define FUNC_NAME s_scm_hashx_remove_x
0f2d19dd 851{
92c2555f 852 scm_t_ihashx_closure closure;
0f2d19dd
JB
853 closure.hash = hash;
854 closure.assoc = assoc;
54a9b981
AW
855 closure.key = obj;
856
857 if (SCM_WEAK_TABLE_P (table))
858 {
859 unsigned long h = scm_to_ulong (scm_call_2 (hash, obj,
860 scm_from_ulong (-1)));
861 scm_c_weak_table_remove_x (table, h, assx_predicate, &closure);
07e69928
AW
862 /* See note in hashq-remove!. */
863 return SCM_BOOL_F;
54a9b981
AW
864 }
865
4cff503f
KR
866 return scm_hash_fn_remove_x (table, obj, scm_ihashx, scm_sloppy_assx,
867 (void *) &closure);
0f2d19dd 868}
a9cf5c71 869#undef FUNC_NAME
0f2d19dd 870
711a9fd7 871/* Hash table iterators */
b94903c2 872
162125af
AW
873SCM_DEFINE (scm_hash_fold, "hash-fold", 3, 0, 0,
874 (SCM proc, SCM init, SCM table),
875 "An iterator over hash-table elements.\n"
876 "Accumulates and returns a result by applying PROC successively.\n"
877 "The arguments to PROC are \"(key value prior-result)\" where key\n"
878 "and value are successive pairs from the hash table TABLE, and\n"
879 "prior-result is either INIT (for the first application of PROC)\n"
880 "or the return value of the previous application of PROC.\n"
881 "For example, @code{(hash-fold acons '() tab)} will convert a hash\n"
882 "table into an a-list of key-value pairs.")
883#define FUNC_NAME s_scm_hash_fold
884{
885 SCM_VALIDATE_PROC (1, proc);
54a9b981
AW
886
887 if (SCM_WEAK_TABLE_P (table))
888 return scm_weak_table_fold (proc, init, table);
889
2dd7d8ce 890 SCM_VALIDATE_HASHTABLE (3, table);
162125af
AW
891 return scm_internal_hash_fold ((scm_t_hash_fold_fn) scm_call_3,
892 (void *) SCM_UNPACK (proc), init, table);
893}
894#undef FUNC_NAME
895
896static SCM
897for_each_proc (void *proc, SCM handle)
898{
899 return scm_call_2 (SCM_PACK (proc), SCM_CAR (handle), SCM_CDR (handle));
900}
901
902SCM_DEFINE (scm_hash_for_each, "hash-for-each", 2, 0, 0,
903 (SCM proc, SCM table),
904 "An iterator over hash-table elements.\n"
905 "Applies PROC successively on all hash table items.\n"
906 "The arguments to PROC are \"(key value)\" where key\n"
907 "and value are successive pairs from the hash table TABLE.")
908#define FUNC_NAME s_scm_hash_for_each
909{
910 SCM_VALIDATE_PROC (1, proc);
54a9b981
AW
911
912 if (SCM_WEAK_TABLE_P (table))
07e69928
AW
913 {
914 scm_weak_table_for_each (proc, table);
915 return SCM_UNSPECIFIED;
916 }
54a9b981 917
2dd7d8ce 918 SCM_VALIDATE_HASHTABLE (2, table);
162125af
AW
919
920 scm_internal_hash_for_each_handle (for_each_proc,
921 (void *) SCM_UNPACK (proc),
922 table);
923 return SCM_UNSPECIFIED;
924}
925#undef FUNC_NAME
926
927SCM_DEFINE (scm_hash_for_each_handle, "hash-for-each-handle", 2, 0, 0,
928 (SCM proc, SCM table),
929 "An iterator over hash-table elements.\n"
930 "Applies PROC successively on all hash table handles.")
931#define FUNC_NAME s_scm_hash_for_each_handle
932{
933 SCM_ASSERT (scm_is_true (scm_procedure_p (proc)), proc, 1, FUNC_NAME);
2dd7d8ce 934 SCM_VALIDATE_HASHTABLE (2, table);
162125af
AW
935
936 scm_internal_hash_for_each_handle ((scm_t_hash_handle_fn) scm_call_1,
937 (void *) SCM_UNPACK (proc),
938 table);
939 return SCM_UNSPECIFIED;
940}
941#undef FUNC_NAME
942
943static SCM
944map_proc (void *proc, SCM key, SCM data, SCM value)
945{
946 return scm_cons (scm_call_2 (SCM_PACK (proc), key, data), value);
947}
948
949SCM_DEFINE (scm_hash_map_to_list, "hash-map->list", 2, 0, 0,
950 (SCM proc, SCM table),
951 "An iterator over hash-table elements.\n"
952 "Accumulates and returns as a list the results of applying PROC successively.\n"
953 "The arguments to PROC are \"(key value)\" where key\n"
954 "and value are successive pairs from the hash table TABLE.")
955#define FUNC_NAME s_scm_hash_map_to_list
956{
957 SCM_VALIDATE_PROC (1, proc);
54a9b981
AW
958
959 if (SCM_WEAK_TABLE_P (table))
960 return scm_weak_table_map_to_list (proc, table);
961
2dd7d8ce 962 SCM_VALIDATE_HASHTABLE (2, table);
162125af
AW
963 return scm_internal_hash_fold (map_proc,
964 (void *) SCM_UNPACK (proc),
965 SCM_EOL,
966 table);
967}
968#undef FUNC_NAME
969
3330f00f
DH
970static SCM
971count_proc (void *pred, SCM key, SCM data, SCM value)
972{
973 if (scm_is_false (scm_call_2 (SCM_PACK (pred), key, data)))
974 return value;
975 else
976 return scm_oneplus(value);
977}
978
979SCM_DEFINE (scm_hash_count, "hash-count", 2, 0, 0,
980 (SCM pred, SCM table),
981 "Return the number of elements in the given hash TABLE that\n"
982 "cause `(PRED KEY VALUE)' to return true. To quickly determine\n"
983 "the total number of elements, use `(const #t)' for PRED.")
984#define FUNC_NAME s_scm_hash_count
985{
986 SCM init;
987
988 SCM_VALIDATE_PROC (1, pred);
989 SCM_VALIDATE_HASHTABLE (2, table);
990
991 init = scm_from_int (0);
992 return scm_internal_hash_fold ((scm_t_hash_fold_fn) count_proc,
993 (void *) SCM_UNPACK (pred), init, table);
994}
995#undef FUNC_NAME
996
162125af 997\f
c7df61cd
MD
998
999SCM
a07010bf
LC
1000scm_internal_hash_fold (scm_t_hash_fold_fn fn, void *closure,
1001 SCM init, SCM table)
2dd7d8ce 1002#define FUNC_NAME s_scm_hash_fold
c7df61cd 1003{
87ca11ff
MD
1004 long i, n;
1005 SCM buckets, result = init;
87ca11ff 1006
54a9b981
AW
1007 if (SCM_WEAK_TABLE_P (table))
1008 return scm_c_weak_table_fold (fn, closure, init, table);
1009
2dd7d8ce
AW
1010 SCM_VALIDATE_HASHTABLE (0, table);
1011 buckets = SCM_HASHTABLE_VECTOR (table);
0a4c1355 1012
3ebc1832 1013 n = SCM_SIMPLE_VECTOR_LENGTH (buckets);
c7df61cd
MD
1014 for (i = 0; i < n; ++i)
1015 {
2187975e 1016 SCM ls, handle;
741e83fc 1017
2187975e
AW
1018 for (ls = SCM_SIMPLE_VECTOR_REF (buckets, i); !scm_is_null (ls);
1019 ls = SCM_CDR (ls))
c7df61cd 1020 {
c7df61cd 1021 handle = SCM_CAR (ls);
54a9b981 1022 result = fn (closure, SCM_CAR (handle), SCM_CDR (handle), result);
c7df61cd
MD
1023 }
1024 }
87ca11ff 1025
c7df61cd
MD
1026 return result;
1027}
2dd7d8ce 1028#undef FUNC_NAME
c7df61cd 1029
711a9fd7
MD
1030/* The following redundant code is here in order to be able to support
1031 hash-for-each-handle. An alternative would have been to replace
1032 this code and scm_internal_hash_fold above with a single
1033 scm_internal_hash_fold_handles, but we don't want to promote such
1034 an API. */
1035
711a9fd7 1036void
a07010bf
LC
1037scm_internal_hash_for_each_handle (scm_t_hash_handle_fn fn, void *closure,
1038 SCM table)
2dd7d8ce 1039#define FUNC_NAME s_scm_hash_for_each
711a9fd7
MD
1040{
1041 long i, n;
1042 SCM buckets;
1043
2dd7d8ce
AW
1044 SCM_VALIDATE_HASHTABLE (0, table);
1045 buckets = SCM_HASHTABLE_VECTOR (table);
3ebc1832 1046 n = SCM_SIMPLE_VECTOR_LENGTH (buckets);
2dd7d8ce 1047
711a9fd7
MD
1048 for (i = 0; i < n; ++i)
1049 {
3ebc1832 1050 SCM ls = SCM_SIMPLE_VECTOR_REF (buckets, i), handle;
d2e53ed6 1051 while (!scm_is_null (ls))
711a9fd7 1052 {
d2e53ed6 1053 if (!scm_is_pair (ls))
2dd7d8ce 1054 SCM_WRONG_TYPE_ARG (SCM_ARG3, buckets);
711a9fd7 1055 handle = SCM_CAR (ls);
d2e53ed6 1056 if (!scm_is_pair (handle))
2dd7d8ce 1057 SCM_WRONG_TYPE_ARG (SCM_ARG3, buckets);
711a9fd7
MD
1058 fn (closure, handle);
1059 ls = SCM_CDR (ls);
1060 }
1061 }
1062}
2dd7d8ce 1063#undef FUNC_NAME
711a9fd7 1064
0f2d19dd
JB
1065\f
1066
1cc91f1b 1067
c35738c1
MD
1068void
1069scm_init_hashtab ()
1070{
a0599745 1071#include "libguile/hashtab.x"
0f2d19dd 1072}
89e00824
ML
1073
1074/*
1075 Local Variables:
1076 c-file-style: "gnu"
1077 End:
1078*/