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. */
60 static SCM required_vtable_fields
= SCM_BOOL_F
;
61 static int struct_num
= 0;
65 SCM_PROC (s_struct_make_layout
, "make-struct-layout", 1, 0, 0, scm_make_struct_layout
);
68 scm_make_struct_layout (fields
)
72 SCM_ASSERT (SCM_NIMP (fields
) && SCM_ROSTRINGP (fields
),
73 fields
, SCM_ARG1
, s_struct_make_layout
);
80 len
= SCM_ROLENGTH (fields
);
81 field_desc
= SCM_ROCHARS (fields
);
82 SCM_ASSERT (!(len
& 1), fields
, "odd length field specification", s_struct_make_layout
);
84 for (x
= 0; x
< len
; x
+= 2)
86 switch (field_desc
[x
])
97 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized field type", s_struct_make_layout
);
100 switch (field_desc
[x
+ 1])
103 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
104 "self fields not writable", s_struct_make_layout
);
112 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
113 "self fields not allowed in tail array",
114 s_struct_make_layout
);
115 SCM_ASSERT (x
== len
- 2, SCM_MAKICHR (field_desc
[x
+ 1]),
116 "tail array field must be last field in layout",
117 s_struct_make_layout
);
120 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized ref specification", s_struct_make_layout
);
123 if (field_desc
[x
] == 'd')
125 SCM_ASSERT (field_desc
[x
+ 2] == '-', SCM_MAKINUM (x
/ 2), "missing dash field", s_struct_make_layout
);
131 new_sym
= SCM_CAR (scm_intern_obarray (field_desc
, len
, SCM_BOOL_F
));
133 return scm_return_first (new_sym
, fields
);
141 scm_struct_init (handle
, tail_elts
, inits
)
148 unsigned char * fields_desc
;
149 unsigned char prot
= 0;
154 layout
= SCM_STRUCT_LAYOUT (handle
);
155 data
= SCM_STRUCT_DATA (handle
);
156 fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
157 n_fields
= SCM_LENGTH (layout
) / 2;
158 mem
= SCM_STRUCT_DATA (handle
);
164 prot
= fields_desc
[1];
165 if (SCM_LAYOUT_TAILP (prot
))
168 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
170 n_fields
+= tail_elts
- 1;
176 switch (*fields_desc
)
180 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
184 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
185 inits
= SCM_CDR (inits
);
191 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
195 *mem
= scm_num2ulong (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
196 inits
= SCM_CDR (inits
);
201 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
205 *mem
= SCM_CAR (inits
);
206 inits
= SCM_CDR (inits
);
213 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
214 *((double *)mem
) = 0.0;
217 *mem
= scm_num2dbl (SCM_CAR (inits
), "scm_struct_init");
218 inits
= SCM_CDR (inits
);
235 SCM_PROC (s_struct_p
, "struct?", 1, 0, 0, scm_struct_p
);
241 return ((SCM_NIMP (x
) && SCM_STRUCTP (x
))
246 SCM_PROC (s_struct_vtable_p
, "struct-vtable?", 1, 0, 0, scm_struct_vtable_p
);
249 scm_struct_vtable_p (x
)
258 if (!SCM_STRUCTP (x
))
261 layout
= SCM_STRUCT_LAYOUT (x
);
263 if (SCM_LENGTH (layout
) < SCM_LENGTH (required_vtable_fields
))
266 if (strncmp (SCM_CHARS (layout
), SCM_CHARS (required_vtable_fields
),
267 SCM_LENGTH (required_vtable_fields
)))
270 mem
= SCM_STRUCT_DATA (x
);
275 if (SCM_IMP (mem
[0]))
278 return (SCM_SYMBOLP (mem
[0])
284 /* All struct data must be allocated at an address whose bottom three
285 bits are zero. This is because the tag for a struct lives in the
286 bottom three bits of the struct's car, and the upper bits point to
287 the data of its vtable, which is a struct itself. Thus, if the
288 address of that data doesn't end in three zeros, tagging it will
291 This function allocates a block of memory, and returns a pointer at
292 least scm_struct_n_extra_words words into the block. Furthermore,
293 it guarantees that that pointer's least three significant bits are
296 The argument n_words should be the number of words that should
297 appear after the returned address. (That is, it shouldn't include
298 scm_struct_n_extra_words.)
300 This function initializes the following fields of the struct:
302 scm_struct_i_ptr --- the actual stort of the block of memory; the
303 address you should pass to 'free' to dispose of the block.
304 This field allows us to both guarantee that the returned
305 address is divisible by eight, and allow the GC to free the
308 scm_struct_i_n_words --- the number of words allocated to the
309 block, including the extra fields. This is used by the GC.
311 scm_struct_i_tag --- a unique tag assigned to this struct,
312 allocated according to struct_num.
318 scm_alloc_struct (int n_words
, int n_extra
, char *who
)
320 int size
= sizeof (SCM
) * (n_words
+ n_extra
) + 7;
321 SCM
*block
= (SCM
*) scm_must_malloc (size
, who
);
323 /* Adjust the pointer to hide the extra words. */
324 SCM
*p
= block
+ n_extra
;
326 /* Adjust it even further so it's aligned on an eight-byte boundary. */
327 p
= (SCM
*) (((SCM
) p
+ 7) & ~7);
329 /* Initialize a few fields as described above, except for the tag. */
330 p
[scm_struct_i_ptr
] = (SCM
) block
;
331 p
[scm_struct_i_n_words
] = (SCM
) (n_words
+ n_extra
);
337 SCM_PROC (s_make_struct
, "make-struct", 2, 0, 1, scm_make_struct
);
340 scm_make_struct (vtable
, tail_array_size
, init
)
351 SCM_ASSERT ((SCM_BOOL_F
!= scm_struct_vtable_p (vtable
)),
352 vtable
, SCM_ARG1
, s_make_struct
);
353 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
356 layout
= SCM_STRUCT_DATA (vtable
)[scm_vtable_index_layout
];
357 basic_size
= SCM_LENGTH (layout
) / 2;
358 tail_elts
= SCM_INUM (tail_array_size
);
359 SCM_NEWCELL (handle
);
361 if (SCM_STRUCT_DATA (vtable
)[scm_struct_i_flags
] & SCM_STRUCTF_ENTITY
)
363 data
= scm_alloc_struct (basic_size
+ tail_elts
,
364 scm_struct_entity_n_extra_words
,
366 data
[scm_struct_i_proc
+ 0] = SCM_BOOL_F
;
367 data
[scm_struct_i_proc
+ 1] = SCM_BOOL_F
;
368 data
[scm_struct_i_proc
+ 2] = SCM_BOOL_F
;
369 data
[scm_struct_i_proc
+ 3] = SCM_BOOL_F
;
370 data
[scm_struct_i_setter
] = SCM_BOOL_F
;
373 data
= scm_alloc_struct (basic_size
+ tail_elts
,
374 scm_struct_n_extra_words
,
376 data
[scm_struct_i_tag
] = struct_num
++;
377 SCM_SETCDR (handle
, data
);
378 SCM_SETCAR (handle
, ((SCM
)SCM_STRUCT_DATA (vtable
)) + scm_tc3_cons_gloc
);
379 scm_struct_init (handle
, tail_elts
, init
);
386 SCM_PROC (s_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable
);
389 scm_make_vtable_vtable (extra_fields
, tail_array_size
, init
)
401 SCM_ASSERT (SCM_NIMP (extra_fields
) && SCM_ROSTRINGP (extra_fields
),
402 extra_fields
, SCM_ARG1
, s_make_vtable_vtable
);
403 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
404 s_make_vtable_vtable
);
406 fields
= scm_string_append (scm_listify (required_vtable_fields
,
409 layout
= scm_make_struct_layout (fields
);
410 basic_size
= SCM_LENGTH (layout
) / 2;
411 tail_elts
= SCM_INUM (tail_array_size
);
412 SCM_NEWCELL (handle
);
414 data
= scm_alloc_struct (basic_size
+ tail_elts
,
415 scm_struct_n_extra_words
,
416 "make-vtable-vtable");
417 data
[scm_struct_i_tag
] = struct_num
++;
418 SCM_SETCDR (handle
, data
);
419 SCM_SETCAR (handle
, ((SCM
)data
) + scm_tc3_cons_gloc
);
420 SCM_STRUCT_LAYOUT (handle
) = layout
;
421 scm_struct_init (handle
, tail_elts
, scm_cons (layout
, init
));
429 SCM_PROC (s_struct_ref
, "struct-ref", 2, 0, 0, scm_struct_ref
);
432 scm_struct_ref (handle
, pos
)
436 SCM answer
= SCM_UNDEFINED
;
441 unsigned char * fields_desc
;
442 unsigned char field_type
= 0;
445 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
446 SCM_ARG1
, s_struct_ref
);
447 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
449 layout
= SCM_STRUCT_LAYOUT (handle
);
450 data
= SCM_STRUCT_DATA (handle
);
453 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
454 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
456 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_ref
);
458 if (p
* 2 < SCM_LENGTH (layout
))
461 field_type
= fields_desc
[p
* 2];
462 ref
= fields_desc
[p
* 2 + 1];
463 if ((ref
!= 'r') && (ref
!= 'w'))
465 if ((ref
== 'R') || (ref
== 'W'))
468 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
471 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
472 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
475 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
482 answer
= scm_ulong2num (data
[p
]);
487 answer
= scm_long2num (data
[p
]);
491 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
502 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_ref
);
510 SCM_PROC (s_struct_set_x
, "struct-set!", 3, 0, 0, scm_struct_set_x
);
513 scm_struct_set_x (handle
, pos
, val
)
522 unsigned char * fields_desc
;
523 unsigned char field_type
= 0;
527 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
528 SCM_ARG1
, s_struct_ref
);
529 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
531 layout
= SCM_STRUCT_LAYOUT (handle
);
532 data
= SCM_STRUCT_DATA (handle
);
535 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
536 n_fields
= data
[scm_struct_i_n_words
] - scm_struct_n_extra_words
;
538 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_set_x
);
540 if (p
* 2 < SCM_LENGTH (layout
))
543 field_type
= fields_desc
[p
* 2];
544 set_x
= fields_desc
[p
* 2 + 1];
546 SCM_ASSERT (0, pos
, "set_x denied", s_struct_set_x
);
548 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
549 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
552 SCM_ASSERT (0, pos
, "set_x denied", s_struct_ref
);
559 data
[p
] = (SCM
)scm_num2ulong (val
, (char *)SCM_ARG3
, s_struct_set_x
);
564 data
[p
] = scm_num2long (val
, (char *)SCM_ARG3
, s_struct_set_x
);
568 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
577 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "self fields immutable", s_struct_set_x
);
581 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_set_x
);
589 SCM_PROC (s_struct_vtable
, "struct-vtable", 1, 0, 0, scm_struct_vtable
);
592 scm_struct_vtable (handle
)
595 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
596 SCM_ARG1
, s_struct_vtable
);
597 return SCM_STRUCT_VTABLE (handle
);
601 SCM_PROC (s_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0, scm_struct_vtable_tag
);
604 scm_struct_vtable_tag (handle
)
607 SCM_ASSERT (SCM_NFALSEP (scm_struct_vtable_p (handle
)),
608 handle
, SCM_ARG1
, s_struct_vtable_tag
);
609 return scm_long2num (SCM_STRUCT_DATA (handle
)[scm_struct_i_tag
]);
612 /* {Associating names and classes with vtables}
614 * The name of a vtable should probably be stored as a slot. This is
615 * a backward compatible solution until agreement has been achieved on
616 * how to associate names with vtables.
620 scm_struct_ihashq (SCM obj
, unsigned int n
)
622 return (SCM_STRUCT_DATA (obj
)[scm_struct_i_tag
] & ~SCM_STRUCTF_MASK
) % n
;
626 scm_struct_create_handle (SCM obj
)
628 SCM handle
= scm_hash_fn_create_handle_x (scm_struct_table
,
634 if (SCM_FALSEP (SCM_CDR (handle
)))
635 SCM_SETCDR (handle
, scm_cons (SCM_BOOL_F
, SCM_BOOL_F
));
639 SCM_PROC (s_struct_vtable_name
, "struct-vtable-name", 1, 0, 0, scm_struct_vtable_name
);
642 scm_struct_vtable_name (SCM vtable
)
644 SCM_ASSERT (SCM_NFALSEP (scm_struct_vtable_p (vtable
)),
645 vtable
, SCM_ARG1
, s_struct_vtable_name
);
647 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable
)));
650 SCM_PROC (s_set_struct_vtable_name_x
, "set-struct-vtable-name!", 2, 0, 0, scm_set_struct_vtable_name_x
);
653 scm_set_struct_vtable_name_x (SCM vtable
, SCM name
)
655 SCM_ASSERT (SCM_NIMP (vtable
) && SCM_NFALSEP (scm_struct_vtable_p (vtable
)),
656 vtable
, SCM_ARG1
, s_set_struct_vtable_name_x
);
657 SCM_ASSERT (SCM_NIMP (name
) && SCM_SYMBOLP (name
),
658 name
, SCM_ARG2
, s_set_struct_vtable_name_x
);
659 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable
)),
661 return SCM_UNSPECIFIED
;
668 scm_print_struct (exp
, port
, pstate
)
671 scm_print_state
*pstate
;
673 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp
))))
674 scm_printer_apply (SCM_STRUCT_PRINTER (exp
), exp
, port
, pstate
);
677 scm_lfwrite ("#<struct ", sizeof ("#<struct ") - 1, port
);
678 scm_intprint (SCM_STRUCT_VTABLE (exp
), 16, port
);
679 scm_putc (':', port
);
680 scm_intprint (exp
, 16, port
);
681 scm_putc ('>', port
);
689 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
690 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosrpw", sizeof ("pruosrpw") - 1, SCM_BOOL_F
));
691 scm_permanent_object (required_vtable_fields
);
692 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout
));
693 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable
));
694 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer
));
695 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user
));