/*
Copyright (C) 2001-2010, Parrot Foundation.
$Id: capture.pmc 48444 2010-08-13 06:39:10Z NotFound $

=head1 NAME

src/pmc/capture.pmc - Capture PMC

=head1 DESCRIPTION

These are the vtable functions for the Capture PMC.

=head2 Functions

=over 4

=cut

*/

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

#define CAPTURE_array_CREATE(i, obj, arr) \
    do { \
        GETATTR_Capture_array((i), (obj), (arr)); \
        if (!(arr)) { \
            PObj_custom_mark_SET(obj); \
            (arr) = Parrot_pmc_new((i), enum_class_ResizablePMCArray); \
            SETATTR_Capture_array((i), (obj), (arr)); \
        } \
    } while (0)
#define CAPTURE_hash_CREATE(i, obj, hsh) \
    do { \
        GETATTR_Capture_hash((i), (obj), (hsh)); \
        if (!(hsh)) { \
            PObj_custom_mark_SET(obj); \
            (hsh) = Parrot_pmc_new((i), enum_class_Hash); \
            SETATTR_Capture_hash((i), (obj), (hsh)); \
        } \
    } while (0)

pmclass Capture auto_attrs {
    ATTR PMC    *array;
    ATTR PMC    *hash;

/*

=item C<PMC *clone()>

Creates an identical copy of the Capture.

=cut

*/

    VTABLE PMC *clone() {
        PMC *array, *hash;
        PMC *dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
        GET_ATTR_array(INTERP, SELF, array);
        GET_ATTR_hash(INTERP, SELF, hash);
        if (!PMC_IS_NULL(array)) {
            PObj_custom_mark_SET(dest);
            array = VTABLE_clone(INTERP, array);
            SET_ATTR_array(INTERP, dest, array);
        }
        if (!PMC_IS_NULL(hash)) {
            PObj_custom_mark_SET(dest);
            hash = VTABLE_clone(INTERP, hash);
            SET_ATTR_hash(INTERP, dest, hash);
        }

        return dest;
    }

/*

=item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>

=item C<void set_integer_keyed_int(INTVAL key, INTVAL value)>

=item C<void set_pmc_keyed_int(INTVAL key, PMC *value)>

=item C<void set_string_keyed_int(INTVAL key, STRING *value)>

Sets a value in the array component of the Capture.

=cut

*/

    VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_set_number_keyed_int(INTERP, array, key, value);
    }

    VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_set_integer_keyed_int(INTERP, array, key, value);
    }

    VTABLE void set_pmc_keyed_int(INTVAL key, PMC *value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_set_pmc_keyed_int(INTERP, array, key, value);
    }

    VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_set_string_keyed_int(INTERP, array, key, value);
    }

/*

=item C<FLOATVAL get_number_keyed_int(INTVAL key)>

=item C<INTVAL get_integer_keyed_int(INTVAL key)>

=item C<PMC *get_pmc_keyed_int(INTVAL key)>

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

Retrieves a value in the array component of the Capture.

=cut

*/

    VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return 0.0;

        return VTABLE_get_number_keyed_int(INTERP, array, key);
    }

    VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return 0;

        return VTABLE_get_integer_keyed_int(INTERP, array, key);
    }

    VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return PMCNULL;

        return VTABLE_get_pmc_keyed_int(INTERP, array, key);
    }

    VTABLE STRING *get_string_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return CONST_STRING(INTERP, "");

        return VTABLE_get_string_keyed_int(INTERP, array, key);
    }

/*

=item C<void push_float(FLOATVAL value)>

=item C<void push_integer(INTVAL value)>

=item C<void push_pmc(PMC *value)>

=item C<void push_string(STRING *value)>

Push a value onto the array component of the Capture.

=item C<void unshift_float(FLOATVAL value)>

=item C<void unshift_integer(INTVAL value)>

=item C<void unshift_pmc(PMC *value)>

=item C<void unshift_string(STRING *value)>

Unshift a value onto the array component of the Capture.

=cut

*/

    VTABLE void push_float(FLOATVAL value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_push_float(INTERP, array, value);
    }

    VTABLE void push_integer(INTVAL value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_push_integer(INTERP, array, value);
    }

    VTABLE void push_pmc(PMC *value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_push_pmc(INTERP, array, value);
    }

    VTABLE void push_string(STRING *value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_push_string(INTERP, array, value);
    }

    VTABLE void unshift_float(FLOATVAL value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_unshift_float(INTERP, array, value);
    }

    VTABLE void unshift_integer(INTVAL value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_unshift_integer(INTERP, array, value);
    }

    VTABLE void unshift_pmc(PMC *value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_unshift_pmc(INTERP, array, value);
    }

    VTABLE void unshift_string(STRING *value) {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        VTABLE_unshift_string(INTERP, array, value);
    }

/*

=item C<FLOATVAL pop_float()>

=item C<INTVAL pop_integer()>

=item C<PMC *pop_pmc()>

=item C<STRING *pop_string()>

Pop a value from the array component of the Capture.

=item C<FLOATVAL shift_float()>

=item C<INTVAL shift_integer()>

=item C<PMC *shift_pmc()>

=item C<STRING *shift_string()>

Shift a value from the array component of the Capture.

=cut

*/

    VTABLE FLOATVAL pop_float() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_pop_float(INTERP, array);
    }

    VTABLE INTVAL pop_integer() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_pop_integer(INTERP, array);
    }

    VTABLE PMC *pop_pmc() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_pop_pmc(INTERP, array);
    }

    VTABLE STRING *pop_string() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_pop_string(INTERP, array);
    }

    VTABLE FLOATVAL shift_float() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_shift_float(INTERP, array);
    }

    VTABLE INTVAL shift_integer() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_shift_integer(INTERP, array);
    }

    VTABLE PMC *shift_pmc() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_shift_pmc(INTERP, array);
    }

    VTABLE STRING *shift_string() {
        PMC *array;

        CAPTURE_array_CREATE(INTERP, SELF, array);
        return VTABLE_shift_string(INTERP, array);
    }

/*

=item C<INTVAL elements()>

Return the number of elements in the array component of the Capture.

=item C<INTVAL defined_keyed_int(INTVAL key)>

Return true if element C<key> of the array component is defined.

=item C<INTVAL exists_keyed_int(INTVAL key)>

Return true if element C<key> of the array component exists.

=item C<void delete_keyed_int(INTVAL key)>

Delete the element corresponding to C<key> in the array component.

=cut

*/

    VTABLE INTVAL elements() {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return 0;

        return VTABLE_elements(INTERP, array);
    }

    VTABLE INTVAL defined_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return 0;

        return VTABLE_defined_keyed_int(INTERP, array, key);
    }

    VTABLE INTVAL exists_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (!array)
            return 0;

        return VTABLE_exists_keyed_int(INTERP, array, key);
    }

    VTABLE void delete_keyed_int(INTVAL key) {
        PMC *array;

        GET_ATTR_array(INTERP, SELF, array);

        if (array)
            VTABLE_delete_keyed_int(INTERP, array, key);
    }

/*

=item C<void set_number_keyed(PMC *key, FLOATVAL value)>

=item C<void set_integer_keyed(PMC *key, INTVAL value)>

=item C<void set_pmc_keyed(PMC *key, PMC *value)>

=item C<void set_string_keyed(PMC *key, STRING *value)>

Sets a value in the hash component of the Capture.

=cut

*/

    VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_number_keyed(INTERP, hash, key, value);
    }

    VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_integer_keyed(INTERP, hash, key, value);
    }

    VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_pmc_keyed(INTERP, hash, key, value);
    }

    VTABLE void set_string_keyed(PMC *key, STRING *value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_string_keyed(INTERP, hash, key, value);
    }

/*

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

=item C<INTVAL get_integer_keyed(PMC *key)>

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

=item C<STRING *get_string_keyed(PMC *key)>

Retrieves a value from the hash component of the Capture.

=cut

*/

    VTABLE FLOATVAL get_number_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0.0;

        return VTABLE_get_number_keyed(INTERP, hash, key);
    }

    VTABLE INTVAL get_integer_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0;

        return VTABLE_get_integer_keyed(INTERP, hash, key);
    }

    VTABLE PMC *get_pmc_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return PMCNULL;

        return VTABLE_get_pmc_keyed(INTERP, hash, key);
    }

    VTABLE STRING *get_string_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return CONST_STRING(INTERP, "");

        return VTABLE_get_string_keyed(INTERP, hash, key);
    }

/*

=item C<void set_number_keyed_str(STRING *key, FLOATVAL value)>

=item C<void set_integer_keyed_str(STRING *key, INTVAL value)>

=item C<void set_pmc_keyed_str(STRING *key, PMC *value)>

=item C<void set_string_keyed_str(STRING *key, STRING *value)>

Sets a value in the hash component of the Capture.

=cut

*/

    VTABLE void set_number_keyed_str(STRING *key, FLOATVAL value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_number_keyed_str(INTERP, hash, key, value);
    }

    VTABLE void set_integer_keyed_str(STRING *key, INTVAL value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_integer_keyed_str(INTERP, hash, key, value);
    }

    VTABLE void set_pmc_keyed_str(STRING *key, PMC *value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_pmc_keyed_str(INTERP, hash, key, value);
    }

    VTABLE void set_string_keyed_str(STRING *key, STRING *value) {
        PMC *hash;

        CAPTURE_hash_CREATE(INTERP, SELF, hash);
        VTABLE_set_string_keyed_str(INTERP, hash, key, value);
    }

/*

=item C<FLOATVAL get_number_keyed_str(STRING *key)>

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

=item C<PMC *get_pmc_keyed_str(STRING *key)>

=item C<STRING *get_string_keyed_str(STRING *key)>

Retrieves a value in the hash component of the Capture.

=cut

*/

    VTABLE FLOATVAL get_number_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0.0;

        return VTABLE_get_number_keyed_str(INTERP, hash, key);
    }

    VTABLE INTVAL get_integer_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0;

        return VTABLE_get_integer_keyed_str(INTERP, hash, key);
    }

    VTABLE PMC *get_pmc_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return PMCNULL;

        return VTABLE_get_pmc_keyed_str(INTERP, hash, key);
    }

    VTABLE STRING *get_string_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return CONST_STRING(INTERP, "");
        return VTABLE_get_string_keyed_str(INTERP, hash, key);
    }

/*

=item C<INTVAL defined_keyed(PMC *key)>

Return true if element C<key> of the hash component is defined.

=item C<INTVAL exists_keyed(PMC *key)>

Return true if element C<key> of the hash component exists.

=item C<void delete_keyed(PMC *key)>

Delete the element corresponding to C<key> in the hash component.

=cut

*/

    VTABLE INTVAL defined_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0;

        return VTABLE_defined_keyed(INTERP, hash, key);
    }

    VTABLE INTVAL exists_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0;

        return VTABLE_exists_keyed(INTERP, hash, key);
    }

    VTABLE void delete_keyed(PMC *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (hash)
            VTABLE_delete_keyed(INTERP, hash, key);
    }

/*

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

Return true if element C<key> of the hash component is defined.

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

Return true if element C<key> of the hash component exists.

=item C<void delete_keyed_str(STRING *key)>

Delete the element corresponding to C<key> in the hash component.

=cut

*/

    VTABLE INTVAL defined_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0;
        return VTABLE_defined_keyed_str(INTERP, hash, key);
    }

    VTABLE INTVAL exists_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (!hash)
            return 0;
        return VTABLE_exists_keyed_str(INTERP, hash, key);
    }

    VTABLE void delete_keyed_str(STRING *key) {
        PMC *hash;

        GET_ATTR_hash(INTERP, SELF, hash);

        if (hash)
            VTABLE_delete_keyed_str(INTERP, hash, key);
    }

/*

=item C<void set_pmc(PMC *capture)>

Set this capture to hold the value of another.  If set to PMCNULL,
erase the contents of the array and hash components.

=cut

*/

    VTABLE void set_pmc(PMC *capture) {
        if (PMC_IS_NULL(capture)) {
            SET_ATTR_array(INTERP, SELF, NULL);
            SET_ATTR_hash(INTERP, SELF, NULL);
        }
        else if (VTABLE_isa(INTERP, capture, CONST_STRING(INTERP, "Capture"))) {
            PMC *array, *hash;
            GET_ATTR_array(INTERP, capture, array);
            GET_ATTR_hash(INTERP, capture, hash);
            SET_ATTR_array(INTERP, SELF, array);
            SET_ATTR_hash(INTERP, SELF, hash);
        }
        else
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "Can only set a capture to another capture.");
    }

/*

=item C<STRING get_string()>

Return a string representation of the hash, showing class
and memory address.

=cut

*/

    VTABLE STRING *get_string() {
        const STRING * const classname = VTABLE_name(INTERP, SELF);
        return Parrot_sprintf_c(INTERP, "%S[0x%x]", classname, SELF);
    }

/*

=item C<void mark(void)>

Mark the array.

=cut

*/

    VTABLE void mark() {
        if (PMC_data(SELF)) {
            PMC *array, *hash;
            GET_ATTR_array(INTERP, SELF, array);
            GET_ATTR_hash(INTERP, SELF, hash);

            Parrot_gc_mark_PMC_alive(INTERP, array);
            Parrot_gc_mark_PMC_alive(INTERP, hash);
        }
    }

/*

=back

=head2 Methods

=over 4

=cut

*/

    METHOD list() {
        PMC *array;
        PMC *capt = SELF;

        /* XXX:  This workaround is for when we get here as
                 part of a subclass of Capture */
        if (PObj_is_object_TEST(SELF)) {
            PMC    *classobj;
            PMC    *ns        = INTERP->root_namespace;
            STRING *attribute = CONST_STRING(INTERP, "proxy");

            ns                = Parrot_ns_get_namespace_keyed_str(INTERP, ns, CONST_STRING(INTERP, "parrot"));
            ns                = Parrot_ns_get_namespace_keyed_str(INTERP, ns, CONST_STRING(INTERP, "Capture"));
            classobj          = Parrot_oo_get_class(INTERP, ns);
            capt              = VTABLE_get_attr_keyed(INTERP, SELF, classobj, attribute);
        }

        CAPTURE_array_CREATE(INTERP, capt, array);
        RETURN(PMC *array);
    }

    METHOD hash() {
        PMC *hash;
        PMC *capt = SELF;
        /* XXX:  This workaround is for when we get here as
                 part of a subclass of Capture */
        if (PObj_is_object_TEST(SELF)) {
            STRING * const classname = CONST_STRING(INTERP, "Capture");
            STRING        *attribute = CONST_STRING(INTERP, "proxy");
            PMC           *classobj  = Parrot_oo_get_class_str(INTERP, classname);

            capt                     = VTABLE_get_attr_keyed(INTERP, SELF, classobj, attribute);
        }

        CAPTURE_hash_CREATE(INTERP, capt, hash);

        RETURN(PMC *hash);
    }

}

/*

=back

=head1 HISTORY

Initial version                  - Patrick Michaud 2006-11-03

=cut

*/

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