* Grammar fix.
[bpt/guile.git] / libguile / struct.c
CommitLineData
2ade72d7 1/* Copyright (C) 1996,1997,1998,1999,2000,2001 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
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"
b380b885
MD
77 "are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque \n"
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",
93 SCM_LIST1 (fields));
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
DH
110 SCM_MISC_ERROR ("unrecognized field type: ~S",
111 SCM_LIST1 (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
DH
133 SCM_MISC_ERROR ("unrecognized ref specification: ~S",
134 SCM_LIST1 (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",
141 SCM_LIST1 (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),
942e5b91
MG
245 "Return @code{#t} iff @var{obj} is a structure object, else\n"
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),
942e5b91 255 "Return @code{#t} iff obj 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
275 if (mem[1] != 0)
276 return SCM_BOOL_F;
277
d8c40b9f 278 return SCM_BOOL (SCM_SYMBOLP (SCM_PACK (mem[0])));
0f2d19dd 279}
1bbd0b84 280#undef FUNC_NAME
0f2d19dd 281
14d1400f
JB
282
283/* All struct data must be allocated at an address whose bottom three
284 bits are zero. This is because the tag for a struct lives in the
285 bottom three bits of the struct's car, and the upper bits point to
286 the data of its vtable, which is a struct itself. Thus, if the
287 address of that data doesn't end in three zeros, tagging it will
288 destroy the pointer.
289
290 This function allocates a block of memory, and returns a pointer at
291 least scm_struct_n_extra_words words into the block. Furthermore,
292 it guarantees that that pointer's least three significant bits are
293 all zero.
294
295 The argument n_words should be the number of words that should
296 appear after the returned address. (That is, it shouldn't include
297 scm_struct_n_extra_words.)
298
299 This function initializes the following fields of the struct:
300
ad196599 301 scm_struct_i_ptr --- the actual start of the block of memory; the
14d1400f
JB
302 address you should pass to 'free' to dispose of the block.
303 This field allows us to both guarantee that the returned
304 address is divisible by eight, and allow the GC to free the
305 block.
306
307 scm_struct_i_n_words --- the number of words allocated to the
308 block, including the extra fields. This is used by the GC.
309
14d1400f
JB
310 Ugh. */
311
312
92c2555f 313scm_t_bits *
a5bfe84d 314scm_alloc_struct (int n_words, int n_extra, char *who)
14d1400f 315{
92c2555f 316 int size = sizeof (scm_t_bits) * (n_words + n_extra) + 7;
c8045e8d 317 void * block = scm_must_malloc (size, who);
14d1400f
JB
318
319 /* Adjust the pointer to hide the extra words. */
92c2555f 320 scm_t_bits * p = (scm_t_bits *) block + n_extra;
14d1400f
JB
321
322 /* Adjust it even further so it's aligned on an eight-byte boundary. */
92c2555f 323 p = (scm_t_bits *) (((scm_t_bits) p + 7) & ~7);
14d1400f 324
ad196599 325 /* Initialize a few fields as described above. */
92c2555f
MV
326 p[scm_struct_i_free] = (scm_t_bits) scm_struct_free_standard;
327 p[scm_struct_i_ptr] = (scm_t_bits) block;
c8045e8d 328 p[scm_struct_i_n_words] = n_words;
ad196599 329 p[scm_struct_i_flags] = 0;
14d1400f
JB
330
331 return p;
332}
333
1be6b49c 334size_t
92c2555f
MV
335scm_struct_free_0 (scm_t_bits * vtable SCM_UNUSED,
336 scm_t_bits * data SCM_UNUSED)
ad196599
MD
337{
338 return 0;
339}
340
1be6b49c 341size_t
92c2555f 342scm_struct_free_light (scm_t_bits * vtable, scm_t_bits * data)
ad196599 343{
cfe66b72 344 scm_must_free (data);
c8045e8d 345 return vtable [scm_struct_i_size] & ~SCM_STRUCTF_MASK;
ad196599
MD
346}
347
1be6b49c 348size_t
92c2555f 349scm_struct_free_standard (scm_t_bits * vtable SCM_UNUSED, scm_t_bits * data)
ad196599 350{
c8045e8d 351 size_t n = (data[scm_struct_i_n_words] + scm_struct_n_extra_words)
92c2555f 352 * sizeof (scm_t_bits) + 7;
cfe66b72 353 scm_must_free ((void *) data[scm_struct_i_ptr]);
ad196599
MD
354 return n;
355}
356
1be6b49c 357size_t
92c2555f 358scm_struct_free_entity (scm_t_bits * vtable SCM_UNUSED, scm_t_bits * data)
ad196599 359{
c8045e8d 360 size_t n = (data[scm_struct_i_n_words] + scm_struct_entity_n_extra_words)
92c2555f 361 * sizeof (scm_t_bits) + 7;
cfe66b72 362 scm_must_free ((void *) data[scm_struct_i_ptr]);
ad196599
MD
363 return n;
364}
14d1400f 365
08c880a3 366static void *
e81d98ec
DH
367scm_struct_gc_init (void *dummy1 SCM_UNUSED,
368 void *dummy2 SCM_UNUSED,
369 void *dummy3 SCM_UNUSED)
08c880a3
MD
370{
371 scm_structs_to_free = SCM_EOL;
372 return 0;
373}
374
375static void *
e81d98ec
DH
376scm_free_structs (void *dummy1 SCM_UNUSED,
377 void *dummy2 SCM_UNUSED,
378 void *dummy3 SCM_UNUSED)
08c880a3
MD
379{
380 SCM newchain = scm_structs_to_free;
381 do
382 {
383 /* Mark vtables in GC chain. GC mark set means delay freeing. */
384 SCM chain = newchain;
1a551638 385 while (!SCM_NULLP (chain))
08c880a3
MD
386 {
387 SCM vtable = SCM_STRUCT_VTABLE (chain);
388 if (SCM_STRUCT_GC_CHAIN (vtable) != 0 && vtable != chain)
389 SCM_SETGCMARK (vtable);
390 chain = SCM_STRUCT_GC_CHAIN (chain);
391 }
392 /* Free unmarked structs. */
393 chain = newchain;
394 newchain = SCM_EOL;
1a551638 395 while (!SCM_NULLP (chain))
08c880a3
MD
396 {
397 SCM obj = chain;
398 chain = SCM_STRUCT_GC_CHAIN (chain);
399 if (SCM_GCMARKP (obj))
400 {
401 SCM_CLRGCMARK (obj);
402 SCM_SET_STRUCT_GC_CHAIN (obj, newchain);
403 newchain = obj;
404 }
405 else
406 {
92c2555f 407 scm_t_bits word0 = SCM_CELL_WORD_0 (obj) - scm_tc3_cons_gloc;
08c880a3 408 /* access as struct */
92c2555f
MV
409 scm_t_bits * vtable_data = (scm_t_bits *) word0;
410 scm_t_bits * data = SCM_STRUCT_DATA (obj);
411 scm_t_struct_free free_struct_data
412 = ((scm_t_struct_free) vtable_data[scm_struct_i_free]);
08c880a3
MD
413 SCM_SET_CELL_TYPE (obj, scm_tc_free_cell);
414 free_struct_data (vtable_data, data);
415 }
416 }
417 }
1a551638 418 while (!SCM_NULLP (newchain));
08c880a3
MD
419 return 0;
420}
421
a1ec6916 422SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
1bbd0b84 423 (SCM vtable, SCM tail_array_size, SCM init),
b380b885 424 "Create a new structure.\n\n"
1bee0e70 425 "@var{type} must be a vtable structure (@pxref{Vtables}).\n\n"
b380b885
MD
426 "@var{tail-elts} must be a non-negative integer. If the layout\n"
427 "specification indicated by @var{type} includes a tail-array,\n"
428 "this is the number of elements allocated to that array.\n\n"
6386e25c 429 "The @var{init1}, @dots{} are optional arguments describing how\n"
04323af4
MD
430 "successive fields of the structure should be initialized. Only fields\n"
431 "with protection 'r' or 'w' can be initialized, except for fields of\n"
432 "type 's', which are automatically initialized to point to the new\n"
433 "structure itself; fields with protection 'o' can not be initialized by\n"
434 "Scheme programs.\n\n"
435 "If fewer optional arguments than initializable fields are supplied,\n"
436 "fields of type 'p' get default value #f while fields of type 'u' are\n"
437 "initialized to 0.\n\n"
438 "Structs are currently the basic representation for record-like data\n"
439 "structures in Guile. The plan is to eventually replace them with a\n"
440 "new representation which will at the same time be easier to use and\n"
441 "more powerful.\n\n"
6386e25c 442 "For more information, see the documentation for @code{make-vtable-vtable}.")
1bbd0b84 443#define FUNC_NAME s_scm_make_struct
0f2d19dd
JB
444{
445 SCM layout;
446 int basic_size;
447 int tail_elts;
92c2555f 448 scm_t_bits * data;
0f2d19dd
JB
449 SCM handle;
450
3b3b36dd
GB
451 SCM_VALIDATE_VTABLE (1,vtable);
452 SCM_VALIDATE_INUM (2,tail_array_size);
af45e3b0 453 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 454
d8c40b9f 455 layout = SCM_PACK (SCM_STRUCT_DATA (vtable) [scm_vtable_index_layout]);
bfa974f0 456 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 457 tail_elts = SCM_INUM (tail_array_size);
08c880a3 458 SCM_NEWCELL2 (handle);
0f2d19dd 459 SCM_DEFER_INTS;
d8c40b9f 460 if (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
a5bfe84d
MD
461 {
462 data = scm_alloc_struct (basic_size + tail_elts,
98d5f601 463 scm_struct_entity_n_extra_words,
a5bfe84d 464 "make-struct");
c8045e8d
DH
465 data[scm_struct_i_procedure] = SCM_UNPACK (SCM_BOOL_F);
466 data[scm_struct_i_setter] = SCM_UNPACK (SCM_BOOL_F);
a5bfe84d
MD
467 }
468 else
469 data = scm_alloc_struct (basic_size + tail_elts,
470 scm_struct_n_extra_words,
471 "make-struct");
54778cd3 472 SCM_SET_CELL_WORD_1 (handle, data);
08c880a3 473 SCM_SET_STRUCT_GC_CHAIN (handle, 0);
f7620510 474 scm_struct_init (handle, layout, data, tail_elts, init);
92c2555f 475 SCM_SET_CELL_WORD_0 (handle, (scm_t_bits) SCM_STRUCT_DATA (vtable) + scm_tc3_cons_gloc);
0f2d19dd
JB
476 SCM_ALLOW_INTS;
477 return handle;
478}
1bbd0b84 479#undef FUNC_NAME
0f2d19dd
JB
480
481
482
a1ec6916 483SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
04323af4 484 (SCM user_fields, SCM tail_array_size, SCM init),
b380b885 485 "Return a new, self-describing vtable structure.\n\n"
04323af4
MD
486 "@var{user-fields} is a string describing user defined fields of the\n"
487 "vtable beginning at index @code{vtable-offset-user}\n"
488 "(see @code{make-struct-layout}).\n\n"
b380b885
MD
489 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
490 "this vtable.\n\n"
6386e25c 491 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
04323af4
MD
492 "the vtable.\n\n"
493 "Vtables have one initializable system field---the struct printer.\n"
494 "This field comes before the user fields in the initializers passed\n"
495 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
496 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
497 "@code{make-struct} when creating vtables:\n\n"
498 "If the value is a procedure, it will be called instead of the standard\n"
499 "printer whenever a struct described by this vtable is printed.\n"
500 "The procedure will be called with arguments STRUCT and PORT.\n\n"
501 "The structure of a struct is described by a vtable, so the vtable is\n"
502 "in essence the type of the struct. The vtable is itself a struct with\n"
503 "a vtable. This could go on forever if it weren't for the\n"
29b4f9fb 504 "vtable-vtables which are self-describing vtables, and thus terminate\n"
04323af4
MD
505 "the chain.\n\n"
506 "There are several potential ways of using structs, but the standard\n"
507 "one is to use three kinds of structs, together building up a type\n"
508 "sub-system: one vtable-vtable working as the root and one or several\n"
509 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
29b4f9fb 510 "compared to the class <class> which is the class of itself.)\n\n"
1e6808ea 511 "@lisp\n"
04323af4
MD
512 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
513 "(define (make-ball-type ball-color)\n"
514 " (make-struct ball-root 0\n"
515 " (make-struct-layout \"pw\")\n"
516 " (lambda (ball port)\n"
517 " (format port \"#<a ~A ball owned by ~A>\"\n"
518 " (color ball)\n"
519 " (owner ball)))\n"
520 " ball-color))\n"
521 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
522 "(define (owner ball) (struct-ref ball 0))\n\n"
523 "(define red (make-ball-type 'red))\n"
524 "(define green (make-ball-type 'green))\n\n"
525 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
526 "(define ball (make-ball green 'Nisse))\n"
527 "ball @result{} #<a green ball owned by Nisse>\n"
1e6808ea 528 "@end lisp\n")
1bbd0b84 529#define FUNC_NAME s_scm_make_vtable_vtable
0f2d19dd
JB
530{
531 SCM fields;
532 SCM layout;
533 int basic_size;
534 int tail_elts;
92c2555f 535 scm_t_bits * data;
0f2d19dd
JB
536 SCM handle;
537
d1ca2c64 538 SCM_VALIDATE_STRING (1, user_fields);
04323af4 539 SCM_VALIDATE_INUM (2, tail_array_size);
af45e3b0 540 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 541
e0c08f17 542 fields = scm_string_append (SCM_LIST2 (required_vtable_fields, user_fields));
0f2d19dd 543 layout = scm_make_struct_layout (fields);
bfa974f0 544 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 545 tail_elts = SCM_INUM (tail_array_size);
08c880a3 546 SCM_NEWCELL2 (handle);
0f2d19dd 547 SCM_DEFER_INTS;
a5bfe84d
MD
548 data = scm_alloc_struct (basic_size + tail_elts,
549 scm_struct_n_extra_words,
550 "make-vtable-vtable");
54778cd3 551 SCM_SET_CELL_WORD_1 (handle, data);
08c880a3 552 SCM_SET_STRUCT_GC_CHAIN (handle, 0);
f7620510
DH
553 data [scm_vtable_index_layout] = SCM_UNPACK (layout);
554 scm_struct_init (handle, layout, data, tail_elts, scm_cons (layout, init));
92c2555f 555 SCM_SET_CELL_WORD_0 (handle, (scm_t_bits) data + scm_tc3_cons_gloc);
0f2d19dd
JB
556 SCM_ALLOW_INTS;
557 return handle;
558}
1bbd0b84 559#undef FUNC_NAME
0f2d19dd
JB
560
561\f
562
563
a1ec6916 564SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
1bbd0b84 565 (SCM handle, SCM pos),
b380b885
MD
566 "@deffnx primitive struct-set! struct n value\n"
567 "Access (or modify) the @var{n}th field of @var{struct}.\n\n"
568 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
569 "If the field is of type 'u', then it can only be set to a non-negative\n"
570 "integer value small enough to fit in one machine word.")
1bbd0b84 571#define FUNC_NAME s_scm_struct_ref
0f2d19dd 572{
5e840c2e 573 SCM answer = SCM_UNDEFINED;
92c2555f 574 scm_t_bits * data;
0f2d19dd
JB
575 SCM layout;
576 int p;
92c2555f 577 scm_t_bits n_fields;
e51fe79c
DH
578 char * fields_desc;
579 char field_type = 0;
0f2d19dd
JB
580
581
3b3b36dd
GB
582 SCM_VALIDATE_STRUCT (1,handle);
583 SCM_VALIDATE_INUM (2,pos);
0f2d19dd
JB
584
585 layout = SCM_STRUCT_LAYOUT (handle);
586 data = SCM_STRUCT_DATA (handle);
587 p = SCM_INUM (pos);
588
e51fe79c 589 fields_desc = SCM_SYMBOL_CHARS (layout);
d8c40b9f 590 n_fields = data[scm_struct_i_n_words];
2c36c351 591
c751e5e3 592 SCM_ASSERT_RANGE(1,pos, p < n_fields);
0f2d19dd 593
bfa974f0 594 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351 595 {
e51fe79c 596 char ref;
2c36c351
MD
597 field_type = fields_desc[p * 2];
598 ref = fields_desc[p * 2 + 1];
599 if ((ref != 'r') && (ref != 'w'))
600 {
601 if ((ref == 'R') || (ref == 'W'))
602 field_type = 'u';
603 else
2ade72d7 604 SCM_MISC_ERROR ("ref denied for field ~A", SCM_LIST1 (pos));
2c36c351
MD
605 }
606 }
bfa974f0
DH
607 else if (fields_desc[SCM_SYMBOL_LENGTH (layout) - 1] != 'O')
608 field_type = fields_desc[SCM_SYMBOL_LENGTH (layout) - 2];
2c36c351 609 else
2ade72d7 610 SCM_MISC_ERROR ("ref denied for field ~A", SCM_LIST1 (pos));
2c36c351 611
0f2d19dd
JB
612 switch (field_type)
613 {
614 case 'u':
d8c40b9f 615 answer = scm_ulong2num (data[p]);
0f2d19dd
JB
616 break;
617
618#if 0
619 case 'i':
620 answer = scm_long2num (data[p]);
621 break;
622
623 case 'd':
f8de44c1 624 answer = scm_make_real (*((double *)&(data[p])));
0f2d19dd
JB
625 break;
626#endif
627
628 case 's':
629 case 'p':
d8c40b9f 630 answer = SCM_PACK (data[p]);
0f2d19dd
JB
631 break;
632
633
634 default:
2ade72d7
DH
635 SCM_MISC_ERROR ("unrecognized field type: ~S",
636 SCM_LIST1 (SCM_MAKE_CHAR (field_type)));
0f2d19dd
JB
637 }
638
639 return answer;
640}
1bbd0b84 641#undef FUNC_NAME
0f2d19dd
JB
642
643
a1ec6916 644SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
1bbd0b84 645 (SCM handle, SCM pos, SCM val),
e3239868
DH
646 "Set the slot of the structure @var{handle} with index @var{pos}\n"
647 "to @var{val}. Signal an error if the slot can not be written\n"
648 "to.")
1bbd0b84 649#define FUNC_NAME s_scm_struct_set_x
0f2d19dd 650{
92c2555f 651 scm_t_bits * data;
0f2d19dd
JB
652 SCM layout;
653 int p;
654 int n_fields;
e51fe79c
DH
655 char * fields_desc;
656 char field_type = 0;
0f2d19dd 657
3b3b36dd
GB
658 SCM_VALIDATE_STRUCT (1,handle);
659 SCM_VALIDATE_INUM (2,pos);
0f2d19dd
JB
660
661 layout = SCM_STRUCT_LAYOUT (handle);
662 data = SCM_STRUCT_DATA (handle);
663 p = SCM_INUM (pos);
664
e51fe79c 665 fields_desc = SCM_SYMBOL_CHARS (layout);
d8c40b9f 666 n_fields = data[scm_struct_i_n_words];
0f2d19dd 667
c751e5e3 668 SCM_ASSERT_RANGE (1,pos, p < n_fields);
0f2d19dd 669
bfa974f0 670 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351 671 {
e51fe79c 672 char set_x;
2c36c351
MD
673 field_type = fields_desc[p * 2];
674 set_x = fields_desc [p * 2 + 1];
675 if (set_x != 'w')
2ade72d7 676 SCM_MISC_ERROR ("set! denied for field ~A", SCM_LIST1 (pos));
2c36c351 677 }
bfa974f0
DH
678 else if (fields_desc[SCM_SYMBOL_LENGTH (layout) - 1] == 'W')
679 field_type = fields_desc[SCM_SYMBOL_LENGTH (layout) - 2];
2c36c351 680 else
2ade72d7 681 SCM_MISC_ERROR ("set! denied for field ~A", SCM_LIST1 (pos));
2c36c351 682
0f2d19dd
JB
683 switch (field_type)
684 {
685 case 'u':
d8c40b9f 686 data[p] = SCM_NUM2ULONG (3, val);
0f2d19dd
JB
687 break;
688
689#if 0
690 case 'i':
e4b265d8 691 data[p] = SCM_NUM2LONG (3, val);
0f2d19dd
JB
692 break;
693
694 case 'd':
695 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
696 break;
697#endif
698
699 case 'p':
d8c40b9f 700 data[p] = SCM_UNPACK (val);
0f2d19dd
JB
701 break;
702
703 case 's':
2ade72d7 704 SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
0f2d19dd
JB
705
706 default:
2ade72d7
DH
707 SCM_MISC_ERROR ("unrecognized field type: ~S",
708 SCM_LIST1 (SCM_MAKE_CHAR (field_type)));
0f2d19dd
JB
709 }
710
711 return val;
712}
1bbd0b84 713#undef FUNC_NAME
0f2d19dd
JB
714
715
a1ec6916 716SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 717 (SCM handle),
b380b885 718 "Return the vtable structure that describes the type of @var{struct}.")
1bbd0b84 719#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 720{
3b3b36dd 721 SCM_VALIDATE_STRUCT (1,handle);
0f2d19dd
JB
722 return SCM_STRUCT_VTABLE (handle);
723}
1bbd0b84 724#undef FUNC_NAME
0f2d19dd
JB
725
726
a1ec6916 727SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 728 (SCM handle),
e3239868 729 "Return the vtable tag of the structure @var{handle}.")
1bbd0b84 730#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 731{
3b3b36dd 732 SCM_VALIDATE_VTABLE (1,handle);
ad196599 733 return scm_long2num ((long) SCM_STRUCT_DATA (handle) >> 3);
98d5f601 734}
1bbd0b84 735#undef FUNC_NAME
98d5f601
MD
736
737/* {Associating names and classes with vtables}
738 *
739 * The name of a vtable should probably be stored as a slot. This is
740 * a backward compatible solution until agreement has been achieved on
741 * how to associate names with vtables.
742 */
743
c014a02e
ML
744unsigned long
745scm_struct_ihashq (SCM obj, unsigned long n)
98d5f601 746{
ad196599
MD
747 /* The length of the hash table should be a relative prime it's not
748 necessary to shift down the address. */
f1267706 749 return SCM_UNPACK (obj) % n;
98d5f601
MD
750}
751
752SCM
753scm_struct_create_handle (SCM obj)
754{
755 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
756 obj,
757 SCM_BOOL_F,
758 scm_struct_ihashq,
759 scm_sloppy_assq,
760 0);
761 if (SCM_FALSEP (SCM_CDR (handle)))
762 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
763 return handle;
764}
765
a1ec6916 766SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 767 (SCM vtable),
e3239868 768 "Return the name of the vtable @var{vtable}.")
1bbd0b84 769#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 770{
3b3b36dd 771 SCM_VALIDATE_VTABLE (1,vtable);
98d5f601
MD
772 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
773}
1bbd0b84 774#undef FUNC_NAME
98d5f601 775
a1ec6916 776SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 777 (SCM vtable, SCM name),
e3239868 778 "Set the name of the vtable @var{vtable} to @var{name}.")
1bbd0b84 779#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 780{
3b3b36dd
GB
781 SCM_VALIDATE_VTABLE (1,vtable);
782 SCM_VALIDATE_SYMBOL (2,name);
98d5f601
MD
783 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
784 name);
785 return SCM_UNSPECIFIED;
0f2d19dd 786}
1bbd0b84 787#undef FUNC_NAME
0f2d19dd
JB
788
789
790\f
791
bafcafb2 792void
1bbd0b84 793scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 794{
4bfdf158
MD
795 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
796 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
797 else
bafcafb2 798 {
a1ae1799
MD
799 SCM vtable = SCM_STRUCT_VTABLE (exp);
800 SCM name = scm_struct_vtable_name (vtable);
801 scm_puts ("#<", port);
802 if (SCM_NFALSEP (name))
803 scm_display (name, port);
804 else
805 scm_puts ("struct", port);
806 scm_putc (' ', port);
54778cd3 807 scm_intprint (SCM_UNPACK (vtable), 16, port);
b7f3516f 808 scm_putc (':', port);
54778cd3 809 scm_intprint (SCM_UNPACK (exp), 16, port);
b7f3516f 810 scm_putc ('>', port);
bafcafb2 811 }
bafcafb2 812}
1cc91f1b 813
08c880a3
MD
814void
815scm_struct_prehistory ()
816{
817 scm_c_hook_add (&scm_before_mark_c_hook, scm_struct_gc_init, 0, 0);
818 scm_c_hook_add (&scm_after_sweep_c_hook, scm_free_structs, 0, 0);
819}
820
0f2d19dd
JB
821void
822scm_init_struct ()
0f2d19dd 823{
98d5f601
MD
824 scm_struct_table
825 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
7c31152f 826 required_vtable_fields = scm_makfrom0str ("pruosrpw");
0f2d19dd 827 scm_permanent_object (required_vtable_fields);
86d31dfe
MV
828 scm_c_define ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout));
829 scm_c_define ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable));
830 scm_c_define ("vtable-index-printer",
831 SCM_MAKINUM (scm_vtable_index_printer));
832 scm_c_define ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user));
8dc9439f 833#ifndef SCM_MAGIC_SNARFER
a0599745 834#include "libguile/struct.x"
8dc9439f 835#endif
0f2d19dd 836}
89e00824
ML
837
838/*
839 Local Variables:
840 c-file-style: "gnu"
841 End:
842*/