/*
Copyright (C) 2001-2010, Parrot Foundation.
$Id: fixedstringarray.pmc 48450 2010-08-13 13:52:14Z mikehh $

=head1 NAME

src/pmc/fixedstringarray.pmc - fixed size array for strings only

=head1 DESCRIPTION

This class, FixedStringArray, implements an array of fixed size which
stores Parrot strings.

=head2 Functions

=over 4

=cut

*/

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */

pmclass FixedStringArray auto_attrs provides array {
    ATTR STRING **str_array; /* where the STRINGs are stored */
    ATTR UINTVAL  size;      /* element count */

/*

=back

=head2 Methods

=over 4

=item C<void init_int(INTVAL size)>

Initializes the array.

=cut

*/

    VTABLE void init_int(INTVAL size) {
        if (size < 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                _("FixedStringArray: Cannot set array size to a negative number (%d)"), size);
        if (size) {
            SET_ATTR_size(INTERP, SELF, size);
            SET_ATTR_str_array(INTERP,
                               SELF, mem_gc_allocate_n_zeroed_typed(INTERP, size, STRING *));
            PObj_custom_mark_destroy_SETALL(SELF);
        }
    }


/*

=item C<void destroy()>

Destroys the array.

=cut

*/

    VTABLE void destroy() {

        STRING **str_array;

        GET_ATTR_str_array(INTERP, SELF, str_array);

        if (str_array)
            mem_gc_free(INTERP, str_array);
    }

/*

=item C<PMC *clone()>

Creates and returns a copy of the array.

=cut

*/

    VTABLE PMC *clone() {

        STRING    **my_str_array, **dest_str_array;
        PMC        *const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type);

        GET_ATTR_str_array(INTERP, SELF, my_str_array);

        if (my_str_array) {
            INTVAL size;
            size_t mem_size;

            GET_ATTR_size(INTERP, SELF, size);
            mem_size = size * sizeof (STRING *);

            dest_str_array = mem_gc_allocate_n_zeroed_typed(INTERP, size, STRING *);
            mem_sys_memcopy(dest_str_array, my_str_array, mem_size);
            SET_ATTR_str_array(INTERP, dest, dest_str_array);
            SET_ATTR_size(INTERP, dest, size);

            PObj_custom_mark_destroy_SETALL(dest);
        }

        return dest;
    }

/*

=item C<void mark()>

Marks the array as live.

=cut

*/

    VTABLE void mark() {

        STRING **str_array;
        GET_ATTR_str_array(INTERP, SELF, str_array);

        if (str_array) {
            UINTVAL size, i;
            GET_ATTR_size(INTERP, SELF, size);

            for (i = 0; i < size; ++i) {
                Parrot_gc_mark_STRING_alive(INTERP, str_array[i]);
            }
        }
    }

/*

=item C<INTVAL get_bool()>

Returns 1 if the array has any elements; otherwise, returns 0.
Since this is a fixed size array, C<get_bool> will always
return true once the array has been initialized and had its
size set by C<set_integer_native>.

=cut

*/
    VTABLE INTVAL get_bool() {
        const INTVAL size = SELF.elements();
        return (INTVAL)(size != 0);
    }

/*

=item C<PMC *get_iter()>

Gets an iterator for the array.

=cut

*/
    VTABLE PMC *get_iter() {
        return Parrot_pmc_new_init(INTERP, enum_class_ArrayIterator, SELF);
    }

/*

=item C<INTVAL elements()>

Returns the number of elements in the array.

=cut

*/

    VTABLE INTVAL elements() {
        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() {
        return SELF.elements();
    }

/*

=item C<FLOATVAL get_number()>

Returns the number of elements in the array.

=cut

*/

    VTABLE FLOATVAL get_number() {
        const INTVAL e = SELF.elements();
        return (FLOATVAL)e;
    }

/*

=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) {
        STRING * const element = SELF.get_string_keyed_int(key);
        return Parrot_str_to_int(INTERP, element);
    }

/*

=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) {
        /* 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) {
        STRING * const element = SELF.get_string_keyed_int(key);
        return Parrot_str_to_num(INTERP, element);
    }

/*

=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) {
        const INTVAL k = VTABLE_get_integer(INTERP, key);
        return SELF.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

*/

    VTABLE STRING *get_string_keyed_int(INTVAL key) {
        STRING **str_array;
        UINTVAL  size;

        GET_ATTR_size(INTERP, SELF, size);
        if (key < 0 || (UINTVAL)key >= size)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "FixedStringArray: index out of bounds!");

        GET_ATTR_str_array(INTERP, SELF, str_array);
        return str_array[key];
    }

/*

=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) {
        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) {
        PMC    * const ret = Parrot_pmc_new(INTERP, enum_class_String);
        STRING * const val = SELF.get_string_keyed_int(key);

        VTABLE_set_string_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

*/

    VTABLE PMC *get_pmc_keyed(PMC *key) {
        const INTVAL k = VTABLE_get_integer(INTERP, key);
        return SELF.get_pmc_keyed_int(k);
    }

/*

=item C<void set_integer_native(INTVAL size)>

Sets the size of the array to C<size> elements. Once the array
has been given an initial size, attempts to resize it will
cause an exception to be thrown.

=cut

*/

    VTABLE void set_integer_native(INTVAL new_size) {

        UINTVAL  old_size;
        GET_ATTR_size(INTERP, SELF, old_size);

        if (old_size || new_size < 1)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "FixedStringArray: Can't resize!");

        SET_ATTR_size(INTERP, SELF, new_size);
        SET_ATTR_str_array(INTERP, SELF,
                mem_gc_allocate_n_zeroed_typed(INTERP, new_size, STRING*));

        PObj_custom_mark_destroy_SETALL(SELF);
    }

/*

=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) {
        STRING *val = Parrot_str_from_int(INTERP, value);
        SELF.set_string_keyed_int(key, val);
    }

/*

=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) {
        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) {
        STRING *val = Parrot_str_from_num(INTERP, value);
        SELF.set_string_keyed_int(key, val);
    }

/*

=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) {
        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) {
        STRING **str_array;

        if (key < 0 || key >= SELF.elements())
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
                "FixedStringArray: index out of bounds!");

        GET_ATTR_str_array(INTERP, SELF, str_array);

        str_array[key] = value;
    }

/*

=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) {
        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) {
        STRING * const temp = VTABLE_get_string(INTERP, src);
        SELF.set_string_keyed_int(key, temp);
    }

/*

=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) {
        const INTVAL k = VTABLE_get_integer(INTERP, key);
        SELF.set_pmc_keyed_int(k, value);
    }

/*

=item C<STRING *get_string()>

=item C<STRING *get_repr()>

Returns the Parrot string representation C<key>.

=cut

*/
    VTABLE STRING *get_string() {
        return STATICSELF.get_repr();
    }

    VTABLE STRING *get_repr() {

        STRING       *res = CONST_STRING(INTERP, "[ ");
        const INTVAL  n   = SELF.get_integer();
        INTVAL        j;

        for (j = 0; j < n; ++j) {
            STRING * const val = SELF.get_string_keyed_int(j);
            res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, "\""));
            res = Parrot_str_concat(INTERP, res, val);
            res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, "\""));

            if (j < n - 1)
                res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, ", "));
        }

        res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, " ]"));
        return res;
    }


/*

=item C<INTVAL is_equal(PMC *value)>

The C<==> operation. Compares two array to hold equal elements.

=cut

*/

    VTABLE INTVAL is_equal(PMC *value) {
        INTVAL j, n;

        if (value->vtable->base_type != SELF->vtable->base_type)
            return 0;

        n = SELF.elements();

        if (VTABLE_elements(INTERP, value) != n)
            return 0;

        for (j = 0; j < n; ++j) {
            STRING * const item1 = SELF.get_string_keyed_int(j);
            STRING * const item2 = VTABLE_get_string_keyed_int(INTERP, value, j);

            if (item1 == item2)
                continue;

            if (STRING_IS_NULL(item1) ||  STRING_IS_NULL(item2))
                return 0;

            if (!Parrot_str_equal(INTERP, item1, item2))
                return 0;
        }

        return 1;
    }

/*

=back

=head2 Freeze/thaw Interface

=over 4

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

Used to archive the string.

=cut

*/
    VTABLE void freeze(PMC *info) {
        STRING           **str_array;
        UINTVAL            size, i;

        GET_ATTR_size(INTERP, SELF, size);
        GET_ATTR_str_array(INTERP, SELF, str_array);
        VTABLE_push_integer(INTERP, info, size);

        for (i = 0; i < size; ++i)
            VTABLE_push_string(INTERP, info, str_array[i]);
    }

/*

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

Used to unarchive the string.

=cut

*/
    VTABLE void thaw(PMC *info) {
        UINTVAL  i, size;
        STRING **str_array;

        SELF.init();
        SUPER(info);

        size   = VTABLE_shift_integer(INTERP, info);
        SELF.set_integer_native((INTVAL)size);
        GET_ATTR_str_array(INTERP, SELF, str_array);

        for (i = 0; i < size; ++i)
            str_array[i] = VTABLE_shift_string(INTERP, info);
    }
}

/*

=back

=head1 SEE ALSO

F<docs/pdds/pdd17_basic_types.pod>.

=cut

*/

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