1 /* Copyright (C) 1996, 97, 98, 99, 2000 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 */
48 #include "libguile/_scm.h"
49 #include "libguile/chars.h"
50 #include "libguile/eval.h"
51 #include "libguile/alist.h"
52 #include "libguile/weaks.h"
53 #include "libguile/hashtab.h"
54 #include "libguile/ports.h"
55 #include "libguile/strings.h"
57 #include "libguile/validate.h"
58 #include "libguile/struct.h"
66 static SCM required_vtable_fields
= SCM_BOOL_F
;
70 SCM_DEFINE (scm_make_struct_layout
, "make-struct-layout", 1, 0, 0,
72 "Return a new structure layout object.\n\n"
73 "@var{fields} must be a read-only string made up of pairs of characters\n"
74 "strung together. The first character of each pair describes a field\n"
75 "type, the second a field protection. Allowed types are 'p' for\n"
76 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
77 "fields that should point to the structure itself. Allowed protections\n"
78 "are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque \n"
79 "fields. The last field protection specification may be capitalized to\n"
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_MAKE_CHAR (field_desc
[x
]) , "unrecognized field type", FUNC_NAME
);
110 switch (field_desc
[x
+ 1])
113 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKE_CHAR (field_desc
[x
+ 1]),
114 "self fields not writable", FUNC_NAME
);
122 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKE_CHAR (field_desc
[x
+ 1]),
123 "self fields not allowed in tail array",
125 SCM_ASSERT (x
== len
- 2, SCM_MAKE_CHAR (field_desc
[x
+ 1]),
126 "tail array field must be last field in layout",
130 SCM_ASSERT (0, SCM_MAKE_CHAR (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
)
154 SCM layout
= SCM_STRUCT_LAYOUT (handle
);
155 unsigned char * fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
156 unsigned char prot
= 0;
157 int n_fields
= SCM_LENGTH (layout
) / 2;
158 scm_bits_t
* mem
= SCM_STRUCT_DATA (handle
);
166 prot
= fields_desc
[1];
167 if (SCM_LAYOUT_TAILP (prot
))
170 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
172 n_fields
+= tail_elts
- 1;
178 switch (*fields_desc
)
182 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
186 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "scm_struct_init");
187 inits
= SCM_CDR (inits
);
193 if ((prot
!= 'r' && prot
!= 'w') || SCM_NULLP (inits
))
197 *mem
= scm_num2ulong (SCM_CAR (inits
),
200 inits
= SCM_CDR (inits
);
205 if ((prot
!= 'r' && prot
!= 'w') || SCM_NULLP (inits
))
206 *mem
= SCM_UNPACK (SCM_BOOL_F
);
209 *mem
= SCM_UNPACK (SCM_CAR (inits
));
210 inits
= SCM_CDR (inits
);
217 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
218 *((double *)mem
) = 0.0;
221 *mem
= scm_num2dbl (SCM_CAR (inits
), "scm_struct_init");
222 inits
= SCM_CDR (inits
);
229 *mem
= SCM_UNPACK (handle
);
239 SCM_DEFINE (scm_struct_p
, "struct?", 1, 0, 0,
241 "Return #t iff @var{obj} is a structure object, else #f.")
242 #define FUNC_NAME s_scm_struct_p
244 return SCM_BOOL(SCM_STRUCTP (x
));
248 SCM_DEFINE (scm_struct_vtable_p
, "struct-vtable?", 1, 0, 0,
250 "Return #t iff obj is a vtable structure.")
251 #define FUNC_NAME s_scm_struct_vtable_p
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 return SCM_BOOL (SCM_SYMBOLP (SCM_PACK (mem
[0])));
278 /* All struct data must be allocated at an address whose bottom three
279 bits are zero. This is because the tag for a struct lives in the
280 bottom three bits of the struct's car, and the upper bits point to
281 the data of its vtable, which is a struct itself. Thus, if the
282 address of that data doesn't end in three zeros, tagging it will
285 This function allocates a block of memory, and returns a pointer at
286 least scm_struct_n_extra_words words into the block. Furthermore,
287 it guarantees that that pointer's least three significant bits are
290 The argument n_words should be the number of words that should
291 appear after the returned address. (That is, it shouldn't include
292 scm_struct_n_extra_words.)
294 This function initializes the following fields of the struct:
296 scm_struct_i_ptr --- the actual start of the block of memory; the
297 address you should pass to 'free' to dispose of the block.
298 This field allows us to both guarantee that the returned
299 address is divisible by eight, and allow the GC to free the
302 scm_struct_i_n_words --- the number of words allocated to the
303 block, including the extra fields. This is used by the GC.
309 scm_alloc_struct (int n_words
, int n_extra
, char *who
)
311 int size
= sizeof (scm_bits_t
) * (n_words
+ n_extra
) + 7;
312 void * block
= scm_must_malloc (size
, who
);
314 /* Adjust the pointer to hide the extra words. */
315 scm_bits_t
* p
= (scm_bits_t
*) block
+ n_extra
;
317 /* Adjust it even further so it's aligned on an eight-byte boundary. */
318 p
= (scm_bits_t
*) (((scm_bits_t
) p
+ 7) & ~7);
320 /* Initialize a few fields as described above. */
321 p
[scm_struct_i_free
] = (scm_bits_t
) scm_struct_free_standard
;
322 p
[scm_struct_i_ptr
] = (scm_bits_t
) block
;
323 p
[scm_struct_i_n_words
] = n_words
;
324 p
[scm_struct_i_flags
] = 0;
330 scm_struct_free_0 (scm_bits_t
* vtable
, scm_bits_t
* data
)
336 scm_struct_free_light (scm_bits_t
* vtable
, scm_bits_t
* data
)
338 scm_must_free (data
);
339 return vtable
[scm_struct_i_size
] & ~SCM_STRUCTF_MASK
;
343 scm_struct_free_standard (scm_bits_t
* vtable
, scm_bits_t
* data
)
345 size_t n
= (data
[scm_struct_i_n_words
] + scm_struct_n_extra_words
)
346 * sizeof (scm_bits_t
) + 7;
347 scm_must_free ((void *) data
[scm_struct_i_ptr
]);
352 scm_struct_free_entity (scm_bits_t
* vtable
, scm_bits_t
* data
)
354 size_t n
= (data
[scm_struct_i_n_words
] + scm_struct_entity_n_extra_words
)
355 * sizeof (scm_bits_t
) + 7;
356 scm_must_free ((void *) data
[scm_struct_i_ptr
]);
360 SCM_DEFINE (scm_make_struct
, "make-struct", 2, 0, 1,
361 (SCM vtable
, SCM tail_array_size
, SCM init
),
362 "Create a new structure.\n\n"
363 "@var{type} must be a vtable structure (@xref{Vtables}).\n\n"
364 "@var{tail-elts} must be a non-negative integer. If the layout\n"
365 "specification indicated by @var{type} includes a tail-array,\n"
366 "this is the number of elements allocated to that array.\n\n"
367 "The @var{inits} are optional arguments describing how successive fields\n"
368 "of the structure should be initialized. Only fields with protection 'r'\n"
369 "or 'w' can be initialized -- fields of protection 's' are automatically\n"
370 "initialized to point to the new structure itself; fields of protection 'o'\n"
371 "can not be initialized by Scheme programs.")
372 #define FUNC_NAME s_scm_make_struct
380 SCM_VALIDATE_VTABLE (1,vtable
);
381 SCM_VALIDATE_INUM (2,tail_array_size
);
383 layout
= SCM_PACK (SCM_STRUCT_DATA (vtable
) [scm_vtable_index_layout
]);
384 basic_size
= SCM_LENGTH (layout
) / 2;
385 tail_elts
= SCM_INUM (tail_array_size
);
386 SCM_NEWCELL (handle
);
388 if (SCM_STRUCT_DATA (vtable
)[scm_struct_i_flags
] & SCM_STRUCTF_ENTITY
)
390 data
= scm_alloc_struct (basic_size
+ tail_elts
,
391 scm_struct_entity_n_extra_words
,
393 data
[scm_struct_i_procedure
] = SCM_UNPACK (SCM_BOOL_F
);
394 data
[scm_struct_i_setter
] = SCM_UNPACK (SCM_BOOL_F
);
397 data
= scm_alloc_struct (basic_size
+ tail_elts
,
398 scm_struct_n_extra_words
,
400 SCM_SET_CELL_WORD_1 (handle
, data
);
401 SCM_SET_CELL_WORD_0 (handle
, (scm_bits_t
) SCM_STRUCT_DATA (vtable
) + scm_tc3_cons_gloc
);
402 scm_struct_init (handle
, tail_elts
, init
);
410 SCM_DEFINE (scm_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1,
411 (SCM extra_fields
, SCM tail_array_size
, SCM init
),
412 "Return a new, self-describing vtable structure.\n\n"
413 "@var{new-fields} is a layout specification describing fields\n"
414 "of the resulting structure beginning at the position bound to\n"
415 "@code{vtable-offset-user}.\n\n"
416 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
418 "@var{inits} initializes the fields of the vtable. Minimally, one\n"
419 "initializer must be provided: the layout specification for instances\n"
420 "of the type this vtable will describe. If a second initializer is\n"
421 "provided, it will be interpreted as a print call-back function.\n\n"
423 ";;; loading ,a...\n"
425 " (make-vtable-vtable (make-struct-layout (quote pw))\n"
430 "(struct-vtable? x)\n"
432 "(eq? x (struct-vtable x))\n"
434 "(struct-ref x vtable-offset-user)\n"
437 "@result{} pruosrpwpw\n\n\n"
441 " (make-struct-layout (quote pwpwpw))\n"
445 "(struct-vtable? y)\n"
449 "(eq? x (struct-vtable y))\n"
453 "(struct-ref y vtable-offset-user)\n"
454 "@result{} bar\n\n\n"
455 "(define z (make-struct y 0 'a 'b 'c))\n\n"
458 "(struct-vtable? z)\n"
460 "(eq? y (struct-vtable z))\n"
462 "(map (lambda (n) (struct-ref z n)) '(0 1 2))\n"
463 "@result{} (a b c)\n"
466 #define FUNC_NAME s_scm_make_vtable_vtable
475 SCM_VALIDATE_ROSTRING (1,extra_fields
);
476 SCM_VALIDATE_INUM (2,tail_array_size
);
478 fields
= scm_string_append (scm_listify (required_vtable_fields
,
481 layout
= scm_make_struct_layout (fields
);
482 basic_size
= SCM_LENGTH (layout
) / 2;
483 tail_elts
= SCM_INUM (tail_array_size
);
484 SCM_NEWCELL (handle
);
486 data
= scm_alloc_struct (basic_size
+ tail_elts
,
487 scm_struct_n_extra_words
,
488 "make-vtable-vtable");
489 SCM_SET_CELL_WORD_1 (handle
, data
);
490 SCM_SET_CELL_WORD_0 (handle
, (scm_bits_t
) data
+ scm_tc3_cons_gloc
);
491 SCM_SET_STRUCT_LAYOUT (handle
, layout
);
492 scm_struct_init (handle
, tail_elts
, scm_cons (layout
, init
));
501 SCM_DEFINE (scm_struct_ref
, "struct-ref", 2, 0, 0,
502 (SCM handle
, SCM pos
),
503 "@deffnx primitive struct-set! struct n value\n"
504 "Access (or modify) the @var{n}th field of @var{struct}.\n\n"
505 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
506 "If the field is of type 'u', then it can only be set to a non-negative\n"
507 "integer value small enough to fit in one machine word.")
508 #define FUNC_NAME s_scm_struct_ref
510 SCM answer
= SCM_UNDEFINED
;
515 unsigned char * fields_desc
;
516 unsigned char field_type
= 0;
519 SCM_VALIDATE_STRUCT (1,handle
);
520 SCM_VALIDATE_INUM (2,pos
);
522 layout
= SCM_STRUCT_LAYOUT (handle
);
523 data
= SCM_STRUCT_DATA (handle
);
526 fields_desc
= (unsigned char *) SCM_CHARS (layout
);
527 n_fields
= data
[scm_struct_i_n_words
];
529 SCM_ASSERT_RANGE(1,pos
, p
< n_fields
);
531 if (p
* 2 < SCM_LENGTH (layout
))
534 field_type
= fields_desc
[p
* 2];
535 ref
= fields_desc
[p
* 2 + 1];
536 if ((ref
!= 'r') && (ref
!= 'w'))
538 if ((ref
== 'R') || (ref
== 'W'))
541 SCM_ASSERT (0, pos
, "ref denied", FUNC_NAME
);
544 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
545 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
548 SCM_ASSERT (0, pos
, "ref denied", FUNC_NAME
);
555 answer
= scm_ulong2num (data
[p
]);
560 answer
= scm_long2num (data
[p
]);
564 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
570 answer
= SCM_PACK (data
[p
]);
575 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type
), "unrecognized field type", FUNC_NAME
);
584 SCM_DEFINE (scm_struct_set_x
, "struct-set!", 3, 0, 0,
585 (SCM handle
, SCM pos
, SCM val
),
587 #define FUNC_NAME s_scm_struct_set_x
593 unsigned char * fields_desc
;
594 unsigned char field_type
= 0;
596 SCM_VALIDATE_STRUCT (1,handle
);
597 SCM_VALIDATE_INUM (2,pos
);
599 layout
= SCM_STRUCT_LAYOUT (handle
);
600 data
= SCM_STRUCT_DATA (handle
);
603 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
604 n_fields
= data
[scm_struct_i_n_words
];
606 SCM_ASSERT_RANGE (1,pos
, p
< n_fields
);
608 if (p
* 2 < SCM_LENGTH (layout
))
611 field_type
= fields_desc
[p
* 2];
612 set_x
= fields_desc
[p
* 2 + 1];
614 SCM_ASSERT (0, pos
, "set_x denied", FUNC_NAME
);
616 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
617 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
620 SCM_ASSERT (0, pos
, "set_x denied", FUNC_NAME
);
627 data
[p
] = SCM_NUM2ULONG (3, val
);
632 data
[p
] = SCM_NUM2LONG (3,val
);
636 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
641 data
[p
] = SCM_UNPACK (val
);
645 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type
), "self fields immutable", FUNC_NAME
);
649 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type
), "unrecognized field type", FUNC_NAME
);
658 SCM_DEFINE (scm_struct_vtable
, "struct-vtable", 1, 0, 0,
660 "Return the vtable structure that describes the type of @var{struct}.")
661 #define FUNC_NAME s_scm_struct_vtable
663 SCM_VALIDATE_STRUCT (1,handle
);
664 return SCM_STRUCT_VTABLE (handle
);
669 SCM_DEFINE (scm_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0,
672 #define FUNC_NAME s_scm_struct_vtable_tag
674 SCM_VALIDATE_VTABLE (1,handle
);
675 return scm_long2num ((long) SCM_STRUCT_DATA (handle
) >> 3);
679 /* {Associating names and classes with vtables}
681 * The name of a vtable should probably be stored as a slot. This is
682 * a backward compatible solution until agreement has been achieved on
683 * how to associate names with vtables.
687 scm_struct_ihashq (SCM obj
, unsigned int n
)
689 /* The length of the hash table should be a relative prime it's not
690 necessary to shift down the address. */
691 return SCM_UNPACK (obj
) % n
;
695 scm_struct_create_handle (SCM obj
)
697 SCM handle
= scm_hash_fn_create_handle_x (scm_struct_table
,
703 if (SCM_FALSEP (SCM_CDR (handle
)))
704 SCM_SETCDR (handle
, scm_cons (SCM_BOOL_F
, SCM_BOOL_F
));
708 SCM_DEFINE (scm_struct_vtable_name
, "struct-vtable-name", 1, 0, 0,
711 #define FUNC_NAME s_scm_struct_vtable_name
713 SCM_VALIDATE_VTABLE (1,vtable
);
714 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable
)));
718 SCM_DEFINE (scm_set_struct_vtable_name_x
, "set-struct-vtable-name!", 2, 0, 0,
719 (SCM vtable
, SCM name
),
721 #define FUNC_NAME s_scm_set_struct_vtable_name_x
723 SCM_VALIDATE_VTABLE (1,vtable
);
724 SCM_VALIDATE_SYMBOL (2,name
);
725 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable
)),
727 return SCM_UNSPECIFIED
;
735 scm_print_struct (SCM exp
, SCM port
, scm_print_state
*pstate
)
737 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp
))))
738 scm_printer_apply (SCM_STRUCT_PRINTER (exp
), exp
, port
, pstate
);
741 SCM vtable
= SCM_STRUCT_VTABLE (exp
);
742 SCM name
= scm_struct_vtable_name (vtable
);
743 scm_puts ("#<", port
);
744 if (SCM_NFALSEP (name
))
745 scm_display (name
, port
);
747 scm_puts ("struct", port
);
748 scm_putc (' ', port
);
749 scm_intprint (SCM_UNPACK (vtable
), 16, port
);
750 scm_putc (':', port
);
751 scm_intprint (SCM_UNPACK (exp
), 16, port
);
752 scm_putc ('>', port
);
760 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
761 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosrpw", sizeof ("pruosrpw") - 1, SCM_BOOL_F
));
762 scm_permanent_object (required_vtable_fields
);
763 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout
));
764 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable
));
765 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer
));
766 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user
));
767 #include "libguile/struct.x"