/*
Copyright (C) 2005-2008, The Perl Foundation.
$Id: /mirror/trunk/src/pmc/pair.pmc 31699 2008-10-05T11:30:01.049343Z allison  $

=head1 NAME

src/pmc/pair.pmc - Pair PMC

=head1 DESCRIPTION

A Pair PMC represents one key => value mapping like a one element hash.

=head2 Functions

=over 4

=cut

*/

#include "parrot/parrot.h"
#include "pmc_pair.h"

pmclass Pair need_ext {
    ATTR PMC *key;
    ATTR PMC *value;

/*

=item C<void init()>

Initializes the instance.

=item C<PMC *instantiate(PMC *sig)>

Class method to construct an Integer according to passed arguments.

=cut

*/

    VTABLE void init() {
        PMC_data(SELF) = mem_allocate_zeroed_typed(Parrot_Pair_attributes);
        PObj_custom_mark_SET(SELF);
    }

    VTABLE PMC *instantiate(PMC *sig) {
        return PMCNULL;

        /* TODO -- really create this thing */
#if 0
        PMC * const  _class = REG_PMC(interp, 2);
        Parrot_Pair_attributes *pair   = PARROT_PAIR(SELF);
        const int    argcP  = REG_INT(interp, 3);
        const int    argcS  = REG_INT(interp, 2);

        SELF = pmc_new(INTERP, _class->vtable->base_type);
        if (argcS == 1 && argcP == 1) {
            PObj_key_is_string_SET(SELF);
            pair->key   = REG_STR(interp, 5);
            pair->value = REG_PMC(interp, 5);
        }
        else if (argcP == 2) {
            pair->key   = REG_PMC(interp, 5);
            pair->value = REG_PMC(interp, 6);
        }
        else
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "wrong argument count for Pair creation");

        return SELF;
#endif
    }
/*

=item C<void mark()>

Marks the hash as live.

=cut

*/

    VTABLE void mark() {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);

        if (pair->key)
            pobject_lives(INTERP, (PObj *)pair->key);

        if (pair->value)
            pobject_lives(INTERP, (PObj *)pair->value);
    }

/*

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

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

=cut

*/

    VTABLE PMC *get_pmc_keyed_str(STRING *key) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        /* check key ? */
        return pair->value;
    }

    VTABLE PMC *get_pmc_keyed(PMC *key) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        /* check key ? */
        return pair->value;
    }

/*

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

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

Set key and value. The key can only set once.

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

Set the value of the Pair.

=cut

*/

    VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);

        if (pair->key)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "attempt to set existing Pair key");


        pair->key   = key;
        pair->value = value;
    }


    VTABLE void set_pmc_keyed_str(STRING *key, PMC *value) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        PMC                *key_pmc;

        if (pair->key)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "attempt to set existing Pair key");


        key_pmc = pmc_new(interp, enum_class_String);
        VTABLE_set_string_native(interp, key_pmc, key);

        pair->key   = key_pmc;
        pair->value = value;
    }

    VTABLE void assign_pmc(PMC *value) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        pair->value              = value;
    }

/*

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

Sets this pair to hold the value of another.

=cut

*/

    void set_pmc(PMC *pair) {
        if (pair->vtable->base_type == enum_class_Pair) {
            Parrot_Pair_attributes * const from = PARROT_PAIR(SELF);
            Parrot_Pair_attributes * const to   = PARROT_PAIR(SELF);

            to->key   = from->key;
            to->value = from->value;
        }
        else
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "Can only set a pair to another pair.");
    }

/*

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

The C<==> operation.

Check if two Pairs hold the same keys and values.

=cut

*/

    VTABLE INTVAL is_equal(PMC *value) {
        Parrot_Pair_attributes * const from = PARROT_PAIR(SELF);
        Parrot_Pair_attributes * const to   = PARROT_PAIR(SELF);
        PMC *p1, *p2;
        PMC *k1, *k2;
        INTVAL result;

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

        k1 = from->key;
        k2 = to->key;

        Parrot_mmd_multi_dispatch_from_c_args(INTERP, "is_equal",
            "PP->I", k1, k2, &result);
        if (!result)
            return 0;

        p1 = from->value;
        p2 = to->value;

        if (!p1 && !p2)
            return 1;
        else
            return 0;
    }

/*

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

Used during archiving to visit the elements in the pair.

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

Used to archive the Pair.

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

Used to unarchive the Pair.

=cut

*/

    VTABLE void visit(visit_info *info) {
        PMC               **pos;
        Parrot_Pair_attributes * const pair     = PARROT_PAIR(SELF);
        IMAGE_IO    * const io       = info->image_io;
        DPOINTER   ** const temp_pos = (DPOINTER **)pair->key;
        info->thaw_ptr               = (PMC **)temp_pos;
        (info->visit_pmc_now)(INTERP, (PMC *)temp_pos, info);

        pos            = &pair->value;
        info->thaw_ptr = pos;

        (info->visit_pmc_now)(INTERP, *pos, info);

        SUPER(info);
    }

    VTABLE void freeze(visit_info *info) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        IMAGE_IO    * const io   = info->image_io;
        SUPER(info);
        VTABLE_push_pmc(INTERP, io, pair->key);
        VTABLE_push_pmc(INTERP, io, pair->value);
    }

    VTABLE void thaw(visit_info *info) {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        IMAGE_IO    * const io   = info->image_io;

        SUPER(info);

        pair->key   = VTABLE_shift_pmc(interp, io);
        pair->value = VTABLE_shift_pmc(interp, io);
    }
/*

=back

=head2 Methods

=over 4

=item C<METHOD key()>

Return the key of the pair.

=cut

*/

    METHOD key() {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        PMC                *key  = pair->key;

        RETURN(PMC *key);
    }

/*

=item C<METHOD value()>

Return the value of the pair.

=cut

*/

    METHOD value() {
        Parrot_Pair_attributes * const pair  = PARROT_PAIR(SELF);
        PMC         * const value = pair->value;
        RETURN(PMC *value);
    }

/*

=item C<METHOD kv()>

Return a tuple of (key, value) for the pair.

=cut

*/

    METHOD kv() {
        Parrot_Pair_attributes * const pair = PARROT_PAIR(SELF);
        PMC         * const t    = pmc_new(INTERP,
            Parrot_get_ctx_HLL_type(INTERP, enum_class_FixedPMCArray));

        VTABLE_set_integer_native(INTERP, t, 2);
        VTABLE_set_pmc_keyed_int(INTERP, t, 0, pair->key);

        VTABLE_set_pmc_keyed_int(INTERP, t, 1, pair->value);
        RETURN(PMC *t);
    }
}

/*

=back

=cut

*/

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