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