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