Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
652 lines (413 sloc) 13.5 KB
/*
Copyright (C) 2001-2014, Parrot Foundation.
=head1 NAME
src/pmc/fixedbooleanarray.pmc - FixedBooleanArray PMC
=head1 DESCRIPTION
Fixed size array for booleans only.
The C<FixedBooleanArray> PMC implements an array of fixed size, which
stores booleans. It uses the C<Boolean> PMC for all conversions. The
C<FixedBooleanArray> PMC is extended by the C<ResizableBooleanArray>
PMC.
=head2 Functions
=over 4
=item C<static UINTVAL get_size_in_bytes(UINTVAL size)>
Auxiliar function to avoid repeating the size evaluation.
=cut
*/
#define BITS_PER_CHAR 8
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
PARROT_INLINE
PARROT_CONST_FUNCTION
static UINTVAL get_size_in_bytes(UINTVAL size);
#define ASSERT_ARGS_get_size_in_bytes __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
PARROT_INLINE
PARROT_CONST_FUNCTION
static UINTVAL
get_size_in_bytes(UINTVAL size)
{
ASSERT_ARGS(get_size_in_bytes)
return (size + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
}
pmclass FixedBooleanArray auto_attrs provides array {
ATTR UINTVAL size; /* # of bits this fba holds */
ATTR UINTVAL resize_threshold; /* max capacity before resizing */
ATTR unsigned char * bit_array; /* where the bits go */
/*
=back
=head2 Vtable functions
=over 4
=item C<void init()>
Initializes the array.
=cut
*/
VTABLE void init() {
PObj_custom_destroy_SET(SELF);
}
/*
=item C<void init_int(INTVAL size)>
Initializes the array.
=cut
*/
VTABLE void init_int(INTVAL size) {
const size_t size_in_bytes = get_size_in_bytes(size);
if (size < 0)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"illegal argument");
SET_ATTR_size(INTERP, SELF, size);
SET_ATTR_resize_threshold(INTERP, SELF, size_in_bytes * BITS_PER_CHAR);
SET_ATTR_bit_array(INTERP, SELF, mem_gc_allocate_n_zeroed_typed(INTERP, size_in_bytes,
unsigned char));
PObj_custom_destroy_SET(SELF);
}
/*
=item C<void destroy()>
Destroys the array.
=cut
*/
VTABLE void destroy() :no_wb {
unsigned char *bit_array;
GET_ATTR_bit_array(INTERP, SELF, bit_array);
if (bit_array)
mem_gc_free(INTERP, bit_array);
}
/*
=item C<PMC *clone()>
Creates and returns a copy of the array.
=cut
*/
VTABLE PMC *clone() :no_wb {
unsigned char * my_bit_array;
UINTVAL resize_threshold, size;
PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
GET_ATTR_bit_array(INTERP, SELF, my_bit_array);
GET_ATTR_size(INTERP, SELF, size);
GET_ATTR_resize_threshold(INTERP, SELF, resize_threshold);
if (my_bit_array) {
unsigned char * clone_bit_array;
const size_t size_in_bytes = get_size_in_bytes(resize_threshold);
SET_ATTR_size(INTERP, dest, size);
SET_ATTR_resize_threshold(INTERP, dest, resize_threshold);
clone_bit_array = mem_gc_allocate_n_typed(INTERP, size_in_bytes, unsigned char);
memcpy(clone_bit_array, my_bit_array, size_in_bytes);
SET_ATTR_bit_array(INTERP, dest, clone_bit_array);
}
PObj_custom_destroy_SET(dest);
return dest;
}
/*
=item C<INTVAL get_bool()>
Returns whether the array has any elements (meaning been initialized, for a
fixed sized array).
=cut
*/
VTABLE INTVAL get_bool() :no_wb {
return SELF.elements() ? 1 : 0;
}
/*
=item C<INTVAL elements()>
=cut
*/
VTABLE INTVAL elements() :no_wb {
UINTVAL size;
GET_ATTR_size(INTERP, SELF, size);
return size;
}
/*
=item C<INTVAL get_integer()>
Returns the number of elements in the array.
=cut
*/
VTABLE INTVAL get_integer() :no_wb {
return SELF.elements();
}
/*
=item C<INTVAL get_integer_keyed_int(INTVAL key)>
Returns the integer value of the element at index C<key>.
=cut
*/
VTABLE INTVAL get_integer_keyed_int(INTVAL key) :no_wb {
UINTVAL size;
const unsigned char * bit_array;
GET_ATTR_bit_array(INTERP, SELF, bit_array);
GET_ATTR_size(INTERP, SELF, size);
if (key < 0)
key += size;
if (key < 0 || (UINTVAL)key >= size)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"index out of bounds");
return (bit_array[key / BITS_PER_CHAR] & (1 << (key % BITS_PER_CHAR))) ? 1 : 0;
}
/*
=item C<INTVAL get_integer_keyed(PMC *key)>
Returns the integer value of the element at index C<*key>.
=cut
*/
VTABLE INTVAL get_integer_keyed(PMC *key) :no_wb {
/* simple int keys only */
const INTVAL k = VTABLE_get_integer(INTERP, key);
return SELF.get_integer_keyed_int(k);
}
/*
=item C<FLOATVAL get_number_keyed_int(INTVAL key)>
Returns the floating-point value of the element at index C<key>.
=cut
*/
VTABLE FLOATVAL get_number_keyed_int(INTVAL key) :no_wb {
const INTVAL i = SELF.get_integer_keyed_int(key);
return (FLOATVAL)i;
}
/*
=item C<FLOATVAL get_number_keyed(PMC *key)>
Returns the floating-point value of the element at index C<*key>.
=cut
*/
VTABLE FLOATVAL get_number_keyed(PMC *key) :no_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
return SELF.get_number_keyed_int(k);
}
/*
=item C<STRING *get_string()>
Returns the Parrot string representation of the array.
=cut
*/
VTABLE STRING *get_string() :no_wb {
STRING *str = STRINGNULL;
UINTVAL i;
const UINTVAL elems = SELF.elements();
const STRING * const zero = CONST_STRING(INTERP, "0");
const STRING * const one = CONST_STRING(INTERP, "1");
for (i = 0; i < elems; ++i) {
str = Parrot_str_concat(INTERP, str,
SELF.get_integer_keyed_int((INTVAL)i) ? one : zero);
}
return str;
}
/*
=item C<STRING *get_string_keyed_int(INTVAL key)>
Returns the Parrot string value of the element at index C<key>.
=cut
*/
VTABLE STRING *get_string_keyed_int(INTVAL key) :no_wb {
PMC * const val = SELF.get_pmc_keyed_int(key);
return VTABLE_get_string(INTERP, val);
}
/*
=item C<STRING *get_string_keyed(PMC *key)>
Returns the Parrot string value of the element at index C<*key>.
=cut
*/
VTABLE STRING *get_string_keyed(PMC *key) :no_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
return SELF.get_string_keyed_int(k);
}
/*
=item C<PMC *get_pmc_keyed_int(INTVAL key)>
Returns the PMC value of the element at index C<key>.
=cut
*/
VTABLE PMC *get_pmc_keyed_int(INTVAL key) :no_wb {
return Parrot_pmc_new_init_int(INTERP, enum_class_Boolean,
SELF.get_integer_keyed_int(key));
}
/*
=item C<PMC *get_pmc_keyed(PMC *key)>
Returns the PMC value of the element at index C<*key>.
=cut
*/
VTABLE PMC *get_pmc_keyed(PMC *key) :no_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
return SELF.get_pmc_keyed_int(k);
}
/*
=item C<void set_integer_native(INTVAL size)>
Resizes the array to C<size> elements.
=cut
*/
VTABLE void set_integer_native(INTVAL size) {
const size_t size_in_bytes = get_size_in_bytes(size);
UINTVAL old_size;
unsigned char *bit_array;
GET_ATTR_size(INTERP, SELF, old_size);
if (old_size || size < 1)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"Can't resize");
SET_ATTR_size(INTERP, SELF, size);
SET_ATTR_resize_threshold(INTERP, SELF, size_in_bytes * BITS_PER_CHAR);
bit_array = mem_gc_allocate_n_typed(INTERP, size_in_bytes, unsigned char);
memset(bit_array, 0, size_in_bytes);
SET_ATTR_bit_array(INTERP, SELF, bit_array);
}
/*
=item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>
Sets the integer value of the element at index C<key> to C<value>.
=cut
*/
VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
UINTVAL size;
unsigned char * bit_array;
GET_ATTR_bit_array(INTERP, SELF, bit_array);
GET_ATTR_size(INTERP, SELF, size);
if (key < 0)
key += size;
if (key < 0 || (UINTVAL)key >= size)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"index out of bounds");
if (value)
bit_array[key/BITS_PER_CHAR] |= (1 << (key % BITS_PER_CHAR));
else
bit_array[key/BITS_PER_CHAR] &= ~(1 << (key % BITS_PER_CHAR));
}
/*
=item C<void set_integer_keyed(PMC *key, INTVAL value)>
Sets the integer value of the element at index C<key> to C<value>.
=cut
*/
VTABLE void set_integer_keyed(PMC *key, INTVAL value) :manual_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
SELF.set_integer_keyed_int(k, value);
}
/*
=item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
Sets the floating-point value of the element at index C<key> to
C<value>.
=cut
*/
VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) :manual_wb {
SELF.set_integer_keyed_int(key, !FLOAT_IS_ZERO(value));
}
/*
=item C<void set_number_keyed(PMC *key, FLOATVAL value)>
Sets the floating-point value of the element at index C<key> to
C<value>.
=cut
*/
VTABLE void set_number_keyed(PMC *key, FLOATVAL value) :manual_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
SELF.set_number_keyed_int(k, value);
}
/*
=item C<void set_string_keyed_int(INTVAL key, STRING *value)>
Sets the Parrot string value of the element at index C<key> to C<value>.
=cut
*/
VTABLE void set_string_keyed_int(INTVAL key, STRING *value) :manual_wb {
INTVAL tempInt;
PMC * const tempPMC = Parrot_pmc_new(INTERP, enum_class_Boolean);
VTABLE_set_string_native(INTERP, tempPMC, value);
tempInt = VTABLE_get_integer(INTERP, tempPMC);
SELF.set_integer_keyed_int(key, tempInt);
}
/*
=item C<void set_string_keyed(PMC *key, STRING *value)>
Sets the string value of the element at index C<key> to
C<value>.
=cut
*/
VTABLE void set_string_keyed(PMC *key, STRING *value) :manual_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
SELF.set_string_keyed_int(k, value);
}
/*
=item C<void set_pmc_keyed_int(INTVAL key, PMC *src)>
Sets the PMC value of the element at index C<key> to C<*src>.
=cut
*/
VTABLE void set_pmc_keyed_int(INTVAL key, PMC *src) :manual_wb {
const INTVAL tempInt = VTABLE_get_integer(INTERP, src);
SELF.set_integer_keyed_int(key, tempInt);
}
/*
=item C<void set_pmc_keyed(PMC *key, PMC *value)>
Sets the string value of the element at index C<key> to
C<value>.
=cut
*/
VTABLE void set_pmc_keyed(PMC *key, PMC *value) :manual_wb {
const INTVAL k = VTABLE_get_integer(INTERP, key);
SELF.set_pmc_keyed_int(k, value);
}
/*
=item C<PMC *get_iter()>
Return a new iterator for SELF.
=cut
*/
VTABLE PMC *get_iter() :no_wb {
return Parrot_pmc_new_init(INTERP, enum_class_ArrayIterator, SELF);
}
/*
=back
=head2 Freeze/thaw Interface
=over 4
=item C<void freeze(PMC *info)>
Used to archive the string.
=cut
*/
VTABLE void freeze(PMC *info) :no_wb {
UINTVAL size, resize_threshold;
unsigned char * bit_array;
STRING * s;
GET_ATTR_size(INTERP, SELF, size);
GET_ATTR_resize_threshold(INTERP, SELF, resize_threshold);
GET_ATTR_bit_array(INTERP, SELF, bit_array);
s = Parrot_str_new_init(INTERP, (char*)bit_array,
(resize_threshold / BITS_PER_CHAR),
Parrot_binary_encoding_ptr, 0);
VTABLE_push_integer(INTERP, info, size);
VTABLE_push_string(INTERP, info, s);
}
/*
=item C<void thaw(PMC *info)>
Used to unarchive the string.
=cut
*/
VTABLE void thaw(PMC *info) {
SUPER(info);
{
const INTVAL size = VTABLE_shift_integer(INTERP, info);
STRING * const s = VTABLE_shift_string(INTERP, info);
const size_t size_in_bytes = get_size_in_bytes(size);
unsigned char *bit_array;
SELF.set_integer_native(size);
if (s->bufused < size_in_bytes)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_BAD_BUFFER_SIZE,
"FixedBooleanArray: invalid buffer size during thaw");
GET_ATTR_bit_array(INTERP, SELF, bit_array);
memcpy(bit_array, s->strstart, size_in_bytes);
}
}
/*
=back
=head2 Methods
=over 4
=item C<METHOD fill(INTVAL fill)>
Sets all of the entries to true if fill is a true value, otherwise
sets them all to false.
=cut
*/
METHOD fill(INTVAL fill) {
UINTVAL size;
unsigned char * bit_array;
size_t size_in_bytes;
GET_ATTR_bit_array(INTERP, SELF, bit_array);
GET_ATTR_size(INTERP, SELF, size);
size_in_bytes = get_size_in_bytes(size);
if (size_in_bytes)
memset(bit_array, fill ? 0xff : 0, size_in_bytes);
}
}
/*
=back
=head1 SEE ALSO
F<docs/pdds/pdd17_basic_types.pod>.
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/