/*
Copyright (C) 2001-2012, Parrot Foundation.
=head1 NAME
src/pmc/unmanagedstruct.pmc - C struct with unmanaged memory
=head1 DESCRIPTION
PMC class to hold C C<struct>s that Parrot's not responsible for
disposing of.
Buffer can be accessed using keyed assignments to PMC. Out of
bounds access will very likely segfault.
=head2 Functions
=over 4
=cut
*/
#include "parrot/compiler.h"
#include "parrot/string_funcs.h"
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
PARROT_WARN_UNUSED_RESULT
static int calc_align(PARROT_INTERP,
ARGIN(PMC *type_pmc),
int type,
size_t offs)
__attribute__nonnull__(1)
__attribute__nonnull__(2);
static void calc_offsets(PARROT_INTERP,
ARGIN(PMC *pmc),
ARGIN(PMC *value),
size_t toff)
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
static char * char_offset_int(PARROT_INTERP,
ARGIN(PMC *pmc),
INTVAL ix,
ARGOUT(int *type))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(4)
FUNC_MODIFIES(*type);
PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
static char * char_offset_key(PARROT_INTERP,
ARGIN(PMC *pmc),
ARGIN(PMC *key),
ARGOUT(int *type))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3)
__attribute__nonnull__(4)
FUNC_MODIFIES(*type);
PARROT_WARN_UNUSED_RESULT
static INTVAL key_2_idx(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(PMC *key))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT
static FLOATVAL ret_float(PARROT_INTERP, ARGIN(const char *p), int type)
__attribute__nonnull__(1)
__attribute__nonnull__(2);
PARROT_WARN_UNUSED_RESULT
static INTVAL ret_int(PARROT_INTERP, ARGIN(const char *p), int type)
__attribute__nonnull__(1)
__attribute__nonnull__(2);
PARROT_WARN_UNUSED_RESULT
PARROT_CANNOT_RETURN_NULL
static PMC* ret_pmc(PARROT_INTERP,
ARGIN(PMC *pmc),
ARGIN(char *p),
int type,
INTVAL idx)
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT
PARROT_CANNOT_RETURN_NULL
static STRING* ret_string(PARROT_INTERP, ARGIN(char *p), int type)
__attribute__nonnull__(1)
__attribute__nonnull__(2);
static void set_float(PARROT_INTERP,
ARGOUT(char *p),
int type,
FLOATVAL value)
__attribute__nonnull__(1)
__attribute__nonnull__(2)
FUNC_MODIFIES(*p);
static void set_int(PARROT_INTERP, ARGOUT(char *p), int type, INTVAL value)
__attribute__nonnull__(1)
__attribute__nonnull__(2)
FUNC_MODIFIES(*p);
static void set_string(PARROT_INTERP,
ARGOUT(char *p),
int type,
ARGIN(STRING *value))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(4)
FUNC_MODIFIES(*p);
#define ASSERT_ARGS_calc_align __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(type_pmc))
#define ASSERT_ARGS_calc_offsets __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pmc) \
, PARROT_ASSERT_ARG(value))
#define ASSERT_ARGS_char_offset_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pmc) \
, PARROT_ASSERT_ARG(type))
#define ASSERT_ARGS_char_offset_key __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pmc) \
, PARROT_ASSERT_ARG(key) \
, PARROT_ASSERT_ARG(type))
#define ASSERT_ARGS_key_2_idx __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pmc) \
, PARROT_ASSERT_ARG(key))
#define ASSERT_ARGS_ret_float __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(p))
#define ASSERT_ARGS_ret_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(p))
#define ASSERT_ARGS_ret_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pmc) \
, PARROT_ASSERT_ARG(p))
#define ASSERT_ARGS_ret_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(p))
#define ASSERT_ARGS_set_float __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(p))
#define ASSERT_ARGS_set_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(p))
#define ASSERT_ARGS_set_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(p) \
, PARROT_ASSERT_ARG(value))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=item C<static char * char_offset_int(PARROT_INTERP, PMC *pmc, INTVAL ix, int
*type)>
Returns the pointer for the element at index C<ix>, and sets the element
type in C<*type>.
=cut
*/
PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
static char *
char_offset_int(PARROT_INTERP, ARGIN(PMC *pmc), INTVAL ix, ARGOUT(int *type))
{
ASSERT_ARGS(char_offset_int)
size_t offs, n;
ix *= 3;
if (!PARROT_UNMANAGEDSTRUCT(pmc)->init)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNEXPECTED_NULL,
"Missing struct initializer");
n = (size_t)VTABLE_elements(interp, PARROT_UNMANAGEDSTRUCT(pmc)->init);
if ((size_t)ix >= n)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNEXPECTED_NULL,
"Non existent elements in struct ix = %d n=%d", (int)ix, (int)n);
/* use structure init */
*type = (int) VTABLE_get_integer_keyed_int(interp,
PARROT_UNMANAGEDSTRUCT(pmc)->init, ix);
offs = (size_t) VTABLE_get_integer_keyed_int(interp,
PARROT_UNMANAGEDSTRUCT(pmc)->init, ix + 2);
return ((char *)VTABLE_get_pointer(interp, pmc)) + offs;
}
/*
=item C<static INTVAL key_2_idx(PARROT_INTERP, PMC *pmc, PMC *key)>
Returns the index for the element associated with key C<*key>. Raises an
exception if the key doesn't exist.
=cut
*/
PARROT_WARN_UNUSED_RESULT
static INTVAL
key_2_idx(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(PMC *key))
{
ASSERT_ARGS(key_2_idx)
int ix = 0;
if (!PARROT_UNMANAGEDSTRUCT(pmc)->init)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNEXPECTED_NULL,
"Missing struct initializer");
if (PObj_get_FLAGS(key) & KEY_string_FLAG) {
PMC * const types = PARROT_UNMANAGEDSTRUCT(pmc)->init;
if (types->vtable->base_type == enum_class_OrderedHash) {
const Hash * const hash = (Hash *)VTABLE_get_pointer(interp,
VTABLE_get_pmc(interp, types));
const HashBucket * const b = Parrot_hash_get_bucket(interp, hash,
Parrot_hash_key_from_string(interp, hash, VTABLE_get_string(interp, key)));
if (!b)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_KEY_NOT_FOUND,
"key doesn't exist");
ix = b - hash->buckets;
}
else
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
"unhandled type aggregate");
ix /= 3;
}
else
ix = VTABLE_get_integer(interp, key);
return ix;
}
/*
=item C<static char * char_offset_key(PARROT_INTERP, PMC *pmc, PMC *key, int
*type)>
Returns the pointer for the element associated with key C<*key>, and
sets the element type in C<*type>.
=cut
*/
PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
static char *
char_offset_key(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(PMC *key), ARGOUT(int *type))
{
ASSERT_ARGS(char_offset_key)
size_t count, size, max;
int ix;
PMC *next, *init;
char *p;
#ifdef STRUCT_DEBUG
trace_key_dump(interp, key);
#endif
ix = key_2_idx(interp, pmc, key);
next = Parrot_key_next(interp, key);
p = char_offset_int(interp, pmc, ix, type);
ix *= 3;
if (!next)
return p;
if (PObj_get_FLAGS(next) & KEY_integer_FLAG)
count = VTABLE_get_integer(interp, next);
else
count = 1;
init = PARROT_UNMANAGEDSTRUCT(pmc)->init;
max = (size_t)VTABLE_get_integer_keyed_int(interp, init, ix + 1);
#ifdef STRUCT_DEBUG
Parrot_io_eprintf(interp, " count = %d ix = %d max = %d\n",
(int)count, (int)ix, (int)max);
#endif
if (*type == enum_type_struct_ptr || *type == enum_type_struct) {
/* the struct PMC is hanging off the initializer element
* as property "_struct" */
PMC * const ptr = VTABLE_get_pmc_keyed_int(interp, init, ix);
init = Parrot_pmc_getprop(interp, ptr, CONST_STRING(interp, "_struct"));
PARROT_ASSERT(init
&& (init->vtable->base_type == enum_class_UnManagedStruct
|| init->vtable->base_type == enum_class_ManagedStruct));
/* array of structs */
if (max > 1) {
size_t offs;
if (Parrot_key_next(interp, next))
next = Parrot_key_next(interp, next);
offs = VTABLE_get_integer(interp, init);
#ifdef STRUCT_DEBUG
Parrot_io_eprintf(interp, "offs = %d\n", (int)offs);
#endif
p += offs * count;
}
if (init->vtable->base_type == enum_class_UnManagedStruct) {
/* now point ptr to the real data */
if (*type == enum_type_struct_ptr) {
/* that is either a pointer */
VTABLE_set_pointer(interp, init, *(void**)p);
}
/* or just an offset for nested structs */
else
VTABLE_set_pointer(interp, init, p);
}
else if (init->vtable->base_type == enum_class_ManagedStruct
&& *type == enum_type_struct_ptr) {
/* a nested struct pointer belonging to us
* p is the location of the struct pointer in the
* outer struct, the inner is at PMC_data(init) */
*(void **)p = VTABLE_get_pointer(interp, init);
}
return char_offset_key(interp, init, next, type);
}
if (count >= max)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_OUT_OF_BOUNDS,
"Non existent array element in struct: "
"count = %d max=%d", (int)count, (int)max);
size = data_types[*type - enum_first_type].size;
return p + count * size;
}
/*
=item C<static INTVAL ret_int(PARROT_INTERP, const char *p, int type)>
Returns the element of type C<type> starting at C<*p> as an C<INTVAL>.
If, for example, C<char> or c<short> type size doesn't match, this will fail
we need some more configure support for type sizes.
=cut
*/
PARROT_WARN_UNUSED_RESULT
static INTVAL
ret_int(PARROT_INTERP, ARGIN(const char *p), int type)
{
ASSERT_ARGS(ret_int)
switch (type) {
case enum_type_INTVAL:
return *(const INTVAL*) p;
#if INT_SIZE == 4
case enum_type_int32:
case enum_type_uint32:
#endif
#if INT_SIZE == 8
case enum_type_int64:
case enum_type_uint64:
#endif
case enum_type_int:
return *(const int *)p;
#if (LONG_SIZE == 4) && !(INT_SIZE == 4) /* Unlikely combination. */
case enum_type_int32:
case enum_type_uint32:
#endif
#if (LONG_SIZE == 8) && !(INT_SIZE == 8)
case enum_type_int64:
case enum_type_uint64:
#endif
case enum_type_long:
case enum_type_ulong:
return *(const long *)p;
#if SHORT_SIZE == 2
case enum_type_int16:
case enum_type_uint16:
#endif
/* If SHORT_SIZE != 2 getting int16s requires extra tricks. */
case enum_type_short:
return *(const short *)p;
case enum_type_uint8:
case enum_type_uchar:
{
const unsigned char *uc = (const unsigned char *)p;
return (INTVAL)*uc;
}
case enum_type_int8:
case enum_type_char:
return *p;
default:
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"returning unhandled int type in struct");
}
}
/*
=item C<static FLOATVAL ret_float(PARROT_INTERP, const char *p, int type)>
Returns the element of type C<type> starting at C<*p> as a C<FLOATVAL>.
=cut
*/
PARROT_WARN_UNUSED_RESULT
static FLOATVAL
ret_float(PARROT_INTERP, ARGIN(const char *p), int type)
{
ASSERT_ARGS(ret_float)
switch (type) {
case enum_type_FLOATVAL:
return (FLOATVAL) *(const FLOATVAL *)p;
case enum_type_float:
return (FLOATVAL) *(const float *)p;
case enum_type_double:
return (FLOATVAL) *(const double *)p;
default:
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"returning unhandled float type in struct");
}
}
/*
=item C<static STRING* ret_string(PARROT_INTERP, char *p, int type)>
Returns the element of type C<type> starting at C<*p> as a Parrot string.
=cut
*/
PARROT_WARN_UNUSED_RESULT
PARROT_CANNOT_RETURN_NULL
static STRING*
ret_string(PARROT_INTERP, ARGIN(char *p), int type)
{
ASSERT_ARGS(ret_string)
if (type == enum_type_cstr) {
const char * const cstr = *(const char **) p;
if (cstr) {
const size_t len = strlen(cstr);
/* TODO
Can't assume that the C string is constant during the
life of the returned parrot string, so can't be
flagged as external in general.
If avoid the copy for speed reasons is a concern,
other type or flag must be added.
Need to provide some way to specify charset and encoding.
*/
return Parrot_str_new_init(interp, cstr, len,
Parrot_latin1_encoding_ptr, 0);
}
else
return STRINGNULL;
}
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
"returning unhandled string type in struct");
}
/*
=item C<static PMC* ret_pmc(PARROT_INTERP, PMC *pmc, char *p, int type, INTVAL
idx)>
Returns the element of type C<type> starting at C<*p> as a PMC.
=cut
*/
PARROT_WARN_UNUSED_RESULT
PARROT_CANNOT_RETURN_NULL
static PMC*
ret_pmc(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(char *p), int type, INTVAL idx)
{
ASSERT_ARGS(ret_pmc)
PMC * const init = PARROT_UNMANAGEDSTRUCT(pmc)->init;
PMC * const ptr = VTABLE_get_pmc_keyed_int(interp, init, idx * 3);
PMC *ret = NULL;
switch (type) {
case enum_type_func_ptr:
/* this is a raw function pointer - not a PMC */
ret = *(PMC**) p;
/* now check if initializer has a signature attached */
if (PMC_metadata(ptr)) {
STRING *signature_str = CONST_STRING(interp, "_signature");
PMC * const sig = Parrot_pmc_getprop(interp, ptr, signature_str);
if (VTABLE_defined(interp, sig)) {
STRING * const sig_str = VTABLE_get_string(interp, sig);
ret = Parrot_pmc_new(interp, enum_class_NCI);
VTABLE_set_pointer_keyed_str(interp, ret, sig_str,
*(PMC **)p);
}
}
return ret;
case enum_type_struct_ptr:
/* check the metadata for an initializer */
/* grab the struct from the metadata */
if (PMC_metadata(ptr))
ret = Parrot_pmc_getprop(interp, ptr, CONST_STRING(interp, "_struct"));
else {
Parrot_ex_throw_from_c_args(interp, NULL,
EXCEPTION_INVALID_OPERATION,
"no initializer available for nested struct");
}
VTABLE_set_pointer(interp, ret, *(void**)p);
return ret;
default:
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
"returning unhandled pmc type (%d) in struct", type);
}
}
/*
=item C<static void set_int(PARROT_INTERP, char *p, int type, INTVAL value)>
Set int value based on int type
=cut
*/
static void
set_int(PARROT_INTERP, ARGOUT(char *p), int type, INTVAL value)
{
ASSERT_ARGS(set_int)
switch (type) {
case enum_type_uint8:
case enum_type_int8:
case enum_type_char:
case enum_type_uchar:
*(char *)p = (char)(value & 0xff);
break;
case enum_type_INTVAL:
*(INTVAL *)p = value;
break;
case enum_type_int:
*(int *)p = value;
break;
case enum_type_int16:
case enum_type_uint16:
case enum_type_short:
*(short *)p = (short)value;
break;
default:
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"setting unhandled int type in struct");
break;
}
}
/*
=item C<static void set_float(PARROT_INTERP, char *p, int type, FLOATVAL value)>
Sets the value of the element of type C<type> starting at C<*p> to
C<value>.
=cut
*/
static void
set_float(PARROT_INTERP, ARGOUT(char *p), int type, FLOATVAL value)
{
ASSERT_ARGS(set_float)
switch (type) {
case enum_type_FLOATVAL:
*(FLOATVAL *)p = (FLOATVAL)value;
break;
case enum_type_float:
*(float *)p = (float)value;
break;
case enum_type_double:
*(double *)p = (double)value;
break;
default:
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"setting unhandled float type in struct");
break;
}
}
/*
=item C<static void set_string(PARROT_INTERP, char *p, int type, STRING *value)>
Sets the value of the element of type C<type> starting at C<*p> to
C<*value>.
=cut
*/
static void
set_string(PARROT_INTERP, ARGOUT(char *p), int type, ARGIN(STRING *value))
{
ASSERT_ARGS(set_string)
if (type == enum_type_cstr) {
/* assuming 0-terminated C-string here;
* we can't use Parrot_str_to_cstring easily */
char * const cstr = (char *)Buffer_bufstart(value);
*(char **)p = cstr;
}
else
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"setting unhandled string type in struct (%d)", type);
}
/*
=item C<static int calc_align(PARROT_INTERP, PMC *type_pmc, int type, size_t
offs)>
Alignment of contained structures is the alignment of the biggest item in that
C<struct>.
i386: C<long long> or C<double> is aligned on 4.
This is recursive as structure definitions.
=cut
*/
PARROT_WARN_UNUSED_RESULT
static int
calc_align(PARROT_INTERP, ARGIN(PMC *type_pmc), int type, size_t offs)
{
ASSERT_ARGS(calc_align)
int align = data_types[type - enum_first_type].size;
PMC *nested = NULL;
PMC *nested_init = NULL;
if (type == enum_type_struct || type == enum_type_struct_ptr) {
/* a nested structs alignment is the biggest item in it
* so go through that struct and check */
nested = Parrot_pmc_getprop(interp, type_pmc, CONST_STRING(interp, "_struct"));
nested_init = PARROT_UNMANAGEDSTRUCT(nested)->init;
}
if (type == enum_type_struct) {
INTVAL i;
const INTVAL n = (size_t)VTABLE_elements(interp, nested_init);
int a_max = 0;
if (n % 3)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
"Illegal initializer for struct");
for (i = 0; i < n; i += 3) {
PMC * const nested_type_pmc = VTABLE_get_pmc_keyed_int(interp,
nested_init, i);
const int nested_type = (int)VTABLE_get_integer(interp,
nested_type_pmc);
const int new_offs = calc_align(interp, nested_type_pmc, nested_type, offs);
if (new_offs > a_max)
a_max = new_offs;
}
align = a_max;
}
if (align && offs % align) {
const int diff = align - (offs % align);
offs += diff;
}
if (type == enum_type_struct || type == enum_type_struct_ptr)
calc_offsets(interp, nested, nested_init, 0);
return offs;
}
/*
=item C<static void calc_offsets(PARROT_INTERP, PMC *pmc, PMC *value, size_t
toff)>
Calculates the offsets for the C<struct>. See C<init_pmc()> for a description
of C<*value>.
=cut
*/
static void
calc_offsets(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(PMC *value), size_t toff)
{
ASSERT_ARGS(calc_offsets)
STRING * const _struct = CONST_STRING(interp, "_struct");
const INTVAL n = (size_t)VTABLE_elements(interp, value);
INTVAL i;
if (n % 3)
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
"Illegal initializer for struct");
for (i = 0; i < n; i += 3) {
PMC * const type_pmc = VTABLE_get_pmc_keyed_int(interp, value, i);
const int type = (int)VTABLE_get_integer(interp, type_pmc);
int count = (int)VTABLE_get_integer_keyed_int(interp, value, i + 1);
int offs = (int)VTABLE_get_integer_keyed_int(interp, value, i + 2);
int size;
if (type < enum_first_type || type >= enum_last_type)
Parrot_ex_throw_from_c_args(interp, NULL,
EXCEPTION_INVALID_OPERATION,
"Illegal type (%d) in initializer for struct", type);
if (count <= 0) {
count = 1;
VTABLE_set_integer_keyed_int(interp, value, i + 1, count);
}
if (offs <= 0) {
offs = toff = calc_align(interp, type_pmc, type, toff);
VTABLE_set_integer_keyed_int(interp, value, i + 2, offs);
}
else
toff = offs;
if (type == enum_type_struct) {
PMC * const nested = Parrot_pmc_getprop(interp, type_pmc, _struct);
size = VTABLE_get_integer(interp, nested);
}
else if (type == enum_type_struct_ptr) {
PMC * const nested = Parrot_pmc_getprop(interp, type_pmc, _struct);
/* must clone this struct so as not to share its memory */
if (nested->vtable->base_type == enum_class_ManagedStruct)
Parrot_pmc_setprop(interp, type_pmc, _struct,
VTABLE_clone(interp, nested));
size = data_types[type - enum_first_type].size;
}
else
size = data_types[type - enum_first_type].size;
toff += count * size;
/* set / allocate size */
if (i == n - 3)
VTABLE_set_integer_native(interp, pmc, (INTVAL)toff);
}
}
pmclass UnManagedStruct auto_attrs no_ro {
ATTR void *ptr; /* the struct that this UnManagedStruct isn't managing */
ATTR PMC *init; /* the initializer used with this UnManagedStruct */
ATTR INTVAL size; /* the size of the struct */
/*
=back
=head2 Vtable Functions
=over 4
=item C<void init_pmc(PMC *value)>
Initialize the struct with some data.
C<*value> should be an array of triples of:
=over 4
=item 0
The datatype. See the C<enum> in F<include/parrot/datatypes.h>.
=item 1
The count.
=item 2
The offset.
=back
=cut
*/
VTABLE void init_pmc(PMC *value) {
SELF.set_pmc(value);
}
/*
=item C<PMC *clone()>
Return a clone of this PMC.
=cut
*/
VTABLE PMC *clone() {
PMC * const clone = Parrot_pmc_new(INTERP, enum_class_UnManagedStruct);
memmove(PMC_data(clone), PMC_data(SELF),
sizeof (Parrot_UnManagedStruct_attributes));
PARROT_UNMANAGEDSTRUCT(clone)->init =
VTABLE_clone(INTERP, PARROT_UNMANAGEDSTRUCT(SELF)->init);
return clone;
}
/*
=item C<void set_pmc(PMC *value)>
Sets C<*value> (see C<init_pmc()> and calculates the offsets.
=cut
*/
VTABLE void set_pmc(PMC *value) {
PARROT_UNMANAGEDSTRUCT(SELF)->init = value;
PObj_custom_mark_SET(SELF);
calc_offsets(INTERP, SELF, value, 0);
}
/*
=item C<void mark()>
Marks the C<struct> as live.
=cut
*/
VTABLE void mark() {
PMC * const init = PARROT_UNMANAGEDSTRUCT(SELF)->init;
Parrot_gc_mark_PMC_alive(INTERP, init);
}
/*
=item C<INTVAL is_equal(PMC *value)>
Returns whether the two C<struct>s are equivalent.
=cut
*/
VTABLE INTVAL is_equal(PMC *value) {
return (SELF->vtable == value->vtable
&& SELF.get_pointer() == VTABLE_get_pointer(INTERP, value));
}
/*
=item C<INTVAL get_bool()>
=item C<INTVAL defined()>
Returns whether the C<struct> is defined.
=cut
*/
VTABLE INTVAL get_bool() {
return SELF.get_pointer() != NULL;
}
VTABLE INTVAL defined() {
return SELF.get_pointer() != NULL;
}
/*
=item C<INTVAL get_integer()>
Returns the size of the C<struct>.
=cut
*/
VTABLE INTVAL get_integer() {
UNUSED(INTERP);
return PARROT_UNMANAGEDSTRUCT(SELF)->size;
}
/*
=item C<void set_integer_native(INTVAL size)>
Sets the size of the C<struct>.
=cut
*/
VTABLE void set_integer_native(INTVAL size) {
UNUSED(INTERP);
PARROT_UNMANAGEDSTRUCT(SELF)->size = size;
}
/*
=item C<INTVAL get_integer_keyed_int(INTVAL ix)>
Returns the integer value at index C<ix>.
=cut
*/
VTABLE INTVAL get_integer_keyed_int(INTVAL ix) {
int type;
const char * const p = char_offset_int(INTERP, SELF, ix, &type);
return ret_int(INTERP, p, type);
}
/*
=item C<INTVAL get_integer_keyed(PMC *key)>
Returns the integer value associated with C<*key>.
=cut
*/
VTABLE INTVAL get_integer_keyed(PMC *key) {
int type;
const char * const p = char_offset_key(INTERP, SELF, key, &type);
return ret_int(INTERP, p, type);
}
/*
=item C<FLOATVAL get_number_keyed_int(INTVAL key)>
Returns the floating-point value at index C<ix>.
=cut
*/
VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
int type;
const char * const p = char_offset_int(INTERP, SELF, key, &type);
return ret_float(INTERP, p, type);
}
/*
=item C<FLOATVAL get_number_keyed(PMC *key)>
Returns the floating-point value associated with C<*key>.
=cut
*/
VTABLE FLOATVAL get_number_keyed(PMC *key) {
int type;
const char * const p = char_offset_key(INTERP, SELF, key, &type);
return ret_float(INTERP, p, type);
}
/*
=item C<STRING *get_string_keyed_int(INTVAL key)>
Returns the Parrot string value at index C<ix>.
=cut
*/
VTABLE STRING *get_string_keyed_int(INTVAL key) {
int type;
char * const p = char_offset_int(INTERP, SELF, key, &type);
return ret_string(INTERP, p, type);
}
/*
=item C<STRING *get_string_keyed(PMC *key)>
Returns the Parrot string value associated with C<*key>.
=cut
*/
VTABLE STRING *get_string_keyed(PMC *key) {
int type;
char * const p = char_offset_key(INTERP, SELF, key, &type);
return ret_string(INTERP, p, type);
}
/*
=item C<PMC *get_pmc_keyed_int(INTVAL key)>
Returns the PMC value at index C<ix>.
=cut
*/
VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
int type;
char * const p = char_offset_int(INTERP, SELF, key, &type);
return ret_pmc(INTERP, SELF, p, type, key);
}
/*
=item C<PMC *get_pmc_keyed(PMC *key)>
Returns the PMC value associated with C<*key>.
=cut
*/
VTABLE PMC *get_pmc_keyed(PMC *key) {
int type;
char * const p = char_offset_key(INTERP, SELF, key, &type);
return ret_pmc(INTERP, SELF, p, type, key_2_idx(INTERP, SELF, key));
}
/*
=item C<void *get_pointer()>
Returns the pointer to the actual C C<struct>.
=cut
*/
VTABLE void *get_pointer() {
UNUSED(INTERP);
return PARROT_UNMANAGEDSTRUCT(SELF)->ptr;
}
/*
=item C<void set_pointer(void *value)>
Set the pointer to the actual C C<struct>.
=cut
*/
VTABLE void set_pointer(void *value) {
UNUSED(INTERP);
PARROT_UNMANAGEDSTRUCT(SELF)->ptr = value;
}
/*
=item C<void set_integer_keyed_int(INTVAL ix, INTVAL value)>
Sets the value of the element at index C<ix> to C<value>.
=cut
*/
VTABLE void set_integer_keyed_int(INTVAL ix, INTVAL value) {
int type;
char * const p = char_offset_int(INTERP, SELF, ix, &type);
set_int(INTERP, p, type, value);
}
/*
=item C<void set_integer_keyed(PMC *key, INTVAL value)>
Sets the value of the element associated with key C<*key> to C<value>.
May cause segfaults if value is out of bounds.
=cut
*/
VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
int type;
char * const p = char_offset_key(INTERP, SELF, key, &type);
set_int(INTERP, p, type, value);
}
/*
=item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
Sets the value of the element at index C<ix> to C<value>.
=cut
*/
VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
int type;
char * const p = char_offset_int(INTERP, SELF, key, &type);
set_float(INTERP, p, type, value);
}
/*
=item C<void set_number_keyed(PMC *key, FLOATVAL value)>
Sets the value of the element associated with key C<*key> to C<value>.
=cut
*/
VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
int type;
char * const p = char_offset_key(INTERP, SELF, key, &type);
set_float(INTERP, p, type, value);
}
/*
=item C<void set_string_keyed_int(INTVAL key, STRING *value)>
Sets the value of the element at index C<key> to C<*value>.
=cut
*/
VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
int type;
char * const p = char_offset_int(INTERP, SELF, key, &type);
set_string(INTERP, p, type, value);
}
/*
=item C<void set_string_keyed(PMC *key, STRING *value)>
Sets the value of the element associated with key C<*key> to C<*value>.
=cut
*/
VTABLE void set_string_keyed(PMC *key, STRING *value) {
int type;
char * const p = char_offset_key(INTERP, SELF, key, &type);
set_string(INTERP, p, type, value);
}
/*
=back
=head2 Methods
=over 4
=item C<as_string(string encodingname)>
Create a string from the buffer, assumed to be a C string, with the encoding
specified. If the encoding is omitted or null, use platform encoding.
=cut
*/
METHOD as_string(STRING *encodingname :optional) {
const char * content = (const char *)SELF.get_pointer();
STRING * const result = Parrot_str_new_from_cstring(INTERP, content, encodingname);
RETURN(STRING result);
}
}
/*
=back
=head1 SEE ALSO
F<docs/pmc/struct.pod>
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/