1 /* Copyright (C) 1996 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;
59 static SCM struct_printer_var
;
62 SCM_PROC (s_struct_make_layout
, "make-struct-layout", 1, 0, 0, scm_make_struct_layout
);
65 scm_make_struct_layout (fields
)
69 SCM_ASSERT (SCM_NIMP (fields
) && SCM_ROSTRINGP (fields
),
70 fields
, SCM_ARG1
, s_struct_make_layout
);
77 len
= SCM_ROLENGTH (fields
);
78 field_desc
= SCM_ROCHARS (fields
);
79 SCM_ASSERT (!(len
& 1), fields
, "odd length field specification", s_struct_make_layout
);
81 for (x
= 0; x
< len
; x
+= 2)
83 switch (field_desc
[x
])
94 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized field type", s_struct_make_layout
);
97 switch (field_desc
[x
+ 1])
100 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
101 "self fields not writable", s_struct_make_layout
);
109 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
110 "self fields not allowed in tail array",
111 s_struct_make_layout
);
112 SCM_ASSERT (x
== len
- 2, SCM_MAKICHR (field_desc
[x
+ 1]),
113 "tail array field must be last field in layout",
114 s_struct_make_layout
);
117 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized ref specification", s_struct_make_layout
);
120 if (field_desc
[x
] == 'd')
122 SCM_ASSERT (field_desc
[x
+ 2] == '-', SCM_MAKINUM (x
/ 2), "missing dash field", s_struct_make_layout
);
128 new_sym
= SCM_CAR (scm_intern_obarray (field_desc
, len
, SCM_BOOL_F
));
130 return scm_return_first (new_sym
, fields
);
137 static void init_struct
SCM_P ((SCM handle
, int tail_elts
, SCM inits
));
140 init_struct (handle
, tail_elts
, inits
)
147 unsigned char * fields_desc
;
148 unsigned char prot
= 0;
153 layout
= SCM_STRUCT_LAYOUT (handle
);
154 data
= SCM_STRUCT_DATA (handle
);
155 fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
156 n_fields
= SCM_LENGTH (layout
) / 2;
157 mem
= SCM_STRUCT_DATA (handle
);
163 prot
= fields_desc
[1];
164 if (SCM_LAYOUT_TAILP (prot
))
167 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
169 n_fields
+= tail_elts
- 1;
175 switch (*fields_desc
)
179 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
183 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "init_struct");
184 inits
= SCM_CDR (inits
);
190 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
194 *mem
= scm_num2ulong (SCM_CAR (inits
), SCM_ARGn
, "init_struct");
195 inits
= SCM_CDR (inits
);
200 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
204 *mem
= SCM_CAR (inits
);
205 inits
= SCM_CDR (inits
);
212 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
213 *((double *)mem
) = 0.0;
216 *mem
= scm_num2dbl (SCM_CAR (inits
), "init_struct");
217 inits
= SCM_CDR (inits
);
234 SCM_PROC (s_struct_p
, "struct?", 1, 0, 0, scm_struct_p
);
240 return ((SCM_NIMP (x
) && SCM_STRUCTP (x
))
245 SCM_PROC (s_struct_vtable_p
, "struct-vtable?", 1, 0, 0, scm_struct_vtable_p
);
248 scm_struct_vtable_p (x
)
257 if (!SCM_STRUCTP (x
))
260 layout
= SCM_STRUCT_LAYOUT (x
);
262 if (SCM_LENGTH (layout
) < SCM_LENGTH (required_vtable_fields
))
265 if (strncmp (SCM_CHARS (layout
), SCM_CHARS (required_vtable_fields
),
266 SCM_LENGTH (required_vtable_fields
)))
269 mem
= SCM_STRUCT_DATA (x
);
274 if (SCM_IMP (mem
[0]))
277 return (SCM_SYMBOLP (mem
[0])
283 /* All struct data must be allocated at an address whose bottom three
284 bits are zero. This is because the tag for a struct lives in the
285 bottom three bits of the struct's car, and the upper bits point to
286 the data of its vtable, which is a struct itself. Thus, if the
287 address of that data doesn't end in three zeros, tagging it will
290 This function allocates a block of memory, and returns a pointer at
291 least scm_struct_n_extra_words words into the block. Furthermore,
292 it guarantees that that pointer's least three significant bits are
295 The argument n_words should be the number of words that should
296 appear after the returned address. (That is, it shouldn't include
297 scm_struct_n_extra_words.)
299 This function initializes the following fields of the struct:
301 scm_struct_i_ptr --- the actual stort of the block of memory; the
302 address you should pass to 'free' to dispose of the block.
303 This field allows us to both guarantee that the returned
304 address is divisible by eight, and allow the GC to free the
307 scm_struct_i_n_words --- the number of words allocated to the
308 block, including the extra fields. This is used by the GC.
310 scm_struct_i_tag --- a unique tag assigned to this struct,
311 allocated according to struct_num.
316 static SCM
*alloc_struct
SCM_P ((int n_words
, char *who
));
319 alloc_struct (n_words
, who
)
323 int size
= sizeof (SCM
) * (n_words
+ scm_struct_n_extra_words
) + 7;
324 SCM
*block
= (SCM
*) scm_must_malloc (size
, who
);
326 /* Adjust the pointer to hide the extra words. */
327 SCM
*p
= block
+ scm_struct_n_extra_words
;
329 /* Adjust it even further so it's aligned on an eight-byte boundary. */
330 p
= (SCM
*) (((SCM
) p
+ 7) & ~7);
332 /* Initialize a few fields as described above. */
333 p
[scm_struct_i_ptr
] = (SCM
) block
;
334 p
[scm_struct_i_n_words
] = (SCM
) (scm_struct_n_extra_words
+ n_words
);
335 p
[scm_struct_i_tag
] = struct_num
++;
341 SCM_PROC (s_make_struct
, "make-struct", 2, 0, 1, scm_make_struct
);
344 scm_make_struct (vtable
, tail_array_size
, init
)
355 SCM_ASSERT ((SCM_BOOL_F
!= scm_struct_vtable_p (vtable
)),
356 vtable
, SCM_ARG1
, s_make_struct
);
357 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
360 layout
= SCM_STRUCT_DATA (vtable
)[scm_struct_i_layout
];
361 basic_size
= SCM_LENGTH (layout
) / 2;
362 tail_elts
= SCM_INUM (tail_array_size
);
363 SCM_NEWCELL (handle
);
365 data
= alloc_struct (basic_size
+ tail_elts
, "make-struct");
366 SCM_SETCDR (handle
, data
);
367 SCM_SETCAR (handle
, ((SCM
)SCM_STRUCT_DATA (vtable
)) + scm_tc3_cons_gloc
);
368 init_struct (handle
, tail_elts
, init
);
375 SCM_PROC (s_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable
);
378 scm_make_vtable_vtable (extra_fields
, tail_array_size
, init
)
390 SCM_ASSERT (SCM_NIMP (extra_fields
) && SCM_ROSTRINGP (extra_fields
),
391 extra_fields
, SCM_ARG1
, s_make_vtable_vtable
);
392 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
393 s_make_vtable_vtable
);
395 fields
= scm_string_append (scm_listify (required_vtable_fields
,
398 layout
= scm_make_struct_layout (fields
);
399 basic_size
= SCM_LENGTH (layout
) / 2;
400 tail_elts
= SCM_INUM (tail_array_size
);
401 SCM_NEWCELL (handle
);
403 data
= alloc_struct (basic_size
+ tail_elts
, "make-vtable-vtable");
404 SCM_SETCDR (handle
, data
);
405 SCM_SETCAR (handle
, ((SCM
)data
) + scm_tc3_cons_gloc
);
406 SCM_STRUCT_LAYOUT (handle
) = layout
;
407 init_struct (handle
, tail_elts
, scm_cons (layout
, init
));
415 SCM_PROC (s_struct_ref
, "struct-ref", 2, 0, 0, scm_struct_ref
);
418 scm_struct_ref (handle
, pos
)
422 SCM answer
= SCM_UNDEFINED
;
427 unsigned char * fields_desc
;
428 unsigned char field_type
;
431 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
432 SCM_ARG1
, s_struct_ref
);
433 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
435 layout
= SCM_STRUCT_LAYOUT (handle
);
436 data
= SCM_STRUCT_DATA (handle
);
439 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
440 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
442 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_ref
);
444 if (p
* 2 < SCM_LENGTH (layout
))
447 field_type
= fields_desc
[p
* 2];
448 ref
= fields_desc
[p
* 2 + 1];
449 if ((ref
!= 'r') && (ref
!= 'w'))
451 if ((ref
== 'R') || (ref
== 'W'))
454 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
457 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
458 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
461 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
468 answer
= scm_ulong2num (data
[p
]);
473 answer
= scm_long2num (data
[p
]);
477 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
488 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_ref
);
496 SCM_PROC (s_struct_set_x
, "struct-set!", 3, 0, 0, scm_struct_set_x
);
499 scm_struct_set_x (handle
, pos
, val
)
508 unsigned char * fields_desc
;
509 unsigned char field_type
;
513 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
514 SCM_ARG1
, s_struct_ref
);
515 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
517 layout
= SCM_STRUCT_LAYOUT (handle
);
518 data
= SCM_STRUCT_DATA (handle
);
521 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
522 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
524 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_set_x
);
526 if (p
* 2 < SCM_LENGTH (layout
))
529 field_type
= fields_desc
[p
* 2];
530 set_x
= fields_desc
[p
* 2 + 1];
532 SCM_ASSERT (0, pos
, "set_x denied", s_struct_set_x
);
534 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
535 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
538 SCM_ASSERT (0, pos
, "set_x denied", s_struct_ref
);
545 data
[p
] = (SCM
)scm_num2ulong (val
, (char *)SCM_ARG3
, s_struct_set_x
);
550 data
[p
] = scm_num2long (val
, (char *)SCM_ARG3
, s_struct_set_x
);
554 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
563 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "self fields immutable", s_struct_set_x
);
567 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_set_x
);
575 SCM_PROC (s_struct_vtable
, "struct-vtable", 1, 0, 0, scm_struct_vtable
);
578 scm_struct_vtable (handle
)
581 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
582 SCM_ARG1
, s_struct_vtable
);
583 return SCM_STRUCT_VTABLE (handle
);
587 SCM_PROC (s_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0, scm_struct_vtable_tag
);
590 scm_struct_vtable_tag (handle
)
593 SCM_ASSERT (SCM_NIMP (handle
) && (SCM_BOOL_F
!= scm_struct_vtable_p (handle
)),
594 handle
, SCM_ARG1
, s_struct_vtable_tag
);
595 return scm_long2num (SCM_STRUCT_DATA (handle
)[-1]);
602 scm_print_struct (exp
, port
, pstate
)
605 scm_print_state
*pstate
;
607 SCM prt
= SCM_CDR (struct_printer_var
);
608 if (SCM_FALSEP(prt
) ||
609 SCM_FALSEP(scm_printer_apply (prt
, exp
, port
, pstate
)))
611 scm_gen_write (scm_regular_string
, "#<struct ", sizeof ("#<struct ") - 1,
613 scm_intprint (exp
, 16, port
);
614 scm_gen_putc ('>', port
);
621 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosr", sizeof ("pruosr") - 1, SCM_BOOL_F
));
622 scm_permanent_object (required_vtable_fields
);
623 scm_sysintern ("struct-vtable-offset", SCM_MAKINUM (scm_struct_i_vtable_offset
));
624 struct_printer_var
= scm_sysintern("*struct-printer*", SCM_BOOL_F
);