1 /* Copyright (C) 1995,1996,1998,2000,2001, 2003, 2006, 2008 Free Software Foundation, Inc.
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.
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.
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
27 #include "libguile/_scm.h"
28 #include "libguile/vectors.h"
29 #include "libguile/lang.h"
30 #include "libguile/hashtab.h"
32 #include "libguile/validate.h"
33 #include "libguile/weaks.h"
37 /* 1. The current hash table implementation in hashtab.c uses weak alist
38 * vectors (formerly called weak hash tables) internally.
40 * 2. All hash table operations still work on alist vectors.
42 * 3. The weak vector and alist vector Scheme API is accessed through
43 * the module (ice-9 weak-vector).
51 SCM_DEFINE (scm_make_weak_vector
, "make-weak-vector", 1, 1, 0,
53 "Return a weak vector with @var{size} elements. If the optional\n"
54 "argument @var{fill} is given, all entries in the vector will be\n"
55 "set to @var{fill}. The default value for @var{fill} is the\n"
57 #define FUNC_NAME s_scm_make_weak_vector
59 return scm_i_allocate_weak_vector (0, size
, fill
);
64 SCM_REGISTER_PROC(s_list_to_weak_vector
, "list->weak-vector", 1, 0, 0, scm_weak_vector
);
66 SCM_DEFINE (scm_weak_vector
, "weak-vector", 0, 0, 1,
68 "@deffnx {Scheme Procedure} list->weak-vector l\n"
69 "Construct a weak vector from a list: @code{weak-vector} uses\n"
70 "the list of its arguments while @code{list->weak-vector} uses\n"
71 "its only argument @var{l} (a list) to construct a weak vector\n"
72 "the same way @code{list->vector} would.")
73 #define FUNC_NAME s_scm_weak_vector
75 scm_t_array_handle handle
;
80 SCM_ASSERT (i
>= 0, l
, SCM_ARG1
, FUNC_NAME
);
82 res
= scm_make_weak_vector (scm_from_int (i
), SCM_UNSPECIFIED
);
83 data
= scm_vector_writable_elements (res
, &handle
, NULL
, NULL
);
85 while (scm_is_pair (l
) && i
> 0)
87 *data
++ = SCM_CAR (l
);
92 scm_array_handle_release (&handle
);
99 SCM_DEFINE (scm_weak_vector_p
, "weak-vector?", 1, 0, 0,
101 "Return @code{#t} if @var{obj} is a weak vector. Note that all\n"
102 "weak hashes are also weak vectors.")
103 #define FUNC_NAME s_scm_weak_vector_p
105 return scm_from_bool (SCM_I_WVECTP (obj
) && !SCM_IS_WHVEC (obj
));
111 SCM_DEFINE (scm_make_weak_key_alist_vector
, "make-weak-key-alist-vector", 0, 1, 0,
113 "@deffnx {Scheme Procedure} make-weak-value-alist-vector size\n"
114 "@deffnx {Scheme Procedure} make-doubly-weak-alist-vector size\n"
115 "Return a weak hash table with @var{size} buckets. As with any\n"
116 "hash table, choosing a good size for the table requires some\n"
119 "You can modify weak hash tables in exactly the same way you\n"
120 "would modify regular hash tables. (@pxref{Hash Tables})")
121 #define FUNC_NAME s_scm_make_weak_key_alist_vector
123 return scm_i_allocate_weak_vector
124 (1, SCM_UNBNDP (size
) ? scm_from_int (31) : size
, SCM_EOL
);
129 SCM_DEFINE (scm_make_weak_value_alist_vector
, "make-weak-value-alist-vector", 0, 1, 0,
131 "Return a hash table with weak values with @var{size} buckets.\n"
132 "(@pxref{Hash Tables})")
133 #define FUNC_NAME s_scm_make_weak_value_alist_vector
135 return scm_i_allocate_weak_vector
136 (2, SCM_UNBNDP (size
) ? scm_from_int (31) : size
, SCM_EOL
);
141 SCM_DEFINE (scm_make_doubly_weak_alist_vector
, "make-doubly-weak-alist-vector", 1, 0, 0,
143 "Return a hash table with weak keys and values with @var{size}\n"
144 "buckets. (@pxref{Hash Tables})")
145 #define FUNC_NAME s_scm_make_doubly_weak_alist_vector
147 return scm_i_allocate_weak_vector
148 (3, SCM_UNBNDP (size
) ? scm_from_int (31) : size
, SCM_EOL
);
153 SCM_DEFINE (scm_weak_key_alist_vector_p
, "weak-key-alist-vector?", 1, 0, 0,
155 "@deffnx {Scheme Procedure} weak-value-alist-vector? obj\n"
156 "@deffnx {Scheme Procedure} doubly-weak-alist-vector? obj\n"
157 "Return @code{#t} if @var{obj} is the specified weak hash\n"
158 "table. Note that a doubly weak hash table is neither a weak key\n"
159 "nor a weak value hash table.")
160 #define FUNC_NAME s_scm_weak_key_alist_vector_p
162 return scm_from_bool (SCM_I_WVECTP (obj
) && SCM_IS_WHVEC (obj
));
167 SCM_DEFINE (scm_weak_value_alist_vector_p
, "weak-value-alist-vector?", 1, 0, 0,
169 "Return @code{#t} if @var{obj} is a weak value hash table.")
170 #define FUNC_NAME s_scm_weak_value_alist_vector_p
172 return scm_from_bool (SCM_I_WVECTP (obj
) && SCM_IS_WHVEC_V (obj
));
177 SCM_DEFINE (scm_doubly_weak_alist_vector_p
, "doubly-weak-alist-vector?", 1, 0, 0,
179 "Return @code{#t} if @var{obj} is a doubly weak hash table.")
180 #define FUNC_NAME s_scm_doubly_weak_alist_vector_p
182 return scm_from_bool (SCM_I_WVECTP (obj
) && SCM_IS_WHVEC_B (obj
));
186 #define UNMARKED_CELL_P(x) (SCM_NIMP(x) && !SCM_GC_MARK_P (x))
188 static SCM weak_vectors
;
191 scm_i_init_weak_vectors_for_gc ()
193 weak_vectors
= SCM_EOL
;
197 scm_i_mark_weak_vector (SCM w
)
199 SCM_I_SET_WVECT_GC_CHAIN (w
, weak_vectors
);
204 scm_i_mark_weak_vector_non_weaks (SCM w
)
208 if (SCM_IS_WHVEC_ANY (w
))
211 long n
= SCM_I_WVECT_LENGTH (w
);
213 int weak_keys
= SCM_IS_WHVEC (w
) || SCM_IS_WHVEC_B (w
);
214 int weak_values
= SCM_IS_WHVEC_V (w
) || SCM_IS_WHVEC_B (w
);
216 ptr
= SCM_I_WVECT_GC_WVELTS (w
);
218 for (j
= 0; j
< n
; ++j
)
220 SCM alist
, slow_alist
;
223 /* We do not set the mark bits of the alist spine cells here
224 since we do not want to ever create the situation where a
225 marked cell references an unmarked cell (except in
226 scm_gc_mark, where the referenced cells will be marked
227 immediately). Thus, we can not use mark bits to stop us
228 from looping indefinitely over a cyclic alist. Instead,
229 we use the standard tortoise and hare trick to catch
230 cycles. The fast walker does the work, and stops when it
231 catches the slow walker to ensure that the whole cycle
235 alist
= slow_alist
= ptr
[j
];
237 while (scm_is_pair (alist
))
239 SCM elt
= SCM_CAR (alist
);
241 if (UNMARKED_CELL_P (elt
))
243 if (scm_is_pair (elt
))
245 SCM key
= SCM_CAR (elt
);
246 SCM value
= SCM_CDR (elt
);
248 if (!((weak_keys
&& UNMARKED_CELL_P (key
))
249 || (weak_values
&& UNMARKED_CELL_P (value
))))
251 /* The item should be kept. We need to mark it
260 /* A non-pair cell element. This should not
261 appear in a real alist, but when it does, we
269 alist
= SCM_CDR (alist
);
271 if (slow_toggle
&& scm_is_pair (slow_alist
))
273 slow_alist
= SCM_CDR (slow_alist
);
274 slow_toggle
= !slow_toggle
;
275 if (scm_is_eq (slow_alist
, alist
))
279 if (!scm_is_pair (alist
))
288 scm_i_mark_weak_vectors_non_weaks ()
291 SCM w
= weak_vectors
;
292 while (!scm_is_null (w
))
294 if (scm_i_mark_weak_vector_non_weaks (w
))
296 w
= SCM_I_WVECT_GC_CHAIN (w
);
302 scm_i_remove_weaks (SCM w
)
304 SCM
*ptr
= SCM_I_WVECT_GC_WVELTS (w
);
305 size_t n
= SCM_I_WVECT_LENGTH (w
);
308 if (!SCM_IS_WHVEC_ANY (w
))
310 for (i
= 0; i
< n
; ++i
)
311 if (UNMARKED_CELL_P (ptr
[i
]))
318 for (i
= 0; i
< n
; ++i
)
324 while (scm_is_pair (alist
) && !SCM_GC_MARK_P (alist
))
326 if (UNMARKED_CELL_P (SCM_CAR (alist
)))
328 *fixup
= SCM_CDR (alist
);
333 SCM_SET_GC_MARK (alist
);
334 fixup
= SCM_CDRLOC (alist
);
341 fprintf (stderr
, "vector %p, delta %d\n", w
, delta
);
343 SCM_I_SET_WVECT_DELTA (w
, delta
);
348 scm_i_remove_weaks_from_weak_vectors ()
350 SCM w
= weak_vectors
;
351 while (!scm_is_null (w
))
353 scm_i_remove_weaks (w
);
354 w
= SCM_I_WVECT_GC_CHAIN (w
);
361 scm_init_weaks_builtins ()
363 #include "libguile/weaks.x"
364 return SCM_UNSPECIFIED
;
370 scm_c_define_gsubr ("%init-weaks-builtins", 0, 0, 0,
371 scm_init_weaks_builtins
);