1 /* Copyright (C) 1996, 1997, 1998, 1999 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. */
42 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
56 #include "scm_validate.h"
65 static SCM required_vtable_fields
= SCM_BOOL_F
;
69 GUILE_PROC (scm_make_struct_layout
, "make-struct-layout", 1, 0, 0,
71 "Return a new structure layout object.
73 @var{fields} must be a read-only string made up of pairs of characters
74 strung together. The first character of each pair describes a field
75 type, the second a field protection. Allowed types are 'p' for
76 GC-protected Scheme data, 'u' for unprotected binary data, and 's' for
77 fields that should point to the structure itself. Allowed protections
78 are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque
79 fields. The last field protection specification may be capitalized to
80 indicate that the field is a tail-array.")
81 #define FUNC_NAME s_scm_make_struct_layout
84 SCM_VALIDATE_ROSTRING(1,fields
);
90 len
= SCM_ROLENGTH (fields
);
91 field_desc
= SCM_ROCHARS (fields
);
92 SCM_ASSERT (!(len
& 1), fields
, "odd length field specification", FUNC_NAME
);
94 for (x
= 0; x
< len
; x
+= 2)
96 switch (field_desc
[x
])
107 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized field type", FUNC_NAME
);
110 switch (field_desc
[x
+ 1])
113 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
114 "self fields not writable", FUNC_NAME
);
122 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
123 "self fields not allowed in tail array",
125 SCM_ASSERT (x
== len
- 2, SCM_MAKICHR (field_desc
[x
+ 1]),
126 "tail array field must be last field in layout",
130 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized ref specification", FUNC_NAME
);
133 if (field_desc
[x
] == 'd')
135 SCM_ASSERT (field_desc
[x
+ 2] == '-', SCM_MAKINUM (x
/ 2), "missing dash field", FUNC_NAME
);
141 new_sym
= SCM_CAR (scm_intern_obarray (field_desc
, len
, SCM_BOOL_F
));
143 return scm_return_first (new_sym
, fields
);
152 scm_struct_init (SCM handle
, int tail_elts
, SCM inits
)
156 unsigned char * fields_desc
;
157 unsigned char prot
= 0;
162 layout
= SCM_STRUCT_LAYOUT (handle
);
163 data
= SCM_STRUCT_DATA (handle
);
164 fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
165 n_fields
= SCM_LENGTH (layout
) / 2;
166 mem
= SCM_STRUCT_DATA (handle
);
172 prot
= fields_desc
[1];
173 if (SCM_LAYOUT_TAILP (prot
))
176 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
178 n_fields
+= tail_elts
- 1;
184 switch (*fields_desc
)
188 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
192 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
193 inits
= SCM_CDR (inits
);
199 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
203 *mem
= scm_num2ulong (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
204 inits
= SCM_CDR (inits
);
209 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
213 *mem
= SCM_CAR (inits
);
214 inits
= SCM_CDR (inits
);
221 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
222 *((double *)mem
) = 0.0;
225 *mem
= scm_num2dbl (SCM_CAR (inits
), "scm_struct_init");
226 inits
= SCM_CDR (inits
);
243 GUILE_PROC (scm_struct_p
, "struct?", 1, 0, 0,
245 "Return #t iff @var{obj} is a structure object, else #f.")
246 #define FUNC_NAME s_scm_struct_p
248 return SCM_BOOL(SCM_STRUCTP (x
));
252 GUILE_PROC (scm_struct_vtable_p
, "struct-vtable?", 1, 0, 0,
254 "Return #t iff obj is a vtable structure.")
255 #define FUNC_NAME s_scm_struct_vtable_p
263 if (!SCM_STRUCTP (x
))
266 layout
= SCM_STRUCT_LAYOUT (x
);
268 if (SCM_LENGTH (layout
) < SCM_LENGTH (required_vtable_fields
))
271 if (strncmp (SCM_CHARS (layout
), SCM_CHARS (required_vtable_fields
),
272 SCM_LENGTH (required_vtable_fields
)))
275 mem
= SCM_STRUCT_DATA (x
);
280 if (SCM_IMP (mem
[0]))
283 return SCM_BOOL(SCM_SYMBOLP (mem
[0]));
288 /* All struct data must be allocated at an address whose bottom three
289 bits are zero. This is because the tag for a struct lives in the
290 bottom three bits of the struct's car, and the upper bits point to
291 the data of its vtable, which is a struct itself. Thus, if the
292 address of that data doesn't end in three zeros, tagging it will
295 This function allocates a block of memory, and returns a pointer at
296 least scm_struct_n_extra_words words into the block. Furthermore,
297 it guarantees that that pointer's least three significant bits are
300 The argument n_words should be the number of words that should
301 appear after the returned address. (That is, it shouldn't include
302 scm_struct_n_extra_words.)
304 This function initializes the following fields of the struct:
306 scm_struct_i_ptr --- the actual start of the block of memory; the
307 address you should pass to 'free' to dispose of the block.
308 This field allows us to both guarantee that the returned
309 address is divisible by eight, and allow the GC to free the
312 scm_struct_i_n_words --- the number of words allocated to the
313 block, including the extra fields. This is used by the GC.
319 scm_alloc_struct (int n_words
, int n_extra
, char *who
)
321 int size
= sizeof (SCM
) * (n_words
+ n_extra
) + 7;
322 SCM
*block
= (SCM
*) scm_must_malloc (size
, who
);
324 /* Adjust the pointer to hide the extra words. */
325 SCM
*p
= block
+ n_extra
;
327 /* Adjust it even further so it's aligned on an eight-byte boundary. */
328 p
= (SCM
*) (((SCM
) p
+ 7) & ~7);
330 /* Initialize a few fields as described above. */
331 p
[scm_struct_i_free
] = (SCM
) scm_struct_free_standard
;
332 p
[scm_struct_i_ptr
] = (SCM
) block
;
333 p
[scm_struct_i_n_words
] = (SCM
) n_words
;
334 p
[scm_struct_i_flags
] = 0;
340 scm_struct_free_0 (SCM
*vtable
, SCM
*data
)
346 scm_struct_free_light (SCM
*vtable
, SCM
*data
)
349 return vtable
[scm_struct_i_size
] & ~SCM_STRUCTF_MASK
;
353 scm_struct_free_standard (SCM
*vtable
, SCM
*data
)
355 size_t n
= ((data
[scm_struct_i_n_words
] + scm_struct_n_extra_words
)
357 free ((void *) data
[scm_struct_i_ptr
]);
362 scm_struct_free_entity (SCM
*vtable
, SCM
*data
)
364 size_t n
= ((data
[scm_struct_i_n_words
] + scm_struct_entity_n_extra_words
)
366 free ((void *) data
[scm_struct_i_ptr
]);
370 GUILE_PROC (scm_make_struct
, "make-struct", 2, 0, 1,
371 (SCM vtable
, SCM tail_array_size
, SCM init
),
372 "Create a new structure.
374 @var{type} must be a vtable structure (@xref{Vtables}).
376 @var{tail-elts} must be a non-negative integer. If the layout
377 specification indicated by @var{type} includes a tail-array,
378 this is the number of elements allocated to that array.
380 The @var{inits} are optional arguments describing how successive fields
381 of the structure should be initialized. Only fields with protection 'r'
382 or 'w' can be initialized -- fields of protection 's' are automatically
383 initialized to point to the new structure itself; fields of protection 'o'
384 can not be initialized by Scheme programs.")
385 #define FUNC_NAME s_scm_make_struct
393 SCM_VALIDATE_VTABLE(1,vtable
);
394 SCM_VALIDATE_INT(2,tail_array_size
);
396 layout
= SCM_STRUCT_DATA (vtable
)[scm_vtable_index_layout
];
397 basic_size
= SCM_LENGTH (layout
) / 2;
398 tail_elts
= SCM_INUM (tail_array_size
);
399 SCM_NEWCELL (handle
);
401 if (SCM_STRUCT_DATA (vtable
)[scm_struct_i_flags
] & SCM_STRUCTF_ENTITY
)
403 data
= scm_alloc_struct (basic_size
+ tail_elts
,
404 scm_struct_entity_n_extra_words
,
406 data
[scm_struct_i_procedure
] = SCM_BOOL_F
;
407 data
[scm_struct_i_setter
] = SCM_BOOL_F
;
410 data
= scm_alloc_struct (basic_size
+ tail_elts
,
411 scm_struct_n_extra_words
,
413 SCM_SETCDR (handle
, data
);
414 SCM_SETCAR (handle
, ((SCM
)SCM_STRUCT_DATA (vtable
)) + scm_tc3_cons_gloc
);
415 scm_struct_init (handle
, tail_elts
, init
);
423 GUILE_PROC (scm_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1,
424 (SCM extra_fields
, SCM tail_array_size
, SCM init
),
425 "Return a new, self-describing vtable structure.
427 @var{new-fields} is a layout specification describing fields
428 of the resulting structure beginning at the position bound to
429 @code{vtable-offset-user}.
431 @var{tail-size} specifies the size of the tail-array (if any) of
434 @var{inits} initializes the fields of the vtable. Minimally, one
435 initializer must be provided: the layout specification for instances
436 of the type this vtable will describe. If a second initializer is
437 provided, it will be interpreted as a print call-back function.
442 (make-vtable-vtable (make-struct-layout (quote pw))
450 (eq? x (struct-vtable x))
452 (struct-ref x vtable-offset-user)
461 (make-struct-layout (quote pwpwpw))
470 (eq? x (struct-vtable y))
474 (struct-ref y vtable-offset-user)
478 (define z (make-struct y 0 'a 'b 'c))
484 (eq? y (struct-vtable z))
486 (map (lambda (n) (struct-ref z n)) '(0 1 2))
490 #define FUNC_NAME s_scm_make_vtable_vtable
499 SCM_VALIDATE_ROSTRING(1,extra_fields
);
500 SCM_VALIDATE_INT(2,tail_array_size
);
502 fields
= scm_string_append (scm_listify (required_vtable_fields
,
505 layout
= scm_make_struct_layout (fields
);
506 basic_size
= SCM_LENGTH (layout
) / 2;
507 tail_elts
= SCM_INUM (tail_array_size
);
508 SCM_NEWCELL (handle
);
510 data
= scm_alloc_struct (basic_size
+ tail_elts
,
511 scm_struct_n_extra_words
,
512 "make-vtable-vtable");
513 SCM_SETCDR (handle
, data
);
514 SCM_SETCAR (handle
, ((SCM
)data
) + scm_tc3_cons_gloc
);
515 SCM_STRUCT_LAYOUT (handle
) = layout
;
516 scm_struct_init (handle
, tail_elts
, scm_cons (layout
, init
));
525 GUILE_PROC (scm_struct_ref
, "struct-ref", 2, 0, 0,
526 (SCM handle
, SCM pos
),
527 "@deffnx primitive struct-set! struct n value
528 Access (or modify) the @var{n}th field of @var{struct}.
530 If the field is of type 'p', then it can be set to an arbitrary value.
532 If the field is of type 'u', then it can only be set to a non-negative
533 integer value small enough to fit in one machine word.")
534 #define FUNC_NAME s_scm_struct_ref
536 SCM answer
= SCM_UNDEFINED
;
541 unsigned char * fields_desc
;
542 unsigned char field_type
= 0;
545 SCM_VALIDATE_STRUCT(1,handle
);
546 SCM_VALIDATE_INT(2,pos
);
548 layout
= SCM_STRUCT_LAYOUT (handle
);
549 data
= SCM_STRUCT_DATA (handle
);
552 fields_desc
= (unsigned char *) SCM_CHARS (layout
);
553 n_fields
= data
[scm_struct_i_n_words
];
555 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, FUNC_NAME
);
557 if (p
* 2 < SCM_LENGTH (layout
))
560 field_type
= fields_desc
[p
* 2];
561 ref
= fields_desc
[p
* 2 + 1];
562 if ((ref
!= 'r') && (ref
!= 'w'))
564 if ((ref
== 'R') || (ref
== 'W'))
567 SCM_ASSERT (0, pos
, "ref denied", FUNC_NAME
);
570 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
571 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
574 SCM_ASSERT (0, pos
, "ref denied", FUNC_NAME
);
581 answer
= scm_ulong2num (data
[p
]);
586 answer
= scm_long2num (data
[p
]);
590 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
601 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", FUNC_NAME
);
610 GUILE_PROC (scm_struct_set_x
, "struct-set!", 3, 0, 0,
611 (SCM handle
, SCM pos
, SCM val
),
613 #define FUNC_NAME s_scm_struct_set_x
619 unsigned char * fields_desc
;
620 unsigned char field_type
= 0;
622 SCM_VALIDATE_STRUCT(1,handle
);
623 SCM_VALIDATE_INT(2,pos
);
625 layout
= SCM_STRUCT_LAYOUT (handle
);
626 data
= SCM_STRUCT_DATA (handle
);
629 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
630 n_fields
= data
[scm_struct_i_n_words
];
632 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, FUNC_NAME
);
634 if (p
* 2 < SCM_LENGTH (layout
))
637 field_type
= fields_desc
[p
* 2];
638 set_x
= fields_desc
[p
* 2 + 1];
640 SCM_ASSERT (0, pos
, "set_x denied", FUNC_NAME
);
642 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
643 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
646 SCM_ASSERT (0, pos
, "set_x denied", FUNC_NAME
);
653 data
[p
] = SCM_NUM2ULONG (3,val
);
658 data
[p
] = SCM_NUM2LONG (3,val
);
662 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
671 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "self fields immutable", FUNC_NAME
);
675 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", FUNC_NAME
);
684 GUILE_PROC (scm_struct_vtable
, "struct-vtable", 1, 0, 0,
686 "Return the vtable structure that describes the type of @var{struct}.")
687 #define FUNC_NAME s_scm_struct_vtable
689 SCM_VALIDATE_STRUCT(1,handle
);
690 return SCM_STRUCT_VTABLE (handle
);
695 GUILE_PROC (scm_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0,
698 #define FUNC_NAME s_scm_struct_vtable_tag
700 SCM_VALIDATE_VTABLE(1,handle
);
701 return scm_long2num ((long) SCM_STRUCT_DATA (handle
) >> 3);
705 /* {Associating names and classes with vtables}
707 * The name of a vtable should probably be stored as a slot. This is
708 * a backward compatible solution until agreement has been achieved on
709 * how to associate names with vtables.
713 scm_struct_ihashq (SCM obj
, unsigned int n
)
715 /* The length of the hash table should be a relative prime it's not
716 necessary to shift down the address. */
721 scm_struct_create_handle (SCM obj
)
723 SCM handle
= scm_hash_fn_create_handle_x (scm_struct_table
,
729 if (SCM_FALSEP (SCM_CDR (handle
)))
730 SCM_SETCDR (handle
, scm_cons (SCM_BOOL_F
, SCM_BOOL_F
));
734 GUILE_PROC (scm_struct_vtable_name
, "struct-vtable-name", 1, 0, 0,
737 #define FUNC_NAME s_scm_struct_vtable_name
739 SCM_VALIDATE_VTABLE(1,vtable
);
740 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable
)));
744 GUILE_PROC (scm_set_struct_vtable_name_x
, "set-struct-vtable-name!", 2, 0, 0,
745 (SCM vtable
, SCM name
),
747 #define FUNC_NAME s_scm_set_struct_vtable_name_x
749 SCM_VALIDATE_VTABLE(1,vtable
);
750 SCM_VALIDATE_SYMBOL(2,name
);
751 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable
)),
753 return SCM_UNSPECIFIED
;
761 scm_print_struct (SCM exp
, SCM port
, scm_print_state
*pstate
)
763 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp
))))
764 scm_printer_apply (SCM_STRUCT_PRINTER (exp
), exp
, port
, pstate
);
767 SCM vtable
= SCM_STRUCT_VTABLE (exp
);
768 SCM name
= scm_struct_vtable_name (vtable
);
769 scm_puts ("#<", port
);
770 if (SCM_NFALSEP (name
))
771 scm_display (name
, port
);
773 scm_puts ("struct", port
);
774 scm_putc (' ', port
);
775 scm_intprint (vtable
, 16, port
);
776 scm_putc (':', port
);
777 scm_intprint (exp
, 16, port
);
778 scm_putc ('>', port
);
786 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
787 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosrpw", sizeof ("pruosrpw") - 1, SCM_BOOL_F
));
788 scm_permanent_object (required_vtable_fields
);
789 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout
));
790 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable
));
791 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer
));
792 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user
));