1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
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)
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.
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
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.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
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.
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.
40 * If you do not wish that, delete this exception notice. */
57 static SCM required_vtable_fields
= SCM_BOOL_F
;
58 static int struct_num
= 0;
61 SCM_PROC (s_struct_make_layout
, "make-struct-layout", 1, 0, 0, scm_make_struct_layout
);
64 scm_make_struct_layout (fields
)
68 SCM_ASSERT (SCM_NIMP (fields
) && SCM_ROSTRINGP (fields
),
69 fields
, SCM_ARG1
, s_struct_make_layout
);
76 len
= SCM_ROLENGTH (fields
);
77 field_desc
= SCM_ROCHARS (fields
);
78 SCM_ASSERT (!(len
& 1), fields
, "odd length field specification", s_struct_make_layout
);
80 for (x
= 0; x
< len
; x
+= 2)
82 switch (field_desc
[x
])
93 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized field type", s_struct_make_layout
);
96 switch (field_desc
[x
+ 1])
99 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
100 "self fields not writable", s_struct_make_layout
);
108 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
109 "self fields not allowed in tail array",
110 s_struct_make_layout
);
111 SCM_ASSERT (x
== len
- 2, SCM_MAKICHR (field_desc
[x
+ 1]),
112 "tail array field must be last field in layout",
113 s_struct_make_layout
);
116 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized ref specification", s_struct_make_layout
);
119 if (field_desc
[x
] == 'd')
121 SCM_ASSERT (field_desc
[x
+ 2] == '-', SCM_MAKINUM (x
/ 2), "missing dash field", s_struct_make_layout
);
127 new_sym
= SCM_CAR (scm_intern_obarray (field_desc
, len
, SCM_BOOL_F
));
129 return scm_return_first (new_sym
, fields
);
137 scm_struct_init (handle
, tail_elts
, inits
)
144 unsigned char * fields_desc
;
145 unsigned char prot
= 0;
150 layout
= SCM_STRUCT_LAYOUT (handle
);
151 data
= SCM_STRUCT_DATA (handle
);
152 fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
153 n_fields
= SCM_LENGTH (layout
) / 2;
154 mem
= SCM_STRUCT_DATA (handle
);
160 prot
= fields_desc
[1];
161 if (SCM_LAYOUT_TAILP (prot
))
164 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
166 n_fields
+= tail_elts
- 1;
172 switch (*fields_desc
)
176 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
180 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
181 inits
= SCM_CDR (inits
);
187 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
191 *mem
= scm_num2ulong (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
192 inits
= SCM_CDR (inits
);
197 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
201 *mem
= SCM_CAR (inits
);
202 inits
= SCM_CDR (inits
);
209 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
210 *((double *)mem
) = 0.0;
213 *mem
= scm_num2dbl (SCM_CAR (inits
), "scm_struct_init");
214 inits
= SCM_CDR (inits
);
231 SCM_PROC (s_struct_p
, "struct?", 1, 0, 0, scm_struct_p
);
237 return ((SCM_NIMP (x
) && SCM_STRUCTP (x
))
242 SCM_PROC (s_struct_vtable_p
, "struct-vtable?", 1, 0, 0, scm_struct_vtable_p
);
245 scm_struct_vtable_p (x
)
254 if (!SCM_STRUCTP (x
))
257 layout
= SCM_STRUCT_LAYOUT (x
);
259 if (SCM_LENGTH (layout
) < SCM_LENGTH (required_vtable_fields
))
262 if (strncmp (SCM_CHARS (layout
), SCM_CHARS (required_vtable_fields
),
263 SCM_LENGTH (required_vtable_fields
)))
266 mem
= SCM_STRUCT_DATA (x
);
271 if (SCM_IMP (mem
[0]))
274 return (SCM_SYMBOLP (mem
[0])
280 /* All struct data must be allocated at an address whose bottom three
281 bits are zero. This is because the tag for a struct lives in the
282 bottom three bits of the struct's car, and the upper bits point to
283 the data of its vtable, which is a struct itself. Thus, if the
284 address of that data doesn't end in three zeros, tagging it will
287 This function allocates a block of memory, and returns a pointer at
288 least scm_struct_n_extra_words words into the block. Furthermore,
289 it guarantees that that pointer's least three significant bits are
292 The argument n_words should be the number of words that should
293 appear after the returned address. (That is, it shouldn't include
294 scm_struct_n_extra_words.)
296 This function initializes the following fields of the struct:
298 scm_struct_i_ptr --- the actual stort of the block of memory; the
299 address you should pass to 'free' to dispose of the block.
300 This field allows us to both guarantee that the returned
301 address is divisible by eight, and allow the GC to free the
304 scm_struct_i_n_words --- the number of words allocated to the
305 block, including the extra fields. This is used by the GC.
307 scm_struct_i_tag --- a unique tag assigned to this struct,
308 allocated according to struct_num.
314 scm_alloc_struct (int n_words
, int n_extra
, char *who
)
316 int size
= sizeof (SCM
) * (n_words
+ n_extra
) + 7;
317 SCM
*block
= (SCM
*) scm_must_malloc (size
, who
);
319 /* Adjust the pointer to hide the extra words. */
320 SCM
*p
= block
+ n_extra
;
322 /* Adjust it even further so it's aligned on an eight-byte boundary. */
323 p
= (SCM
*) (((SCM
) p
+ 7) & ~7);
325 /* Initialize a few fields as described above. */
326 p
[scm_struct_i_ptr
] = (SCM
) block
;
327 p
[scm_struct_i_n_words
] = (SCM
) (n_words
+ n_extra
);
328 p
[scm_struct_i_tag
] = struct_num
++;
334 SCM_PROC (s_make_struct
, "make-struct", 2, 0, 1, scm_make_struct
);
337 scm_make_struct (vtable
, tail_array_size
, init
)
348 SCM_ASSERT ((SCM_BOOL_F
!= scm_struct_vtable_p (vtable
)),
349 vtable
, SCM_ARG1
, s_make_struct
);
350 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
353 layout
= SCM_STRUCT_DATA (vtable
)[scm_vtable_index_layout
];
354 basic_size
= SCM_LENGTH (layout
) / 2;
355 tail_elts
= SCM_INUM (tail_array_size
);
356 SCM_NEWCELL (handle
);
358 if (SCM_STRUCT_DATA (vtable
)[scm_struct_i_flags
] & SCM_STRUCTF_ENTITY
)
360 data
= scm_alloc_struct (basic_size
+ tail_elts
,
361 scm_struct_n_extra_words
+ 4,
363 data
[scm_struct_i_proc
+ 0] = SCM_BOOL_F
;
364 data
[scm_struct_i_proc
+ 1] = SCM_BOOL_F
;
365 data
[scm_struct_i_proc
+ 2] = SCM_BOOL_F
;
366 data
[scm_struct_i_proc
+ 3] = SCM_BOOL_F
;
369 data
= scm_alloc_struct (basic_size
+ tail_elts
,
370 scm_struct_n_extra_words
,
372 SCM_SETCDR (handle
, data
);
373 SCM_SETCAR (handle
, ((SCM
)SCM_STRUCT_DATA (vtable
)) + scm_tc3_cons_gloc
);
374 scm_struct_init (handle
, tail_elts
, init
);
381 SCM_PROC (s_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable
);
384 scm_make_vtable_vtable (extra_fields
, tail_array_size
, init
)
396 SCM_ASSERT (SCM_NIMP (extra_fields
) && SCM_ROSTRINGP (extra_fields
),
397 extra_fields
, SCM_ARG1
, s_make_vtable_vtable
);
398 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
399 s_make_vtable_vtable
);
401 fields
= scm_string_append (scm_listify (required_vtable_fields
,
404 layout
= scm_make_struct_layout (fields
);
405 basic_size
= SCM_LENGTH (layout
) / 2;
406 tail_elts
= SCM_INUM (tail_array_size
);
407 SCM_NEWCELL (handle
);
409 data
= scm_alloc_struct (basic_size
+ tail_elts
,
410 scm_struct_n_extra_words
,
411 "make-vtable-vtable");
412 SCM_SETCDR (handle
, data
);
413 SCM_SETCAR (handle
, ((SCM
)data
) + scm_tc3_cons_gloc
);
414 SCM_STRUCT_LAYOUT (handle
) = layout
;
415 scm_struct_init (handle
, tail_elts
, scm_cons (layout
, init
));
423 SCM_PROC (s_struct_ref
, "struct-ref", 2, 0, 0, scm_struct_ref
);
426 scm_struct_ref (handle
, pos
)
430 SCM answer
= SCM_UNDEFINED
;
435 unsigned char * fields_desc
;
436 unsigned char field_type
= 0;
439 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
440 SCM_ARG1
, s_struct_ref
);
441 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
443 layout
= SCM_STRUCT_LAYOUT (handle
);
444 data
= SCM_STRUCT_DATA (handle
);
447 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
448 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
450 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_ref
);
452 if (p
* 2 < SCM_LENGTH (layout
))
455 field_type
= fields_desc
[p
* 2];
456 ref
= fields_desc
[p
* 2 + 1];
457 if ((ref
!= 'r') && (ref
!= 'w'))
459 if ((ref
== 'R') || (ref
== 'W'))
462 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
465 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
466 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
469 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
476 answer
= scm_ulong2num (data
[p
]);
481 answer
= scm_long2num (data
[p
]);
485 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
496 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_ref
);
504 SCM_PROC (s_struct_set_x
, "struct-set!", 3, 0, 0, scm_struct_set_x
);
507 scm_struct_set_x (handle
, pos
, val
)
516 unsigned char * fields_desc
;
517 unsigned char field_type
= 0;
521 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
522 SCM_ARG1
, s_struct_ref
);
523 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
525 layout
= SCM_STRUCT_LAYOUT (handle
);
526 data
= SCM_STRUCT_DATA (handle
);
529 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
530 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
532 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_set_x
);
534 if (p
* 2 < SCM_LENGTH (layout
))
537 field_type
= fields_desc
[p
* 2];
538 set_x
= fields_desc
[p
* 2 + 1];
540 SCM_ASSERT (0, pos
, "set_x denied", s_struct_set_x
);
542 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
543 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
546 SCM_ASSERT (0, pos
, "set_x denied", s_struct_ref
);
553 data
[p
] = (SCM
)scm_num2ulong (val
, (char *)SCM_ARG3
, s_struct_set_x
);
558 data
[p
] = scm_num2long (val
, (char *)SCM_ARG3
, s_struct_set_x
);
562 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
571 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "self fields immutable", s_struct_set_x
);
575 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_set_x
);
583 SCM_PROC (s_struct_vtable
, "struct-vtable", 1, 0, 0, scm_struct_vtable
);
586 scm_struct_vtable (handle
)
589 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
590 SCM_ARG1
, s_struct_vtable
);
591 return SCM_STRUCT_VTABLE (handle
);
595 SCM_PROC (s_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0, scm_struct_vtable_tag
);
598 scm_struct_vtable_tag (handle
)
601 SCM_ASSERT (SCM_NIMP (handle
) && (SCM_BOOL_F
!= scm_struct_vtable_p (handle
)),
602 handle
, SCM_ARG1
, s_struct_vtable_tag
);
603 return scm_long2num (SCM_STRUCT_DATA (handle
)[-1]);
610 scm_print_struct (exp
, port
, pstate
)
613 scm_print_state
*pstate
;
615 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp
))))
616 scm_printer_apply (SCM_STRUCT_PRINTER (exp
), exp
, port
, pstate
);
619 scm_lfwrite ("#<struct ", sizeof ("#<struct ") - 1, port
);
620 scm_intprint (SCM_STRUCT_VTABLE (exp
), 16, port
);
621 scm_putc (':', port
);
622 scm_intprint (exp
, 16, port
);
623 scm_putc ('>', port
);
630 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosrpw", sizeof ("pruosrpw") - 1, SCM_BOOL_F
));
631 scm_permanent_object (required_vtable_fields
);
632 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout
));
633 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable
));
634 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer
));
635 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user
));