1 /* Copyright (C) 1996, 1997 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
);
136 static void init_struct
SCM_P ((SCM handle
, int tail_elts
, SCM inits
));
139 init_struct (handle
, tail_elts
, inits
)
146 unsigned char * fields_desc
;
147 unsigned char prot
= 0;
152 layout
= SCM_STRUCT_LAYOUT (handle
);
153 data
= SCM_STRUCT_DATA (handle
);
154 fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
155 n_fields
= SCM_LENGTH (layout
) / 2;
156 mem
= SCM_STRUCT_DATA (handle
);
162 prot
= fields_desc
[1];
163 if (SCM_LAYOUT_TAILP (prot
))
166 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
168 n_fields
+= tail_elts
- 1;
174 switch (*fields_desc
)
178 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
182 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "init_struct");
183 inits
= SCM_CDR (inits
);
189 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
193 *mem
= scm_num2ulong (SCM_CAR (inits
), SCM_ARGn
, "init_struct");
194 inits
= SCM_CDR (inits
);
199 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
203 *mem
= SCM_CAR (inits
);
204 inits
= SCM_CDR (inits
);
211 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
212 *((double *)mem
) = 0.0;
215 *mem
= scm_num2dbl (SCM_CAR (inits
), "init_struct");
216 inits
= SCM_CDR (inits
);
233 SCM_PROC (s_struct_p
, "struct?", 1, 0, 0, scm_struct_p
);
239 return ((SCM_NIMP (x
) && SCM_STRUCTP (x
))
244 SCM_PROC (s_struct_vtable_p
, "struct-vtable?", 1, 0, 0, scm_struct_vtable_p
);
247 scm_struct_vtable_p (x
)
256 if (!SCM_STRUCTP (x
))
259 layout
= SCM_STRUCT_LAYOUT (x
);
261 if (SCM_LENGTH (layout
) < SCM_LENGTH (required_vtable_fields
))
264 if (strncmp (SCM_CHARS (layout
), SCM_CHARS (required_vtable_fields
),
265 SCM_LENGTH (required_vtable_fields
)))
268 mem
= SCM_STRUCT_DATA (x
);
273 if (SCM_IMP (mem
[0]))
276 return (SCM_SYMBOLP (mem
[0])
282 /* All struct data must be allocated at an address whose bottom three
283 bits are zero. This is because the tag for a struct lives in the
284 bottom three bits of the struct's car, and the upper bits point to
285 the data of its vtable, which is a struct itself. Thus, if the
286 address of that data doesn't end in three zeros, tagging it will
289 This function allocates a block of memory, and returns a pointer at
290 least scm_struct_n_extra_words words into the block. Furthermore,
291 it guarantees that that pointer's least three significant bits are
294 The argument n_words should be the number of words that should
295 appear after the returned address. (That is, it shouldn't include
296 scm_struct_n_extra_words.)
298 This function initializes the following fields of the struct:
300 scm_struct_i_ptr --- the actual stort of the block of memory; the
301 address you should pass to 'free' to dispose of the block.
302 This field allows us to both guarantee that the returned
303 address is divisible by eight, and allow the GC to free the
306 scm_struct_i_n_words --- the number of words allocated to the
307 block, including the extra fields. This is used by the GC.
309 scm_struct_i_tag --- a unique tag assigned to this struct,
310 allocated according to struct_num.
315 static SCM
*alloc_struct
SCM_P ((int n_words
, char *who
));
318 alloc_struct (n_words
, who
)
322 int size
= sizeof (SCM
) * (n_words
+ scm_struct_n_extra_words
) + 7;
323 SCM
*block
= (SCM
*) scm_must_malloc (size
, who
);
325 /* Adjust the pointer to hide the extra words. */
326 SCM
*p
= block
+ scm_struct_n_extra_words
;
328 /* Adjust it even further so it's aligned on an eight-byte boundary. */
329 p
= (SCM
*) (((SCM
) p
+ 7) & ~7);
331 /* Initialize a few fields as described above. */
332 p
[scm_struct_i_ptr
] = (SCM
) block
;
333 p
[scm_struct_i_n_words
] = (SCM
) (scm_struct_n_extra_words
+ n_words
);
334 p
[scm_struct_i_tag
] = struct_num
++;
340 SCM_PROC (s_make_struct
, "make-struct", 2, 0, 1, scm_make_struct
);
343 scm_make_struct (vtable
, tail_array_size
, init
)
354 SCM_ASSERT ((SCM_BOOL_F
!= scm_struct_vtable_p (vtable
)),
355 vtable
, SCM_ARG1
, s_make_struct
);
356 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
359 layout
= SCM_STRUCT_DATA (vtable
)[scm_vtable_index_layout
];
360 basic_size
= SCM_LENGTH (layout
) / 2;
361 tail_elts
= SCM_INUM (tail_array_size
);
362 SCM_NEWCELL (handle
);
364 data
= alloc_struct (basic_size
+ tail_elts
, "make-struct");
365 SCM_SETCDR (handle
, data
);
366 SCM_SETCAR (handle
, ((SCM
)SCM_STRUCT_DATA (vtable
)) + scm_tc3_cons_gloc
);
367 init_struct (handle
, tail_elts
, init
);
374 SCM_PROC (s_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable
);
377 scm_make_vtable_vtable (extra_fields
, tail_array_size
, init
)
389 SCM_ASSERT (SCM_NIMP (extra_fields
) && SCM_ROSTRINGP (extra_fields
),
390 extra_fields
, SCM_ARG1
, s_make_vtable_vtable
);
391 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
392 s_make_vtable_vtable
);
394 fields
= scm_string_append (scm_listify (required_vtable_fields
,
397 layout
= scm_make_struct_layout (fields
);
398 basic_size
= SCM_LENGTH (layout
) / 2;
399 tail_elts
= SCM_INUM (tail_array_size
);
400 SCM_NEWCELL (handle
);
402 data
= alloc_struct (basic_size
+ tail_elts
, "make-vtable-vtable");
403 SCM_SETCDR (handle
, data
);
404 SCM_SETCAR (handle
, ((SCM
)data
) + scm_tc3_cons_gloc
);
405 SCM_STRUCT_LAYOUT (handle
) = layout
;
406 init_struct (handle
, tail_elts
, scm_cons (layout
, init
));
414 SCM_PROC (s_struct_ref
, "struct-ref", 2, 0, 0, scm_struct_ref
);
417 scm_struct_ref (handle
, pos
)
421 SCM answer
= SCM_UNDEFINED
;
426 unsigned char * fields_desc
;
427 unsigned char field_type
= 0;
430 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
431 SCM_ARG1
, s_struct_ref
);
432 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
434 layout
= SCM_STRUCT_LAYOUT (handle
);
435 data
= SCM_STRUCT_DATA (handle
);
438 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
439 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
441 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_ref
);
443 if (p
* 2 < SCM_LENGTH (layout
))
446 field_type
= fields_desc
[p
* 2];
447 ref
= fields_desc
[p
* 2 + 1];
448 if ((ref
!= 'r') && (ref
!= 'w'))
450 if ((ref
== 'R') || (ref
== 'W'))
453 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
456 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
457 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
460 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
467 answer
= scm_ulong2num (data
[p
]);
472 answer
= scm_long2num (data
[p
]);
476 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
487 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_ref
);
495 SCM_PROC (s_struct_set_x
, "struct-set!", 3, 0, 0, scm_struct_set_x
);
498 scm_struct_set_x (handle
, pos
, val
)
507 unsigned char * fields_desc
;
508 unsigned char field_type
= 0;
512 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
513 SCM_ARG1
, s_struct_ref
);
514 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
516 layout
= SCM_STRUCT_LAYOUT (handle
);
517 data
= SCM_STRUCT_DATA (handle
);
520 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
521 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
523 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_set_x
);
525 if (p
* 2 < SCM_LENGTH (layout
))
528 field_type
= fields_desc
[p
* 2];
529 set_x
= fields_desc
[p
* 2 + 1];
531 SCM_ASSERT (0, pos
, "set_x denied", s_struct_set_x
);
533 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
534 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
537 SCM_ASSERT (0, pos
, "set_x denied", s_struct_ref
);
544 data
[p
] = (SCM
)scm_num2ulong (val
, (char *)SCM_ARG3
, s_struct_set_x
);
549 data
[p
] = scm_num2long (val
, (char *)SCM_ARG3
, s_struct_set_x
);
553 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
562 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "self fields immutable", s_struct_set_x
);
566 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_set_x
);
574 SCM_PROC (s_struct_vtable
, "struct-vtable", 1, 0, 0, scm_struct_vtable
);
577 scm_struct_vtable (handle
)
580 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
581 SCM_ARG1
, s_struct_vtable
);
582 return SCM_STRUCT_VTABLE (handle
);
586 SCM_PROC (s_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0, scm_struct_vtable_tag
);
589 scm_struct_vtable_tag (handle
)
592 SCM_ASSERT (SCM_NIMP (handle
) && (SCM_BOOL_F
!= scm_struct_vtable_p (handle
)),
593 handle
, SCM_ARG1
, s_struct_vtable_tag
);
594 return scm_long2num (SCM_STRUCT_DATA (handle
)[-1]);
601 scm_print_struct (exp
, port
, pstate
)
604 scm_print_state
*pstate
;
606 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp
))))
607 scm_printer_apply (SCM_STRUCT_PRINTER (exp
), exp
, port
, pstate
);
610 scm_lfwrite ("#<struct ", sizeof ("#<struct ") - 1, port
);
611 scm_intprint (SCM_STRUCT_VTABLE (exp
), 16, port
);
612 scm_putc (':', port
);
613 scm_intprint (exp
, 16, port
);
614 scm_putc ('>', port
);
621 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosrpw", sizeof ("pruosrpw") - 1, SCM_BOOL_F
));
622 scm_permanent_object (required_vtable_fields
);
623 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout
));
624 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable
));
625 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer
));
626 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user
));