Class-XSConstructor

 view release on metacpan or  search on metacpan

XSConstructor.xs  view on Meta::CPAN

    ENTER;
    SAVETMPS;

    /* Ensure the key SV is released */
    SAVEDESTRUCTOR_X(dec_sv_refcnt, (void *)mutexkey_sv);

    /* Ensure the mutex is deleted on scope exit */
    struct delete_ent_ctx *ctx;
    Newxz(ctx, 1, struct delete_ent_ctx);
    ctx->hv  = object_hv;
    ctx->key = mutexkey_sv;
    SAVEDESTRUCTOR_X(delete_mutex, ctx);

    svp = hv_fetch(object_hv, attr_name, attr_len, 0);
    value_sv = svp ? *svp : &PL_sv_undef;

    SV* trigger_sv = param->trigger_sv;

    if (!SvROK(trigger_sv)) {
        PUSHMARK(SP);
        XPUSHs((SV *)object);
        XPUSHs(value_sv);
        PUTBACK;
        call_method(SvPV_nolen(trigger_sv), G_VOID);
    }
    else if (SvTYPE(SvRV(trigger_sv)) == SVt_PVCV) {
        PUSHMARK(SP);
        XPUSHs((SV *)object);
        XPUSHs(value_sv);
        PUTBACK;
        call_sv(trigger_sv, G_VOID);
    }
    else {
        croak("Unexpected trigger type");
    }

    FREETMPS;
    LEAVE;
}

int
xscon_initialize_object(const xscon_constructor_t* sig, const char* klass, SV* const object, HV* const args, bool const is_cloning)
{
    dTHX;

    assert(sig);
    assert(object);
    assert(args);

    if (sig->is_placeholder) {
        croak("Called on a placeholder");
    }

    if(mg_find((SV*)args, PERL_MAGIC_tied)){
        croak("You cannot use tied HASH reference as initializing arguments");
    }

    I32 i;
    int used = 0;

    /* we can weaken everything at the end */
    AV *weakrefs = NULL;

    /* copy allowed attributes */
    for (i = 0; i < sig->num_params; i++) {
        xscon_param_t *param = &sig->params[i];
        int flags = param->flags;
        char *keyname = param->name;
        int keylen = strlen(param->name);
        char *init_arg = param->init_arg;
        int init_arg_len = -1;
        if ( param->init_arg ) {
            init_arg_len = strlen(param->init_arg);
        }

        SV** valref;
        SV* val;
        bool has_value = FALSE;
        bool value_was_from_args = FALSE;

        if ( (!( flags & XSCON_FLAG_NO_INIT_ARG )) && init_arg_len >= 0 && hv_exists(args, init_arg, init_arg_len) ) {
            /* Value provided in args hash */
            valref = hv_fetch(args, init_arg, init_arg_len, 0);
            val = newSVsv(*valref);
            has_value = TRUE;
            value_was_from_args = TRUE;
            used++;
        }

        if ( flags & XSCON_FLAG_HAS_ALIASES ) {
            I32 i;
            for (i = 0; i < param->num_aliases; i++) {
                char *alias = param->aliases[i];
                int alias_len = strlen(alias);
                if ( hv_exists(args, alias, alias_len) ) {
                    if ( has_value ) {
                        croak("Superfluous alias used for attribute '%s': %s", keyname, alias);
                    }
                    else {
                        valref = hv_fetch(args, alias, alias_len, 0);
                        val = newSVsv(*valref);
                        has_value = TRUE;
                        value_was_from_args = TRUE;
                        used++;
                    }
                }
            }
        }

        if ( value_was_from_args && ( flags & XSCON_FLAG_UNDEF_TOLERANT ) && !SvOK(val) ) {
            has_value = FALSE;
            val = NULL;
        }

        if ( !has_value && flags & XSCON_FLAG_HAS_DEFAULT ) {
            /* There is a default/builder
             * Some very common defaults are worth hardcoding into the flags
             * so we won't need to do anything expensive to fill them in.
             */
            I32 has_common_default = ( flags >> XSCON_BITSHIFT_DEFAULTS ) & 255;
            val = xscon_run_default( object, keyname, has_common_default, param->default_sv );

XSConstructor.xs  view on Meta::CPAN

        croak("ARG! Something went really wrong while installing a new XSUB!");

    xscon_reader_t *sig;
    Newxz(sig, 1, xscon_reader_t);
    sig->slot           = savepv(slot);
    sig->has_default    = has_default;
    sig->default_flags  = default_flags;
    sig->default_sv     = SvREFCNT_inc(default_sv);
    sig->check_flags    = check_flags;
    
    if (check && IsCodeRef(check)) {
        sig->has_check = TRUE;
        sig->check_cv = (CV *)SvREFCNT_inc(SvRV(check));
    }
    else {
        sig->has_check = FALSE;
        sig->check_cv = NULL;
    }
    
    if (coercion && IsCodeRef(coercion)) {
        sig->has_coercion = TRUE;
        sig->coercion_cv = (CV *)SvREFCNT_inc(SvRV(coercion));
    }
    else {
        sig->has_coercion = FALSE;
        sig->coercion_cv = NULL;
    }

    SV *cloner = &PL_sv_undef;
    if (items >= 9) {
        cloner = ST(8);
    }

    if (cloner && IsCodeRef(cloner)) {
        sig->should_clone = TRUE;
        sig->cloner_cv = (CV *)SvREFCNT_inc(SvRV(cloner));
    }
    else if (cloner && SvTRUE(cloner)) {
        sig->should_clone = TRUE;
        sig->cloner_cv = NULL;
    }
    else {
        sig->has_coercion = FALSE;
        sig->coercion_cv = NULL;
    }

    CvXSUBANY(cv).any_ptr = sig;
}

void
clone(self, depth=-1)
    SV *self
    int depth
    PREINIT:
    SV *clone = &PL_sv_undef;
    HV *hseen = newHV();
    AV *weakrefs = newAV();
    PPCODE:
    TRACEME(("ref = 0x%x\n", self));
    clone = sv_clone( aTHX_ self, hseen, depth, 0, weakrefs );
    /* Now apply deferred weakening.
     * All strong references in the clone graph are established,
     * so it is safe to weaken references without destroying referents. */
    HANDLE_WEAKREFS( weakrefs );
    hv_clear(hseen);  /* Free HV */
    SvREFCNT_dec((SV *)hseen);
    EXTEND(SP,1);
    PUSHs(sv_2mortal(clone));



( run in 0.660 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )