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