Clone

 view release on metacpan or  search on metacpan

Clone.xs  view on Meta::CPAN

              obj = sv_clone(mg->mg_obj, hseen, -1, rdepth, weakrefs);
          }
        } 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);
              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);
          } 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");
          }

          sv_magic(clone,
                   obj,
                   mg->mg_type,
                   mg_ptr,
                   mg->mg_len);

        }
      }
      /* Null the qr vtable -- avoid mg_find traversal if we already know */
      if (has_qr && (mg = mg_find(clone, 'r')))
        mg->mg_virtual = (MGVTBL *) NULL;
    }
    /* 2: HASH/ARRAY  - (with 'internal' elements) */
    /* For tied HV/AV (magic_ref > 0): skip direct element iteration;
     * the tie magic cloned above handles the data. */
  if ( !magic_ref )
  {
    if ( SvTYPE(ref) == SVt_PVHV )
      clone = hv_clone (ref, clone, hseen, depth, rdepth, weakrefs);
    else if ( SvTYPE(ref) == SVt_PVAV )
      clone = av_clone (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 (SvRV(ref), hseen, depth, rdepth, weakrefs); /* Clone the referent */
        if (SvOBJECT(SvRV(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. (fixes GH #15) */
            av_push(weakrefs, SvREFCNT_inc_simple_NN(clone));
        }
      }
  }

  TRACEME(("clone = 0x%x(%d)\n", clone, SvREFCNT(clone)));
  return clone;
}

MODULE = Clone		PACKAGE = Clone

PROTOTYPES: ENABLE

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(self, hseen, depth, 0, weakrefs);
	/* Now apply deferred weakening (GH #15).
	 * All strong references in the clone graph are established,
	 * so it is safe to weaken references without destroying referents. */
	{
	    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);
	        }
	    }
	}
	hv_clear(hseen);  /* Free HV */
        SvREFCNT_dec((SV *)hseen);
        SvREFCNT_dec((SV *)weakrefs);
	EXTEND(SP,1);
	PUSHs(sv_2mortal(clone));



( run in 1.670 second using v1.01-cache-2.11-cpan-7f9471e7e0a )