Data-Clone

 view release on metacpan or  search on metacpan

lib/Data/Clone.xs  view on Meta::CPAN

        }
    }

    if(SvOBJECT(sv) && !SvRXOK(cloning)){
        proto = dc_clone_object(aTHX_ aMY_CXT_ cloning, MY_CXT.clone_method);

        if(proto){
            proto = SvRV(proto);
            goto finish;
        }

        /* fall through to make a deep copy */
    }
    else if((mg = SvTIED_mg(sv, PERL_MAGIC_tied))){
        assert(SvTYPE(sv) == SVt_PVAV || SvTYPE(sv) == SVt_PVHV);
        proto = dc_clone_object(aTHX_ aMY_CXT_ SvTIED_obj(sv, mg), MY_CXT.tieclone_method);

        if(proto){
            SV* const varsv = (SvTYPE(sv) == SVt_PVHV
                ? (SV*)newHV()
                : (SV*)newAV()); // can we use newSV_type()?
            sv_magic(varsv,  proto, PERL_MAGIC_tied, NULL, 0);
            proto = varsv;
            goto finish;
        }

        /* fall through to make a deep copy */
    }

    /* XXX: need to save caller_cv, or not? */
    //old_cv           = MY_CXT.caller_cv;
    MY_CXT.caller_cv = NULL;

    if(SvTYPE(sv) == SVt_PVAV){
        proto = sv_2mortal((SV*)newAV());
        if(may_be_circular){
            store_to_seen(aTHX_ aMY_CXT_ sv, proto);
        }
        clone_av_to(aTHX_ aMY_CXT_ (AV*)sv, (AV*)proto);
    }
    else if(SvTYPE(sv) == SVt_PVHV){
        proto = sv_2mortal((SV*)newHV());
        if(may_be_circular){
            store_to_seen(aTHX_ aMY_CXT_ sv, proto);
        }
        clone_hv_to(aTHX_ aMY_CXT_ (HV*)sv, (HV*)proto);
    }
    else {
        proto = sv; /* do nothing */
    }

    //MY_CXT.caller_cv = old_cv;

    finish:
    cloned = newRV_inc(proto);

    if(SvOBJECT(sv)){
        sv_bless(cloned, SvSTASH(sv));
    }

    return SvWEAKREF(cloning) ? sv_rvweaken(cloned) : cloned;
}

/* as SV* sv_clone(SV* sv) */
SV*
Data_Clone_sv_clone(pTHX_ SV* const sv) {
    SV* VOL retval = NULL;
    CV* VOL old_cv;
    dMY_CXT;
    dXCPT;

    if(++MY_CXT.depth == U32_MAX){
        croak("Depth overflow on clone()");
    }

    old_cv = MY_CXT.caller_cv;
    MY_CXT.caller_cv = caller_cv(aTHX);

    XCPT_TRY_START {
        retval = sv_2mortal(clone_sv(aTHX_ aMY_CXT_ sv));
    } XCPT_TRY_END

    MY_CXT.caller_cv = old_cv;

    if(--MY_CXT.depth == 0){
        hv_undef(MY_CXT.seen);
    }

    XCPT_CATCH {
        XCPT_RETHROW;
    }
    return retval;
}

static void
my_cxt_initialize(pTHX_ pMY_CXT) {
    MY_CXT.depth    = 0;
    MY_CXT.seen     = newHV();
    MY_CXT.my_clone = CvGV(get_cvs("Data::Clone::clone", GV_ADD));

    MY_CXT.object_callback = gv_fetchpvs("Data::Clone::ObjectCallback", GV_ADDMULTI, SVt_PV);

    MY_CXT.clone_method    = newSVpvs_share("clone");
    MY_CXT.tieclone_method = newSVpvs_share("TIECLONE");
}

MODULE = Data::Clone        PACKAGE = Data::Clone

PROTOTYPES: DISABLE

BOOT:
{
    MY_CXT_INIT;
    my_cxt_initialize(aTHX_ aMY_CXT);
}

#ifdef USE_ITHREADS

void
CLONE(...)
CODE:



( run in 1.893 second using v1.01-cache-2.11-cpan-39bf76dae61 )