/*
Copyright (C) 2001-2010, Parrot Foundation.
$Id: default.pmc 48325 2010-08-05 06:30:27Z NotFound $

=head1 NAME

src/pmc/default.pmc - Abstract root class

=head1 DESCRIPTION

These are the vtable functions for the default PMC class.

All methods which are not defined here get a default implementation
generated from F<src/vtable.tbl> by F<tools/build/pmc2c.pl>.

=head2 Functions

=over 4

=cut

*/

#define INT2KEY(i, k) key_new_integer((i), (k))

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */

PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static STRING * caller(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc))
        __attribute__nonnull__(1);

PARROT_DOES_NOT_RETURN
static void cant_do_method(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), int index)
        __attribute__nonnull__(1);

PARROT_DOES_NOT_RETURN
static void cant_do_write_method(PARROT_INTERP,
    ARGIN_NULLOK(PMC *pmc),
    int index)
        __attribute__nonnull__(1);

PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
static PMC* check_get_std_props(PARROT_INTERP,
    ARGIN(const PMC *self),
    ARGIN(const STRING *key))
        __attribute__nonnull__(1)
        __attribute__nonnull__(2)
        __attribute__nonnull__(3);

PARROT_WARN_UNUSED_RESULT
static INTVAL check_set_std_props(PARROT_INTERP,
    ARGMOD(PMC *pmc),
    ARGIN(const STRING *key),
    ARGIN(PMC *value))
        __attribute__nonnull__(1)
        __attribute__nonnull__(2)
        __attribute__nonnull__(3)
        __attribute__nonnull__(4)
        FUNC_MODIFIES(*pmc);

static INTVAL has_pending_std_props(ARGIN(const PMC *self))
        __attribute__nonnull__(1);

PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static PMC* make_prop_hash(PARROT_INTERP, ARGMOD(PMC *self))
        __attribute__nonnull__(1)
        __attribute__nonnull__(2)
        FUNC_MODIFIES(*self);

static void propagate_std_props(PARROT_INTERP,
    ARGIN(PMC *self),
    ARGIN(PMC *prop_hash))
        __attribute__nonnull__(1)
        __attribute__nonnull__(2)
        __attribute__nonnull__(3);

#define ASSERT_ARGS_caller __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_cant_do_method __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_cant_do_write_method __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_check_get_std_props __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp) \
    , PARROT_ASSERT_ARG(self) \
    , PARROT_ASSERT_ARG(key))
#define ASSERT_ARGS_check_set_std_props __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp) \
    , PARROT_ASSERT_ARG(pmc) \
    , PARROT_ASSERT_ARG(key) \
    , PARROT_ASSERT_ARG(value))
#define ASSERT_ARGS_has_pending_std_props __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(self))
#define ASSERT_ARGS_make_prop_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp) \
    , PARROT_ASSERT_ARG(self))
#define ASSERT_ARGS_propagate_std_props __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
       PARROT_ASSERT_ARG(interp) \
    , PARROT_ASSERT_ARG(self) \
    , PARROT_ASSERT_ARG(prop_hash))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
/* HEADERIZER END: static */

/*

=item C<static STRING * caller(PARROT_INTERP, PMC *pmc)>

Returns a C string for the name of C<*pmc>.

=cut

*/

PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static STRING *
caller(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc))
{
    ASSERT_ARGS(caller)

    return !PMC_IS_NULL(pmc) && pmc->vtable && pmc->vtable->whoami
                ? VTABLE_name(interp, pmc)
                : CONST_STRING(interp, "(null)");
}

/*

=item C<static void cant_do_method(PARROT_INTERP, PMC *pmc, int index)>

Throws an exception "$methname() not implemented in class '$class'", used by
all unimplemented messages.

=cut

*/

PARROT_DOES_NOT_RETURN
static void
cant_do_method(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), int index)
{
    ASSERT_ARGS(cant_do_method)

    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ILL_INHERIT,
            "%s() not implemented in class '%Ss'",
            Parrot_get_vtable_name(interp, index),
            caller(interp, pmc));
}


/*

=item C<static void cant_do_write_method(PARROT_INTERP, PMC *pmc, int index)>

Throws an exception "$methname() on read-only instance of '$class'", used by
all updating messages on read-only instances.

=cut

*/

PARROT_DOES_NOT_RETURN
static void
cant_do_write_method(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), int index)
{
    ASSERT_ARGS(cant_do_write_method)

    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_WRITE_TO_CONSTCLASS,
            "%s() in read-only instance of '%Ss'",
            Parrot_get_vtable_name(interp, index),
            caller(interp, pmc));
}

/*

=item C<static INTVAL check_set_std_props(PARROT_INTERP, PMC *pmc, const STRING
*key, PMC *value)>

Called from C<setprop()>.

Returns a true value if C<setprop()> can avoid actually setting a property
in the prophash. If it returns true, the property setting will be reflected
in a future call to C<propagate_std_props()>

=cut

*/

PARROT_WARN_UNUSED_RESULT
static INTVAL
check_set_std_props(PARROT_INTERP, ARGMOD(PMC *pmc), ARGIN(const STRING *key), ARGIN(PMC *value))
{
    ASSERT_ARGS(check_set_std_props)

    /*
     * s2 in Parrot_str_equal is freed here
     */
    if (Parrot_str_equal(interp, key, CONST_STRING(interp, "_ro"))) {
        /* pmc should set/clear readonly */
        const INTVAL on = VTABLE_get_bool(interp, value);

        /* morph to Const/normal class or readonly class */
        if (on && (pmc->vtable->flags & VTABLE_HAS_CONST_TOO))
            pmc->vtable = interp->vtables[pmc->vtable->base_type + 1];
        else if (!on && (pmc->vtable->flags & (VTABLE_IS_CONST_FLAG)))
            VTABLE_morph(interp, pmc, interp->vtables[pmc->vtable->base_type - 1]->pmc_class);
        else if (on && (pmc->vtable->flags & VTABLE_HAS_READONLY_FLAG))
            pmc->vtable = pmc->vtable->ro_variant_vtable;
        else if (!on && (pmc->vtable->flags & VTABLE_IS_READONLY_FLAG)
                && pmc->vtable->ro_variant_vtable)
            pmc->vtable = pmc->vtable->ro_variant_vtable;
        else
            return 0;

        return 1;
    }

    return 0;
}

/*

=item C<static void propagate_std_props(PARROT_INTERP, PMC *self, PMC
*prop_hash)>

Set pending standard properties in C<prop_hash>.

=cut

*/

static void
propagate_std_props(PARROT_INTERP, ARGIN(PMC *self), ARGIN(PMC *prop_hash))
{
    ASSERT_ARGS(propagate_std_props)

    if (self->vtable->flags & (VTABLE_IS_CONST_FLAG | VTABLE_IS_READONLY_FLAG)){
        PMC * const pmc_true  = Parrot_pmc_new_init_int(interp,
                enum_class_Integer, 1);
        VTABLE_set_pmc_keyed_str(interp, prop_hash, CONST_STRING(interp, "_ro"), pmc_true);
    }
}

/*

=item C<static INTVAL has_pending_std_props(const PMC *self)>

Returns true if propagate_std_props() would create a non-empty prophash.

=cut

*/

static INTVAL
has_pending_std_props(ARGIN(const PMC *self))
{
    ASSERT_ARGS(has_pending_std_props)

    if (self->vtable->flags & (VTABLE_IS_CONST_FLAG | VTABLE_IS_READONLY_FLAG))
        return 1;
    else
        return 0;
}


/*

=item C<static PMC* check_get_std_props(PARROT_INTERP, const PMC *self, const
STRING *key)>

Checks if we can infer the value of C<key> property from C<self> without
looking at its prophash. Returns C<PMCNULL> if not, returns the value otherwise.

=cut
*/

PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
static PMC*
check_get_std_props(PARROT_INTERP, ARGIN(const PMC *self), ARGIN(const STRING *key))
{
    ASSERT_ARGS(check_get_std_props)

    if ((self->vtable->flags & (VTABLE_IS_CONST_FLAG | VTABLE_IS_READONLY_FLAG))
       && Parrot_str_equal(interp, key, CONST_STRING(interp, "_ro"))) {
        PMC * const ret_val = Parrot_pmc_new_init_int(interp,
                enum_class_Integer, 1);
        return ret_val;
    }
    else
        return PMCNULL;
}

/*

=item C<static PMC* make_prop_hash(PARROT_INTERP, PMC *self)>

Create a property hash for C<self>. Returns the created hash. Inferred
properties will be added to the hash.

=cut

*/

PARROT_CANNOT_RETURN_NULL
PARROT_WARN_UNUSED_RESULT
static PMC*
make_prop_hash(PARROT_INTERP, ARGMOD(PMC *self))
{
    ASSERT_ARGS(make_prop_hash)

    PMC * const prop = Parrot_pmc_new(interp, enum_class_Hash);
    propagate_std_props(interp, self, prop);
    return prop;
}

pmclass default abstract {

/*

=back

=head2 Methods

=over 4

=item C<void init()>

Does nothing.

=cut

*/

    VTABLE void init() {
    }

/*

=item C<void init_pmc(PMC *initializer)>

With a null C<initializer>, calls C<init()>, else throws an exception.

=cut

*/

    VTABLE void init_pmc(PMC *initializer) {
        if (PMC_IS_NULL(initializer))
            SELF.init();
        else
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
                "init_pmc() not implemented in class '%Ss'",
                caller(INTERP, SELF));
    }

/*

=item C<void init_int(INTVAL initvalue)>

Calls C<init()> and C<set_integer_native(initvalue)>.
Default implementation to allow more usages of init_int without having to
implement it everywhere.

=cut

*/

    VTABLE void init_int(INTVAL initvalue) {
        SELF.init();
        SELF.set_integer_native(initvalue);
    }

/*

=item C<void destroy()>

Does nothing.

=cut

*/

    VTABLE void destroy() {
    }

/*

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

Default fallback. Creates a new PMC of the type of the class SELF and
calls init().

=cut

*/

    VTABLE PMC *instantiate(PMC *init) {
        const INTVAL type = VTABLE_type(INTERP, SELF);

        /* Ensure no looping, as Parrot_pmc_new calls the instantiate vtable entry for
         * classes. */
        if (PObj_is_class_TEST(SELF))
            Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
                    "All high-level classes should override instantiate");

        if (!PMC_IS_NULL(init))
            return Parrot_pmc_new_init(INTERP, type, init);

        return Parrot_pmc_new(INTERP, type);
    }

/*

=item C<void mark()>

Panics with a "no custom mark routine defined" error message.

=cut

*/

    VTABLE void mark() {
        PANIC(INTERP, "custom_mark flag set but no custom mark routine defined");
    }

/*

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

Returns the property for C<*key>. If no property is defined then the
NULL PMC is returned.

=cut

*/

    VTABLE PMC *getprop(STRING *key) {
        if (PMC_IS_NULL(PMC_metadata(SELF)))
            return check_get_std_props(INTERP, SELF, key);
        else
            return VTABLE_get_pmc_keyed_str(INTERP, PMC_metadata(SELF), key);
    }

/*

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

Sets the property for C<*key> to C<*value>.

=cut

*/

    VTABLE void setprop(STRING *key, PMC *value) {
        if (check_set_std_props(INTERP, SELF, key, value))
            return;

        if (PMC_IS_NULL(PMC_metadata(SELF)))
            PMC_metadata(SELF) = make_prop_hash(INTERP, SELF);

        VTABLE_set_pmc_keyed_str(INTERP, PMC_metadata(SELF), key, value);
    }

/*

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

Deletes the property for C<*key>.

=cut

*/

    VTABLE void delprop(STRING *key) {
        if (!PMC_IS_NULL(PMC_metadata(SELF)))
            VTABLE_delete_keyed_str(INTERP, PMC_metadata(SELF), key);
    }

/*

=item C<PMC *getprops()>

Returns the PMC's properties or the NULL PMC if no properties exist.

=cut

*/

    VTABLE PMC *getprops() {
        if (PMC_IS_NULL(PMC_metadata(SELF))) {
            if (has_pending_std_props(SELF))
                PMC_metadata(SELF) = make_prop_hash(INTERP, SELF);
            else
                return PMCNULL;
        }

        return PMC_metadata(SELF);
    }

/*

=item C<INTVAL type()>

Returns the PMC's type.

=cut

*/

    VTABLE INTVAL type() {
        return SELF->vtable->base_type;
    }

/*

=item C<STRING *name()>

Returns the name of the PMC.

=cut

*/

    VTABLE STRING *name() {
        return SELF->vtable->whoami;
    }


/*

=item C<PMC *get_namespace>

Return the namespace for this PMC.

=item C<PMC *find_method(STRING *method_name)>

Looks up the method for C<*method_name> and returns it. If no method is
found then C<NULL> is returned.

=item C<void add_method(STRING *method_name, PMC *sub)>

Store the method as a global in the namespace of this class.

=cut

*/

    VTABLE PMC *get_namespace() {

        /* Because singletons are shared between interpreters, we need to make
         * special effort to use the right namespace for method lookups.
         * Note that this trick won't work if the singleton inherits from
         * something else (because the MRO will still be shared).
         * Having this code here avoids creating a special case for singletons
         * elsewhere.
         */

        return INTERP->vtables[SELF->vtable->base_type]->_namespace;
    }


    VTABLE PMC *find_method(STRING *method_name) {
        return Parrot_find_method_with_cache(INTERP, SELF, method_name);
    }

    VTABLE void add_method(STRING *method_name, PMC *sub_pmc) {
        VTABLE_set_pmc_keyed_str(INTERP, SELF->vtable->_namespace,
                                 method_name, sub_pmc);
    }
/*

=item C<INTVAL get_integer_keyed_int(INTVAL key)>

Converts C<key> to a PMC key and returns the result of calling
C<get_integer_keyed()> with it.

=cut

*/

    VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
        PMC *const r_key = INT2KEY(INTERP, key);
        return SELF.get_integer_keyed(r_key);
    }

/*

=item C<FLOATVAL get_number_keyed_int(INTVAL key)>

Converts C<key> to a PMC key and returns the result of calling
C<get_number_keyed()> with it.

=cut

*/

    VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
        PMC *const r_key = INT2KEY(INTERP, key);
        return SELF.get_number_keyed(r_key);
    }


/*

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

Converts C<key> to a PMC key and returns the result of calling
C<get_string_keyed()> with it.

=cut

*/

    VTABLE STRING *get_string_keyed_int(INTVAL key) {
        PMC *const r_key = INT2KEY(INTERP, key);
        return SELF.get_string_keyed(r_key);
    }

/*

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

Converts C<key> to a PMC key and returns the result of calling
C<get_pmc_keyed()> with it.

=cut

*/

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

/*

=item C<void *get_pointer()>

Returns the address of the PMC.

=cut

*/

    VTABLE void *get_pointer() {
        return SELF;
    }

/*

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

Returns whether the PMC is the same PMC as C<value> (whether they're the
same pointer).

=cut

*/

    VTABLE INTVAL is_same(PMC *value) {
        return SELF == value;
    }

/*

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

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

Defaults fall back to C<set_pmc> and C<set_string_native>.

=cut

*/

    VTABLE void assign_pmc(PMC *value) {
        STRING * const undef = CONST_STRING(INTERP, "Undef");

        if (VTABLE_isa(INTERP, value, undef))
            Parrot_pmc_reuse(INTERP, SELF, value->vtable->base_type, 0);
        else
            SELF.set_pmc(value);
    }

    VTABLE void assign_string_native(STRING *value) {
        SELF.set_string_native(value);
    }

/*

=item C<void morph(PMC* type)>

Changes the PMC to a PMC of a new type

=cut

*/

    VTABLE void morph(PMC* type) {
        Parrot_pmc_reuse(INTERP, SELF, VTABLE_get_integer(INTERP, type), 0);
    }

/*

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

Converts C<key> to a PMC key and calls C<set_integer_keyed()> with it
and C<value>.

=cut

*/

    VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
        PMC *const r_key = INT2KEY(INTERP, key);
        SELF.set_integer_keyed(r_key, value);
    }

/*

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

Converts C<key> to a PMC key and calls C<set_number_keyed()> with it
and C<value>.

=cut

*/

    VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
        PMC *const r_key = INT2KEY(INTERP, key);
        SELF.set_number_keyed(r_key, value);
    }

/*

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

Converts C<key> to a PMC key and calls C<set_string_keyed()> with it
and C<value>.

=cut

*/

    VTABLE void set_string_keyed_int(INTVAL key, STRING *string) {
        PMC *const r_key = INT2KEY(INTERP, key);
        SELF.set_string_keyed(r_key, string);
    }

/*

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

Converts C<key> to a PMC key and calls C<set_pmc_keyed()> with it
and C<value>.

=cut

*/

    VTABLE void set_pmc_keyed_int(INTVAL key, PMC *value) {
        PMC *const r_key = INT2KEY(INTERP, key);
        SELF.set_pmc_keyed(r_key, value);
    }

/*

=item C<INTVAL hashvalue()>

Calculate hashvalue for PMC. Default behaviour stringify and use string.

=cut

*/

    INTVAL hashvalue() {
        STRING *s = SELF.get_string();
        return key_hash_STRING(INTERP, s, 0);
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'is_equal'.

=cut

*/

    VTABLE INTVAL is_equal(PMC *value) {
        INTVAL retval;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "is_equal", "PP->I", SELF, value, &retval);

        return retval;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'is_equal_num'.

=cut

*/

    VTABLE INTVAL is_equal_num(PMC *value) {
        INTVAL retval;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "is_equal_num", "PP->I", SELF, value, &retval);

        return retval;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'is_equal'.

=cut

*/

    VTABLE INTVAL is_equal_string(PMC *value) {
        INTVAL retval;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "is_equal_string", "PP->I", SELF, value, &retval);

        return retval;
    }

/*

=item C<INTVAL exists_keyed_int(INTVAL key)>

Converts C<key> to a PMC key and returns the result of calling
C<exists_keyed()> with it.

=cut

*/

    VTABLE INTVAL exists_keyed_int(INTVAL key) {
        PMC *const r_key = INT2KEY(INTERP, key);
        return SELF.exists_keyed(r_key);
    }

/*

=item C<INTVAL defined()>

Returns true.

=cut

*/

    VTABLE INTVAL defined() {
        return 1;
    }

/*

=item C<INTVAL defined_keyed_int(INTVAL key)>

Converts C<key> to a PMC key and returns the result of calling
C<defined_keyed()> with it.

=cut

*/

    VTABLE INTVAL defined_keyed_int(INTVAL key) {
        PMC *const r_key = INT2KEY(INTERP, key);
        return SELF.defined_keyed(r_key);
    }

/*

=item C<void delete_keyed_int(INTVAL key)>

Converts C<key> to a PMC key and calls C<delete_keyed()> with it.

=cut

*/

    VTABLE void delete_keyed_int(INTVAL key) {
        PMC *const r_key = INT2KEY(INTERP, key);
        SELF.delete_keyed(r_key);
    }

/*

=item C<INTVAL can(STRING *method)>

Reports whether the PMC "can" perform C<method>.
If the PMC implements the vtable function C<method>,
true (1) is returned; otherwise, false (0) is returned.

=cut

*/

    VTABLE INTVAL can(STRING *method) {
        return !PMC_IS_NULL(VTABLE_find_method(INTERP, SELF, method));
    }

/*

=item C<INTVAL does(STRING *interface_name)>

Reports whether the PMC "does" perform C<interface_name>.
If the interface C<interface_name> is found in the PMC's interface list,
true (1) is returned; otherwise, false (0) is returned.

=cut

*/

    VTABLE INTVAL does(STRING *interface_name) {
        return Parrot_pmc_type_does(INTERP, interface_name, SELF->vtable->base_type);
    }

/*

=item C<INTVAL does_pmc(PMC *role)>

Reports whether the PMC "does" the C<role>.

=cut

*/

    VTABLE INTVAL does_pmc(PMC *role) {
        UNUSED(role)
        /* No C-level roles yet. */
        return 0;
    }

/*

=item C<INTVAL isa_pmc(PMC *_class)>

Reports whether the PMC "isa" C<_class>.
If the class C<_class> is found in the PMC's class hierarchy,
true (1) is returned; otherwise, false (0) is returned.

=cut

*/

    VTABLE INTVAL isa_pmc(PMC *lookup) {
        if (PMC_IS_NULL(lookup))
            return 0;
        else {
            Hash   * const isa_hash = SELF->vtable->isa_hash;
            STRING * const pmc_name = VTABLE_get_string(INTERP, lookup);
            return parrot_hash_exists(INTERP, isa_hash, pmc_name);
        }
    }

/*

=item C<INTVAL isa(STRING *_class)>

Reports whether the PMC "isa" C<_class>.
If the class C<_class> is found in the PMC's class hierarchy,
true (1) is returned; otherwise, false (0) is returned.

=cut

*/

    VTABLE INTVAL isa(STRING *_class) {
        if (SELF->vtable->whoami == _class)
            return 1;
        else {
            const Hash * const isa_hash = SELF->vtable->isa_hash;
            if (!isa_hash)
                return Parrot_str_equal(INTERP, SELF->vtable->whoami, _class);

            return parrot_hash_exists(INTERP, isa_hash, (void *)_class);
        }
    }

/*

=item C<PMC *inspect_str(STRING *what)>

Provides introspection of a specific piece of information about the PMC.

=cut

*/

    VTABLE PMC *inspect_str(STRING *name) {
        if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "flags"))) {
            PMC *found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer,
                    (INTVAL)PObj_get_FLAGS(SELF));
            return found;
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "mro"))) {
            return VTABLE_clone(INTERP, SELF->vtable->mro);
        }
        else
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "Unknown introspection value '%S'", name);
    }

/*

=item C<PMC *inspect()>

Returns a Hash describing the class, with key/value pairs as described in
inspect_str.

=cut

*/
    VTABLE PMC *inspect() {
        PMC    * const metadata    = Parrot_pmc_new(INTERP, enum_class_Hash);
        STRING * const flags_str   = CONST_STRING(INTERP, "flags");

        VTABLE_set_pmc_keyed_str(INTERP, metadata, flags_str,
            VTABLE_inspect_str(INTERP, SELF, flags_str));

        return metadata;
    }

/*

=item C<PMC *get_class()>

Returns SELF. A PMC is its own class.

=cut

*/
    VTABLE PMC *get_class() {
        PMC * const ns     = VTABLE_get_namespace(INTERP, SELF);
        PMC *_class = PMCNULL;

        if (!PMC_IS_NULL(ns))
            _class = VTABLE_get_class(INTERP, ns);

        if (PMC_IS_NULL(_class)) {
            const INTVAL type      = VTABLE_type(INTERP, SELF);
            return Parrot_pmc_new_init_int(INTERP, enum_class_PMCProxy, type);
        }

        return _class;

    }

/*

=item C<PMC *get_attr_keyed(PMC *key, STRING *name)>

Default version of keyed attribute lookups. Discards the key and does a lookup
by the string name passed in.

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

Default version of keyed attribute set. Discards the key and does a set by
the string name passed in.

=cut

*/
    VTABLE PMC *get_attr_keyed(PMC *key, STRING *name) {
        UNUSED(key)
        return VTABLE_get_attr_str(INTERP, SELF, name);
    }

    VTABLE void set_attr_keyed(PMC *key, STRING *name, PMC *value) {
        UNUSED(key)
        VTABLE_set_attr_str(INTERP, SELF, name, value);
    }

/*

=item C<void add_parent(PMC *parent)>

Add class C<parent> to the list of our parents.

=cut

*/

    VTABLE void add_parent(PMC *parent) {
        UNUSED(parent)
        if (!PObj_is_class_TEST(SELF))
            Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
                "Only classes can be subclassed");

        Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
                "All classes should override add_parent");
    }

/*

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

Used by GC to mark the PMC.

=cut

*/

    VTABLE void visit(PMC *info) {
    }

/*

=item C<PMC* clone()>

Clones this PMC.  By default, this just does a freeze and thaw.

=cut

*/

    VTABLE PMC* clone() {
        return Parrot_thaw(INTERP, Parrot_freeze(INTERP, SELF));
    }

/*

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

Does nothing.

=cut

*/

    VTABLE void freeze(PMC *info) {
        UNUSED(info)
        /* default - no action */
    }

/*

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

Initializes the PMC during unarchiving.

=cut

*/

    VTABLE void thaw(PMC *info) {
        /* default - initialize the PMC */
        SELF.init();
    }

/*

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

Does nothing.

=cut

*/

    VTABLE void thawfinish(PMC *info) {
        UNUSED(info)
        /* default - no action */
    }

/*

=item C<PMC *add(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'add'.

=cut

*/

    VTABLE PMC *add(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "add", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *add_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'add_int'.

=cut

*/

    VTABLE PMC *add_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "add_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *add_float(FLOATVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'add_float'.

=cut

*/

    VTABLE PMC *add_float(FLOATVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() + value);
        return dest;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_add'.

=cut

*/

    VTABLE void i_add(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_add", "PP", SELF, value);
    }

/*

=item C<void i_add_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_add_int'.

=cut

*/

    VTABLE void i_add_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_add_int", "PI", SELF, value);
    }

/*

=item C<void i_add_float(FLOATVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_add_float'.

=cut

*/

    VTABLE void i_add_float(FLOATVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_add_float", "PN", SELF, value);
    }

/*

=item C<PMC *subtract(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'subtract'.

=cut

*/

    VTABLE PMC *subtract(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "subtract", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *subtract_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'subtract_int'.

=cut

*/

    VTABLE PMC *subtract_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "subtract_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *subtract_float(FLOATVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'subtract_float'.

=cut

*/

    VTABLE PMC *subtract_float(FLOATVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "subtract_float", "PNP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_subtract'.

=cut

*/

    VTABLE void i_subtract(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_subtract", "PP", SELF, value);
    }

/*

=item C<void i_subtract_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_subtract_int'.

=cut

*/

    VTABLE void i_subtract_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_subtract_int", "PI", SELF, value);
    }

/*

=item C<void i_subtract_float(FLOATVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_subtract_float'.

=cut

*/

    VTABLE void i_subtract_float(FLOATVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_subtract_float", "PN", SELF, value);
    }

/*

=item C<PMC *multiply(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'multiply'.

=cut

*/

    VTABLE PMC *multiply(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "multiply", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *multiply_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'multiply_int'.

=cut

*/

    VTABLE PMC *multiply_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "multiply_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *multiply_float(FLOATVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'multiply_float'.

=cut

*/

    VTABLE PMC *multiply_float(FLOATVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "multiply_float", "PNP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_multiply'.

=cut

*/

    VTABLE void i_multiply(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_multiply", "PP", SELF, value);
    }

/*

=item C<void i_multiply_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_multiply_int'.

=cut

*/

    VTABLE void i_multiply_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_multiply_int", "PI", SELF, value);
    }

/*

=item C<void i_multiply_float(FLOATVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_multiply_float'.

=cut

*/

    VTABLE void i_multiply_float(FLOATVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_multiply_float", "PN", SELF, value);
    }

/*

=item C<PMC *divide(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'divide'.

=cut

*/

    VTABLE PMC *divide(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "divide", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *divide_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'divide_int'.

=cut

*/

    VTABLE PMC *divide_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "divide_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *divide_float(FLOATVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'divide_float'.

=cut

*/

    VTABLE PMC *divide_float(FLOATVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "divide_float", "PNP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_divide'.

=cut

*/

    VTABLE void i_divide(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_divide", "PP", SELF, value);
    }

/*

=item C<void i_divide_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_divide_int'.

=cut

*/

    VTABLE void i_divide_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_divide_int", "PI", SELF, value);
    }

/*

=item C<void i_divide_float(FLOATVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_divide_float'.

=cut

*/

    VTABLE void i_divide_float(FLOATVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_divide_float", "PN", SELF, value);
    }

/*

=item C<PMC *floor_divide(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'floor_divide'.

=cut

*/

    VTABLE PMC *floor_divide(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "floor_divide", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *floor_divide_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'floor_divide_int'.

=cut

*/

    VTABLE PMC *floor_divide_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "floor_divide_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *floor_divide_float(FLOATVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'floor_divide_float'.

=cut

*/

    VTABLE PMC *floor_divide_float(FLOATVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "floor_divide_float", "PNP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_floor_divide'.

=cut

*/

    VTABLE void i_floor_divide(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_floor_divide", "PP", SELF, value);
    }

/*

=item C<void i_floor_divide_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_floor_divide_int'.

=cut

*/

    VTABLE void i_floor_divide_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_floor_divide_int", "PI", SELF, value);
    }

/*

=item C<void i_floor_divide_float(FLOATVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_floor_divide_float'.

=cut

*/

    VTABLE void i_floor_divide_float(FLOATVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_floor_divide_float", "PN", SELF, value);
    }

/*

=item C<PMC *modulus(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'modulus'.

=cut

*/

    VTABLE PMC *modulus(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "modulus", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *modulus_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'modulus_int'.

=cut

*/

    VTABLE PMC *modulus_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "modulus_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *modulus_float(FLOATVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'modulus_float'.

=cut

*/

    VTABLE PMC *modulus_float(FLOATVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "modulus_float", "PNP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_modulus'.

=cut

*/

    VTABLE void i_modulus(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_modulus", "PP", SELF, value);
    }

/*

=item C<void i_modulus_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_modulus_int'.

=cut

*/

    VTABLE void i_modulus_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_modulus_int", "PI", SELF, value);
    }

/*

=item C<void i_modulus_float(FLOATVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_modulus_float'.

=cut

*/

    VTABLE void i_modulus_float(FLOATVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_modulus_float", "PN", SELF, value);
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'cmp'.

=cut

*/

    VTABLE INTVAL cmp(PMC *value) {
        INTVAL retval;

        /* Don't multidispatch if you've got two pointers to the same PMC. They
         * are equal. */
        if (SELF == value)
            return 0;

        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "cmp", "PP->I", SELF, value, &retval);

        return retval;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'cmp_num'.

=cut

*/

    VTABLE INTVAL cmp_num(PMC *value) {
        INTVAL retval;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "cmp_num", "PP->I", SELF, value, &retval);

        return retval;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'cmp_string'.

=cut

*/

    VTABLE INTVAL cmp_string(PMC *value) {
        INTVAL retval;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "cmp_string", "PP->I", SELF, value, &retval);

        return retval;
    }

/*

=item C<PMC *cmp_pmc(PMC *value)>

Default fallback. Performs a multiple dispatch call for 'cmp_pmc'.

=cut

*/

    VTABLE PMC *cmp_pmc(PMC *value) {
        PMC *retval;

        /* Don't multidispatch if you've got two pointers to the same PMC. They
         * are equal. */
        if (SELF == value)
            return NULL;

        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "cmp_pmc", "PP->P", SELF, value, &retval);

        return retval;
    }
/*

=item C<PMC *logical_or(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'logical_or'.

=cut

*/

    VTABLE PMC *logical_or(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "logical_or", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *logical_and(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'logical_and'.

=cut

*/

    VTABLE PMC *logical_and(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "logical_and", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *logical_xor(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'logical_xor'.

=cut

*/

    VTABLE PMC *logical_xor(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "logical_xor", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *concatenate(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'concatenate'.

=cut

*/

    VTABLE PMC *concatenate(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "concatenate", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *concatenate_str(STRING *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'concatenate_str'.

=cut

*/

    VTABLE PMC *concatenate_str(STRING *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "concatenate_str", "PSP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_concatenate'.

=cut

*/

    VTABLE void i_concatenate(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_concatenate", "PP", SELF, value);
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_concatenate_str'.

=cut

*/

    VTABLE void i_concatenate_str(STRING *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_concatenate_str", "PS", SELF, value);
    }

/*

=item C<PMC *repeat(PMC *value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'repeat'.

=cut

*/

    VTABLE PMC *repeat(PMC *value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "repeat", "PPP->P", SELF, value, dest, &result);
        return result;
    }

/*

=item C<PMC *repeat_int(INTVAL value, PMC *dest)>

Default fallback. Performs a multiple dispatch call for 'repeat_int'.

=cut

*/

    VTABLE PMC *repeat_int(INTVAL value, PMC *dest) {
        PMC *result = PMCNULL;
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "repeat_int", "PIP->P", SELF, value, dest, &result);
        return result;
    }

/*

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

Default fallback. Performs a multiple dispatch call for 'i_repeat'.

=cut

*/

    VTABLE void i_repeat(PMC *value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_repeat", "PP", SELF, value);
    }

/*

=item C<void i_repeat_int(INTVAL value)>

Default fallback. Performs a multiple dispatch call for 'i_repeat_int'.

=cut

*/

    VTABLE void i_repeat_int(INTVAL value) {
        Parrot_mmd_multi_dispatch_from_c_args(INTERP,
                "i_repeat_int", "PI", SELF, value);
    }
}

/*

=back

=cut

*/

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