* Deprecated macros SCM_ROCHARS and SCM_ROUCHARS.
[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 }
141 new_sym = SCM_CAR (scm_intern_obarray (field_desc, len, SCM_BOOL_F));
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),
b380b885 239 "Return #t iff @var{obj} is a structure object, else #f.")
1bbd0b84 240#define FUNC_NAME s_scm_struct_p
0f2d19dd 241{
0c95b57d 242 return SCM_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),
b380b885 248 "Return #t iff obj is a vtable structure.")
1bbd0b84 249#define FUNC_NAME s_scm_struct_vtable_p
0f2d19dd
JB
250{
251 SCM layout;
d8c40b9f 252 scm_bits_t * mem;
0f2d19dd
JB
253
254 if (!SCM_STRUCTP (x))
255 return SCM_BOOL_F;
256
257 layout = SCM_STRUCT_LAYOUT (x);
258
bfa974f0 259 if (SCM_SYMBOL_LENGTH (layout) < SCM_STRING_LENGTH (required_vtable_fields))
0f2d19dd
JB
260 return SCM_BOOL_F;
261
a002f1a2 262 if (strncmp (SCM_SYMBOL_CHARS (layout), SCM_STRING_CHARS (required_vtable_fields),
bfa974f0 263 SCM_STRING_LENGTH (required_vtable_fields)))
0f2d19dd
JB
264 return SCM_BOOL_F;
265
266 mem = SCM_STRUCT_DATA (x);
267
268 if (mem[1] != 0)
269 return SCM_BOOL_F;
270
d8c40b9f 271 return SCM_BOOL (SCM_SYMBOLP (SCM_PACK (mem[0])));
0f2d19dd 272}
1bbd0b84 273#undef FUNC_NAME
0f2d19dd 274
14d1400f
JB
275
276/* All struct data must be allocated at an address whose bottom three
277 bits are zero. This is because the tag for a struct lives in the
278 bottom three bits of the struct's car, and the upper bits point to
279 the data of its vtable, which is a struct itself. Thus, if the
280 address of that data doesn't end in three zeros, tagging it will
281 destroy the pointer.
282
283 This function allocates a block of memory, and returns a pointer at
284 least scm_struct_n_extra_words words into the block. Furthermore,
285 it guarantees that that pointer's least three significant bits are
286 all zero.
287
288 The argument n_words should be the number of words that should
289 appear after the returned address. (That is, it shouldn't include
290 scm_struct_n_extra_words.)
291
292 This function initializes the following fields of the struct:
293
ad196599 294 scm_struct_i_ptr --- the actual start of the block of memory; the
14d1400f
JB
295 address you should pass to 'free' to dispose of the block.
296 This field allows us to both guarantee that the returned
297 address is divisible by eight, and allow the GC to free the
298 block.
299
300 scm_struct_i_n_words --- the number of words allocated to the
301 block, including the extra fields. This is used by the GC.
302
14d1400f
JB
303 Ugh. */
304
305
c8045e8d 306scm_bits_t *
a5bfe84d 307scm_alloc_struct (int n_words, int n_extra, char *who)
14d1400f 308{
c8045e8d
DH
309 int size = sizeof (scm_bits_t) * (n_words + n_extra) + 7;
310 void * block = scm_must_malloc (size, who);
14d1400f
JB
311
312 /* Adjust the pointer to hide the extra words. */
c8045e8d 313 scm_bits_t * p = (scm_bits_t *) block + n_extra;
14d1400f
JB
314
315 /* Adjust it even further so it's aligned on an eight-byte boundary. */
c8045e8d 316 p = (scm_bits_t *) (((scm_bits_t) p + 7) & ~7);
14d1400f 317
ad196599 318 /* Initialize a few fields as described above. */
c8045e8d
DH
319 p[scm_struct_i_free] = (scm_bits_t) scm_struct_free_standard;
320 p[scm_struct_i_ptr] = (scm_bits_t) block;
321 p[scm_struct_i_n_words] = n_words;
ad196599 322 p[scm_struct_i_flags] = 0;
14d1400f
JB
323
324 return p;
325}
326
97056309 327scm_sizet
c8045e8d 328scm_struct_free_0 (scm_bits_t * vtable, scm_bits_t * data)
ad196599
MD
329{
330 return 0;
331}
332
97056309 333scm_sizet
c8045e8d 334scm_struct_free_light (scm_bits_t * vtable, scm_bits_t * data)
ad196599 335{
cfe66b72 336 scm_must_free (data);
c8045e8d 337 return vtable [scm_struct_i_size] & ~SCM_STRUCTF_MASK;
ad196599
MD
338}
339
97056309 340scm_sizet
c8045e8d 341scm_struct_free_standard (scm_bits_t * vtable, scm_bits_t * data)
ad196599 342{
c8045e8d
DH
343 size_t n = (data[scm_struct_i_n_words] + scm_struct_n_extra_words)
344 * sizeof (scm_bits_t) + 7;
cfe66b72 345 scm_must_free ((void *) data[scm_struct_i_ptr]);
ad196599
MD
346 return n;
347}
348
97056309 349scm_sizet
c8045e8d 350scm_struct_free_entity (scm_bits_t * vtable, scm_bits_t * data)
ad196599 351{
c8045e8d
DH
352 size_t n = (data[scm_struct_i_n_words] + scm_struct_entity_n_extra_words)
353 * sizeof (scm_bits_t) + 7;
cfe66b72 354 scm_must_free ((void *) data[scm_struct_i_ptr]);
ad196599
MD
355 return n;
356}
14d1400f 357
08c880a3
MD
358static void *
359scm_struct_gc_init (void *dummy1, void *dummy2, void *dummy3)
360{
361 scm_structs_to_free = SCM_EOL;
362 return 0;
363}
364
365static void *
366scm_free_structs (void *dummy1, void *dummy2, void *dummy3)
367{
368 SCM newchain = scm_structs_to_free;
369 do
370 {
371 /* Mark vtables in GC chain. GC mark set means delay freeing. */
372 SCM chain = newchain;
373 while (SCM_NNULLP (chain))
374 {
375 SCM vtable = SCM_STRUCT_VTABLE (chain);
376 if (SCM_STRUCT_GC_CHAIN (vtable) != 0 && vtable != chain)
377 SCM_SETGCMARK (vtable);
378 chain = SCM_STRUCT_GC_CHAIN (chain);
379 }
380 /* Free unmarked structs. */
381 chain = newchain;
382 newchain = SCM_EOL;
383 while (SCM_NNULLP (chain))
384 {
385 SCM obj = chain;
386 chain = SCM_STRUCT_GC_CHAIN (chain);
387 if (SCM_GCMARKP (obj))
388 {
389 SCM_CLRGCMARK (obj);
390 SCM_SET_STRUCT_GC_CHAIN (obj, newchain);
391 newchain = obj;
392 }
393 else
394 {
395 scm_bits_t word0 = SCM_CELL_WORD_0 (obj) - scm_tc3_cons_gloc;
396 /* access as struct */
397 scm_bits_t * vtable_data = (scm_bits_t *) word0;
398 scm_bits_t * data = (scm_bits_t *) SCM_UNPACK (SCM_CDR (obj));
399 scm_struct_free_t free_struct_data
400 = ((scm_struct_free_t) vtable_data[scm_struct_i_free]);
401 SCM_SET_CELL_TYPE (obj, scm_tc_free_cell);
402 free_struct_data (vtable_data, data);
403 }
404 }
405 }
406 while (SCM_NNULLP (newchain));
407 return 0;
408}
409
a1ec6916 410SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
1bbd0b84 411 (SCM vtable, SCM tail_array_size, SCM init),
b380b885 412 "Create a new structure.\n\n"
1bee0e70 413 "@var{type} must be a vtable structure (@pxref{Vtables}).\n\n"
b380b885
MD
414 "@var{tail-elts} must be a non-negative integer. If the layout\n"
415 "specification indicated by @var{type} includes a tail-array,\n"
416 "this is the number of elements allocated to that array.\n\n"
6386e25c 417 "The @var{init1}, @dots{} are optional arguments describing how\n"
04323af4
MD
418 "successive fields of the structure should be initialized. Only fields\n"
419 "with protection 'r' or 'w' can be initialized, except for fields of\n"
420 "type 's', which are automatically initialized to point to the new\n"
421 "structure itself; fields with protection 'o' can not be initialized by\n"
422 "Scheme programs.\n\n"
423 "If fewer optional arguments than initializable fields are supplied,\n"
424 "fields of type 'p' get default value #f while fields of type 'u' are\n"
425 "initialized to 0.\n\n"
426 "Structs are currently the basic representation for record-like data\n"
427 "structures in Guile. The plan is to eventually replace them with a\n"
428 "new representation which will at the same time be easier to use and\n"
429 "more powerful.\n\n"
6386e25c 430 "For more information, see the documentation for @code{make-vtable-vtable}.")
1bbd0b84 431#define FUNC_NAME s_scm_make_struct
0f2d19dd
JB
432{
433 SCM layout;
434 int basic_size;
435 int tail_elts;
c8045e8d 436 scm_bits_t * data;
0f2d19dd
JB
437 SCM handle;
438
3b3b36dd
GB
439 SCM_VALIDATE_VTABLE (1,vtable);
440 SCM_VALIDATE_INUM (2,tail_array_size);
af45e3b0 441 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 442
d8c40b9f 443 layout = SCM_PACK (SCM_STRUCT_DATA (vtable) [scm_vtable_index_layout]);
bfa974f0 444 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 445 tail_elts = SCM_INUM (tail_array_size);
08c880a3 446 SCM_NEWCELL2 (handle);
0f2d19dd 447 SCM_DEFER_INTS;
d8c40b9f 448 if (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
a5bfe84d
MD
449 {
450 data = scm_alloc_struct (basic_size + tail_elts,
98d5f601 451 scm_struct_entity_n_extra_words,
a5bfe84d 452 "make-struct");
c8045e8d
DH
453 data[scm_struct_i_procedure] = SCM_UNPACK (SCM_BOOL_F);
454 data[scm_struct_i_setter] = SCM_UNPACK (SCM_BOOL_F);
a5bfe84d
MD
455 }
456 else
457 data = scm_alloc_struct (basic_size + tail_elts,
458 scm_struct_n_extra_words,
459 "make-struct");
54778cd3 460 SCM_SET_CELL_WORD_1 (handle, data);
08c880a3 461 SCM_SET_STRUCT_GC_CHAIN (handle, 0);
f7620510 462 scm_struct_init (handle, layout, data, tail_elts, init);
c8045e8d 463 SCM_SET_CELL_WORD_0 (handle, (scm_bits_t) SCM_STRUCT_DATA (vtable) + scm_tc3_cons_gloc);
0f2d19dd
JB
464 SCM_ALLOW_INTS;
465 return handle;
466}
1bbd0b84 467#undef FUNC_NAME
0f2d19dd
JB
468
469
470
a1ec6916 471SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
04323af4 472 (SCM user_fields, SCM tail_array_size, SCM init),
b380b885 473 "Return a new, self-describing vtable structure.\n\n"
04323af4
MD
474 "@var{user-fields} is a string describing user defined fields of the\n"
475 "vtable beginning at index @code{vtable-offset-user}\n"
476 "(see @code{make-struct-layout}).\n\n"
b380b885
MD
477 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
478 "this vtable.\n\n"
6386e25c 479 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
04323af4
MD
480 "the vtable.\n\n"
481 "Vtables have one initializable system field---the struct printer.\n"
482 "This field comes before the user fields in the initializers passed\n"
483 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
484 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
485 "@code{make-struct} when creating vtables:\n\n"
486 "If the value is a procedure, it will be called instead of the standard\n"
487 "printer whenever a struct described by this vtable is printed.\n"
488 "The procedure will be called with arguments STRUCT and PORT.\n\n"
489 "The structure of a struct is described by a vtable, so the vtable is\n"
490 "in essence the type of the struct. The vtable is itself a struct with\n"
491 "a vtable. This could go on forever if it weren't for the\n"
29b4f9fb 492 "vtable-vtables which are self-describing vtables, and thus terminate\n"
04323af4
MD
493 "the chain.\n\n"
494 "There are several potential ways of using structs, but the standard\n"
495 "one is to use three kinds of structs, together building up a type\n"
496 "sub-system: one vtable-vtable working as the root and one or several\n"
497 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
29b4f9fb 498 "compared to the class <class> which is the class of itself.)\n\n"
b380b885 499 "@example\n"
04323af4
MD
500 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
501 "(define (make-ball-type ball-color)\n"
502 " (make-struct ball-root 0\n"
503 " (make-struct-layout \"pw\")\n"
504 " (lambda (ball port)\n"
505 " (format port \"#<a ~A ball owned by ~A>\"\n"
506 " (color ball)\n"
507 " (owner ball)))\n"
508 " ball-color))\n"
509 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
510 "(define (owner ball) (struct-ref ball 0))\n\n"
511 "(define red (make-ball-type 'red))\n"
512 "(define green (make-ball-type 'green))\n\n"
513 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
514 "(define ball (make-ball green 'Nisse))\n"
515 "ball @result{} #<a green ball owned by Nisse>\n"
b380b885
MD
516 "@end example\n"
517 "")
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;
0f2d19dd 569 unsigned char * fields_desc;
f3667f52 570 unsigned 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
a002f1a2 580 fields_desc = SCM_SYMBOL_UCHARS (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
MD
586 {
587 unsigned char ref;
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),
b380b885 640 "")
1bbd0b84 641#define FUNC_NAME s_scm_struct_set_x
0f2d19dd 642{
d8c40b9f 643 scm_bits_t * data;
0f2d19dd
JB
644 SCM layout;
645 int p;
646 int n_fields;
647 unsigned char * fields_desc;
f3667f52 648 unsigned char field_type = 0;
0f2d19dd 649
3b3b36dd
GB
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
a002f1a2 657 fields_desc = SCM_SYMBOL_UCHARS (layout);
d8c40b9f 658 n_fields = data[scm_struct_i_n_words];
0f2d19dd 659
c751e5e3 660 SCM_ASSERT_RANGE (1,pos, p < n_fields);
0f2d19dd 661
bfa974f0 662 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351
MD
663 {
664 unsigned char set_x;
665 field_type = fields_desc[p * 2];
666 set_x = fields_desc [p * 2 + 1];
667 if (set_x != 'w')
1bbd0b84 668 SCM_ASSERT (0, pos, "set_x denied", FUNC_NAME);
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
MD
672 else
673 {
1bbd0b84 674 SCM_ASSERT (0, pos, "set_x denied", FUNC_NAME);
35de7ebe 675 abort ();
2c36c351
MD
676 }
677
0f2d19dd
JB
678 switch (field_type)
679 {
680 case 'u':
d8c40b9f 681 data[p] = SCM_NUM2ULONG (3, val);
0f2d19dd
JB
682 break;
683
684#if 0
685 case 'i':
1bbd0b84 686 data[p] = SCM_NUM2LONG (3,val);
0f2d19dd
JB
687 break;
688
689 case 'd':
690 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
691 break;
692#endif
693
694 case 'p':
d8c40b9f 695 data[p] = SCM_UNPACK (val);
0f2d19dd
JB
696 break;
697
698 case 's':
7866a09b 699 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "self fields immutable", FUNC_NAME);
0f2d19dd
JB
700 break;
701
702 default:
7866a09b 703 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "unrecognized field type", FUNC_NAME);
0f2d19dd
JB
704 break;
705 }
706
707 return val;
708}
1bbd0b84 709#undef FUNC_NAME
0f2d19dd
JB
710
711
a1ec6916 712SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 713 (SCM handle),
b380b885 714 "Return the vtable structure that describes the type of @var{struct}.")
1bbd0b84 715#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 716{
3b3b36dd 717 SCM_VALIDATE_STRUCT (1,handle);
0f2d19dd
JB
718 return SCM_STRUCT_VTABLE (handle);
719}
1bbd0b84 720#undef FUNC_NAME
0f2d19dd
JB
721
722
a1ec6916 723SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 724 (SCM handle),
b380b885 725 "")
1bbd0b84 726#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 727{
3b3b36dd 728 SCM_VALIDATE_VTABLE (1,handle);
ad196599 729 return scm_long2num ((long) SCM_STRUCT_DATA (handle) >> 3);
98d5f601 730}
1bbd0b84 731#undef FUNC_NAME
98d5f601
MD
732
733/* {Associating names and classes with vtables}
734 *
735 * The name of a vtable should probably be stored as a slot. This is
736 * a backward compatible solution until agreement has been achieved on
737 * how to associate names with vtables.
738 */
739
740unsigned int
741scm_struct_ihashq (SCM obj, unsigned int n)
742{
ad196599
MD
743 /* The length of the hash table should be a relative prime it's not
744 necessary to shift down the address. */
f1267706 745 return SCM_UNPACK (obj) % n;
98d5f601
MD
746}
747
748SCM
749scm_struct_create_handle (SCM obj)
750{
751 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
752 obj,
753 SCM_BOOL_F,
754 scm_struct_ihashq,
755 scm_sloppy_assq,
756 0);
757 if (SCM_FALSEP (SCM_CDR (handle)))
758 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
759 return handle;
760}
761
a1ec6916 762SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 763 (SCM vtable),
b380b885 764 "")
1bbd0b84 765#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 766{
3b3b36dd 767 SCM_VALIDATE_VTABLE (1,vtable);
98d5f601
MD
768 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
769}
1bbd0b84 770#undef FUNC_NAME
98d5f601 771
a1ec6916 772SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 773 (SCM vtable, SCM name),
b380b885 774 "")
1bbd0b84 775#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 776{
3b3b36dd
GB
777 SCM_VALIDATE_VTABLE (1,vtable);
778 SCM_VALIDATE_SYMBOL (2,name);
98d5f601
MD
779 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
780 name);
781 return SCM_UNSPECIFIED;
0f2d19dd 782}
1bbd0b84 783#undef FUNC_NAME
0f2d19dd
JB
784
785
786\f
787
bafcafb2 788void
1bbd0b84 789scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 790{
4bfdf158
MD
791 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
792 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
793 else
bafcafb2 794 {
a1ae1799
MD
795 SCM vtable = SCM_STRUCT_VTABLE (exp);
796 SCM name = scm_struct_vtable_name (vtable);
797 scm_puts ("#<", port);
798 if (SCM_NFALSEP (name))
799 scm_display (name, port);
800 else
801 scm_puts ("struct", port);
802 scm_putc (' ', port);
54778cd3 803 scm_intprint (SCM_UNPACK (vtable), 16, port);
b7f3516f 804 scm_putc (':', port);
54778cd3 805 scm_intprint (SCM_UNPACK (exp), 16, port);
b7f3516f 806 scm_putc ('>', port);
bafcafb2 807 }
bafcafb2 808}
1cc91f1b 809
08c880a3
MD
810void
811scm_struct_prehistory ()
812{
813 scm_c_hook_add (&scm_before_mark_c_hook, scm_struct_gc_init, 0, 0);
814 scm_c_hook_add (&scm_after_sweep_c_hook, scm_free_structs, 0, 0);
815}
816
0f2d19dd
JB
817void
818scm_init_struct ()
0f2d19dd 819{
98d5f601
MD
820 scm_struct_table
821 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
7c31152f 822 required_vtable_fields = scm_makfrom0str ("pruosrpw");
0f2d19dd 823 scm_permanent_object (required_vtable_fields);
4bfdf158
MD
824 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout));
825 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable));
826 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer));
827 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user));
8dc9439f 828#ifndef SCM_MAGIC_SNARFER
a0599745 829#include "libguile/struct.x"
8dc9439f 830#endif
0f2d19dd 831}
89e00824
ML
832
833/*
834 Local Variables:
835 c-file-style: "gnu"
836 End:
837*/