/*
Copyright (C) 2001-2005, The Perl Foundation.
$Id: fixedbooleanarray.pmc 16275 2006-12-28 01:20:44Z particle $

=head1 NAME

src/pmc/fixedbooleanarray.pmc - fixed size array for booleans only

=head1 DESCRIPTION

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

=cut

*/

#include "parrot/parrot.h"


/*
 * TODO merge this with functions from BigInt PMC
 */

#define BITS_PER_CHAR 8

static void
booleanarray_init(Interp *interp, PMC *self) {
    PMC_int_val(self) = 0;
    PMC_int_val2(self) = 0;
    PMC_data(self) = NULL;
}

static void
booleanarray_clone(Interp *interp, PMC *self, PMC *dest) {
    PMC_int_val(dest)  = PMC_int_val(self);
    PMC_int_val2(dest) = PMC_int_val2(self);
    if (PMC_data(self)) {
        PMC_data(dest) = malloc(PMC_int_val2(self) / BITS_PER_CHAR);
        mem_sys_memcopy(PMC_data(dest),
                        PMC_data(self), PMC_int_val2(self) / BITS_PER_CHAR);
    }
    else
        PMC_data(dest) = NULL;
}

static void
booleanarray_clear(Interp *interp, PMC *self) {
    PMC_int_val(self) = 0;
    PMC_int_val2(self) = 0;
    if (PMC_data(self)) {
        mem_sys_free(PMC_data(self));
        PMC_data(self) = NULL;
    }
}

pmclass FixedBooleanArray need_ext does array {

/*

=back

=head2 Methods

=over 4

=item C<void init()>

Initializes the array.

=cut

*/

    void init() {
        booleanarray_init(INTERP, SELF);
        PObj_active_destroy_SET(SELF);
    }


/*

=item C<void morph(INTVAL type)>

Const PMCs must have a C<morph()>.

=cut

*/

    void morph(INTVAL type) {
        SUPER(type);
    }


/*

=item C<void destroy()>

Destroys the array.

=cut

*/

    void destroy() {
        booleanarray_clear(INTERP, SELF);
    }

/*

=item C<PMC *clone()>

Creates and returns a copy of the array.

=cut

*/

    PMC* clone() {
        PMC * dest = pmc_new(INTERP, SELF->vtable->base_type);
        booleanarray_clone(INTERP, SELF, dest);
        PObj_active_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

*/
    INTVAL get_bool() {
        return SELF.elements() ? 1 : 0;
    }

/*

=item C<INTVAL elements()>

=cut

*/

    INTVAL elements() {
        return PMC_int_val(SELF);
    }

/*

=item C<INTVAL get_integer()>

Returns the number of elements in the array.

=cut

*/

    INTVAL get_integer() {
        return SELF.elements();
    }


/*

=item C<INTVAL get_integer_keyed_int(INTVAL key)>

Returns the integer value of the element at index C<key>.

=cut

*/

    INTVAL get_integer_keyed_int(INTVAL key) {
        Parrot_UInt1 *sd = PMC_data(SELF);

        if (key < 0 || key >= PMC_int_val(SELF))
            real_exception(INTERP, NULL, E_IndexError,
                "FixedBooleanArray: index out of bounds!");

        return (sd[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

*/

    INTVAL get_integer_keyed(PMC* key) {
        /* simple int keys only */
        INTVAL k = key_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

*/

    FLOATVAL get_number_keyed_int(INTVAL key) {
        return (FLOATVAL)DYNSELF.get_integer_keyed_int(key);
    }

/*

=item C<FLOATVAL get_number_keyed(PMC* key)>

Returns the floating-point value of the element at index C<*key>.

=cut

*/

    FLOATVAL get_number_keyed(PMC* key) {
        INTVAL k = key_integer(INTERP, key);
        return DYNSELF.get_number_keyed_int(k);
    }

/*

=item C<STRING *get_string_keyed_int(INTVAL key)>

Returns the Parrot string value of the element at index C<key>.

=cut

*/

    STRING* get_string_keyed_int(INTVAL key) {
        PMC *val = DYNSELF.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

*/

    STRING* get_string_keyed(PMC* key) {
        INTVAL k = key_integer(INTERP, key);
        return DYNSELF.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

*/

    PMC* get_pmc_keyed_int(INTVAL key) {
        PMC *ret = pmc_new(INTERP, enum_class_Boolean);
        INTVAL val = DYNSELF.get_integer_keyed_int(key);
        VTABLE_set_integer_native(INTERP, ret, val);
        return ret;
    }

/*

=item C<PMC *get_pmc_keyed(PMC *key)>

Returns the PMC value of the element at index C<*key>.

=cut

*/

    PMC* get_pmc_keyed(PMC* key) {
        INTVAL k = key_integer(INTERP, key);
        return DYNSELF.get_pmc_keyed_int(k);
    }

/*

=item C<void set_integer_native(INTVAL size)>

Resizes the array to C<size> elements.

=cut

*/

    void set_integer_native(INTVAL size) {
        if (PMC_int_val(SELF) || size < 1)
            real_exception(INTERP, NULL, E_IndexError,
                    "FixedBooleanArray: Can't resize!");

        PMC_int_val(SELF) = size;
        PMC_int_val2(SELF) = (size / BITS_PER_CHAR + 1) * BITS_PER_CHAR;
        PMC_data(SELF) =
            mem_sys_allocate_zeroed(PMC_int_val2(SELF) / BITS_PER_CHAR);
    }

/*

=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

*/

    void set_integer_keyed_int(INTVAL key, INTVAL value) {
        Parrot_UInt1 *sd = PMC_data(SELF);

        if (key < 0 || key >= PMC_int_val(SELF))
            real_exception(INTERP, NULL, E_IndexError,
                "FixedBooleanArray: index out of bounds!");

        if ( value ) {
            sd[key/BITS_PER_CHAR] |= ( 1 << ( key % BITS_PER_CHAR ) );
        }
        else {
            sd[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

*/

    void set_integer_keyed(PMC *key, INTVAL value) {
        INTVAL k = key_integer(INTERP, key);
        DYNSELF.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

*/

    void set_number_keyed_int(INTVAL key, FLOATVAL value) {
        DYNSELF.set_integer_keyed_int(key, ( value ? 1 : 0 ));
    }

/*

=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

*/

    void set_number_keyed(PMC *key, FLOATVAL value) {
        INTVAL k = key_integer(INTERP, key);
        DYNSELF.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

*/

    void set_string_keyed_int(INTVAL key, STRING* value) {
        INTVAL tempInt;
        PMC *tempPMC;

        tempPMC = pmc_new(INTERP, enum_class_Boolean);
        VTABLE_set_string_native(INTERP, tempPMC, value);
        tempInt = VTABLE_get_integer(INTERP, tempPMC);
        DYNSELF.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

*/

    void set_string_keyed(PMC *key, STRING* value) {
        INTVAL k = key_integer(INTERP, key);
        DYNSELF.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

*/

    void set_pmc_keyed_int(INTVAL key, PMC* src) {
        INTVAL tempInt;

        tempInt = VTABLE_get_integer(INTERP, src);
        DYNSELF.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

*/

    void set_pmc_keyed(PMC *key, PMC* value) {
        INTVAL k;
        k = key_integer(INTERP, key);
        DYNSELF.set_pmc_keyed_int(k, value);
    }

/*

=item C<void push_integer(INTVAL value)>

Extends the array by adding an element of value C<value> to the end of
the array.

=cut

*/

    void push_integer(INTVAL value) {
        INTVAL nextix = DYNSELF.elements();
        DYNSELF.set_integer_keyed_int(nextix, value);
    }

/*

=back

=head2 Freeze/thaw Interface

=over 4

=item C<void freeze(visit_info *info)>

Used to archive the string.

=cut

*/
    void freeze(visit_info *info) {
        IMAGE_IO *io = info->image_io;
        STRING *s;
        io->vtable->push_integer(INTERP, io, PMC_int_val(SELF));
        s = string_from_cstring(INTERP,
                                PMC_data(SELF),
                                PMC_int_val2(SELF)/BITS_PER_CHAR);
        io->vtable->push_string(INTERP, io, s);
    }

/*

=item C<void thaw(visit_info *info)>

Used to unarchive the string.

=cut

*/
    void thaw(visit_info *info) {
        IMAGE_IO *io = info->image_io;
        SUPER(info);
        if (info->extra_flags == EXTRA_IS_NULL) {
            INTVAL size = io->vtable->shift_integer(INTERP, io);
            STRING * s  = io->vtable->shift_string(INTERP, io);
            PMC_int_val(SELF) = size;
            PMC_int_val2(pmc) = s->bufused * BITS_PER_CHAR;
            PMC_data(pmc) = mem_sys_allocate_zeroed(s->bufused);
            mem_sys_memcopy(PMC_data(SELF), s->strstart, s->bufused);
        }
    }

/*

=item C<METHOD void fill(INTVAL fill)>

Sets all of the entires to true if fill is a true value, otherwise
sets them all to false.

=cut

*/

    METHOD void fill(INTVAL fill) {
        Parrot_UInt1 *sd = PMC_data(SELF);
        INTVAL j;
        j = PMC_int_val(SELF) / BITS_PER_CHAR + 1;
        if (fill)
            memset(sd, 0xff, j);
        else
            memset(sd, 0, j);
    }
}

/*

=back

=head1 SEE ALSO

F<docs/pdds/pdd17_basic_types.pod>.

=head1 HISTORY

Initial version 2004.06.11 by Matt Fowles

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
