set struct names for <standard-vtable>, etc
[bpt/guile.git] / libguile / struct.c
1 /* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 \f
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <alloca.h>
25 #include <assert.h>
26
27 #define SCM_BUILDING_DEPRECATED_CODE
28
29 #include "libguile/_scm.h"
30 #include "libguile/async.h"
31 #include "libguile/chars.h"
32 #include "libguile/eval.h"
33 #include "libguile/alist.h"
34 #include "libguile/weaks.h"
35 #include "libguile/hashtab.h"
36 #include "libguile/ports.h"
37 #include "libguile/strings.h"
38 #include "libguile/srfi-13.h"
39
40 #include "libguile/validate.h"
41 #include "libguile/struct.h"
42
43 #include "libguile/eq.h"
44
45 #ifdef HAVE_STRING_H
46 #include <string.h>
47 #endif
48
49 #include "libguile/bdw-gc.h"
50
51 \f
52
53 /* A needlessly obscure test. */
54 #define SCM_LAYOUT_TAILP(X) (((X) & 32) == 0) /* R, W or O */
55
56 static SCM required_vtable_fields = SCM_BOOL_F;
57 static SCM required_applicable_fields = SCM_BOOL_F;
58 static SCM required_applicable_with_setter_fields = SCM_BOOL_F;
59 SCM scm_applicable_struct_vtable_vtable;
60 SCM scm_applicable_struct_with_setter_vtable_vtable;
61 SCM scm_standard_vtable_vtable;
62
63
64 \f
65 SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
66 (SCM fields),
67 "Return a new structure layout object.\n\n"
68 "@var{fields} must be a string made up of pairs of characters\n"
69 "strung together. The first character of each pair describes a field\n"
70 "type, the second a field protection. Allowed types are 'p' for\n"
71 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
72 "a field that points to the structure itself. Allowed protections\n"
73 "are 'w' for mutable fields, 'h' for hidden fields, 'r' for read-only\n"
74 "fields, and 'o' for opaque fields.\n\n"
75 "Hidden fields are writable, but they will not consume an initializer arg\n"
76 "passed to @code{make-struct}. They are useful to add slots to a struct\n"
77 "in a way that preserves backward-compatibility with existing calls to\n"
78 "@code{make-struct}, especially for derived vtables.\n\n"
79 "The last field protection specification may be capitalized to indicate\n"
80 "that the field is a tail-array.")
81 #define FUNC_NAME s_scm_make_struct_layout
82 {
83 SCM new_sym;
84 scm_t_wchar c;
85
86 SCM_VALIDATE_STRING (1, fields);
87
88 { /* scope */
89 size_t len;
90 int x;
91
92 len = scm_i_string_length (fields);
93 if (len % 2 == 1)
94 SCM_MISC_ERROR ("odd length field specification: ~S",
95 scm_list_1 (fields));
96
97 for (x = 0; x < len; x += 2)
98 {
99 switch (c = scm_i_string_ref (fields, x))
100 {
101 case 'u':
102 case 'p':
103 #if 0
104 case 'i':
105 case 'd':
106 #endif
107 case 's':
108 break;
109 default:
110 SCM_MISC_ERROR ("unrecognized field type: ~S",
111 scm_list_1 (SCM_MAKE_CHAR (c)));
112 }
113
114 switch (c = scm_i_string_ref (fields, x + 1))
115 {
116 case 'w':
117 case 'h':
118 if (scm_i_string_ref (fields, x) == 's')
119 SCM_MISC_ERROR ("self fields not writable", SCM_EOL);
120 case 'r':
121 case 'o':
122 break;
123 case 'R':
124 case 'W':
125 case 'O':
126 if (scm_i_string_ref (fields, x) == 's')
127 SCM_MISC_ERROR ("self fields not allowed in tail array",
128 SCM_EOL);
129 if (x != len - 2)
130 SCM_MISC_ERROR ("tail array field must be last field in layout",
131 SCM_EOL);
132 break;
133 default:
134 SCM_MISC_ERROR ("unrecognized ref specification: ~S",
135 scm_list_1 (SCM_MAKE_CHAR (c)));
136 }
137 #if 0
138 if (scm_i_string_ref (fields, x, 'd'))
139 {
140 if (!scm_i_string_ref (fields, x+2, '-'))
141 SCM_MISC_ERROR ("missing dash field at position ~A",
142 scm_list_1 (scm_from_int (x / 2)));
143 x += 2;
144 goto recheck_ref;
145 }
146 #endif
147 }
148 new_sym = scm_string_to_symbol (fields);
149 }
150 scm_remember_upto_here_1 (fields);
151 return new_sym;
152 }
153 #undef FUNC_NAME
154
155 \f
156 /* Check whether VTABLE instances have a simple layout (i.e., either only "pr"
157 or only "pw" fields) and update its flags accordingly. */
158 static void
159 set_vtable_layout_flags (SCM vtable)
160 {
161 size_t len, field;
162 SCM layout;
163 const char *c_layout;
164 scm_t_bits flags = SCM_VTABLE_FLAG_SIMPLE;
165
166 layout = SCM_VTABLE_LAYOUT (vtable);
167 c_layout = scm_i_symbol_chars (layout);
168 len = scm_i_symbol_length (layout);
169
170 assert (len % 2 == 0);
171
172 /* Update FLAGS according to LAYOUT. */
173 for (field = 0;
174 field < len && flags & SCM_VTABLE_FLAG_SIMPLE;
175 field += 2)
176 {
177 if (c_layout[field] != 'p')
178 flags = 0;
179 else
180 switch (c_layout[field + 1])
181 {
182 case 'w':
183 case 'W':
184 if (field == 0)
185 flags |= SCM_VTABLE_FLAG_SIMPLE_RW;
186 break;
187
188 case 'r':
189 case 'R':
190 flags &= ~SCM_VTABLE_FLAG_SIMPLE_RW;
191 break;
192
193 default:
194 flags = 0;
195 }
196 }
197
198 if (flags & SCM_VTABLE_FLAG_SIMPLE)
199 {
200 /* VTABLE is simple so update its flags and record the size of its
201 instances. */
202 SCM_SET_VTABLE_FLAGS (vtable, flags);
203 SCM_STRUCT_DATA_SET (vtable, scm_vtable_index_size, len / 2);
204 }
205 }
206
207 static int
208 scm_is_valid_vtable_layout (SCM layout)
209 {
210 size_t len, n;
211 const char *c_layout;
212
213 c_layout = scm_i_symbol_chars (layout);
214 len = scm_i_symbol_length (layout);
215
216 if (len % 2)
217 return 0;
218
219 for (n = 0; n < len; n += 2)
220 switch (c_layout[n])
221 {
222 case 'u':
223 case 'p':
224 case 's':
225 switch (c_layout[n+1])
226 {
227 case 'W':
228 case 'R':
229 case 'O':
230 if (n + 2 != len)
231 return 0;
232 case 'w':
233 case 'h':
234 case 'r':
235 case 'o':
236 break;
237 default:
238 return 0;
239 }
240 break;
241 default:
242 return 0;
243 }
244 return 1;
245 }
246
247 /* Have OBJ, a newly created vtable, inherit flags from VTABLE. VTABLE is a
248 vtable-vtable and OBJ is an instance of VTABLE. */
249 void
250 scm_i_struct_inherit_vtable_magic (SCM vtable, SCM obj)
251 #define FUNC_NAME "%inherit-vtable-magic"
252 {
253 /* Verily, what is the deal here, you ask? Basically, we need to know a couple
254 of properties of structures at runtime. For example, "is this structure a
255 vtable of vtables (a metaclass)?"; also, "is this structure applicable?".
256 Both of these questions also imply a certain layout of the structure. So
257 instead of checking the layout at runtime, what we do is pre-verify the
258 layout -- so that at runtime we can just check the applicable flag and
259 dispatch directly to the Scheme procedure in slot 0. */
260 SCM olayout;
261
262 /* Verify that OBJ is a valid vtable. */
263 if (! scm_is_valid_vtable_layout (SCM_VTABLE_LAYOUT (obj)))
264 SCM_MISC_ERROR ("invalid layout for new vtable: ~a",
265 scm_list_1 (SCM_VTABLE_LAYOUT (obj)));
266
267 set_vtable_layout_flags (obj);
268
269 /* If OBJ's vtable is compatible with the required vtable (class) layout, it
270 is a metaclass. */
271 olayout = scm_symbol_to_string (SCM_VTABLE_LAYOUT (obj));
272 if (scm_is_true (scm_leq_p (scm_string_length (required_vtable_fields),
273 scm_string_length (olayout)))
274 && scm_is_true (scm_string_eq (olayout, required_vtable_fields,
275 scm_from_size_t (0),
276 scm_string_length (required_vtable_fields),
277 scm_from_size_t (0),
278 scm_string_length (required_vtable_fields))))
279 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VTABLE);
280
281 /* Finally, if OBJ is an applicable class, verify that its vtable is
282 compatible with the required applicable layout. */
283 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SETTER_VTABLE))
284 {
285 if (scm_is_false (scm_string_eq (olayout, required_applicable_with_setter_fields,
286 scm_from_size_t (0),
287 scm_from_size_t (4),
288 scm_from_size_t (0),
289 scm_from_size_t (4))))
290 SCM_MISC_ERROR ("invalid applicable-with-setter struct layout",
291 scm_list_1 (olayout));
292 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE | SCM_VTABLE_FLAG_SETTER);
293 }
294 else if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_APPLICABLE_VTABLE))
295 {
296 if (scm_is_false (scm_string_eq (olayout, required_applicable_fields,
297 scm_from_size_t (0),
298 scm_from_size_t (2),
299 scm_from_size_t (0),
300 scm_from_size_t (2))))
301 SCM_MISC_ERROR ("invalid applicable struct layout",
302 scm_list_1 (olayout));
303 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE);
304 }
305
306 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VALIDATED);
307 }
308 #undef FUNC_NAME
309
310
311 static void
312 scm_struct_init (SCM handle, SCM layout, size_t n_tail,
313 size_t n_inits, scm_t_bits *inits)
314 {
315 SCM vtable;
316 scm_t_bits *mem;
317
318 vtable = SCM_STRUCT_VTABLE (handle);
319 mem = SCM_STRUCT_DATA (handle);
320
321 if (SCM_UNPACK (vtable) != 0
322 && SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
323 && n_tail == 0
324 && n_inits == SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size))
325 /* The fast path: HANDLE has N_INITS "p" fields. */
326 memcpy (mem, inits, n_inits * sizeof (SCM));
327 else
328 {
329 scm_t_wchar prot = 0;
330 int n_fields = scm_i_symbol_length (layout) / 2;
331 int tailp = 0;
332 int i;
333 size_t inits_idx = 0;
334
335 i = -2;
336 while (n_fields)
337 {
338 if (!tailp)
339 {
340 i += 2;
341 prot = scm_i_symbol_ref (layout, i+1);
342 if (SCM_LAYOUT_TAILP (prot))
343 {
344 tailp = 1;
345 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
346 *mem++ = (scm_t_bits)n_tail;
347 n_fields += n_tail - 1;
348 if (n_fields == 0)
349 break;
350 }
351 }
352 switch (scm_i_symbol_ref (layout, i))
353 {
354 case 'u':
355 if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
356 *mem = 0;
357 else
358 {
359 *mem = scm_to_ulong (SCM_PACK (inits[inits_idx]));
360 inits_idx++;
361 }
362 break;
363
364 case 'p':
365 if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
366 *mem = SCM_UNPACK (SCM_BOOL_F);
367 else
368 {
369 *mem = inits[inits_idx];
370 inits_idx++;
371 }
372
373 break;
374
375 case 's':
376 *mem = SCM_UNPACK (handle);
377 break;
378 }
379
380 n_fields--;
381 mem++;
382 }
383 }
384 }
385
386
387 SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
388 (SCM x),
389 "Return @code{#t} iff @var{x} is a structure object, else\n"
390 "@code{#f}.")
391 #define FUNC_NAME s_scm_struct_p
392 {
393 return scm_from_bool(SCM_STRUCTP (x));
394 }
395 #undef FUNC_NAME
396
397 SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
398 (SCM x),
399 "Return @code{#t} iff @var{x} is a vtable structure.")
400 #define FUNC_NAME s_scm_struct_vtable_p
401 {
402 if (!SCM_STRUCTP (x)
403 || !SCM_STRUCT_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VTABLE))
404 return SCM_BOOL_F;
405 if (!SCM_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VALIDATED))
406 SCM_MISC_ERROR ("vtable has invalid layout: ~A",
407 scm_list_1 (SCM_VTABLE_LAYOUT (x)));
408 return SCM_BOOL_T;
409 }
410 #undef FUNC_NAME
411
412
413 /* Finalization: invoke the finalizer of the struct pointed to by PTR. */
414 static void
415 struct_finalizer_trampoline (void *ptr, void *unused_data)
416 {
417 SCM obj = PTR2SCM (ptr);
418 scm_t_struct_finalize finalize = SCM_STRUCT_FINALIZER (obj);
419
420 if (finalize)
421 finalize (obj);
422 }
423
424 /* All struct data must be allocated at an address whose bottom three
425 bits are zero. This is because the tag for a struct lives in the
426 bottom three bits of the struct's car, and the upper bits point to
427 the data of its vtable, which is a struct itself. Thus, if the
428 address of that data doesn't end in three zeros, tagging it will
429 destroy the pointer.
430
431 I suppose we should make it clear here that, the data must be 8-byte aligned,
432 *within* the struct, and the struct itself should be 8-byte aligned. In
433 practice we ensure this because the data starts two words into a struct.
434
435 This function allocates an 8-byte aligned block of memory, whose first word
436 points to the given vtable data, then a data pointer, then n_words of data.
437 */
438 SCM
439 scm_i_alloc_struct (scm_t_bits *vtable_data, int n_words)
440 {
441 SCM ret;
442
443 ret = scm_words ((scm_t_bits)vtable_data | scm_tc3_struct, n_words + 2);
444 SCM_SET_CELL_WORD_1 (ret, (scm_t_bits)SCM_CELL_OBJECT_LOC (ret, 2));
445
446 /* vtable_data can be null when making a vtable vtable */
447 if (vtable_data && vtable_data[scm_vtable_index_instance_finalize])
448 /* Register a finalizer for the newly created instance. */
449 scm_i_set_finalizer (SCM2PTR (ret), struct_finalizer_trampoline, NULL);
450
451 return ret;
452 }
453
454 \f
455 SCM
456 scm_c_make_structv (SCM vtable, size_t n_tail, size_t n_init, scm_t_bits *init)
457 #define FUNC_NAME "make-struct"
458 {
459 SCM layout;
460 size_t basic_size;
461 SCM obj;
462
463 SCM_VALIDATE_VTABLE (1, vtable);
464
465 layout = SCM_VTABLE_LAYOUT (vtable);
466 basic_size = scm_i_symbol_length (layout) / 2;
467
468 if (n_tail != 0)
469 {
470 SCM layout_str, last_char;
471
472 if (basic_size == 0)
473 {
474 bad_tail:
475 SCM_MISC_ERROR ("tail array not allowed unless layout ends R, W, or O", SCM_EOL);
476 }
477
478 layout_str = scm_symbol_to_string (layout);
479 last_char = scm_string_ref (layout_str,
480 scm_from_size_t (2 * basic_size - 1));
481 if (! SCM_LAYOUT_TAILP (SCM_CHAR (last_char)))
482 goto bad_tail;
483 }
484
485 obj = scm_i_alloc_struct (SCM_STRUCT_DATA (vtable), basic_size + n_tail);
486
487 scm_struct_init (obj, layout, n_tail, n_init, init);
488
489 /* If we're making a vtable, validate its layout and inherit
490 flags. However we allow for separation of allocation and
491 initialization, to humor GOOPS, so only validate if the layout was
492 passed as an initarg. */
493 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE)
494 && scm_is_true (SCM_VTABLE_LAYOUT (obj)))
495 scm_i_struct_inherit_vtable_magic (vtable, obj);
496
497 return obj;
498 }
499 #undef FUNC_NAME
500
501 SCM
502 scm_c_make_struct (SCM vtable, size_t n_tail, size_t n_init, scm_t_bits init, ...)
503 {
504 va_list foo;
505 scm_t_bits *v;
506 size_t i;
507
508 v = alloca (sizeof (scm_t_bits) * n_init);
509
510 va_start (foo, init);
511 for (i = 0; i < n_init; i++)
512 {
513 v[i] = init;
514 init = va_arg (foo, scm_t_bits);
515 }
516 va_end (foo);
517
518 return scm_c_make_structv (vtable, n_tail, n_init, v);
519 }
520
521 SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
522 (SCM vtable, SCM tail_array_size, SCM init),
523 "Create a new structure.\n\n"
524 "@var{vtable} must be a vtable structure (@pxref{Vtables}).\n\n"
525 "@var{tail_array_size} must be a non-negative integer. If the layout\n"
526 "specification indicated by @var{vtable} includes a tail-array,\n"
527 "this is the number of elements allocated to that array.\n\n"
528 "The @var{init1}, @dots{} are optional arguments describing how\n"
529 "successive fields of the structure should be initialized. Only fields\n"
530 "with protection 'r' or 'w' can be initialized, except for fields of\n"
531 "type 's', which are automatically initialized to point to the new\n"
532 "structure itself. Fields with protection 'o' can not be initialized by\n"
533 "Scheme programs.\n\n"
534 "If fewer optional arguments than initializable fields are supplied,\n"
535 "fields of type 'p' get default value #f while fields of type 'u' are\n"
536 "initialized to 0.\n\n"
537 "For more information, see the documentation for @code{make-vtable-vtable}.")
538 #define FUNC_NAME s_scm_make_struct
539 {
540 size_t i, n_init;
541 long ilen;
542 scm_t_bits *v;
543
544 SCM_VALIDATE_VTABLE (1, vtable);
545 ilen = scm_ilength (init);
546 if (ilen < 0)
547 SCM_MISC_ERROR ("Rest arguments do not form a proper list.", SCM_EOL);
548
549 n_init = (size_t)ilen;
550
551 /* best to use alloca, but init could be big, so hack to avoid a possible
552 stack overflow */
553 if (n_init < 64)
554 v = alloca (n_init * sizeof(scm_t_bits));
555 else
556 v = scm_gc_malloc (n_init * sizeof(scm_t_bits), "struct");
557
558 for (i = 0; i < n_init; i++, init = SCM_CDR (init))
559 v[i] = SCM_UNPACK (SCM_CAR (init));
560
561 return scm_c_make_structv (vtable, scm_to_size_t (tail_array_size), n_init, v);
562 }
563 #undef FUNC_NAME
564
565
566
567 #if SCM_ENABLE_DEPRECATED == 1
568 SCM
569 scm_make_vtable_vtable (SCM user_fields, SCM tail_array_size, SCM init)
570 #define FUNC_NAME "make-vtable-vtable"
571 {
572 SCM fields, layout, obj;
573 size_t basic_size, n_tail, i, n_init;
574 long ilen;
575 scm_t_bits *v;
576
577 SCM_VALIDATE_STRING (1, user_fields);
578 ilen = scm_ilength (init);
579 if (ilen < 0)
580 SCM_MISC_ERROR ("Rest arguments do not form a proper list.", SCM_EOL);
581
582 n_init = (size_t)ilen + 1; /* + 1 for the layout */
583
584 /* best to use alloca, but init could be big, so hack to avoid a possible
585 stack overflow */
586 if (n_init < 64)
587 v = alloca (n_init * sizeof(scm_t_bits));
588 else
589 v = scm_gc_malloc (n_init * sizeof(scm_t_bits), "struct");
590
591 fields = scm_string_append (scm_list_2 (required_vtable_fields,
592 user_fields));
593 layout = scm_make_struct_layout (fields);
594 if (!scm_is_valid_vtable_layout (layout))
595 SCM_MISC_ERROR ("invalid user fields", scm_list_1 (user_fields));
596
597 basic_size = scm_i_symbol_length (layout) / 2;
598 n_tail = scm_to_size_t (tail_array_size);
599
600 i = 0;
601 v[i++] = SCM_UNPACK (layout);
602 for (; i < n_init; i++, init = SCM_CDR (init))
603 v[i] = SCM_UNPACK (SCM_CAR (init));
604
605 SCM_CRITICAL_SECTION_START;
606 obj = scm_i_alloc_struct (NULL, basic_size + n_tail);
607 /* Make it so that the vtable of OBJ is itself. */
608 SCM_SET_CELL_WORD_0 (obj, (scm_t_bits) SCM_STRUCT_DATA (obj) | scm_tc3_struct);
609 SCM_CRITICAL_SECTION_END;
610
611 scm_struct_init (obj, layout, n_tail, n_init, v);
612 SCM_SET_VTABLE_FLAGS (obj,
613 SCM_VTABLE_FLAG_VTABLE | SCM_VTABLE_FLAG_VALIDATED);
614
615 return obj;
616 }
617 #undef FUNC_NAME
618 #endif
619
620 SCM
621 scm_i_make_vtable_vtable (SCM user_fields)
622 #define FUNC_NAME "make-vtable-vtable"
623 {
624 SCM fields, layout, obj;
625 size_t basic_size;
626 scm_t_bits v;
627
628 SCM_VALIDATE_STRING (1, user_fields);
629
630 fields = scm_string_append (scm_list_2 (required_vtable_fields,
631 user_fields));
632 layout = scm_make_struct_layout (fields);
633 if (!scm_is_valid_vtable_layout (layout))
634 SCM_MISC_ERROR ("invalid user fields", scm_list_1 (user_fields));
635
636 basic_size = scm_i_symbol_length (layout) / 2;
637
638 obj = scm_i_alloc_struct (NULL, basic_size);
639 /* Make it so that the vtable of OBJ is itself. */
640 SCM_SET_CELL_WORD_0 (obj, (scm_t_bits) SCM_STRUCT_DATA (obj) | scm_tc3_struct);
641
642 v = SCM_UNPACK (layout);
643 scm_struct_init (obj, layout, 0, 1, &v);
644 SCM_SET_VTABLE_FLAGS (obj,
645 SCM_VTABLE_FLAG_VTABLE | SCM_VTABLE_FLAG_VALIDATED);
646
647 return obj;
648 }
649 #undef FUNC_NAME
650
651 SCM_DEFINE (scm_make_vtable, "make-vtable", 1, 1, 0,
652 (SCM fields, SCM printer),
653 "Create a vtable, for creating structures with the given\n"
654 "@var{fields}.\n"
655 "\n"
656 "The optional @var{printer} argument is a function to be called\n"
657 "@code{(@var{printer} struct port)} on the structures created.\n"
658 "It should look at @var{struct} and write to @var{port}.")
659 #define FUNC_NAME s_scm_make_vtable
660 {
661 if (SCM_UNBNDP (printer))
662 printer = SCM_BOOL_F;
663
664 return scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
665 scm_list_2 (scm_make_struct_layout (fields),
666 printer));
667 }
668 #undef FUNC_NAME
669
670
671 /* Return true if S1 and S2 are equal structures, i.e., if their vtable and
672 contents are the same. Field protections are honored. Thus, it is an
673 error to test the equality of structures that contain opaque fields. */
674 SCM
675 scm_i_struct_equalp (SCM s1, SCM s2)
676 #define FUNC_NAME "scm_i_struct_equalp"
677 {
678 SCM vtable1, vtable2, layout;
679 size_t struct_size, field_num;
680
681 SCM_VALIDATE_STRUCT (1, s1);
682 SCM_VALIDATE_STRUCT (2, s2);
683
684 vtable1 = SCM_STRUCT_VTABLE (s1);
685 vtable2 = SCM_STRUCT_VTABLE (s2);
686
687 if (!scm_is_eq (vtable1, vtable2))
688 return SCM_BOOL_F;
689
690 layout = SCM_STRUCT_LAYOUT (s1);
691 struct_size = scm_i_symbol_length (layout) / 2;
692
693 for (field_num = 0; field_num < struct_size; field_num++)
694 {
695 SCM s_field_num;
696 SCM field1, field2;
697
698 /* We have to use `scm_struct_ref ()' here so that fields are accessed
699 consistently, notably wrt. field types and access rights. */
700 s_field_num = scm_from_size_t (field_num);
701 field1 = scm_struct_ref (s1, s_field_num);
702 field2 = scm_struct_ref (s2, s_field_num);
703
704 /* Self-referencing fields (type `s') must be skipped to avoid infinite
705 recursion. */
706 if (!(scm_is_eq (field1, s1) && (scm_is_eq (field2, s2))))
707 if (scm_is_false (scm_equal_p (field1, field2)))
708 return SCM_BOOL_F;
709 }
710
711 /* FIXME: Tail elements should be tested for equality. */
712
713 return SCM_BOOL_T;
714 }
715 #undef FUNC_NAME
716
717
718 \f
719
720
721 SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
722 (SCM handle, SCM pos),
723 "Access the @var{pos}th field of struct associated with\n"
724 "@var{handle}.\n"
725 "\n"
726 "If the field is of type 'p', then it can be set to an arbitrary\n"
727 "value.\n"
728 "\n"
729 "If the field is of type 'u', then it can only be set to a\n"
730 "non-negative integer value small enough to fit in one machine\n"
731 "word.")
732 #define FUNC_NAME s_scm_struct_ref
733 {
734 SCM vtable, answer = SCM_UNDEFINED;
735 scm_t_bits *data;
736 size_t p;
737
738 SCM_VALIDATE_STRUCT (1, handle);
739
740 vtable = SCM_STRUCT_VTABLE (handle);
741 data = SCM_STRUCT_DATA (handle);
742 p = scm_to_size_t (pos);
743
744 if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
745 && p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
746 /* The fast path: HANDLE is a struct with only "p" fields. */
747 answer = SCM_PACK (data[p]);
748 else
749 {
750 SCM layout;
751 size_t layout_len, n_fields;
752 scm_t_wchar field_type = 0;
753
754 layout = SCM_STRUCT_LAYOUT (handle);
755 layout_len = scm_i_symbol_length (layout);
756 n_fields = layout_len / 2;
757
758 if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
759 n_fields += data[n_fields - 1];
760
761 SCM_ASSERT_RANGE (1, pos, p < n_fields);
762
763 if (p * 2 < layout_len)
764 {
765 scm_t_wchar ref;
766 field_type = scm_i_symbol_ref (layout, p * 2);
767 ref = scm_i_symbol_ref (layout, p * 2 + 1);
768 if ((ref != 'r') && (ref != 'w') && (ref != 'h'))
769 {
770 if ((ref == 'R') || (ref == 'W'))
771 field_type = 'u';
772 else
773 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
774 }
775 }
776 else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
777 field_type = scm_i_symbol_ref(layout, layout_len - 2);
778 else
779 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
780
781 switch (field_type)
782 {
783 case 'u':
784 answer = scm_from_ulong (data[p]);
785 break;
786
787 #if 0
788 case 'i':
789 answer = scm_from_long (data[p]);
790 break;
791
792 case 'd':
793 answer = scm_make_real (*((double *)&(data[p])));
794 break;
795 #endif
796
797 case 's':
798 case 'p':
799 answer = SCM_PACK (data[p]);
800 break;
801
802
803 default:
804 SCM_MISC_ERROR ("unrecognized field type: ~S",
805 scm_list_1 (SCM_MAKE_CHAR (field_type)));
806 }
807 }
808
809 return answer;
810 }
811 #undef FUNC_NAME
812
813
814 SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
815 (SCM handle, SCM pos, SCM val),
816 "Set the slot of the structure @var{handle} with index @var{pos}\n"
817 "to @var{val}. Signal an error if the slot can not be written\n"
818 "to.")
819 #define FUNC_NAME s_scm_struct_set_x
820 {
821 SCM vtable;
822 scm_t_bits *data;
823 size_t p;
824
825 SCM_VALIDATE_STRUCT (1, handle);
826
827 vtable = SCM_STRUCT_VTABLE (handle);
828 data = SCM_STRUCT_DATA (handle);
829 p = scm_to_size_t (pos);
830
831 if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
832 && SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE_RW)
833 && p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
834 /* The fast path: HANDLE is a struct with only "pw" fields. */
835 data[p] = SCM_UNPACK (val);
836 else
837 {
838 SCM layout;
839 size_t layout_len, n_fields;
840 scm_t_wchar field_type = 0;
841
842 layout = SCM_STRUCT_LAYOUT (handle);
843 layout_len = scm_i_symbol_length (layout);
844 n_fields = layout_len / 2;
845
846 if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
847 n_fields += data[n_fields - 1];
848
849 SCM_ASSERT_RANGE (1, pos, p < n_fields);
850
851 if (p * 2 < layout_len)
852 {
853 char set_x;
854 field_type = scm_i_symbol_ref (layout, p * 2);
855 set_x = scm_i_symbol_ref (layout, p * 2 + 1);
856 if (set_x != 'w' && set_x != 'h')
857 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
858 }
859 else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
860 field_type = scm_i_symbol_ref (layout, layout_len - 2);
861 else
862 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
863
864 switch (field_type)
865 {
866 case 'u':
867 data[p] = SCM_NUM2ULONG (3, val);
868 break;
869
870 #if 0
871 case 'i':
872 data[p] = SCM_NUM2LONG (3, val);
873 break;
874
875 case 'd':
876 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
877 break;
878 #endif
879
880 case 'p':
881 data[p] = SCM_UNPACK (val);
882 break;
883
884 case 's':
885 SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
886
887 default:
888 SCM_MISC_ERROR ("unrecognized field type: ~S",
889 scm_list_1 (SCM_MAKE_CHAR (field_type)));
890 }
891 }
892
893 return val;
894 }
895 #undef FUNC_NAME
896
897
898 SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
899 (SCM handle),
900 "Return the vtable structure that describes the type of struct\n"
901 "associated with @var{handle}.")
902 #define FUNC_NAME s_scm_struct_vtable
903 {
904 SCM_VALIDATE_STRUCT (1, handle);
905 return SCM_STRUCT_VTABLE (handle);
906 }
907 #undef FUNC_NAME
908
909
910 /* {Associating names and classes with vtables}
911 *
912 * The name of a vtable should probably be stored as a slot. This is
913 * a backward compatible solution until agreement has been achieved on
914 * how to associate names with vtables.
915 */
916
917 unsigned long
918 scm_struct_ihashq (SCM obj, unsigned long n, void *closure)
919 {
920 /* The length of the hash table should be a relative prime it's not
921 necessary to shift down the address. */
922 return SCM_UNPACK (obj) % n;
923 }
924
925 SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
926 (SCM vtable),
927 "Return the name of the vtable @var{vtable}.")
928 #define FUNC_NAME s_scm_struct_vtable_name
929 {
930 SCM_VALIDATE_VTABLE (1, vtable);
931 return SCM_VTABLE_NAME (vtable);
932 }
933 #undef FUNC_NAME
934
935 SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
936 (SCM vtable, SCM name),
937 "Set the name of the vtable @var{vtable} to @var{name}.")
938 #define FUNC_NAME s_scm_set_struct_vtable_name_x
939 {
940 SCM_VALIDATE_VTABLE (1, vtable);
941 SCM_VALIDATE_SYMBOL (2, name);
942 SCM_SET_VTABLE_NAME (vtable, name);
943 /* FIXME: remove this, and implement proper struct classes instead.
944 (Vtables *are* classes.) */
945 scm_i_define_class_for_vtable (vtable);
946 return SCM_UNSPECIFIED;
947 }
948 #undef FUNC_NAME
949
950
951 \f
952
953 void
954 scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
955 {
956 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
957 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
958 else
959 {
960 SCM vtable = SCM_STRUCT_VTABLE (exp);
961 SCM name = scm_struct_vtable_name (vtable);
962 scm_puts ("#<", port);
963 if (scm_is_true (name))
964 {
965 scm_display (name, port);
966 scm_putc (' ', port);
967 }
968 else
969 {
970 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE))
971 scm_puts ("vtable:", port);
972 else
973 scm_puts ("struct:", port);
974 scm_uintprint (SCM_UNPACK (vtable), 16, port);
975 scm_putc (' ', port);
976 scm_write (SCM_VTABLE_LAYOUT (vtable), port);
977 scm_putc (' ', port);
978 }
979 scm_uintprint (SCM_UNPACK (exp), 16, port);
980 /* hackety hack */
981 if (SCM_STRUCT_APPLICABLE_P (exp))
982 {
983 if (scm_is_true (SCM_STRUCT_PROCEDURE (exp)))
984 {
985 scm_puts (" proc: ", port);
986 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PROCEDURE (exp))))
987 scm_write (SCM_STRUCT_PROCEDURE (exp), port);
988 else
989 scm_puts ("(not a procedure?)", port);
990 }
991 if (SCM_STRUCT_SETTER_P (exp))
992 {
993 scm_puts (" setter: ", port);
994 scm_write (SCM_STRUCT_SETTER (exp), port);
995 }
996 }
997 scm_putc ('>', port);
998 }
999 }
1000
1001 void
1002 scm_init_struct ()
1003 {
1004 SCM name;
1005
1006 /* The first word of a struct is equal to `SCM_STRUCT_DATA (vtable) +
1007 scm_tc3_struct', and `SCM_STRUCT_DATA (vtable)' is 2 words after VTABLE by
1008 default. */
1009 GC_REGISTER_DISPLACEMENT (2 * sizeof (scm_t_bits) + scm_tc3_struct);
1010
1011 /* In the general case, `SCM_STRUCT_DATA (obj)' points 2 words after the
1012 beginning of a GC-allocated region; that region is different from that of
1013 OBJ once OBJ has undergone class redefinition. */
1014 GC_REGISTER_DISPLACEMENT (2 * sizeof (scm_t_bits));
1015
1016 required_vtable_fields = scm_from_locale_string (SCM_VTABLE_BASE_LAYOUT);
1017 scm_c_define ("standard-vtable-fields", required_vtable_fields);
1018 required_applicable_fields = scm_from_locale_string (SCM_APPLICABLE_BASE_LAYOUT);
1019 required_applicable_with_setter_fields = scm_from_locale_string (SCM_APPLICABLE_WITH_SETTER_BASE_LAYOUT);
1020
1021 scm_standard_vtable_vtable = scm_i_make_vtable_vtable (scm_nullstr);
1022 name = scm_from_utf8_symbol ("<standard-vtable>");
1023 scm_set_struct_vtable_name_x (scm_standard_vtable_vtable, name);
1024 scm_define (name, scm_standard_vtable_vtable);
1025
1026 scm_applicable_struct_vtable_vtable =
1027 scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
1028 scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
1029 name = scm_from_utf8_symbol ("<applicable-struct-vtable>");
1030 SCM_SET_VTABLE_FLAGS (scm_applicable_struct_vtable_vtable,
1031 SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
1032 scm_set_struct_vtable_name_x (scm_applicable_struct_vtable_vtable, name);
1033 scm_define (name, scm_applicable_struct_vtable_vtable);
1034
1035 scm_applicable_struct_with_setter_vtable_vtable =
1036 scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
1037 scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
1038 name = scm_from_utf8_symbol ("<applicable-struct-with-setter-vtable>");
1039 scm_set_struct_vtable_name_x (scm_applicable_struct_with_setter_vtable_vtable, name);
1040 SCM_SET_VTABLE_FLAGS (scm_applicable_struct_with_setter_vtable_vtable,
1041 SCM_VTABLE_FLAG_APPLICABLE_VTABLE | SCM_VTABLE_FLAG_SETTER_VTABLE);
1042 scm_define (name, scm_applicable_struct_with_setter_vtable_vtable);
1043
1044 scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
1045 scm_c_define ("vtable-index-printer",
1046 scm_from_int (scm_vtable_index_instance_printer));
1047 scm_c_define ("vtable-offset-user", scm_from_int (scm_vtable_offset_user));
1048 #include "libguile/struct.x"
1049 #if SCM_ENABLE_DEPRECATED
1050 scm_c_define_gsubr ("make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable);
1051 #endif
1052 }
1053
1054 /*
1055 Local Variables:
1056 c-file-style: "gnu"
1057 End:
1058 */