The struct vtable data is now an array of scm_bits_t variables.
[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>
48#include "_scm.h"
20e6290e 49#include "chars.h"
916d65b1 50#include "eval.h"
98d5f601
MD
51#include "alist.h"
52#include "weaks.h"
53#include "hashtab.h"
f04d8caf 54#include "ports.h"
7ab3fdd5 55#include "strings.h"
20e6290e 56
b6791b2e 57#include "validate.h"
20e6290e 58#include "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
MD
72 "Return a new structure layout object.\n\n"
73 "@var{fields} must be a read-only string made up of pairs of characters\n"
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"
77 "fields that should point to the structure itself. Allowed protections\n"
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;
3b3b36dd 84 SCM_VALIDATE_ROSTRING (1,fields);
1bbd0b84 85 { /* scope */
0f2d19dd
JB
86 char * field_desc;
87 int len;
88 int x;
89
90 len = SCM_ROLENGTH (fields);
91 field_desc = SCM_ROCHARS (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
a5bfe84d 151void
1bbd0b84 152scm_struct_init (SCM handle, int tail_elts, SCM inits)
0f2d19dd
JB
153{
154 SCM layout;
155 SCM * data;
156 unsigned char * fields_desc;
35de7ebe 157 unsigned char prot = 0;
0f2d19dd
JB
158 int n_fields;
159 SCM * mem;
2c36c351
MD
160 int tailp = 0;
161
0f2d19dd
JB
162 layout = SCM_STRUCT_LAYOUT (handle);
163 data = SCM_STRUCT_DATA (handle);
2c36c351 164 fields_desc = (unsigned char *) SCM_CHARS (layout) - 2;
0f2d19dd
JB
165 n_fields = SCM_LENGTH (layout) / 2;
166 mem = SCM_STRUCT_DATA (handle);
167 while (n_fields)
168 {
2c36c351
MD
169 if (!tailp)
170 {
171 fields_desc += 2;
172 prot = fields_desc[1];
173 if (SCM_LAYOUT_TAILP (prot))
174 {
175 tailp = 1;
176 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
f1267706 177 *mem++ = SCM_PACK (tail_elts);
2c36c351
MD
178 n_fields += tail_elts - 1;
179 if (n_fields == 0)
180 break;
181 }
182 }
183
0f2d19dd
JB
184 switch (*fields_desc)
185 {
186#if 0
187 case 'i':
2c36c351 188 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
189 *mem = 0;
190 else
191 {
a5bfe84d 192 *mem = scm_num2long (SCM_CAR (inits), SCM_ARGn, "scm_struct_init");
0f2d19dd
JB
193 inits = SCM_CDR (inits);
194 }
195 break;
196#endif
197
198 case 'u':
54778cd3 199 if ((prot != 'r' && prot != 'w') || SCM_NULLP (inits))
0f2d19dd
JB
200 *mem = 0;
201 else
202 {
f1267706 203 *mem = SCM_PACK (scm_num2ulong (SCM_CAR (inits),
8dee1541
MD
204 SCM_ARGn,
205 "scm_struct_init"));
0f2d19dd
JB
206 inits = SCM_CDR (inits);
207 }
208 break;
209
210 case 'p':
54778cd3 211 if ((prot != 'r' && prot != 'w') || SCM_NULLP (inits))
916d65b1 212 *mem = SCM_BOOL_F;
0f2d19dd
JB
213 else
214 {
215 *mem = SCM_CAR (inits);
216 inits = SCM_CDR (inits);
217 }
218
219 break;
220
221#if 0
222 case 'd':
2c36c351 223 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
224 *((double *)mem) = 0.0;
225 else
226 {
a5bfe84d 227 *mem = scm_num2dbl (SCM_CAR (inits), "scm_struct_init");
0f2d19dd
JB
228 inits = SCM_CDR (inits);
229 }
230 fields_desc += 2;
231 break;
232#endif
233
234 case 's':
235 *mem = handle;
236 break;
237 }
238
0f2d19dd
JB
239 n_fields--;
240 mem++;
241 }
242}
243
244
a1ec6916 245SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
1bbd0b84 246 (SCM x),
b380b885 247 "Return #t iff @var{obj} is a structure object, else #f.")
1bbd0b84 248#define FUNC_NAME s_scm_struct_p
0f2d19dd 249{
0c95b57d 250 return SCM_BOOL(SCM_STRUCTP (x));
0f2d19dd 251}
1bbd0b84 252#undef FUNC_NAME
0f2d19dd 253
a1ec6916 254SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
1bbd0b84 255 (SCM x),
b380b885 256 "Return #t iff obj is a vtable structure.")
1bbd0b84 257#define FUNC_NAME s_scm_struct_vtable_p
0f2d19dd
JB
258{
259 SCM layout;
260 SCM * mem;
261
262 if (SCM_IMP (x))
263 return SCM_BOOL_F;
264
265 if (!SCM_STRUCTP (x))
266 return SCM_BOOL_F;
267
268 layout = SCM_STRUCT_LAYOUT (x);
269
270 if (SCM_LENGTH (layout) < SCM_LENGTH (required_vtable_fields))
271 return SCM_BOOL_F;
272
273 if (strncmp (SCM_CHARS (layout), SCM_CHARS (required_vtable_fields),
274 SCM_LENGTH (required_vtable_fields)))
275 return SCM_BOOL_F;
276
277 mem = SCM_STRUCT_DATA (x);
278
279 if (mem[1] != 0)
280 return SCM_BOOL_F;
281
282 if (SCM_IMP (mem[0]))
283 return SCM_BOOL_F;
284
1bbd0b84 285 return SCM_BOOL(SCM_SYMBOLP (mem[0]));
0f2d19dd 286}
1bbd0b84 287#undef FUNC_NAME
0f2d19dd 288
14d1400f
JB
289
290/* All struct data must be allocated at an address whose bottom three
291 bits are zero. This is because the tag for a struct lives in the
292 bottom three bits of the struct's car, and the upper bits point to
293 the data of its vtable, which is a struct itself. Thus, if the
294 address of that data doesn't end in three zeros, tagging it will
295 destroy the pointer.
296
297 This function allocates a block of memory, and returns a pointer at
298 least scm_struct_n_extra_words words into the block. Furthermore,
299 it guarantees that that pointer's least three significant bits are
300 all zero.
301
302 The argument n_words should be the number of words that should
303 appear after the returned address. (That is, it shouldn't include
304 scm_struct_n_extra_words.)
305
306 This function initializes the following fields of the struct:
307
ad196599 308 scm_struct_i_ptr --- the actual start of the block of memory; the
14d1400f
JB
309 address you should pass to 'free' to dispose of the block.
310 This field allows us to both guarantee that the returned
311 address is divisible by eight, and allow the GC to free the
312 block.
313
314 scm_struct_i_n_words --- the number of words allocated to the
315 block, including the extra fields. This is used by the GC.
316
14d1400f
JB
317 Ugh. */
318
319
a5bfe84d
MD
320SCM *
321scm_alloc_struct (int n_words, int n_extra, char *who)
14d1400f 322{
a5bfe84d 323 int size = sizeof (SCM) * (n_words + n_extra) + 7;
14d1400f
JB
324 SCM *block = (SCM *) scm_must_malloc (size, who);
325
326 /* Adjust the pointer to hide the extra words. */
a5bfe84d 327 SCM *p = block + n_extra;
14d1400f
JB
328
329 /* Adjust it even further so it's aligned on an eight-byte boundary. */
f1267706 330 p = (SCM *) (((scm_bits_t) SCM_UNPACK (p) + 7) & ~7);
14d1400f 331
ad196599
MD
332 /* Initialize a few fields as described above. */
333 p[scm_struct_i_free] = (SCM) scm_struct_free_standard;
14d1400f 334 p[scm_struct_i_ptr] = (SCM) block;
ad196599
MD
335 p[scm_struct_i_n_words] = (SCM) n_words;
336 p[scm_struct_i_flags] = 0;
14d1400f
JB
337
338 return p;
339}
340
97056309 341scm_sizet
ad196599
MD
342scm_struct_free_0 (SCM *vtable, SCM *data)
343{
344 return 0;
345}
346
97056309 347scm_sizet
ad196599
MD
348scm_struct_free_light (SCM *vtable, SCM *data)
349{
350 free (data);
f1267706 351 return SCM_UNPACK (vtable[scm_struct_i_size]) & ~SCM_STRUCTF_MASK;
ad196599
MD
352}
353
97056309 354scm_sizet
ad196599
MD
355scm_struct_free_standard (SCM *vtable, SCM *data)
356{
f1267706 357 size_t n = ((SCM_UNPACK (data[scm_struct_i_n_words]) + scm_struct_n_extra_words)
ad196599
MD
358 * sizeof (SCM) + 7);
359 free ((void *) data[scm_struct_i_ptr]);
360 return n;
361}
362
97056309 363scm_sizet
ad196599
MD
364scm_struct_free_entity (SCM *vtable, SCM *data)
365{
f1267706 366 size_t n = (SCM_UNPACK(data[scm_struct_i_n_words] + scm_struct_entity_n_extra_words)
ad196599
MD
367 * sizeof (SCM) + 7);
368 free ((void *) data[scm_struct_i_ptr]);
369 return n;
370}
14d1400f 371
a1ec6916 372SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
1bbd0b84 373 (SCM vtable, SCM tail_array_size, SCM init),
b380b885
MD
374 "Create a new structure.\n\n"
375 "@var{type} must be a vtable structure (@xref{Vtables}).\n\n"
376 "@var{tail-elts} must be a non-negative integer. If the layout\n"
377 "specification indicated by @var{type} includes a tail-array,\n"
378 "this is the number of elements allocated to that array.\n\n"
379 "The @var{inits} are optional arguments describing how successive fields\n"
380 "of the structure should be initialized. Only fields with protection 'r'\n"
381 "or 'w' can be initialized -- fields of protection 's' are automatically\n"
382 "initialized to point to the new structure itself; fields of protection 'o'\n"
383 "can not be initialized by Scheme programs.")
1bbd0b84 384#define FUNC_NAME s_scm_make_struct
0f2d19dd
JB
385{
386 SCM layout;
387 int basic_size;
388 int tail_elts;
389 SCM * data;
390 SCM handle;
391
3b3b36dd
GB
392 SCM_VALIDATE_VTABLE (1,vtable);
393 SCM_VALIDATE_INUM (2,tail_array_size);
0f2d19dd 394
4bfdf158 395 layout = SCM_STRUCT_DATA (vtable)[scm_vtable_index_layout];
0f2d19dd
JB
396 basic_size = SCM_LENGTH (layout) / 2;
397 tail_elts = SCM_INUM (tail_array_size);
398 SCM_NEWCELL (handle);
399 SCM_DEFER_INTS;
f1267706 400 if (SCM_UNPACK (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags]) & SCM_STRUCTF_ENTITY)
a5bfe84d
MD
401 {
402 data = scm_alloc_struct (basic_size + tail_elts,
98d5f601 403 scm_struct_entity_n_extra_words,
a5bfe84d 404 "make-struct");
2c53acd5 405 data[scm_struct_i_procedure] = SCM_BOOL_F;
25c94826 406 data[scm_struct_i_setter] = SCM_BOOL_F;
a5bfe84d
MD
407 }
408 else
409 data = scm_alloc_struct (basic_size + tail_elts,
410 scm_struct_n_extra_words,
411 "make-struct");
54778cd3 412 SCM_SET_CELL_WORD_1 (handle, data);
35457f1e 413 SCM_SETCAR (handle, ((SCM)SCM_STRUCT_DATA (vtable)) + scm_tc3_cons_gloc);
a5bfe84d 414 scm_struct_init (handle, tail_elts, init);
0f2d19dd
JB
415 SCM_ALLOW_INTS;
416 return handle;
417}
1bbd0b84 418#undef FUNC_NAME
0f2d19dd
JB
419
420
421
a1ec6916 422SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
1bbd0b84 423 (SCM extra_fields, SCM tail_array_size, SCM init),
b380b885
MD
424 "Return a new, self-describing vtable structure.\n\n"
425 "@var{new-fields} is a layout specification describing fields\n"
426 "of the resulting structure beginning at the position bound to\n"
427 "@code{vtable-offset-user}.\n\n"
428 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
429 "this vtable.\n\n"
430 "@var{inits} initializes the fields of the vtable. Minimally, one\n"
431 "initializer must be provided: the layout specification for instances\n"
432 "of the type this vtable will describe. If a second initializer is\n"
433 "provided, it will be interpreted as a print call-back function.\n\n"
434 "@example\n"
435 ";;; loading ,a...\n"
436 "(define x\n"
437 " (make-vtable-vtable (make-struct-layout (quote pw))\n"
438 " 0\n"
439 " 'foo))\n\n"
440 "(struct? x)\n"
441 "@result{} #t\n"
442 "(struct-vtable? x)\n"
443 "@result{} #t\n"
444 "(eq? x (struct-vtable x))\n"
445 "@result{} #t\n"
446 "(struct-ref x vtable-offset-user)\n"
447 "@result{} foo\n"
448 "(struct-ref x 0)\n"
449 "@result{} pruosrpwpw\n\n\n"
450 "(define y\n"
451 " (make-struct x\n"
452 " 0\n"
453 " (make-struct-layout (quote pwpwpw))\n"
454 " 'bar))\n\n"
455 "(struct? y)\n"
456 "@result{} #t\n"
457 "(struct-vtable? y)\n"
458 "@result{} #t\n"
459 "(eq? x y)\n"
460 "@result{} ()\n"
461 "(eq? x (struct-vtable y))\n"
462 "@result{} #t\n"
463 "(struct-ref y 0)\n"
464 "@result{} pwpwpw\n"
465 "(struct-ref y vtable-offset-user)\n"
466 "@result{} bar\n\n\n"
467 "(define z (make-struct y 0 'a 'b 'c))\n\n"
468 "(struct? z)\n"
469 "@result{} #t\n"
470 "(struct-vtable? z)\n"
471 "@result{} ()\n"
472 "(eq? y (struct-vtable z))\n"
473 "@result{} #t\n"
474 "(map (lambda (n) (struct-ref z n)) '(0 1 2))\n"
475 "@result{} (a b c)\n"
476 "@end example\n"
477 "")
1bbd0b84 478#define FUNC_NAME s_scm_make_vtable_vtable
0f2d19dd
JB
479{
480 SCM fields;
481 SCM layout;
482 int basic_size;
483 int tail_elts;
484 SCM * data;
485 SCM handle;
486
3b3b36dd
GB
487 SCM_VALIDATE_ROSTRING (1,extra_fields);
488 SCM_VALIDATE_INUM (2,tail_array_size);
0f2d19dd
JB
489
490 fields = scm_string_append (scm_listify (required_vtable_fields,
491 extra_fields,
492 SCM_UNDEFINED));
493 layout = scm_make_struct_layout (fields);
494 basic_size = SCM_LENGTH (layout) / 2;
495 tail_elts = SCM_INUM (tail_array_size);
496 SCM_NEWCELL (handle);
497 SCM_DEFER_INTS;
a5bfe84d
MD
498 data = scm_alloc_struct (basic_size + tail_elts,
499 scm_struct_n_extra_words,
500 "make-vtable-vtable");
54778cd3 501 SCM_SET_CELL_WORD_1 (handle, data);
35457f1e 502 SCM_SETCAR (handle, ((SCM)data) + scm_tc3_cons_gloc);
1c3e63f0 503 SCM_SET_STRUCT_LAYOUT (handle, layout);
a5bfe84d 504 scm_struct_init (handle, tail_elts, scm_cons (layout, init));
0f2d19dd
JB
505 SCM_ALLOW_INTS;
506 return handle;
507}
1bbd0b84 508#undef FUNC_NAME
0f2d19dd
JB
509
510\f
511
512
a1ec6916 513SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
1bbd0b84 514 (SCM handle, SCM pos),
b380b885
MD
515 "@deffnx primitive struct-set! struct n value\n"
516 "Access (or modify) the @var{n}th field of @var{struct}.\n\n"
517 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
518 "If the field is of type 'u', then it can only be set to a non-negative\n"
519 "integer value small enough to fit in one machine word.")
1bbd0b84 520#define FUNC_NAME s_scm_struct_ref
0f2d19dd 521{
5e840c2e 522 SCM answer = SCM_UNDEFINED;
0f2d19dd
JB
523 SCM * data;
524 SCM layout;
525 int p;
4d45e7b6 526 scm_bits_t n_fields;
0f2d19dd 527 unsigned char * fields_desc;
f3667f52 528 unsigned char field_type = 0;
0f2d19dd
JB
529
530
3b3b36dd
GB
531 SCM_VALIDATE_STRUCT (1,handle);
532 SCM_VALIDATE_INUM (2,pos);
0f2d19dd
JB
533
534 layout = SCM_STRUCT_LAYOUT (handle);
535 data = SCM_STRUCT_DATA (handle);
536 p = SCM_INUM (pos);
537
ad196599 538 fields_desc = (unsigned char *) SCM_CHARS (layout);
f1267706 539 n_fields = SCM_UNPACK (data[scm_struct_i_n_words]);
2c36c351 540
c751e5e3 541 SCM_ASSERT_RANGE(1,pos, p < n_fields);
0f2d19dd 542
2c36c351
MD
543 if (p * 2 < SCM_LENGTH (layout))
544 {
545 unsigned char ref;
546 field_type = fields_desc[p * 2];
547 ref = fields_desc[p * 2 + 1];
548 if ((ref != 'r') && (ref != 'w'))
549 {
550 if ((ref == 'R') || (ref == 'W'))
551 field_type = 'u';
552 else
1bbd0b84 553 SCM_ASSERT (0, pos, "ref denied", FUNC_NAME);
2c36c351
MD
554 }
555 }
556 else if (fields_desc[SCM_LENGTH (layout) - 1] != 'O')
557 field_type = fields_desc[SCM_LENGTH (layout) - 2];
558 else
559 {
1bbd0b84 560 SCM_ASSERT (0, pos, "ref denied", FUNC_NAME);
35de7ebe 561 abort ();
2c36c351
MD
562 }
563
0f2d19dd
JB
564 switch (field_type)
565 {
566 case 'u':
f1267706 567 answer = scm_ulong2num (SCM_UNPACK (data[p]));
0f2d19dd
JB
568 break;
569
570#if 0
571 case 'i':
572 answer = scm_long2num (data[p]);
573 break;
574
575 case 'd':
576 answer = scm_makdbl (*((double *)&(data[p])), 0.0);
577 break;
578#endif
579
580 case 's':
581 case 'p':
582 answer = data[p];
583 break;
584
585
586 default:
7866a09b 587 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "unrecognized field type", FUNC_NAME);
0f2d19dd
JB
588 break;
589 }
590
591 return answer;
592}
1bbd0b84 593#undef FUNC_NAME
0f2d19dd
JB
594
595
a1ec6916 596SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
1bbd0b84 597 (SCM handle, SCM pos, SCM val),
b380b885 598 "")
1bbd0b84 599#define FUNC_NAME s_scm_struct_set_x
0f2d19dd
JB
600{
601 SCM * data;
602 SCM layout;
603 int p;
604 int n_fields;
605 unsigned char * fields_desc;
f3667f52 606 unsigned char field_type = 0;
0f2d19dd 607
3b3b36dd
GB
608 SCM_VALIDATE_STRUCT (1,handle);
609 SCM_VALIDATE_INUM (2,pos);
0f2d19dd
JB
610
611 layout = SCM_STRUCT_LAYOUT (handle);
612 data = SCM_STRUCT_DATA (handle);
613 p = SCM_INUM (pos);
614
615 fields_desc = (unsigned char *)SCM_CHARS (layout);
f1267706 616 n_fields = SCM_UNPACK (data[scm_struct_i_n_words]);
0f2d19dd 617
c751e5e3 618 SCM_ASSERT_RANGE (1,pos, p < n_fields);
0f2d19dd 619
2c36c351
MD
620 if (p * 2 < SCM_LENGTH (layout))
621 {
622 unsigned char set_x;
623 field_type = fields_desc[p * 2];
624 set_x = fields_desc [p * 2 + 1];
625 if (set_x != 'w')
1bbd0b84 626 SCM_ASSERT (0, pos, "set_x denied", FUNC_NAME);
2c36c351
MD
627 }
628 else if (fields_desc[SCM_LENGTH (layout) - 1] == 'W')
629 field_type = fields_desc[SCM_LENGTH (layout) - 2];
630 else
631 {
1bbd0b84 632 SCM_ASSERT (0, pos, "set_x denied", FUNC_NAME);
35de7ebe 633 abort ();
2c36c351
MD
634 }
635
0f2d19dd
JB
636 switch (field_type)
637 {
638 case 'u':
f1267706 639 data[p] = SCM_PACK (SCM_NUM2ULONG (3, val));
0f2d19dd
JB
640 break;
641
642#if 0
643 case 'i':
1bbd0b84 644 data[p] = SCM_NUM2LONG (3,val);
0f2d19dd
JB
645 break;
646
647 case 'd':
648 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
649 break;
650#endif
651
652 case 'p':
653 data[p] = val;
654 break;
655
656 case 's':
7866a09b 657 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "self fields immutable", FUNC_NAME);
0f2d19dd
JB
658 break;
659
660 default:
7866a09b 661 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "unrecognized field type", FUNC_NAME);
0f2d19dd
JB
662 break;
663 }
664
665 return val;
666}
1bbd0b84 667#undef FUNC_NAME
0f2d19dd
JB
668
669
a1ec6916 670SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 671 (SCM handle),
b380b885 672 "Return the vtable structure that describes the type of @var{struct}.")
1bbd0b84 673#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 674{
3b3b36dd 675 SCM_VALIDATE_STRUCT (1,handle);
0f2d19dd
JB
676 return SCM_STRUCT_VTABLE (handle);
677}
1bbd0b84 678#undef FUNC_NAME
0f2d19dd
JB
679
680
a1ec6916 681SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 682 (SCM handle),
b380b885 683 "")
1bbd0b84 684#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 685{
3b3b36dd 686 SCM_VALIDATE_VTABLE (1,handle);
ad196599 687 return scm_long2num ((long) SCM_STRUCT_DATA (handle) >> 3);
98d5f601 688}
1bbd0b84 689#undef FUNC_NAME
98d5f601
MD
690
691/* {Associating names and classes with vtables}
692 *
693 * The name of a vtable should probably be stored as a slot. This is
694 * a backward compatible solution until agreement has been achieved on
695 * how to associate names with vtables.
696 */
697
698unsigned int
699scm_struct_ihashq (SCM obj, unsigned int n)
700{
ad196599
MD
701 /* The length of the hash table should be a relative prime it's not
702 necessary to shift down the address. */
f1267706 703 return SCM_UNPACK (obj) % n;
98d5f601
MD
704}
705
706SCM
707scm_struct_create_handle (SCM obj)
708{
709 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
710 obj,
711 SCM_BOOL_F,
712 scm_struct_ihashq,
713 scm_sloppy_assq,
714 0);
715 if (SCM_FALSEP (SCM_CDR (handle)))
716 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
717 return handle;
718}
719
a1ec6916 720SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 721 (SCM vtable),
b380b885 722 "")
1bbd0b84 723#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 724{
3b3b36dd 725 SCM_VALIDATE_VTABLE (1,vtable);
98d5f601
MD
726 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
727}
1bbd0b84 728#undef FUNC_NAME
98d5f601 729
a1ec6916 730SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 731 (SCM vtable, SCM name),
b380b885 732 "")
1bbd0b84 733#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 734{
3b3b36dd
GB
735 SCM_VALIDATE_VTABLE (1,vtable);
736 SCM_VALIDATE_SYMBOL (2,name);
98d5f601
MD
737 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
738 name);
739 return SCM_UNSPECIFIED;
0f2d19dd 740}
1bbd0b84 741#undef FUNC_NAME
0f2d19dd
JB
742
743
744\f
745
bafcafb2 746void
1bbd0b84 747scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 748{
4bfdf158
MD
749 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
750 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
751 else
bafcafb2 752 {
a1ae1799
MD
753 SCM vtable = SCM_STRUCT_VTABLE (exp);
754 SCM name = scm_struct_vtable_name (vtable);
755 scm_puts ("#<", port);
756 if (SCM_NFALSEP (name))
757 scm_display (name, port);
758 else
759 scm_puts ("struct", port);
760 scm_putc (' ', port);
54778cd3 761 scm_intprint (SCM_UNPACK (vtable), 16, port);
b7f3516f 762 scm_putc (':', port);
54778cd3 763 scm_intprint (SCM_UNPACK (exp), 16, port);
b7f3516f 764 scm_putc ('>', port);
bafcafb2 765 }
bafcafb2 766}
1cc91f1b 767
0f2d19dd
JB
768void
769scm_init_struct ()
0f2d19dd 770{
98d5f601
MD
771 scm_struct_table
772 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
4bfdf158 773 required_vtable_fields = SCM_CAR (scm_intern_obarray ("pruosrpw", sizeof ("pruosrpw") - 1, SCM_BOOL_F));
0f2d19dd 774 scm_permanent_object (required_vtable_fields);
4bfdf158
MD
775 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout));
776 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable));
777 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer));
778 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user));
0f2d19dd
JB
779#include "struct.x"
780}
89e00824
ML
781
782/*
783 Local Variables:
784 c-file-style: "gnu"
785 End:
786*/