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