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, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
20 * The exception is that, if you link the GUILE library with other files
21 * to produce an executable, this does not by itself cause the
22 * resulting executable to be covered by the GNU General Public License.
23 * Your use of that executable is in no way restricted on account of
24 * linking the GUILE library code into it.
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
29 * This exception applies only to the code released by the
30 * Free Software Foundation under the name GUILE. If you copy
31 * code from other Free Software Foundation releases into a copy of
32 * GUILE, as the General Public License permits, the exception does
33 * not apply to the code that you add in this way. To avoid misleading
34 * anyone as to the status of such modified files, you must delete
35 * this exception notice from them.
37 * If you write modifications of your own for GUILE, it is your choice
38 * whether to permit this exception to apply to your modifications.
39 * If you do not wish that, delete this exception notice.
55 static SCM required_vtable_fields
= SCM_BOOL_F
;
56 static int struct_num
= 0;
59 SCM_PROC (s_struct_make_layout
, "make-struct-layout", 1, 0, 0, scm_make_struct_layout
);
62 scm_make_struct_layout (fields
)
66 SCM_ASSERT (SCM_NIMP (fields
) && SCM_ROSTRINGP (fields
),
67 fields
, SCM_ARG1
, s_struct_make_layout
);
74 len
= SCM_ROLENGTH (fields
);
75 field_desc
= SCM_ROCHARS (fields
);
76 SCM_ASSERT (!(len
& 1), fields
, "odd length field specification", s_struct_make_layout
);
78 for (x
= 0; x
< len
; x
+= 2)
80 switch (field_desc
[x
])
91 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized field type", s_struct_make_layout
);
94 switch (field_desc
[x
+ 1])
97 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
98 "self fields not writable", s_struct_make_layout
);
106 SCM_ASSERT (field_desc
[x
] != 's', SCM_MAKICHR (field_desc
[x
+ 1]),
107 "self fields not allowed in tail array",
108 s_struct_make_layout
);
109 SCM_ASSERT (x
== len
- 2, SCM_MAKICHR (field_desc
[x
+ 1]),
110 "tail array field must be last field in layout",
111 s_struct_make_layout
);
114 SCM_ASSERT (0, SCM_MAKICHR (field_desc
[x
]) , "unrecognized ref specification", s_struct_make_layout
);
117 if (field_desc
[x
] == 'd')
119 SCM_ASSERT (field_desc
[x
+ 2] == '-', SCM_MAKINUM (x
/ 2), "missing dash field", s_struct_make_layout
);
125 new_sym
= SCM_CAR (scm_intern_obarray (field_desc
, len
, SCM_BOOL_F
));
127 return scm_return_first (new_sym
, fields
);
134 static void init_struct
SCM_P ((SCM handle
, int tail_elts
, SCM inits
));
137 init_struct (handle
, tail_elts
, inits
)
144 unsigned char * fields_desc
;
150 layout
= SCM_STRUCT_LAYOUT (handle
);
151 data
= SCM_STRUCT_DATA (handle
);
152 fields_desc
= (unsigned char *) SCM_CHARS (layout
) - 2;
153 n_fields
= SCM_LENGTH (layout
) / 2;
154 mem
= SCM_STRUCT_DATA (handle
);
160 prot
= fields_desc
[1];
161 if (SCM_LAYOUT_TAILP (prot
))
164 prot
= prot
== 'R' ? 'r' : prot
== 'W' ? 'w' : 'o';
166 n_fields
+= tail_elts
- 1;
172 switch (*fields_desc
)
176 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
180 *mem
= scm_num2long (SCM_CAR (inits
), SCM_ARGn
, "init_struct");
181 inits
= SCM_CDR (inits
);
187 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
191 *mem
= scm_num2ulong (SCM_CAR (inits
), SCM_ARGn
, "init_struct");
192 inits
= SCM_CDR (inits
);
197 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
201 *mem
= SCM_CAR (inits
);
202 inits
= SCM_CDR (inits
);
209 if ((prot
!= 'r' && prot
!= 'w') || inits
== SCM_EOL
)
210 *((double *)mem
) = 0.0;
213 *mem
= scm_num2dbl (SCM_CAR (inits
), "init_struct");
214 inits
= SCM_CDR (inits
);
231 SCM_PROC (s_struct_p
, "struct?", 1, 0, 0, scm_struct_p
);
237 return ((SCM_NIMP (x
) && SCM_STRUCTP (x
))
242 SCM_PROC (s_struct_vtable_p
, "struct-vtable?", 1, 0, 0, scm_struct_vtable_p
);
245 scm_struct_vtable_p (x
)
254 if (!SCM_STRUCTP (x
))
257 layout
= SCM_STRUCT_LAYOUT (x
);
259 if (SCM_LENGTH (layout
) < SCM_LENGTH (required_vtable_fields
))
262 if (strncmp (SCM_CHARS (layout
), SCM_CHARS (required_vtable_fields
),
263 SCM_LENGTH (required_vtable_fields
)))
266 mem
= SCM_STRUCT_DATA (x
);
271 if (SCM_IMP (mem
[0]))
274 return (SCM_SYMBOLP (mem
[0])
280 /* All struct data must be allocated at an address whose bottom three
281 bits are zero. This is because the tag for a struct lives in the
282 bottom three bits of the struct's car, and the upper bits point to
283 the data of its vtable, which is a struct itself. Thus, if the
284 address of that data doesn't end in three zeros, tagging it will
287 This function allocates a block of memory, and returns a pointer at
288 least scm_struct_n_extra_words words into the block. Furthermore,
289 it guarantees that that pointer's least three significant bits are
292 The argument n_words should be the number of words that should
293 appear after the returned address. (That is, it shouldn't include
294 scm_struct_n_extra_words.)
296 This function initializes the following fields of the struct:
298 scm_struct_i_ptr --- the actual stort of the block of memory; the
299 address you should pass to 'free' to dispose of the block.
300 This field allows us to both guarantee that the returned
301 address is divisible by eight, and allow the GC to free the
304 scm_struct_i_n_words --- the number of words allocated to the
305 block, including the extra fields. This is used by the GC.
307 scm_struct_i_tag --- a unique tag assigned to this struct,
308 allocated according to struct_num.
313 static SCM
*alloc_struct
SCM_P ((int n_words
, char *who
));
316 alloc_struct (n_words
, who
)
320 int size
= sizeof (SCM
) * (n_words
+ scm_struct_n_extra_words
) + 7;
321 SCM
*block
= (SCM
*) scm_must_malloc (size
, who
);
323 /* Adjust the pointer to hide the extra words. */
324 SCM
*p
= block
+ scm_struct_n_extra_words
;
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. */
330 p
[scm_struct_i_ptr
] = (SCM
) block
;
331 p
[scm_struct_i_n_words
] = (SCM
) (scm_struct_n_extra_words
+ n_words
);
332 p
[scm_struct_i_tag
] = struct_num
++;
338 SCM_PROC (s_make_struct
, "make-struct", 2, 0, 1, scm_make_struct
);
341 scm_make_struct (vtable
, tail_array_size
, init
)
352 SCM_ASSERT ((SCM_BOOL_F
!= scm_struct_vtable_p (vtable
)),
353 vtable
, SCM_ARG1
, s_make_struct
);
354 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
357 layout
= SCM_STRUCT_DATA (vtable
)[scm_struct_i_layout
];
358 basic_size
= SCM_LENGTH (layout
) / 2;
359 tail_elts
= SCM_INUM (tail_array_size
);
360 SCM_NEWCELL (handle
);
362 data
= alloc_struct (basic_size
+ tail_elts
, "make-struct");
363 SCM_SETCDR (handle
, data
);
364 SCM_SETCAR (handle
, ((SCM
)SCM_STRUCT_DATA (vtable
)) + scm_tc3_cons_gloc
);
365 init_struct (handle
, tail_elts
, init
);
372 SCM_PROC (s_make_vtable_vtable
, "make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable
);
375 scm_make_vtable_vtable (extra_fields
, tail_array_size
, init
)
387 SCM_ASSERT (SCM_NIMP (extra_fields
) && SCM_ROSTRINGP (extra_fields
),
388 extra_fields
, SCM_ARG1
, s_make_vtable_vtable
);
389 SCM_ASSERT (SCM_INUMP (tail_array_size
), tail_array_size
, SCM_ARG2
,
390 s_make_vtable_vtable
);
392 fields
= scm_string_append (scm_listify (required_vtable_fields
,
395 layout
= scm_make_struct_layout (fields
);
396 basic_size
= SCM_LENGTH (layout
) / 2;
397 tail_elts
= SCM_INUM (tail_array_size
);
398 SCM_NEWCELL (handle
);
400 data
= alloc_struct (basic_size
+ tail_elts
, "make-vtable-vtable");
401 SCM_SETCDR (handle
, data
);
402 SCM_SETCAR (handle
, ((SCM
)data
) + scm_tc3_cons_gloc
);
403 SCM_STRUCT_LAYOUT (handle
) = layout
;
404 init_struct (handle
, tail_elts
, scm_cons (layout
, init
));
412 SCM_PROC (s_struct_ref
, "struct-ref", 2, 0, 0, scm_struct_ref
);
415 scm_struct_ref (handle
, pos
)
419 SCM answer
= SCM_UNDEFINED
;
424 unsigned char * fields_desc
;
425 unsigned char field_type
;
428 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
429 SCM_ARG1
, s_struct_ref
);
430 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
432 layout
= SCM_STRUCT_LAYOUT (handle
);
433 data
= SCM_STRUCT_DATA (handle
);
436 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
437 n_fields
= data
[- scm_struct_n_extra_words
] - scm_struct_n_extra_words
;
439 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_ref
);
441 if (p
* 2 < SCM_LENGTH (layout
))
444 field_type
= fields_desc
[p
* 2];
445 ref
= fields_desc
[p
* 2 + 1];
446 if ((ref
!= 'r') && (ref
!= 'w'))
448 if ((ref
== 'R') || (ref
== 'W'))
451 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
454 else if (fields_desc
[SCM_LENGTH (layout
) - 1] != 'O')
455 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
458 SCM_ASSERT (0, pos
, "ref denied", s_struct_ref
);
464 answer
= scm_ulong2num (data
[p
]);
469 answer
= scm_long2num (data
[p
]);
473 answer
= scm_makdbl (*((double *)&(data
[p
])), 0.0);
484 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_ref
);
492 SCM_PROC (s_struct_set_x
, "struct-set!", 3, 0, 0, scm_struct_set_x
);
495 scm_struct_set_x (handle
, pos
, val
)
504 unsigned char * fields_desc
;
505 unsigned char field_type
;
509 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
510 SCM_ARG1
, s_struct_ref
);
511 SCM_ASSERT (SCM_INUMP (pos
), pos
, SCM_ARG2
, s_struct_ref
);
513 layout
= SCM_STRUCT_LAYOUT (handle
);
514 data
= SCM_STRUCT_DATA (handle
);
517 fields_desc
= (unsigned char *)SCM_CHARS (layout
);
518 n_fields
= data
[- scm_struct_n_extra_words
] - scm_struct_n_extra_words
;
520 SCM_ASSERT (p
< n_fields
, pos
, SCM_OUTOFRANGE
, s_struct_set_x
);
522 if (p
* 2 < SCM_LENGTH (layout
))
525 field_type
= fields_desc
[p
* 2];
526 set_x
= fields_desc
[p
* 2 + 1];
528 SCM_ASSERT (0, pos
, "set_x denied", s_struct_set_x
);
530 else if (fields_desc
[SCM_LENGTH (layout
) - 1] == 'W')
531 field_type
= fields_desc
[SCM_LENGTH (layout
) - 2];
534 SCM_ASSERT (0, pos
, "set_x denied", s_struct_ref
);
540 data
[p
] = (SCM
)scm_num2ulong (val
, (char *)SCM_ARG3
, s_struct_set_x
);
545 data
[p
] = scm_num2long (val
, (char *)SCM_ARG3
, s_struct_set_x
);
549 *((double *)&(data
[p
])) = scm_num2dbl (val
, (char *)SCM_ARG3
);
558 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "self fields immutable", s_struct_set_x
);
562 SCM_ASSERT (0, SCM_MAKICHR (field_type
), "unrecognized field type", s_struct_set_x
);
570 SCM_PROC (s_struct_vtable
, "struct-vtable", 1, 0, 0, scm_struct_vtable
);
573 scm_struct_vtable (handle
)
576 SCM_ASSERT (SCM_NIMP (handle
) && SCM_STRUCTP (handle
), handle
,
577 SCM_ARG1
, s_struct_vtable
);
578 return SCM_STRUCT_VTABLE (handle
);
582 SCM_PROC (s_struct_vtable_tag
, "struct-vtable-tag", 1, 0, 0, scm_struct_vtable_tag
);
585 scm_struct_vtable_tag (handle
)
588 SCM_ASSERT (SCM_NIMP (handle
) && (SCM_BOOL_F
!= scm_struct_vtable_p (handle
)),
589 handle
, SCM_ARG1
, s_struct_vtable_tag
);
590 return scm_long2num (SCM_STRUCT_DATA (handle
)[-1]);
600 required_vtable_fields
= SCM_CAR (scm_intern_obarray ("pruosr", sizeof ("pruosr") - 1, SCM_BOOL_F
));
601 scm_permanent_object (required_vtable_fields
);
602 scm_sysintern ("struct-vtable-offset", SCM_MAKINUM (scm_struct_i_vtable_offset
));