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