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