Class-XSConstructor
view release on metacpan or search on metacpan
#define PERL_NO_GET_CONTEXT /* we want efficiency */
#include "xshelper.h"
#define MAX_DEPTH 32000
#define CLONE_KEY(x) ((char *) &x)
#define CLONE_STORE(x,y) \
do { \
if (!hv_store(hseen, CLONE_KEY(x), PTRSIZE, SvREFCNT_inc(y), 0)) { \
SvREFCNT_dec(y); /* Restore the refcount */ \
croak("Can't store clone in seen hash (hseen)"); \
} \
else { \
TRACEME(("storing ref = 0x%x clone = 0x%x\n", ref, clone)); \
TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone))); \
TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref))); \
} \
} while (0)
#define CLONE_FETCH(x) (hv_fetch(hseen, CLONE_KEY(x), PTRSIZE, 0))
#define PUSH_WEAKREFS(weakrefs, val) av_push( weakrefs, SvREFCNT_inc_simple_NN(val) )
#define HANDLE_WEAKREFS(weakrefs) \
do { \
I32 i; \
I32 len = av_len((weakrefs)); \
for ( i = 0; i <= len; i++ ) { \
SV **svp = av_fetch( (weakrefs), i, 0 ); \
if ( svp && *svp && SvROK(*svp) ) sv_rvweaken(*svp); \
} \
SvREFCNT_dec( (SV *)(weakrefs) ); \
} while (0)
static SV *hv_clone (pTHX_ SV *, SV *, HV *, int, int, AV *);
static SV *av_clone (pTHX_ SV *, SV *, HV *, int, int, AV *);
static SV *sv_clone (pTHX_ SV *, HV *, int, int, AV *);
/* static SV *rv_clone (pTHX_ SV *, HV *, int, int, AV *); */
static SV *av_clone_iterative(pTHX_ SV *, HV *, int, AV *);
#ifdef DEBUG_CLONE
#define TRACEME(a) printf("%s:%d: ",__FUNCTION__, __LINE__) && printf a;
#else
#define TRACEME(a)
#endif
/* Check whether an mg_obj is a threads::shared::tie instance.
* The mg_obj is an RV pointing to a blessed PVMG. (GH #18) */
static int
is_threads_shared_tie(SV *obj) {
if ( !obj || !SvROK(obj) || !SvOBJECT(SvRV(obj)) )
return 0;
HV* stash = SvSTASH( SvRV(obj) );
if ( ! stash ) return 0;
const char *name = HvNAME(stash);
return ( name && strcmp( name, "threads::shared::tie" ) == 0 );
}
static SV*
hv_clone (pTHX_ SV* ref, SV* target, HV* hseen, int depth, int rdepth, AV* weakrefs) {
HV *clone = (HV *) target;
HV *self = (HV *) ref;
HE *next = NULL;
int recur = depth ? depth - 1 : 0;
assert(SvTYPE(ref) == SVt_PVHV);
TRACEME(("ref = 0x%x(%d)\n", ref, SvREFCNT(ref)));
hv_iterinit (self);
while ((next = hv_iternext(self))) {
SV *key = hv_iterkeysv(next);
TRACEME(("clone item %s\n", SvPV_nolen(key) ));
hv_store_ent(clone, key, sv_clone(aTHX_ hv_iterval(self, next), hseen, recur, rdepth, weakrefs), 0);
}
TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
return (SV *) clone;
}
static SV*
av_clone_iterative (pTHX_ SV* ref, HV* hseen, int rdepth, AV* weakrefs) {
if (!ref) return NULL;
AV *self = (AV *) ref;
SV **seen = NULL;
/* Check if we've already cloned this array */
}
}
else {
TRACEME(("magic object for type %c in NULL\n", mg->mg_type));
}
{ /* clone the mg_ptr pv */
char *mg_ptr = mg->mg_ptr; /* default */
if ( mg->mg_len >= 0 ) { /* copy the pv */
if ( mg_ptr ) {
Newxz( mg_ptr, mg->mg_len+1, char ); /* add +1 for the NULL at the end? */
Copy( mg->mg_ptr, mg_ptr, mg->mg_len, char );
}
}
else if ( mg->mg_len == HEf_SVKEY ) {
/* let's share the SV for now */
SvREFCNT_inc( (SV*)mg->mg_ptr );
/* maybe we also want to clone the SV... */
/* if (mg_ptr) mg->mg_ptr = (char*) sv_clone(aTHX_ (SV*)mg->mg_ptr, hseen, -1); */
}
else if ( mg->mg_len == -1 && mg->mg_type == PERL_MAGIC_utf8 ) { /* copy the cache */
if ( mg->mg_ptr ) {
STRLEN *cache;
Newxz( cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN );
mg_ptr = (char *) cache;
Copy( mg->mg_ptr, mg_ptr, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN );
}
}
else if ( mg->mg_ptr != NULL) {
croak("Unsupported magic_ptr clone");
}
/* this is plain old magic, so do the same thing */
sv_magic( clone, obj, mg->mg_type, mg_ptr, mg->mg_len );
}
}
/* major kludge - why does the vtable for a qr type need to be null? */
if (( mg = mg_find(clone, 'r') ))
mg->mg_virtual = (MGVTBL *) NULL;
}
/* 2: HASH/ARRAY - (with 'internal' elements) */
if ( magic_ref ) {
;;
}
else if ( SvTYPE(ref) == SVt_PVHV )
clone = hv_clone( aTHX_ ref, clone, hseen, depth, rdepth, weakrefs );
else if ( SvTYPE(ref) == SVt_PVAV )
clone = av_clone( aTHX_ ref, clone, hseen, depth, rdepth, weakrefs );
/* 3: REFERENCE (inlined for speed) */
else if ( SvROK(ref) ) {
TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
SvREFCNT_dec( SvRV(clone) );
SvRV(clone) = sv_clone( aTHX_ SvRV(ref), hseen, depth, rdepth, weakrefs ); /* Clone the referent */
if ( sv_isobject(ref) ) {
sv_bless( clone, SvSTASH( SvRV(ref) ) );
}
if ( SvWEAKREF(ref) ) {
/* Defer weakening until after the entire clone graph is built.
* sv_rvweaken decrements the referent's refcount, which can
* destroy it if no other strong references exist yet.
* By deferring, we ensure all strong references are in place
* before any weakening occurs. */
PUSH_WEAKREFS( weakrefs, clone );
}
}
TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
return clone;
}
( run in 1.470 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )