Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
160 lines (142 sloc) 5.6 KB
#include "parrot/parrot.h"
#define FPS_ATTRS_CONST(x) Parrot_FixedPMCStack_attributes * const (x)
#define FPS_GET_ATTRS(x) PARROT_FIXEDPMCSTACK(x)
#define FPS_ALLOCATE(len) (PMC **)mem_sys_allocate((len) * sizeof(PMC *))
#define FPS_NEXT_IDX(i, s) (((i) + 1) % (s))
/* FixedPMCStack is simple stack implemented on a fixed memory buffer in memory.
It is optimized for speed of push/pop operations. */
pmclass FixedPMCStack dynpmc auto_attrs provides stack{
ATTR PMC **storage;
ATTR INTVAL items;
ATTR INTVAL size;
/* Initialize the PMC */
VTABLE void init() {
PObj_custom_mark_destroy_SETALL(SELF);
}
/* Destroy the PMC and free storage */
VTABLE void destroy() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
PMC ** const s = attrs->storage;
if (s)
mem_sys_free(s);
}
/* Mark the PMC for GC */
VTABLE void mark() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
PMC ** const s = attrs->storage;
const INTVAL items = attrs->items;
INTVAL i;
for (i = 0; i < items; i++)
Parrot_gc_mark_PMC_alive(INTERP, s[i]);
}
VTABLE void freeze(PMC *info) {
}
VTABLE void thaw(PMC *info) {
}
VTABLE void visit(PMC *info) {
}
/* Size the PMC */
VTABLE void set_integer_native(INTVAL newsize) {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
const INTVAL size = attrs->size;
if (newsize <= 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"FixedPMCStack: Cannot set to zero or negative size");
else if (newsize != size) {
PMC ** const s = attrs->storage;
attrs->storage = (PMC **)mem_sys_realloc(s, newsize * sizeof(PMC*));
attrs->size = newsize;
}
}
/* Push an item onto the stack */
VTABLE void push_pmc(PMC *item) {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
const INTVAL size = attrs->size;
const INTVAL items = attrs->items;
PMC ** const s = attrs->storage;
if (size == items)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"FixedPMCStack: Cannot push more items than allocated storage");
s[items] = item;
attrs->items = items + 1;
}
/* Pop an item off the stack */
VTABLE PMC* pop_pmc() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
INTVAL items = attrs->items;
PMC ** const s = attrs->storage;
PMC * item;
if (items == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"FixedPMCStack: Cannot pop empty stack");
items--;
item = s[items];
attrs->items = items;
return item;
}
/* Get the number of items on the stack */
VTABLE INTVAL elements() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
const INTVAL items = attrs->items;
return items;
}
VTABLE INTVAL get_bool() {
const INTVAL elems = VTABLE_elements(INTERP, SELF);
const INTVAL has_elems = (elems > 0);
return has_elems;
}
/* Get the total allocated size of the stack */
VTABLE INTVAL get_integer() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
const INTVAL size = attrs->size;
return size;
}
/* Return a FixedPMCArray containing items on the stack. The FPA is the
same length as the allocated stack storage, and all empty spaces are
filled with PMCNULL */
METHOD to_array() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
PMC * const newarray = Parrot_pmc_new(INTERP, enum_class_FixedPMCArray);
const INTVAL size = attrs->size;
const INTVAL items = attrs->items;
PMC ** const s = attrs->storage;
INTVAL i;
/* TODO: A little bit of an issue here. set_integer_native on FPA
allocates storage, but it's that number that is returned later
on FPA.get_integer, so the results are off. For a real faithful
representation, we should return the same memory layout as we
have here (including unpopulated null areas), but for now we
need to truncate. When Parrot's core array types become sane,
fix this. */
VTABLE_set_integer_native(INTERP, newarray, items);
for (i = 0; i < items; i++)
VTABLE_set_pmc_keyed_int(INTERP, newarray, i, s[i]);
RETURN(PMC * newarray);
}
/* Get the total size of the PMC, in bytes. This includes allocated storage
for stack data, the PMC structure, and the attributes structure */
METHOD total_mem_size() {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
const INTVAL size = attrs->size;
const INTVAL struct_size = sizeof(PMC) + sizeof(Parrot_FixedPMCStack_attributes);
const INTVAL total_size = size + struct_size;
RETURN(INTVAL total_size);
}
/* Clear the stack, optionally resizing it */
METHOD clear(INTVAL newsize :optional, INTVAL has_newsize :opt_flag) {
FPS_ATTRS_CONST(attrs) = FPS_GET_ATTRS(SELF);
if (has_newsize) {
if (newsize > 0) {
PMC ** const s = attrs->storage;
if (s)
mem_sys_free(s);
attrs->storage = FPS_ALLOCATE(newsize);
attrs->size = newsize;
}
else
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"FixedPMCStack: Cannot set zero or negative size");
}
attrs->items = 0;
}
}