* eq.c (s_scm_eqv_p): scm_i_bigcomp -> scm_i_bigcmp.
[bpt/guile.git] / libguile / struct.c
CommitLineData
53af8255 1/* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84 41
0f2d19dd 42\f
a6f7f57d
RB
43#if HAVE_CONFIG_H
44# include <config.h>
45#endif
0f2d19dd 46
a0599745
MD
47#include "libguile/_scm.h"
48#include "libguile/chars.h"
49#include "libguile/eval.h"
50#include "libguile/alist.h"
51#include "libguile/weaks.h"
52#include "libguile/hashtab.h"
53#include "libguile/ports.h"
54#include "libguile/strings.h"
55
56#include "libguile/validate.h"
57#include "libguile/struct.h"
0f2d19dd 58
95b88819
GH
59#ifdef HAVE_STRING_H
60#include <string.h>
61#endif
62
0f2d19dd
JB
63\f
64
65static SCM required_vtable_fields = SCM_BOOL_F;
98d5f601 66SCM scm_struct_table;
0f2d19dd
JB
67
68\f
a1ec6916 69SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
1bbd0b84 70 (SCM fields),
b380b885 71 "Return a new structure layout object.\n\n"
7c31152f 72 "@var{fields} must be a string made up of pairs of characters\n"
b380b885
MD
73 "strung together. The first character of each pair describes a field\n"
74 "type, the second a field protection. Allowed types are 'p' for\n"
75 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
04323af4 76 "a field that points to the structure itself. Allowed protections\n"
9401323e 77 "are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque\n"
b380b885
MD
78 "fields. The last field protection specification may be capitalized to\n"
79 "indicate that the field is a tail-array.")
1bbd0b84 80#define FUNC_NAME s_scm_make_struct_layout
0f2d19dd
JB
81{
82 SCM new_sym;
d1ca2c64 83 SCM_VALIDATE_STRING (1, fields);
2ade72d7 84
1bbd0b84 85 { /* scope */
0f2d19dd 86 char * field_desc;
1be6b49c 87 size_t len;
0f2d19dd
JB
88 int x;
89
d1ca2c64 90 len = SCM_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
34f0f2b8 95 field_desc = SCM_STRING_CHARS (fields);
0f2d19dd
JB
96
97 for (x = 0; x < len; x += 2)
98 {
99 switch (field_desc[x])
100 {
101 case 'u':
102 case 'p':
103#if 0
104 case 'i':
105 case 'd':
106#endif
107 case 's':
108 break;
109 default:
2ade72d7 110 SCM_MISC_ERROR ("unrecognized field type: ~S",
1afff620 111 scm_list_1 (SCM_MAKE_CHAR (field_desc[x])));
0f2d19dd
JB
112 }
113
114 switch (field_desc[x + 1])
115 {
116 case 'w':
2ade72d7
DH
117 if (field_desc[x] == 's')
118 SCM_MISC_ERROR ("self fields not writable", SCM_EOL);
0f2d19dd
JB
119 case 'r':
120 case 'o':
121 break;
2c36c351
MD
122 case 'R':
123 case 'W':
124 case 'O':
2ade72d7
DH
125 if (field_desc[x] == 's')
126 SCM_MISC_ERROR ("self fields not allowed in tail array",
127 SCM_EOL);
128 if (x != len - 2)
129 SCM_MISC_ERROR ("tail array field must be last field in layout",
130 SCM_EOL);
2c36c351 131 break;
0f2d19dd 132 default:
2ade72d7 133 SCM_MISC_ERROR ("unrecognized ref specification: ~S",
1afff620 134 scm_list_1 (SCM_MAKE_CHAR (field_desc[x + 1])));
0f2d19dd
JB
135 }
136#if 0
137 if (field_desc[x] == 'd')
138 {
2ade72d7
DH
139 if (field_desc[x + 2] != '-')
140 SCM_MISC_ERROR ("missing dash field at position ~A",
1afff620 141 scm_list_1 (SCM_MAKINUM (x / 2)));
0f2d19dd
JB
142 x += 2;
143 goto recheck_ref;
144 }
145#endif
146 }
38ae064c 147 new_sym = scm_mem2symbol (field_desc, len);
0f2d19dd
JB
148 }
149 return scm_return_first (new_sym, fields);
150}
1bbd0b84 151#undef FUNC_NAME
0f2d19dd
JB
152
153\f
154
155
1cc91f1b 156
f7620510 157static void
92c2555f 158scm_struct_init (SCM handle, SCM layout, scm_t_bits * mem, int tail_elts, SCM inits)
0f2d19dd 159{
a002f1a2 160 unsigned char * fields_desc = (unsigned char *) SCM_SYMBOL_CHARS (layout) - 2;
35de7ebe 161 unsigned char prot = 0;
bfa974f0 162 int n_fields = SCM_SYMBOL_LENGTH (layout) / 2;
2c36c351 163 int tailp = 0;
d8c40b9f 164
0f2d19dd
JB
165 while (n_fields)
166 {
2c36c351
MD
167 if (!tailp)
168 {
169 fields_desc += 2;
170 prot = fields_desc[1];
171 if (SCM_LAYOUT_TAILP (prot))
172 {
173 tailp = 1;
174 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
d8c40b9f 175 *mem++ = tail_elts;
2c36c351
MD
176 n_fields += tail_elts - 1;
177 if (n_fields == 0)
178 break;
179 }
180 }
181
0f2d19dd
JB
182 switch (*fields_desc)
183 {
184#if 0
185 case 'i':
2c36c351 186 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
187 *mem = 0;
188 else
189 {
a5bfe84d 190 *mem = scm_num2long (SCM_CAR (inits), SCM_ARGn, "scm_struct_init");
0f2d19dd
JB
191 inits = SCM_CDR (inits);
192 }
193 break;
194#endif
195
196 case 'u':
54778cd3 197 if ((prot != 'r' && prot != 'w') || SCM_NULLP (inits))
0f2d19dd
JB
198 *mem = 0;
199 else
200 {
d8c40b9f
DH
201 *mem = scm_num2ulong (SCM_CAR (inits),
202 SCM_ARGn,
203 "scm_struct_init");
0f2d19dd
JB
204 inits = SCM_CDR (inits);
205 }
206 break;
207
208 case 'p':
54778cd3 209 if ((prot != 'r' && prot != 'w') || SCM_NULLP (inits))
d8c40b9f 210 *mem = SCM_UNPACK (SCM_BOOL_F);
0f2d19dd
JB
211 else
212 {
d8c40b9f 213 *mem = SCM_UNPACK (SCM_CAR (inits));
0f2d19dd
JB
214 inits = SCM_CDR (inits);
215 }
216
217 break;
218
219#if 0
220 case 'd':
2c36c351 221 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
222 *((double *)mem) = 0.0;
223 else
224 {
a5bfe84d 225 *mem = scm_num2dbl (SCM_CAR (inits), "scm_struct_init");
0f2d19dd
JB
226 inits = SCM_CDR (inits);
227 }
228 fields_desc += 2;
229 break;
230#endif
231
232 case 's':
d8c40b9f 233 *mem = SCM_UNPACK (handle);
0f2d19dd
JB
234 break;
235 }
236
0f2d19dd
JB
237 n_fields--;
238 mem++;
239 }
240}
241
242
a1ec6916 243SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
1bbd0b84 244 (SCM x),
0233bfc1 245 "Return @code{#t} iff @var{x} is a structure object, else\n"
942e5b91 246 "@code{#f}.")
1bbd0b84 247#define FUNC_NAME s_scm_struct_p
0f2d19dd 248{
0c95b57d 249 return SCM_BOOL(SCM_STRUCTP (x));
0f2d19dd 250}
1bbd0b84 251#undef FUNC_NAME
0f2d19dd 252
a1ec6916 253SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
1bbd0b84 254 (SCM x),
0233bfc1 255 "Return @code{#t} iff @var{x} is a vtable structure.")
1bbd0b84 256#define FUNC_NAME s_scm_struct_vtable_p
0f2d19dd
JB
257{
258 SCM layout;
92c2555f 259 scm_t_bits * mem;
0f2d19dd
JB
260
261 if (!SCM_STRUCTP (x))
262 return SCM_BOOL_F;
263
264 layout = SCM_STRUCT_LAYOUT (x);
265
bfa974f0 266 if (SCM_SYMBOL_LENGTH (layout) < SCM_STRING_LENGTH (required_vtable_fields))
0f2d19dd
JB
267 return SCM_BOOL_F;
268
a002f1a2 269 if (strncmp (SCM_SYMBOL_CHARS (layout), SCM_STRING_CHARS (required_vtable_fields),
bfa974f0 270 SCM_STRING_LENGTH (required_vtable_fields)))
0f2d19dd
JB
271 return SCM_BOOL_F;
272
273 mem = SCM_STRUCT_DATA (x);
274
6902384e 275 return SCM_BOOL (SCM_SYMBOLP (SCM_PACK (mem[scm_vtable_index_layout])));
0f2d19dd 276}
1bbd0b84 277#undef FUNC_NAME
0f2d19dd 278
14d1400f
JB
279
280/* All struct data must be allocated at an address whose bottom three
281 bits are zero. This is because the tag for a struct lives in the
282 bottom three bits of the struct's car, and the upper bits point to
283 the data of its vtable, which is a struct itself. Thus, if the
284 address of that data doesn't end in three zeros, tagging it will
285 destroy the pointer.
286
287 This function allocates a block of memory, and returns a pointer at
288 least scm_struct_n_extra_words words into the block. Furthermore,
289 it guarantees that that pointer's least three significant bits are
290 all zero.
291
292 The argument n_words should be the number of words that should
293 appear after the returned address. (That is, it shouldn't include
294 scm_struct_n_extra_words.)
295
296 This function initializes the following fields of the struct:
297
ad196599 298 scm_struct_i_ptr --- the actual start of the block of memory; the
14d1400f
JB
299 address you should pass to 'free' to dispose of the block.
300 This field allows us to both guarantee that the returned
301 address is divisible by eight, and allow the GC to free the
302 block.
303
304 scm_struct_i_n_words --- the number of words allocated to the
305 block, including the extra fields. This is used by the GC.
306
14d1400f
JB
307 Ugh. */
308
309
92c2555f 310scm_t_bits *
4c9419ac 311scm_alloc_struct (int n_words, int n_extra, const char *what)
14d1400f 312{
92c2555f 313 int size = sizeof (scm_t_bits) * (n_words + n_extra) + 7;
4c9419ac 314 void * block = scm_gc_malloc (size, what);
14d1400f
JB
315
316 /* Adjust the pointer to hide the extra words. */
92c2555f 317 scm_t_bits * p = (scm_t_bits *) block + n_extra;
14d1400f
JB
318
319 /* Adjust it even further so it's aligned on an eight-byte boundary. */
92c2555f 320 p = (scm_t_bits *) (((scm_t_bits) p + 7) & ~7);
14d1400f 321
ad196599 322 /* Initialize a few fields as described above. */
92c2555f
MV
323 p[scm_struct_i_free] = (scm_t_bits) scm_struct_free_standard;
324 p[scm_struct_i_ptr] = (scm_t_bits) block;
c8045e8d 325 p[scm_struct_i_n_words] = n_words;
ad196599 326 p[scm_struct_i_flags] = 0;
14d1400f
JB
327
328 return p;
329}
330
4c9419ac 331void
92c2555f
MV
332scm_struct_free_0 (scm_t_bits * vtable SCM_UNUSED,
333 scm_t_bits * data SCM_UNUSED)
ad196599 334{
ad196599
MD
335}
336
4c9419ac 337void
92c2555f 338scm_struct_free_light (scm_t_bits * vtable, scm_t_bits * data)
ad196599 339{
4c9419ac
MV
340 size_t n = vtable [scm_struct_i_size] & ~SCM_STRUCTF_MASK;
341 scm_gc_free (data, n, "struct");
ad196599
MD
342}
343
4c9419ac 344void
92c2555f 345scm_struct_free_standard (scm_t_bits * vtable SCM_UNUSED, scm_t_bits * data)
ad196599 346{
c8045e8d 347 size_t n = (data[scm_struct_i_n_words] + scm_struct_n_extra_words)
92c2555f 348 * sizeof (scm_t_bits) + 7;
4c9419ac 349 scm_gc_free ((void *) data[scm_struct_i_ptr], n, "heavy struct");
ad196599
MD
350}
351
4c9419ac 352void
92c2555f 353scm_struct_free_entity (scm_t_bits * vtable SCM_UNUSED, scm_t_bits * data)
ad196599 354{
c8045e8d 355 size_t n = (data[scm_struct_i_n_words] + scm_struct_entity_n_extra_words)
92c2555f 356 * sizeof (scm_t_bits) + 7;
4c9419ac 357 scm_gc_free ((void *) data[scm_struct_i_ptr], n, "entity struct");
ad196599 358}
14d1400f 359
b4a1358c
MD
360static void *
361scm_struct_gc_init (void *dummy1 SCM_UNUSED,
362 void *dummy2 SCM_UNUSED,
363 void *dummy3 SCM_UNUSED)
364{
365 scm_i_structs_to_free = SCM_EOL;
366 return 0;
367}
368
08c880a3 369static void *
e81d98ec
DH
370scm_free_structs (void *dummy1 SCM_UNUSED,
371 void *dummy2 SCM_UNUSED,
372 void *dummy3 SCM_UNUSED)
08c880a3 373{
ffd72400 374 SCM newchain = scm_i_structs_to_free;
08c880a3
MD
375 do
376 {
377 /* Mark vtables in GC chain. GC mark set means delay freeing. */
378 SCM chain = newchain;
1a551638 379 while (!SCM_NULLP (chain))
08c880a3
MD
380 {
381 SCM vtable = SCM_STRUCT_VTABLE (chain);
382 if (SCM_STRUCT_GC_CHAIN (vtable) != 0 && vtable != chain)
c8a1bdc4 383 SCM_SET_GC_MARK (vtable);
08c880a3
MD
384 chain = SCM_STRUCT_GC_CHAIN (chain);
385 }
386 /* Free unmarked structs. */
387 chain = newchain;
388 newchain = SCM_EOL;
1a551638 389 while (!SCM_NULLP (chain))
08c880a3
MD
390 {
391 SCM obj = chain;
392 chain = SCM_STRUCT_GC_CHAIN (chain);
c8a1bdc4 393 if (SCM_GC_MARK_P (obj))
08c880a3 394 {
c8a1bdc4 395 SCM_CLEAR_GC_MARK (obj);
08c880a3
MD
396 SCM_SET_STRUCT_GC_CHAIN (obj, newchain);
397 newchain = obj;
398 }
399 else
400 {
904a077d
MV
401 /* XXX - use less explicit code. */
402 scm_t_bits word0 = SCM_CELL_WORD_0 (obj) - scm_tc3_struct;
92c2555f
MV
403 scm_t_bits * vtable_data = (scm_t_bits *) word0;
404 scm_t_bits * data = SCM_STRUCT_DATA (obj);
405 scm_t_struct_free free_struct_data
406 = ((scm_t_struct_free) vtable_data[scm_struct_i_free]);
08c880a3
MD
407 SCM_SET_CELL_TYPE (obj, scm_tc_free_cell);
408 free_struct_data (vtable_data, data);
409 }
410 }
411 }
1a551638 412 while (!SCM_NULLP (newchain));
08c880a3
MD
413 return 0;
414}
415
a1ec6916 416SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
1bbd0b84 417 (SCM vtable, SCM tail_array_size, SCM init),
b380b885 418 "Create a new structure.\n\n"
1bee0e70 419 "@var{type} must be a vtable structure (@pxref{Vtables}).\n\n"
b380b885
MD
420 "@var{tail-elts} must be a non-negative integer. If the layout\n"
421 "specification indicated by @var{type} includes a tail-array,\n"
422 "this is the number of elements allocated to that array.\n\n"
6386e25c 423 "The @var{init1}, @dots{} are optional arguments describing how\n"
04323af4
MD
424 "successive fields of the structure should be initialized. Only fields\n"
425 "with protection 'r' or 'w' can be initialized, except for fields of\n"
426 "type 's', which are automatically initialized to point to the new\n"
427 "structure itself; fields with protection 'o' can not be initialized by\n"
428 "Scheme programs.\n\n"
429 "If fewer optional arguments than initializable fields are supplied,\n"
430 "fields of type 'p' get default value #f while fields of type 'u' are\n"
431 "initialized to 0.\n\n"
432 "Structs are currently the basic representation for record-like data\n"
433 "structures in Guile. The plan is to eventually replace them with a\n"
434 "new representation which will at the same time be easier to use and\n"
435 "more powerful.\n\n"
6386e25c 436 "For more information, see the documentation for @code{make-vtable-vtable}.")
1bbd0b84 437#define FUNC_NAME s_scm_make_struct
0f2d19dd
JB
438{
439 SCM layout;
440 int basic_size;
441 int tail_elts;
92c2555f 442 scm_t_bits * data;
0f2d19dd
JB
443 SCM handle;
444
34d19ef6
HWN
445 SCM_VALIDATE_VTABLE (1, vtable);
446 SCM_VALIDATE_INUM (2, tail_array_size);
af45e3b0 447 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 448
d8c40b9f 449 layout = SCM_PACK (SCM_STRUCT_DATA (vtable) [scm_vtable_index_layout]);
bfa974f0 450 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 451 tail_elts = SCM_INUM (tail_array_size);
0f2d19dd 452 SCM_DEFER_INTS;
d8c40b9f 453 if (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
a5bfe84d
MD
454 {
455 data = scm_alloc_struct (basic_size + tail_elts,
98d5f601 456 scm_struct_entity_n_extra_words,
4c9419ac 457 "entity struct");
c8045e8d
DH
458 data[scm_struct_i_procedure] = SCM_UNPACK (SCM_BOOL_F);
459 data[scm_struct_i_setter] = SCM_UNPACK (SCM_BOOL_F);
a5bfe84d
MD
460 }
461 else
462 data = scm_alloc_struct (basic_size + tail_elts,
463 scm_struct_n_extra_words,
4c9419ac 464 "struct");
228a24ef
DH
465 handle = scm_double_cell ((((scm_t_bits) SCM_STRUCT_DATA (vtable))
466 + scm_tc3_struct),
467 (scm_t_bits) data, 0, 0);
f7620510 468 scm_struct_init (handle, layout, data, tail_elts, init);
0f2d19dd
JB
469 SCM_ALLOW_INTS;
470 return handle;
471}
1bbd0b84 472#undef FUNC_NAME
0f2d19dd
JB
473
474
475
a1ec6916 476SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
04323af4 477 (SCM user_fields, SCM tail_array_size, SCM init),
b380b885 478 "Return a new, self-describing vtable structure.\n\n"
04323af4
MD
479 "@var{user-fields} is a string describing user defined fields of the\n"
480 "vtable beginning at index @code{vtable-offset-user}\n"
481 "(see @code{make-struct-layout}).\n\n"
b380b885
MD
482 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
483 "this vtable.\n\n"
6386e25c 484 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
04323af4
MD
485 "the vtable.\n\n"
486 "Vtables have one initializable system field---the struct printer.\n"
487 "This field comes before the user fields in the initializers passed\n"
488 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
489 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
490 "@code{make-struct} when creating vtables:\n\n"
491 "If the value is a procedure, it will be called instead of the standard\n"
492 "printer whenever a struct described by this vtable is printed.\n"
493 "The procedure will be called with arguments STRUCT and PORT.\n\n"
494 "The structure of a struct is described by a vtable, so the vtable is\n"
495 "in essence the type of the struct. The vtable is itself a struct with\n"
496 "a vtable. This could go on forever if it weren't for the\n"
29b4f9fb 497 "vtable-vtables which are self-describing vtables, and thus terminate\n"
04323af4
MD
498 "the chain.\n\n"
499 "There are several potential ways of using structs, but the standard\n"
500 "one is to use three kinds of structs, together building up a type\n"
501 "sub-system: one vtable-vtable working as the root and one or several\n"
502 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
29b4f9fb 503 "compared to the class <class> which is the class of itself.)\n\n"
1e6808ea 504 "@lisp\n"
04323af4
MD
505 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
506 "(define (make-ball-type ball-color)\n"
507 " (make-struct ball-root 0\n"
508 " (make-struct-layout \"pw\")\n"
509 " (lambda (ball port)\n"
510 " (format port \"#<a ~A ball owned by ~A>\"\n"
511 " (color ball)\n"
512 " (owner ball)))\n"
513 " ball-color))\n"
514 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
515 "(define (owner ball) (struct-ref ball 0))\n\n"
516 "(define red (make-ball-type 'red))\n"
517 "(define green (make-ball-type 'green))\n\n"
518 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
519 "(define ball (make-ball green 'Nisse))\n"
520 "ball @result{} #<a green ball owned by Nisse>\n"
9401323e 521 "@end lisp")
1bbd0b84 522#define FUNC_NAME s_scm_make_vtable_vtable
0f2d19dd
JB
523{
524 SCM fields;
525 SCM layout;
526 int basic_size;
527 int tail_elts;
92c2555f 528 scm_t_bits * data;
0f2d19dd
JB
529 SCM handle;
530
d1ca2c64 531 SCM_VALIDATE_STRING (1, user_fields);
04323af4 532 SCM_VALIDATE_INUM (2, tail_array_size);
af45e3b0 533 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 534
1afff620
KN
535 fields = scm_string_append (scm_list_2 (required_vtable_fields,
536 user_fields));
0f2d19dd 537 layout = scm_make_struct_layout (fields);
bfa974f0 538 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 539 tail_elts = SCM_INUM (tail_array_size);
0f2d19dd 540 SCM_DEFER_INTS;
a5bfe84d
MD
541 data = scm_alloc_struct (basic_size + tail_elts,
542 scm_struct_n_extra_words,
4c9419ac 543 "struct");
228a24ef
DH
544 handle = scm_double_cell ((scm_t_bits) data + scm_tc3_struct,
545 (scm_t_bits) data, 0, 0);
f7620510
DH
546 data [scm_vtable_index_layout] = SCM_UNPACK (layout);
547 scm_struct_init (handle, layout, data, tail_elts, scm_cons (layout, init));
0f2d19dd
JB
548 SCM_ALLOW_INTS;
549 return handle;
550}
1bbd0b84 551#undef FUNC_NAME
0f2d19dd
JB
552
553\f
554
555
a1ec6916 556SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
1bbd0b84 557 (SCM handle, SCM pos),
8f85c0c6 558 "@deffnx {Scheme Procedure} struct-set! struct n value\n"
b380b885
MD
559 "Access (or modify) the @var{n}th field of @var{struct}.\n\n"
560 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
561 "If the field is of type 'u', then it can only be set to a non-negative\n"
562 "integer value small enough to fit in one machine word.")
1bbd0b84 563#define FUNC_NAME s_scm_struct_ref
0f2d19dd 564{
5e840c2e 565 SCM answer = SCM_UNDEFINED;
92c2555f 566 scm_t_bits * data;
0f2d19dd
JB
567 SCM layout;
568 int p;
92c2555f 569 scm_t_bits n_fields;
e51fe79c
DH
570 char * fields_desc;
571 char field_type = 0;
0f2d19dd
JB
572
573
34d19ef6
HWN
574 SCM_VALIDATE_STRUCT (1, handle);
575 SCM_VALIDATE_INUM (2, pos);
0f2d19dd
JB
576
577 layout = SCM_STRUCT_LAYOUT (handle);
578 data = SCM_STRUCT_DATA (handle);
579 p = SCM_INUM (pos);
580
e51fe79c 581 fields_desc = SCM_SYMBOL_CHARS (layout);
d8c40b9f 582 n_fields = data[scm_struct_i_n_words];
2c36c351 583
34d19ef6 584 SCM_ASSERT_RANGE(1, pos, p < n_fields);
0f2d19dd 585
bfa974f0 586 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351 587 {
e51fe79c 588 char ref;
2c36c351
MD
589 field_type = fields_desc[p * 2];
590 ref = fields_desc[p * 2 + 1];
591 if ((ref != 'r') && (ref != 'w'))
592 {
593 if ((ref == 'R') || (ref == 'W'))
594 field_type = 'u';
595 else
1afff620 596 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
2c36c351
MD
597 }
598 }
bfa974f0
DH
599 else if (fields_desc[SCM_SYMBOL_LENGTH (layout) - 1] != 'O')
600 field_type = fields_desc[SCM_SYMBOL_LENGTH (layout) - 2];
2c36c351 601 else
1afff620 602 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
2c36c351 603
0f2d19dd
JB
604 switch (field_type)
605 {
606 case 'u':
d8c40b9f 607 answer = scm_ulong2num (data[p]);
0f2d19dd
JB
608 break;
609
610#if 0
611 case 'i':
612 answer = scm_long2num (data[p]);
613 break;
614
615 case 'd':
f8de44c1 616 answer = scm_make_real (*((double *)&(data[p])));
0f2d19dd
JB
617 break;
618#endif
619
620 case 's':
621 case 'p':
d8c40b9f 622 answer = SCM_PACK (data[p]);
0f2d19dd
JB
623 break;
624
625
626 default:
2ade72d7 627 SCM_MISC_ERROR ("unrecognized field type: ~S",
1afff620 628 scm_list_1 (SCM_MAKE_CHAR (field_type)));
0f2d19dd
JB
629 }
630
631 return answer;
632}
1bbd0b84 633#undef FUNC_NAME
0f2d19dd
JB
634
635
a1ec6916 636SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
1bbd0b84 637 (SCM handle, SCM pos, SCM val),
e3239868
DH
638 "Set the slot of the structure @var{handle} with index @var{pos}\n"
639 "to @var{val}. Signal an error if the slot can not be written\n"
640 "to.")
1bbd0b84 641#define FUNC_NAME s_scm_struct_set_x
0f2d19dd 642{
92c2555f 643 scm_t_bits * data;
0f2d19dd
JB
644 SCM layout;
645 int p;
646 int n_fields;
e51fe79c
DH
647 char * fields_desc;
648 char field_type = 0;
0f2d19dd 649
34d19ef6
HWN
650 SCM_VALIDATE_STRUCT (1, handle);
651 SCM_VALIDATE_INUM (2, pos);
0f2d19dd
JB
652
653 layout = SCM_STRUCT_LAYOUT (handle);
654 data = SCM_STRUCT_DATA (handle);
655 p = SCM_INUM (pos);
656
e51fe79c 657 fields_desc = SCM_SYMBOL_CHARS (layout);
d8c40b9f 658 n_fields = data[scm_struct_i_n_words];
0f2d19dd 659
34d19ef6 660 SCM_ASSERT_RANGE (1, pos, p < n_fields);
0f2d19dd 661
bfa974f0 662 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351 663 {
e51fe79c 664 char set_x;
2c36c351
MD
665 field_type = fields_desc[p * 2];
666 set_x = fields_desc [p * 2 + 1];
667 if (set_x != 'w')
1afff620 668 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
2c36c351 669 }
bfa974f0
DH
670 else if (fields_desc[SCM_SYMBOL_LENGTH (layout) - 1] == 'W')
671 field_type = fields_desc[SCM_SYMBOL_LENGTH (layout) - 2];
2c36c351 672 else
1afff620 673 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
2c36c351 674
0f2d19dd
JB
675 switch (field_type)
676 {
677 case 'u':
d8c40b9f 678 data[p] = SCM_NUM2ULONG (3, val);
0f2d19dd
JB
679 break;
680
681#if 0
682 case 'i':
e4b265d8 683 data[p] = SCM_NUM2LONG (3, val);
0f2d19dd
JB
684 break;
685
686 case 'd':
687 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
688 break;
689#endif
690
691 case 'p':
d8c40b9f 692 data[p] = SCM_UNPACK (val);
0f2d19dd
JB
693 break;
694
695 case 's':
2ade72d7 696 SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
0f2d19dd
JB
697
698 default:
2ade72d7 699 SCM_MISC_ERROR ("unrecognized field type: ~S",
1afff620 700 scm_list_1 (SCM_MAKE_CHAR (field_type)));
0f2d19dd
JB
701 }
702
703 return val;
704}
1bbd0b84 705#undef FUNC_NAME
0f2d19dd
JB
706
707
a1ec6916 708SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 709 (SCM handle),
b380b885 710 "Return the vtable structure that describes the type of @var{struct}.")
1bbd0b84 711#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 712{
34d19ef6 713 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd
JB
714 return SCM_STRUCT_VTABLE (handle);
715}
1bbd0b84 716#undef FUNC_NAME
0f2d19dd
JB
717
718
a1ec6916 719SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 720 (SCM handle),
e3239868 721 "Return the vtable tag of the structure @var{handle}.")
1bbd0b84 722#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 723{
34d19ef6 724 SCM_VALIDATE_VTABLE (1, handle);
ad196599 725 return scm_long2num ((long) SCM_STRUCT_DATA (handle) >> 3);
98d5f601 726}
1bbd0b84 727#undef FUNC_NAME
98d5f601
MD
728
729/* {Associating names and classes with vtables}
730 *
731 * The name of a vtable should probably be stored as a slot. This is
732 * a backward compatible solution until agreement has been achieved on
733 * how to associate names with vtables.
734 */
735
c014a02e
ML
736unsigned long
737scm_struct_ihashq (SCM obj, unsigned long n)
98d5f601 738{
ad196599
MD
739 /* The length of the hash table should be a relative prime it's not
740 necessary to shift down the address. */
f1267706 741 return SCM_UNPACK (obj) % n;
98d5f601
MD
742}
743
744SCM
745scm_struct_create_handle (SCM obj)
746{
747 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
748 obj,
749 SCM_BOOL_F,
750 scm_struct_ihashq,
751 scm_sloppy_assq,
752 0);
753 if (SCM_FALSEP (SCM_CDR (handle)))
754 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
755 return handle;
756}
757
a1ec6916 758SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 759 (SCM vtable),
e3239868 760 "Return the name of the vtable @var{vtable}.")
1bbd0b84 761#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 762{
34d19ef6 763 SCM_VALIDATE_VTABLE (1, vtable);
98d5f601
MD
764 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
765}
1bbd0b84 766#undef FUNC_NAME
98d5f601 767
a1ec6916 768SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 769 (SCM vtable, SCM name),
e3239868 770 "Set the name of the vtable @var{vtable} to @var{name}.")
1bbd0b84 771#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 772{
34d19ef6
HWN
773 SCM_VALIDATE_VTABLE (1, vtable);
774 SCM_VALIDATE_SYMBOL (2, name);
98d5f601
MD
775 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
776 name);
777 return SCM_UNSPECIFIED;
0f2d19dd 778}
1bbd0b84 779#undef FUNC_NAME
0f2d19dd
JB
780
781
782\f
783
bafcafb2 784void
1bbd0b84 785scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 786{
4bfdf158
MD
787 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
788 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
789 else
bafcafb2 790 {
a1ae1799
MD
791 SCM vtable = SCM_STRUCT_VTABLE (exp);
792 SCM name = scm_struct_vtable_name (vtable);
793 scm_puts ("#<", port);
794 if (SCM_NFALSEP (name))
795 scm_display (name, port);
796 else
797 scm_puts ("struct", port);
798 scm_putc (' ', port);
54778cd3 799 scm_intprint (SCM_UNPACK (vtable), 16, port);
b7f3516f 800 scm_putc (':', port);
54778cd3 801 scm_intprint (SCM_UNPACK (exp), 16, port);
b7f3516f 802 scm_putc ('>', port);
bafcafb2 803 }
bafcafb2 804}
1cc91f1b 805
08c880a3
MD
806void
807scm_struct_prehistory ()
808{
ea5c9285 809 scm_i_structs_to_free = SCM_EOL;
b4a1358c 810 scm_c_hook_add (&scm_before_sweep_c_hook, scm_struct_gc_init, 0, 0);
53af8255
MD
811 /* With the new lazy sweep GC, the point at which the entire heap is
812 swept is just before the mark phase. */
813 scm_c_hook_add (&scm_before_mark_c_hook, scm_free_structs, 0, 0);
08c880a3
MD
814}
815
0f2d19dd
JB
816void
817scm_init_struct ()
0f2d19dd 818{
98d5f601
MD
819 scm_struct_table
820 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
6902384e 821 required_vtable_fields = scm_makfrom0str ("prsrpw");
0f2d19dd 822 scm_permanent_object (required_vtable_fields);
86d31dfe
MV
823 scm_c_define ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout));
824 scm_c_define ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable));
825 scm_c_define ("vtable-index-printer",
826 SCM_MAKINUM (scm_vtable_index_printer));
827 scm_c_define ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user));
a0599745 828#include "libguile/struct.x"
0f2d19dd 829}
89e00824
ML
830
831/*
832 Local Variables:
833 c-file-style: "gnu"
834 End:
835*/