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