#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <alloca.h>
#include <assert.h>
#define SCM_BUILDING_DEPRECATED_CODE
#include "libguile/_scm.h"
#include "libguile/async.h"
#include "libguile/chars.h"
#include "libguile/eval.h"
#include "libguile/alist.h"
#include "libguile/weaks.h"
#include "libguile/hashtab.h"
#include "libguile/ports.h"
#include "libguile/strings.h"
#include "libguile/srfi-13.h"
#include "libguile/validate.h"
#include "libguile/struct.h"
#include "libguile/eq.h"
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "libguile/bdw-gc.h"
#define SCM_LAYOUT_TAILP(X) (((X) & 32) == 0)
static SCM required_vtable_fields = SCM_BOOL_F;
static SCM required_applicable_fields = SCM_BOOL_F;
static SCM required_applicable_with_setter_fields = SCM_BOOL_F;
SCM scm_applicable_struct_vtable_vtable;
SCM scm_applicable_struct_with_setter_vtable_vtable;
SCM scm_standard_vtable_vtable;
SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
(SCM fields),
"Return a new structure layout object.\n\n"
"@var{fields} must be a string made up of pairs of characters\n"
"strung together. The first character of each pair describes a field\n"
"type, the second a field protection. Allowed types are 'p' for\n"
"GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
"a field that points to the structure itself. Allowed protections\n"
"are 'w' for mutable fields, 'h' for hidden fields, 'r' for read-only\n"
"fields, and 'o' for opaque fields.\n\n"
"Hidden fields are writable, but they will not consume an initializer arg\n"
"passed to @code{make-struct}. They are useful to add slots to a struct\n"
"in a way that preserves backward-compatibility with existing calls to\n"
"@code{make-struct}, especially for derived vtables.\n\n"
"The last field protection specification may be capitalized to indicate\n"
"that the field is a tail-array.")
#define FUNC_NAME s_scm_make_struct_layout
{
SCM new_sym;
scm_t_wchar c;
SCM_VALIDATE_STRING (1, fields);
{
size_t len;
int x;
len = scm_i_string_length (fields);
if (len % 2 == 1)
SCM_MISC_ERROR ("odd length field specification: ~S",
scm_list_1 (fields));
for (x = 0; x < len; x += 2)
{
switch (c = scm_i_string_ref (fields, x))
{
case 'u':
case 'p':
#if 0#endif
case 's':
break;
default:
SCM_MISC_ERROR ("unrecognized field type: ~S",
scm_list_1 (SCM_MAKE_CHAR (c)));
}
switch (c = scm_i_string_ref (fields, x + 1))
{
case 'w':
case 'h':
if (scm_i_string_ref (fields, x) == 's')
SCM_MISC_ERROR ("self fields not writable", SCM_EOL);
case 'r':
case 'o':
break;
case 'R':
case 'W':
case 'O':
if (scm_i_string_ref (fields, x) == 's')
SCM_MISC_ERROR ("self fields not allowed in tail array",
SCM_EOL);
if (x != len - 2)
SCM_MISC_ERROR ("tail array field must be last field in layout",
SCM_EOL);
break;
default:
SCM_MISC_ERROR ("unrecognized ref specification: ~S",
scm_list_1 (SCM_MAKE_CHAR (c)));
}
#if 0#endif
}
new_sym = scm_string_to_symbol (fields);
}
scm_remember_upto_here_1 (fields);
return new_sym;
}
#undef FUNC_NAME
static void
set_vtable_layout_flags (SCM vtable)
{
size_t len, field;
SCM layout;
const char *c_layout;
scm_t_bits flags = SCM_VTABLE_FLAG_SIMPLE;
layout = SCM_VTABLE_LAYOUT (vtable);
c_layout = scm_i_symbol_chars (layout);
len = scm_i_symbol_length (layout);
assert (len % 2 == 0);
for (field = 0;
field < len && flags & SCM_VTABLE_FLAG_SIMPLE;
field += 2)
{
if (c_layout[field] != 'p')
flags = 0;
else
switch (c_layout[field + 1])
{
case 'w':
if (field == 0)
flags |= SCM_VTABLE_FLAG_SIMPLE_RW;
break;
case 'r':
flags &= ~SCM_VTABLE_FLAG_SIMPLE_RW;
break;
default:
flags = 0;
}
}
if (flags & SCM_VTABLE_FLAG_SIMPLE)
{
SCM_SET_VTABLE_FLAGS (vtable, flags);
SCM_STRUCT_DATA_SET (vtable, scm_vtable_index_size, len / 2);
}
}
static int
scm_is_valid_vtable_layout (SCM layout)
{
size_t len, n;
const char *c_layout;
c_layout = scm_i_symbol_chars (layout);
len = scm_i_symbol_length (layout);
if (len % 2)
return 0;
for (n = 0; n < len; n += 2)
switch (c_layout[n])
{
case 'u':
case 'p':
case 's':
switch (c_layout[n+1])
{
case 'W':
case 'R':
case 'O':
if (n + 2 != len)
return 0;
case 'w':
case 'h':
case 'r':
case 'o':
break;
default:
return 0;
}
break;
default:
return 0;
}
return 1;
}
void
scm_i_struct_inherit_vtable_magic (SCM vtable, SCM obj)
#define FUNC_NAME "%inherit-vtable-magic"
{
SCM olayout;
if (! scm_is_valid_vtable_layout (SCM_VTABLE_LAYOUT (obj)))
SCM_MISC_ERROR ("invalid layout for new vtable: ~a",
scm_list_1 (SCM_VTABLE_LAYOUT (obj)));
set_vtable_layout_flags (obj);
olayout = scm_symbol_to_string (SCM_VTABLE_LAYOUT (obj));
if (scm_is_true (scm_leq_p (scm_string_length (required_vtable_fields),
scm_string_length (olayout)))
&& scm_is_true (scm_string_eq (olayout, required_vtable_fields,
scm_from_size_t (0),
scm_string_length (required_vtable_fields),
scm_from_size_t (0),
scm_string_length (required_vtable_fields))))
SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VTABLE);
if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SETTER_VTABLE))
{
if (scm_is_false (scm_string_eq (olayout, required_applicable_with_setter_fields,
scm_from_size_t (0),
scm_from_size_t (4),
scm_from_size_t (0),
scm_from_size_t (4))))
SCM_MISC_ERROR ("invalid applicable-with-setter struct layout",
scm_list_1 (olayout));
SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE | SCM_VTABLE_FLAG_SETTER);
}
else if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_APPLICABLE_VTABLE))
{
if (scm_is_false (scm_string_eq (olayout, required_applicable_fields,
scm_from_size_t (0),
scm_from_size_t (2),
scm_from_size_t (0),
scm_from_size_t (2))))
SCM_MISC_ERROR ("invalid applicable struct layout",
scm_list_1 (olayout));
SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE);
}
SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VALIDATED);
}
#undef FUNC_NAME
static void
scm_struct_init (SCM handle, SCM layout, size_t n_tail,
size_t n_inits, scm_t_bits *inits)
{
SCM vtable;
scm_t_bits *mem;
vtable = SCM_STRUCT_VTABLE (handle);
mem = SCM_STRUCT_DATA (handle);
if (SCM_UNPACK (vtable) != 0
&& SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
&& n_tail == 0
&& n_inits == SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size))
memcpy (mem, inits, n_inits * sizeof (SCM));
else
{
scm_t_wchar prot = 0;
int n_fields = scm_i_symbol_length (layout) / 2;
int tailp = 0;
int i;
size_t inits_idx = 0;
i = -2;
while (n_fields)
{
if (!tailp)
{
i += 2;
prot = scm_i_symbol_ref (layout, i+1);
if (SCM_LAYOUT_TAILP (prot))
{
tailp = 1;
prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
*mem++ = (scm_t_bits)n_tail;
n_fields += n_tail - 1;
if (n_fields == 0)
break;
}
}
switch (scm_i_symbol_ref (layout, i))
{
case 'u':
if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
*mem = 0;
else
{
*mem = scm_to_ulong (SCM_PACK (inits[inits_idx]));
inits_idx++;
}
break;
case 'p':
if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
*mem = SCM_UNPACK (SCM_BOOL_F);
else
{
*mem = inits[inits_idx];
inits_idx++;
}
break;
case 's':
*mem = SCM_UNPACK (handle);
break;
}
n_fields--;
mem++;
}
}
}
SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
(SCM x),
"Return @code{#t} iff @var{x} is a structure object, else\n"
"@code{#f}.")
#define FUNC_NAME s_scm_struct_p
{
return scm_from_bool(SCM_STRUCTP (x));
}
#undef FUNC_NAME
SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
(SCM x),
"Return @code{#t} iff @var{x} is a vtable structure.")
#define FUNC_NAME s_scm_struct_vtable_p
{
if (!SCM_STRUCTP (x)
|| !SCM_STRUCT_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VTABLE))
return SCM_BOOL_F;
if (!SCM_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VALIDATED))
SCM_MISC_ERROR ("vtable has invalid layout: ~A",
scm_list_1 (SCM_VTABLE_LAYOUT (x)));
return SCM_BOOL_T;
}
#undef FUNC_NAME
static void
struct_finalizer_trampoline (void *ptr, void *unused_data)
{
SCM obj = PTR2SCM (ptr);
scm_t_struct_finalize finalize = SCM_STRUCT_FINALIZER (obj);
if (finalize)
finalize (obj);
}
SCM
scm_i_alloc_struct (scm_t_bits *vtable_data, int n_words)
{
SCM ret;
ret = scm_words ((scm_t_bits)vtable_data | scm_tc3_struct, n_words + 2);
SCM_SET_CELL_WORD_1 (ret, (scm_t_bits)SCM_CELL_OBJECT_LOC (ret, 2));
if (vtable_data && vtable_data[scm_vtable_index_instance_finalize])
scm_i_set_finalizer (SCM2PTR (ret), struct_finalizer_trampoline, NULL);
return ret;
}
SCM
scm_c_make_structv (SCM vtable, size_t n_tail, size_t n_init, scm_t_bits *init)
#define FUNC_NAME "make-struct"
{
SCM layout;
size_t basic_size;
SCM obj;
SCM_VALIDATE_VTABLE (1, vtable);
layout = SCM_VTABLE_LAYOUT (vtable);
basic_size = scm_i_symbol_length (layout) / 2;
if (n_tail != 0)
{
SCM layout_str, last_char;
if (basic_size == 0)
{
bad_tail:
SCM_MISC_ERROR ("tail array not allowed unless layout ends R, W, or O", SCM_EOL);
}
layout_str = scm_symbol_to_string (layout);
last_char = scm_string_ref (layout_str,
scm_from_size_t (2 * basic_size - 1));
if (! SCM_LAYOUT_TAILP (SCM_CHAR (last_char)))
goto bad_tail;
}
obj = scm_i_alloc_struct (SCM_STRUCT_DATA (vtable), basic_size + n_tail);
scm_struct_init (obj, layout, n_tail, n_init, init);
if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE)
&& scm_is_true (SCM_VTABLE_LAYOUT (obj)))
scm_i_struct_inherit_vtable_magic (vtable, obj);
return obj;
}
#undef FUNC_NAME
SCM
scm_c_make_struct (SCM vtable, size_t n_tail, size_t n_init, scm_t_bits init, ...)
{
va_list foo;
scm_t_bits *v;
size_t i;
v = alloca (sizeof (scm_t_bits) * n_init);
va_start (foo, init);
for (i = 0; i < n_init; i++)
{
v[i] = init;
init = va_arg (foo, scm_t_bits);
}
va_end (foo);
return scm_c_make_structv (vtable, n_tail, n_init, v);
}
SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
(SCM vtable, SCM tail_array_size, SCM init),
"Create a new structure.\n\n"
"@var{vtable} must be a vtable structure (@pxref{Vtables}).\n\n"
"@var{tail_array_size} must be a non-negative integer. If the layout\n"
"specification indicated by @var{vtable} includes a tail-array,\n"
"this is the number of elements allocated to that array.\n\n"
"The @var{init1}, @dots{} are optional arguments describing how\n"
"successive fields of the structure should be initialized. Only fields\n"
"with protection 'r' or 'w' can be initialized, except for fields of\n"
"type 's', which are automatically initialized to point to the new\n"
"structure itself. Fields with protection 'o' can not be initialized by\n"
"Scheme programs.\n\n"
"If fewer optional arguments than initializable fields are supplied,\n"
"fields of type 'p' get default value #f while fields of type 'u' are\n"
"initialized to 0.\n\n"
"For more information, see the documentation for @code{make-vtable-vtable}.")
#define FUNC_NAME s_scm_make_struct
{
size_t i, n_init;
long ilen;
scm_t_bits *v;
SCM_VALIDATE_VTABLE (1, vtable);
ilen = scm_ilength (init);
if (ilen < 0)
SCM_MISC_ERROR ("Rest arguments do not form a proper list.", SCM_EOL);
n_init = (size_t)ilen;
if (n_init < 64)
v = alloca (n_init * sizeof(scm_t_bits));
else
v = scm_gc_malloc (n_init * sizeof(scm_t_bits), "struct");
for (i = 0; i < n_init; i++, init = SCM_CDR (init))
v[i] = SCM_UNPACK (SCM_CAR (init));
return scm_c_make_structv (vtable, scm_to_size_t (tail_array_size), n_init, v);
}
#undef FUNC_NAME
#if SCM_ENABLE_DEPRECATED == 1
SCM
scm_make_vtable_vtable (SCM user_fields, SCM tail_array_size, SCM init)
#define FUNC_NAME "make-vtable-vtable"
{
SCM fields, layout, obj;
size_t basic_size, n_tail, i, n_init;
long ilen;
scm_t_bits *v;
SCM_VALIDATE_STRING (1, user_fields);
ilen = scm_ilength (init);
if (ilen < 0)
SCM_MISC_ERROR ("Rest arguments do not form a proper list.", SCM_EOL);
n_init = (size_t)ilen + 1;
if (n_init < 64)
v = alloca (n_init * sizeof(scm_t_bits));
else
v = scm_gc_malloc (n_init * sizeof(scm_t_bits), "struct");
fields = scm_string_append (scm_list_2 (required_vtable_fields,
user_fields));
layout = scm_make_struct_layout (fields);
if (!scm_is_valid_vtable_layout (layout))
SCM_MISC_ERROR ("invalid user fields", scm_list_1 (user_fields));
basic_size = scm_i_symbol_length (layout) / 2;
n_tail = scm_to_size_t (tail_array_size);
i = 0;
v[i++] = SCM_UNPACK (layout);
for (; i < n_init; i++, init = SCM_CDR (init))
v[i] = SCM_UNPACK (SCM_CAR (init));
SCM_CRITICAL_SECTION_START;
obj = scm_i_alloc_struct (NULL, basic_size + n_tail);
SCM_SET_CELL_WORD_0 (obj, (scm_t_bits) SCM_STRUCT_DATA (obj) | scm_tc3_struct);
SCM_CRITICAL_SECTION_END;
scm_struct_init (obj, layout, n_tail, n_init, v);
SCM_SET_VTABLE_FLAGS (obj,
SCM_VTABLE_FLAG_VTABLE | SCM_VTABLE_FLAG_VALIDATED);
return obj;
}
#undef FUNC_NAME
#endif
SCM
scm_i_make_vtable_vtable (SCM user_fields)
#define FUNC_NAME "make-vtable-vtable"
{
SCM fields, layout, obj;
size_t basic_size;
scm_t_bits v;
SCM_VALIDATE_STRING (1, user_fields);
fields = scm_string_append (scm_list_2 (required_vtable_fields,
user_fields));
layout = scm_make_struct_layout (fields);
if (!scm_is_valid_vtable_layout (layout))
SCM_MISC_ERROR ("invalid user fields", scm_list_1 (user_fields));
basic_size = scm_i_symbol_length (layout) / 2;
obj = scm_i_alloc_struct (NULL, basic_size);
SCM_SET_CELL_WORD_0 (obj, (scm_t_bits) SCM_STRUCT_DATA (obj) | scm_tc3_struct);
v = SCM_UNPACK (layout);
scm_struct_init (obj, layout, 0, 1, &v);
SCM_SET_VTABLE_FLAGS (obj,
SCM_VTABLE_FLAG_VTABLE | SCM_VTABLE_FLAG_VALIDATED);
return obj;
}
#undef FUNC_NAME
SCM_DEFINE (scm_make_vtable, "make-vtable", 1, 1, 0,
(SCM fields, SCM printer),
"Create a vtable, for creating structures with the given\n"
"@var{fields}.\n"
"\n"
"The optional @var{printer} argument is a function to be called\n"
"@code{(@var{printer} struct port)} on the structures created.\n"
"It should look at @var{struct} and write to @var{port}.")
#define FUNC_NAME s_scm_make_vtable
{
if (SCM_UNBNDP (printer))
printer = SCM_BOOL_F;
return scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
scm_list_2 (scm_make_struct_layout (fields),
printer));
}
#undef FUNC_NAME
SCM
scm_i_struct_equalp (SCM s1, SCM s2)
#define FUNC_NAME "scm_i_struct_equalp"
{
SCM vtable1, vtable2, layout;
size_t struct_size, field_num;
SCM_VALIDATE_STRUCT (1, s1);
SCM_VALIDATE_STRUCT (2, s2);
vtable1 = SCM_STRUCT_VTABLE (s1);
vtable2 = SCM_STRUCT_VTABLE (s2);
if (!scm_is_eq (vtable1, vtable2))
return SCM_BOOL_F;
layout = SCM_STRUCT_LAYOUT (s1);
struct_size = scm_i_symbol_length (layout) / 2;
for (field_num = 0; field_num < struct_size; field_num++)
{
SCM s_field_num;
SCM field1, field2;
s_field_num = scm_from_size_t (field_num);
field1 = scm_struct_ref (s1, s_field_num);
field2 = scm_struct_ref (s2, s_field_num);
if (!(scm_is_eq (field1, s1) && (scm_is_eq (field2, s2))))
if (scm_is_false (scm_equal_p (field1, field2)))
return SCM_BOOL_F;
}
return SCM_BOOL_T;
}
#undef FUNC_NAME
SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
(SCM handle, SCM pos),
"Access the @var{pos}th field of struct associated with\n"
"@var{handle}.\n"
"\n"
"If the field is of type 'p', then it can be set to an arbitrary\n"
"value.\n"
"\n"
"If the field is of type 'u', then it can only be set to a\n"
"non-negative integer value small enough to fit in one machine\n"
"word.")
#define FUNC_NAME s_scm_struct_ref
{
SCM vtable, answer = SCM_UNDEFINED;
scm_t_bits *data;
size_t p;
SCM_VALIDATE_STRUCT (1, handle);
vtable = SCM_STRUCT_VTABLE (handle);
data = SCM_STRUCT_DATA (handle);
p = scm_to_size_t (pos);
if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
&& p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
answer = SCM_PACK (data[p]);
else
{
SCM layout;
size_t layout_len, n_fields;
scm_t_wchar field_type = 0;
layout = SCM_STRUCT_LAYOUT (handle);
layout_len = scm_i_symbol_length (layout);
n_fields = layout_len / 2;
if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
n_fields += data[n_fields - 1];
SCM_ASSERT_RANGE (1, pos, p < n_fields);
if (p * 2 < layout_len)
{
scm_t_wchar ref;
field_type = scm_i_symbol_ref (layout, p * 2);
ref = scm_i_symbol_ref (layout, p * 2 + 1);
if ((ref != 'r') && (ref != 'w') && (ref != 'h'))
{
if ((ref == 'R') || (ref == 'W'))
field_type = 'u';
else
SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
}
}
else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
field_type = scm_i_symbol_ref(layout, layout_len - 2);
else
SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
switch (field_type)
{
case 'u':
answer = scm_from_ulong (data[p]);
break;
#if 0#endif
case 's':
case 'p':
answer = SCM_PACK (data[p]);
break;
default:
SCM_MISC_ERROR ("unrecognized field type: ~S",
scm_list_1 (SCM_MAKE_CHAR (field_type)));
}
}
return answer;
}
#undef FUNC_NAME
SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
(SCM handle, SCM pos, SCM val),
"Set the slot of the structure @var{handle} with index @var{pos}\n"
"to @var{val}. Signal an error if the slot can not be written\n"
"to.")
#define FUNC_NAME s_scm_struct_set_x
{
SCM vtable;
scm_t_bits *data;
size_t p;
SCM_VALIDATE_STRUCT (1, handle);
vtable = SCM_STRUCT_VTABLE (handle);
data = SCM_STRUCT_DATA (handle);
p = scm_to_size_t (pos);
if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
&& SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE_RW)
&& p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
data[p] = SCM_UNPACK (val);
else
{
SCM layout;
size_t layout_len, n_fields;
scm_t_wchar field_type = 0;
layout = SCM_STRUCT_LAYOUT (handle);
layout_len = scm_i_symbol_length (layout);
n_fields = layout_len / 2;
if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
n_fields += data[n_fields - 1];
SCM_ASSERT_RANGE (1, pos, p < n_fields);
if (p * 2 < layout_len)
{
char set_x;
field_type = scm_i_symbol_ref (layout, p * 2);
set_x = scm_i_symbol_ref (layout, p * 2 + 1);
if (set_x != 'w' && set_x != 'h')
SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
}
else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
field_type = scm_i_symbol_ref (layout, layout_len - 2);
else
SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
switch (field_type)
{
case 'u':
data[p] = SCM_NUM2ULONG (3, val);
break;
#if 0#endif
case 'p':
data[p] = SCM_UNPACK (val);
break;
case 's':
SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
default:
SCM_MISC_ERROR ("unrecognized field type: ~S",
scm_list_1 (SCM_MAKE_CHAR (field_type)));
}
}
return val;
}
#undef FUNC_NAME
SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
(SCM handle),
"Return the vtable structure that describes the type of struct\n"
"associated with @var{handle}.")
#define FUNC_NAME s_scm_struct_vtable
{
SCM_VALIDATE_STRUCT (1, handle);
return SCM_STRUCT_VTABLE (handle);
}
#undef FUNC_NAME
unsigned long
scm_struct_ihashq (SCM obj, unsigned long n, void *closure)
{
return SCM_UNPACK (obj) % n;
}
unsigned long
scm_i_struct_hash (SCM obj, unsigned long n, size_t depth)
#define FUNC_NAME "hash"
{
SCM layout;
scm_t_bits *data;
size_t struct_size, field_num;
unsigned long hash;
SCM_VALIDATE_STRUCT (1, obj);
layout = SCM_STRUCT_LAYOUT (obj);
struct_size = scm_i_symbol_length (layout) / 2;
data = SCM_STRUCT_DATA (obj);
hash = SCM_UNPACK (SCM_STRUCT_VTABLE (obj)) % n;
if (depth > 0)
for (field_num = 0; field_num < struct_size; field_num++)
{
int protection;
protection = scm_i_symbol_ref (layout, field_num * 2 + 1);
if (protection != 'h' && protection != 'o')
{
int type;
type = scm_i_symbol_ref (layout, field_num * 2);
switch (type)
{
case 'p':
hash ^= scm_hasher (SCM_PACK (data[field_num]), n,
depth / 2);
break;
case 'u':
hash ^= data[field_num] % n;
break;
default:
;
}
}
}
return hash % n;
}
#undef FUNC_NAME
SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
(SCM vtable),
"Return the name of the vtable @var{vtable}.")
#define FUNC_NAME s_scm_struct_vtable_name
{
SCM_VALIDATE_VTABLE (1, vtable);
return SCM_VTABLE_NAME (vtable);
}
#undef FUNC_NAME
SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
(SCM vtable, SCM name),
"Set the name of the vtable @var{vtable} to @var{name}.")
#define FUNC_NAME s_scm_set_struct_vtable_name_x
{
SCM_VALIDATE_VTABLE (1, vtable);
SCM_VALIDATE_SYMBOL (2, name);
SCM_SET_VTABLE_NAME (vtable, name);
scm_i_define_class_for_vtable (vtable);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
void
scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
{
if (scm_is_true (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
else
{
SCM vtable = SCM_STRUCT_VTABLE (exp);
SCM name = scm_struct_vtable_name (vtable);
scm_puts ("#<", port);
if (scm_is_true (name))
{
scm_display (name, port);
scm_putc (' ', port);
}
else
{
if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE))
scm_puts ("vtable:", port);
else
scm_puts ("struct:", port);
scm_uintprint (SCM_UNPACK (vtable), 16, port);
scm_putc (' ', port);
scm_write (SCM_VTABLE_LAYOUT (vtable), port);
scm_putc (' ', port);
}
scm_uintprint (SCM_UNPACK (exp), 16, port);
if (SCM_STRUCT_APPLICABLE_P (exp))
{
if (scm_is_true (SCM_STRUCT_PROCEDURE (exp)))
{
scm_puts (" proc: ", port);
if (scm_is_true (scm_procedure_p (SCM_STRUCT_PROCEDURE (exp))))
scm_write (SCM_STRUCT_PROCEDURE (exp), port);
else
scm_puts ("(not a procedure?)", port);
}
if (SCM_STRUCT_SETTER_P (exp))
{
scm_puts (" setter: ", port);
scm_write (SCM_STRUCT_SETTER (exp), port);
}
}
scm_putc ('>', port);
}
}
void
scm_init_struct ()
{
SCM name;
GC_REGISTER_DISPLACEMENT (2 * sizeof (scm_t_bits) + scm_tc3_struct);
GC_REGISTER_DISPLACEMENT (2 * sizeof (scm_t_bits));
required_vtable_fields = scm_from_locale_string (SCM_VTABLE_BASE_LAYOUT);
scm_c_define ("standard-vtable-fields", required_vtable_fields);
required_applicable_fields = scm_from_locale_string (SCM_APPLICABLE_BASE_LAYOUT);
required_applicable_with_setter_fields = scm_from_locale_string (SCM_APPLICABLE_WITH_SETTER_BASE_LAYOUT);
scm_standard_vtable_vtable = scm_i_make_vtable_vtable (scm_nullstr);
name = scm_from_utf8_symbol ("<standard-vtable>");
scm_set_struct_vtable_name_x (scm_standard_vtable_vtable, name);
scm_define (name, scm_standard_vtable_vtable);
scm_applicable_struct_vtable_vtable =
scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
name = scm_from_utf8_symbol ("<applicable-struct-vtable>");
SCM_SET_VTABLE_FLAGS (scm_applicable_struct_vtable_vtable,
SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
scm_set_struct_vtable_name_x (scm_applicable_struct_vtable_vtable, name);
scm_define (name, scm_applicable_struct_vtable_vtable);
scm_applicable_struct_with_setter_vtable_vtable =
scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
name = scm_from_utf8_symbol ("<applicable-struct-with-setter-vtable>");
scm_set_struct_vtable_name_x (scm_applicable_struct_with_setter_vtable_vtable, name);
SCM_SET_VTABLE_FLAGS (scm_applicable_struct_with_setter_vtable_vtable,
SCM_VTABLE_FLAG_APPLICABLE_VTABLE | SCM_VTABLE_FLAG_SETTER_VTABLE);
scm_define (name, scm_applicable_struct_with_setter_vtable_vtable);
scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
scm_c_define ("vtable-index-printer",
scm_from_int (scm_vtable_index_instance_printer));
scm_c_define ("vtable-offset-user", scm_from_int (scm_vtable_offset_user));
#include "libguile/struct.x"
#if SCM_ENABLE_DEPRECATED
scm_c_define_gsubr ("make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable);
#endif
}