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