08d570069ecea974e1c8986ec83c624e96b30023
[bpt/guile.git] / libguile / weaks.c
1 /* Copyright (C) 1995,1996,1998,2000,2001 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of this library.
20 *
21 * The exception is that, if you link this library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking this library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by
31 * Free Software Foundation as part of this library. If you copy
32 * code from other releases distributed under the terms of the GPL into a copy of
33 * this library, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from such code.
37 *
38 * If you write modifications of your own for this library, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42
43 \f
44
45 #include "libguile/_scm.h"
46 #include "libguile/vectors.h"
47 #include "libguile/lang.h"
48
49 #include "libguile/validate.h"
50 #include "libguile/weaks.h"
51
52 \f
53
54 /* {Weak Vectors}
55 */
56
57
58 /* Allocate memory for a weak vector on behalf of the caller. The allocated
59 * vector will be of the given weak vector subtype. It will contain size
60 * elements which are initialized with the 'fill' object, or, if 'fill' is
61 * undefined, with an unspecified object.
62 */
63 static SCM
64 allocate_weak_vector (scm_t_bits type, SCM size, SCM fill, const char* caller)
65 #define FUNC_NAME caller
66 {
67 if (SCM_INUMP (size))
68 {
69 size_t c_size;
70 SCM v;
71
72 SCM_ASSERT_RANGE (1, size, SCM_INUM (size) >= 0);
73 c_size = SCM_INUM (size);
74
75 if (c_size > 0)
76 {
77 scm_t_bits *base;
78 size_t j;
79
80 if (SCM_UNBNDP (fill))
81 fill = SCM_UNSPECIFIED;
82
83 SCM_ASSERT_RANGE (1, size, c_size <= SCM_VECTOR_MAX_LENGTH);
84 base = scm_gc_malloc (c_size * sizeof (scm_t_bits), "weak vector");
85 for (j = 0; j != c_size; ++j)
86 base[j] = SCM_UNPACK (fill);
87 v = scm_alloc_double_cell (SCM_MAKE_VECTOR_TAG (c_size,
88 scm_tc7_wvect),
89 (scm_t_bits) base,
90 type,
91 SCM_UNPACK (SCM_EOL));
92 scm_remember_upto_here_1 (fill);
93 }
94 else
95 {
96 v = scm_alloc_double_cell (SCM_MAKE_VECTOR_TAG (0,
97 scm_tc7_wvect),
98 (scm_t_bits) NULL,
99 type,
100 SCM_UNPACK (SCM_EOL));
101 }
102
103 return v;
104 }
105 else if (SCM_BIGP (size))
106 SCM_OUT_OF_RANGE (1, size);
107 else
108 SCM_WRONG_TYPE_ARG (1, size);
109 }
110 #undef FUNC_NAME
111
112
113 SCM_DEFINE (scm_make_weak_vector, "make-weak-vector", 1, 1, 0,
114 (SCM size, SCM fill),
115 "Return a weak vector with @var{size} elements. If the optional\n"
116 "argument @var{fill} is given, all entries in the vector will be\n"
117 "set to @var{fill}. The default value for @var{fill} is the\n"
118 "empty list.")
119 #define FUNC_NAME s_scm_make_weak_vector
120 {
121 return allocate_weak_vector (0, size, fill, FUNC_NAME);
122 }
123 #undef FUNC_NAME
124
125
126 SCM_REGISTER_PROC(s_list_to_weak_vector, "list->weak-vector", 1, 0, 0, scm_weak_vector);
127
128 SCM_DEFINE (scm_weak_vector, "weak-vector", 0, 0, 1,
129 (SCM l),
130 "@deffnx {Scheme Procedure} list->weak-vector l\n"
131 "Construct a weak vector from a list: @code{weak-vector} uses\n"
132 "the list of its arguments while @code{list->weak-vector} uses\n"
133 "its only argument @var{l} (a list) to construct a weak vector\n"
134 "the same way @code{list->vector} would.")
135 #define FUNC_NAME s_scm_weak_vector
136 {
137 SCM res;
138 SCM *data;
139 long i;
140
141 /* Dirk:FIXME:: In case of multiple threads, the list might get corrupted
142 while the vector is being created. */
143 i = scm_ilength (l);
144 SCM_ASSERT (i >= 0, l, SCM_ARG1, FUNC_NAME);
145 res = scm_make_weak_vector (SCM_MAKINUM (i), SCM_UNSPECIFIED);
146 data = SCM_VELTS (res);
147
148 while (!SCM_NULL_OR_NIL_P (l))
149 {
150 *data++ = SCM_CAR (l);
151 l = SCM_CDR (l);
152 }
153
154 return res;
155 }
156 #undef FUNC_NAME
157
158
159 SCM_DEFINE (scm_weak_vector_p, "weak-vector?", 1, 0, 0,
160 (SCM obj),
161 "Return @code{#t} if @var{obj} is a weak vector. Note that all\n"
162 "weak hashes are also weak vectors.")
163 #define FUNC_NAME s_scm_weak_vector_p
164 {
165 return SCM_BOOL (SCM_WVECTP (obj) && !SCM_IS_WHVEC (obj));
166 }
167 #undef FUNC_NAME
168
169 \f
170
171 SCM_DEFINE (scm_make_weak_key_hash_table, "make-weak-key-hash-table", 1, 0, 0,
172 (SCM size),
173 "@deffnx {Scheme Procedure} make-weak-value-hash-table size\n"
174 "@deffnx {Scheme Procedure} make-doubly-weak-hash-table size\n"
175 "Return a weak hash table with @var{size} buckets. As with any\n"
176 "hash table, choosing a good size for the table requires some\n"
177 "caution.\n"
178 "\n"
179 "You can modify weak hash tables in exactly the same way you\n"
180 "would modify regular hash tables. (@pxref{Hash Tables})")
181 #define FUNC_NAME s_scm_make_weak_key_hash_table
182 {
183 return allocate_weak_vector (1, size, SCM_EOL, FUNC_NAME);
184 }
185 #undef FUNC_NAME
186
187
188 SCM_DEFINE (scm_make_weak_value_hash_table, "make-weak-value-hash-table", 1, 0, 0,
189 (SCM size),
190 "Return a hash table with weak values with @var{size} buckets.\n"
191 "(@pxref{Hash Tables})")
192 #define FUNC_NAME s_scm_make_weak_value_hash_table
193 {
194 return allocate_weak_vector (2, size, SCM_EOL, FUNC_NAME);
195 }
196 #undef FUNC_NAME
197
198
199 SCM_DEFINE (scm_make_doubly_weak_hash_table, "make-doubly-weak-hash-table", 1, 0, 0,
200 (SCM size),
201 "Return a hash table with weak keys and values with @var{size}\n"
202 "buckets. (@pxref{Hash Tables})")
203 #define FUNC_NAME s_scm_make_doubly_weak_hash_table
204 {
205 return allocate_weak_vector (3, size, SCM_EOL, FUNC_NAME);
206 }
207 #undef FUNC_NAME
208
209
210 SCM_DEFINE (scm_weak_key_hash_table_p, "weak-key-hash-table?", 1, 0, 0,
211 (SCM obj),
212 "@deffnx {Scheme Procedure} weak-value-hash-table? obj\n"
213 "@deffnx {Scheme Procedure} doubly-weak-hash-table? obj\n"
214 "Return @code{#t} if @var{obj} is the specified weak hash\n"
215 "table. Note that a doubly weak hash table is neither a weak key\n"
216 "nor a weak value hash table.")
217 #define FUNC_NAME s_scm_weak_key_hash_table_p
218 {
219 return SCM_BOOL (SCM_WVECTP (obj) && SCM_IS_WHVEC (obj));
220 }
221 #undef FUNC_NAME
222
223
224 SCM_DEFINE (scm_weak_value_hash_table_p, "weak-value-hash-table?", 1, 0, 0,
225 (SCM obj),
226 "Return @code{#t} if @var{obj} is a weak value hash table.")
227 #define FUNC_NAME s_scm_weak_value_hash_table_p
228 {
229 return SCM_BOOL (SCM_WVECTP (obj) && SCM_IS_WHVEC_V (obj));
230 }
231 #undef FUNC_NAME
232
233
234 SCM_DEFINE (scm_doubly_weak_hash_table_p, "doubly-weak-hash-table?", 1, 0, 0,
235 (SCM obj),
236 "Return @code{#t} if @var{obj} is a doubly weak hash table.")
237 #define FUNC_NAME s_scm_doubly_weak_hash_table_p
238 {
239 return SCM_BOOL (SCM_WVECTP (obj) && SCM_IS_WHVEC_B (obj));
240 }
241 #undef FUNC_NAME
242
243
244 static void *
245 scm_weak_vector_gc_init (void *dummy1 SCM_UNUSED,
246 void *dummy2 SCM_UNUSED,
247 void *dummy3 SCM_UNUSED)
248 {
249 scm_weak_vectors = SCM_EOL;
250
251 return 0;
252 }
253
254
255 static void *
256 scm_mark_weak_vector_spines (void *dummy1 SCM_UNUSED,
257 void *dummy2 SCM_UNUSED,
258 void *dummy3 SCM_UNUSED)
259 {
260 SCM w;
261
262 for (w = scm_weak_vectors; !SCM_NULLP (w); w = SCM_WVECT_GC_CHAIN (w))
263 {
264 if (SCM_IS_WHVEC_ANY (w))
265 {
266 SCM *ptr;
267 SCM obj;
268 long j;
269 long n;
270
271 obj = w;
272 ptr = SCM_VELTS (w);
273 n = SCM_VECTOR_LENGTH (w);
274 for (j = 0; j < n; ++j)
275 {
276 SCM alist;
277
278 alist = ptr[j];
279 while ( SCM_CONSP (alist)
280 && !SCM_GCMARKP (alist)
281 && SCM_CONSP (SCM_CAR (alist)))
282 {
283 SCM_SETGCMARK (alist);
284 SCM_SETGCMARK (SCM_CAR (alist));
285 alist = SCM_CDR (alist);
286 }
287 }
288 }
289 }
290
291 return 0;
292 }
293
294
295 static void *
296 scm_scan_weak_vectors (void *dummy1 SCM_UNUSED,
297 void *dummy2 SCM_UNUSED,
298 void *dummy3 SCM_UNUSED)
299 {
300 SCM *ptr, w;
301 for (w = scm_weak_vectors; !SCM_NULLP (w); w = SCM_WVECT_GC_CHAIN (w))
302 {
303 if (!SCM_IS_WHVEC_ANY (w))
304 {
305 register long j, n;
306
307 ptr = SCM_VELTS (w);
308 n = SCM_VECTOR_LENGTH (w);
309 for (j = 0; j < n; ++j)
310 if (SCM_FREE_CELL_P (ptr[j]))
311 ptr[j] = SCM_BOOL_F;
312 }
313 else /* if (SCM_IS_WHVEC_ANY (scm_weak_vectors[i])) */
314 {
315 SCM obj = w;
316 register long n = SCM_VECTOR_LENGTH (w);
317 register long j;
318 int weak_keys = SCM_IS_WHVEC (obj) || SCM_IS_WHVEC_B (obj);
319 int weak_values = SCM_IS_WHVEC_V (obj) || SCM_IS_WHVEC_B (obj);
320
321 ptr = SCM_VELTS (w);
322
323 for (j = 0; j < n; ++j)
324 {
325 SCM * fixup;
326 SCM alist;
327
328 fixup = ptr + j;
329 alist = *fixup;
330
331 while ( SCM_CONSP (alist)
332 && SCM_CONSP (SCM_CAR (alist)))
333 {
334 SCM key;
335 SCM value;
336
337 key = SCM_CAAR (alist);
338 value = SCM_CDAR (alist);
339 if ( (weak_keys && SCM_FREE_CELL_P (key))
340 || (weak_values && SCM_FREE_CELL_P (value)))
341 {
342 *fixup = SCM_CDR (alist);
343 }
344 else
345 fixup = SCM_CDRLOC (alist);
346 alist = SCM_CDR (alist);
347 }
348 }
349 }
350 }
351
352 return 0;
353 }
354
355 \f
356
357 void
358 scm_weaks_prehistory ()
359 {
360 scm_c_hook_add (&scm_before_mark_c_hook, scm_weak_vector_gc_init, 0, 0);
361 scm_c_hook_add (&scm_before_sweep_c_hook, scm_mark_weak_vector_spines, 0, 0);
362 scm_c_hook_add (&scm_after_sweep_c_hook, scm_scan_weak_vectors, 0, 0);
363 }
364
365
366 void
367 scm_init_weaks ()
368 {
369 #ifndef SCM_MAGIC_SNARFER
370 #include "libguile/weaks.x"
371 #endif
372 }
373
374
375 /*
376 Local Variables:
377 c-file-style: "gnu"
378 End:
379 */