Clone
view release on metacpan or search on metacpan
- fix: use platform-adaptive depth in t/10-deep_recursion.t for Windows
- Fix t/10-deep_recursion.t for Windows
- Fix C89 declaration-after-statement violations in Clone.xs
- Fix deep recursion stack overflow on Windows
- Fix cloning of Math::BigInt::GMP objects (fixes #16)
- Fix cloning of threads::shared data structures (fixes #18)
- Add thread safety test for Class::DBI-like patterns (fixes #14)
- Add comprehensive documentation with examples and limitations
- Improve README.md structure and installation instructions
- Add DBI + DBD::SQLite as recommended test dependencies
- Fix weakened reference cloning via deferred weakening (fixes #15)
- Fix memory leak when cloning non-existent hash values (fixes #42)
- Fix segfault when cloning DBI database handles (fixes #27)
- Rewrite t/09-circular.t to fix SEGV on CPAN Testers (fixes #54)
- Replace static recursion_depth with stack parameter
- Fix C++ style comments in Clone.xs for C89 portability
- Fix memory leak in Clone.xs (fixes #42)
- Allow a MAX_DEPTH recursion of 32000 calls (fixes #19 aka RT97525)
- Rename tests with more readable names
- Remove TODO from cow test
- making some tests optional (fixes RT81774) (GARU)
- modernizing synopsis (GARU)
0.33 2012-11-24 11:38:31 garu
- fix typo in croak message (Salvatore Bonaccorso)
0.32 2012-11-22 12:42:19 garu
- Stop skipping SvROK handling for all magical scalars. This fixes
RT issues 67105, 79730 and 80201 (FLORA).
- making the Changes file compliant to the CPAN::Changes spec (GARU).
- Fixing tests when Scalar::Util::weaken is not available. As a
result, tests should now pass even in odd OpenBSD versions (GARU).
- removed dubious documentation on the optional parameter until
it is 'fixed'. Right now it just increases the refcount when it's 0,
and clones otherwise (which isn't exactly what it says). This
fixes RT issue 57773 (GARU).
- updated remark on Storable's dclone() to address RT issue 50174 (GARU)
- updated Makefile.PL to include test dependencies (GARU)
0.31 2009-01-20 04:54:37 ray
- Made changes for build failure on Solaris, apparently compiler warnings
- added a test and fix for tainted variables.
- use a static VERSION in Clone.pm.
0.18 2005-05-23 15:34:31 ray
- moved declaration to top of function, M$ (and other) C compilers choke.
0.17 2005-05-05 22:26:01 ray
- Changed PERL_MAGIC_backref to '<' for compatability with 5.6
0.16 2005-04-20 15:49:35 ray
- Bug fix for id 11997, "Clone dies horribly when Scalar::Util::weaken
is around" see http://rt.cpan.org/Ticket/Display.html?id=11997
for details.
0.15.2.1 2005-05-05 21:55:30 ray
- changed PERL_MAGIC_backref to '<' for backward compatibility with 5.6
0.15 2003-09-07 22:02:35 ray
- VERSION 0.15
0.13.2.3 2003-09-07 21:51:03 ray
my $a = { name => 'A' };
my $b = { name => 'B', ref => $a };
$a->{ref} = $b; # circular reference
my $clone = clone($a);
# Circular structure is preserved in the clone
=head2 Cloning Weakened References
use Scalar::Util 'weaken';
my $obj = { data => 'important' };
my $container = { strong => $obj, weak => $obj };
weaken($container->{weak});
my $clone = clone($container);
# Both strong and weak references are preserved correctly
=head2 Cloning Tied Variables
use Tie::Hash;
tie my %hash, 'Tie::StdHash';
%hash = (a => 1, b => 2);
L<Storable>'s C<dclone()> is a flexible solution for cloning variables,
albeit slower for average-sized data structures. Simple
and naive benchmarks show that Clone is faster for data structures
with 3 or fewer levels, while C<dclone()> can be faster for structures
4 or more levels deep.
Other modules that may be of interest:
L<Clone::PP> - Pure Perl implementation of Clone
L<Scalar::Util> - For C<weaken()> and other scalar utilities
L<Data::Dumper> - For debugging and inspecting data structures
=head1 SUPPORT
=over 4
=item * Bug Reports and Feature Requests
Please report bugs on GitHub: L<https://github.com/garu/Clone/issues>
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
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));
t/03-scalar.t
t/04-tie.t
t/05-dtype.t
t/06-refcnt.t
t/07-magic.t
t/08-fieldhash.t
t/09-circular.t
t/10-deep_recursion.t
t/12-memleak.t
t/13-io-handle.t
t/14-weakened-ref.t
t/15-clone-xs-objects.t
t/16-threads-shared.t
t/17-threads-classdbi.t
t/18-overload.t
t/19-dualvar.t
t/dclone.t
t/dump.pl
t/tied.pl
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
my $b = { name => 'B', ref => $a };
$a->{ref} = $b; # circular reference
my $clone = clone($a);
# Circular structure is preserved in the clone
```
### Cloning Weakened References
```perl
use Scalar::Util 'weaken';
my $obj = { data => 'important' };
my $container = { strong => $obj, weak => $obj };
weaken($container->{weak});
my $clone = clone($container);
# Both strong and weak references are preserved correctly
```
### Cloning Tied Variables
```perl
use Tie::Hash;
tie my %hash, 'Tie::StdHash';
[Storable](https://metacpan.org/pod/Storable)'s `dclone()` is a flexible solution for cloning variables,
albeit slower for average-sized data structures. Simple
and naive benchmarks show that Clone is faster for data structures
with 3 or fewer levels, while `dclone()` can be faster for structures
4 or more levels deep.
Other modules that may be of interest:
* [Clone::PP](https://metacpan.org/pod/Clone::PP) - Pure Perl implementation of Clone
* [Scalar::Util](https://metacpan.org/pod/Scalar::Util) - For `weaken()` and other scalar utilities
* [Data::Dumper](https://metacpan.org/pod/Data::Dumper) - For debugging and inspecting data structures
## Support
* **Bug Reports and Feature Requests**: Please report bugs on [GitHub Issues](https://github.com/garu/Clone/issues)
* **Source Code**: Available on [GitHub](https://github.com/garu/Clone)
COPYRIGHT
---------
sv_resetpvn|5.017005||Viu
SvRMAGICAL|5.003007||Viu
SvRMAGICAL_off|5.003007||Viu
SvRMAGICAL_on|5.003007||Viu
SvROK|5.003007|5.003007|
SvROK_off|5.003007|5.003007|
SvROK_on|5.003007|5.003007|
SvRV|5.003007|5.003007|
SvRV_const|5.010001||Viu
SvRV_set|5.009003|5.003007|p
sv_rvunweaken|5.027004|5.027004|
sv_rvweaken|5.006000|5.006000|
SvRVx|5.003007||Viu
SvRX|5.009005|5.003007|p
SvRXOK|5.009005|5.003007|p
SV_SAVED_COPY|5.009005||Viu
SvSCREAM|5.003007||Viu
SvSCREAM_off|5.003007||Viu
SvSCREAM_on|5.003007||Viu
sv_setbool|5.035004|5.035004|
sv_setbool_mg|5.035004|5.035004|
sv_setgid|5.019001||Viu
t/06-refcnt.t view on Meta::CPAN
# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)
my $HAS_WEAKEN;
BEGIN {
$| = 1;
my $plan = 25;
eval 'use Scalar::Util qw( weaken isweak );';
if ($@) {
$HAS_WEAKEN = 0;
$plan = 15;
}
else {
$HAS_WEAKEN = 1;
}
print "1..$plan\n";
}
t/06-refcnt.t view on Meta::CPAN
bless $a, 'Test::Hash';
bless $b, 'Test::Hash';
}
# test for cloning weak reference
if ($HAS_WEAKEN) {
{
my $a = Test::Hash->new;
my $b = { r => $a };
$a->{r} = $b;
weaken( $b->{'r'} );
my $c = clone($a);
}
# another weak reference problem, this one causes a segfault in 0.24
{
my $a = Test::Hash->new;
{
my $b = [ $a, $a ];
$a->{r} = $b;
weaken( $b->[0] );
weaken( $b->[1] );
}
my $c = clone($a);
# check that references point to the same thing
is( $c->{'r'}[0], $c->{'r'}[1], "references point to the same thing" );
isnt( $c->{'r'}[0], $a->{'r'}[0], "a->{r}->[0] ne c->{r}->[0]" );
require B;
my $c_obj = B::svref_2object($c);
t/07-magic.t view on Meta::CPAN
use strict;
use Clone;
use Test::More tests => 10;
SKIP: {
eval "use Data::Dumper";
skip "Data::Dumper not installed", 1 if $@;
SKIP: {
eval "use Scalar::Util qw( weaken )";
skip "Scalar::Util not installed", 1 if $@;
my $x = { a => "worked\n" };
my $y = $x;
weaken($y);
my $z = Clone::clone($x);
ok( Dumper($x) eq Dumper($z), "Cloned weak reference");
}
## RT 21859: Clone segfault (isolated example)
SKIP: {
my $string = "HDDR-WD-250JS";
eval {
use utf8;
utf8::upgrade($string);
t/14-weakened-ref.t view on Meta::CPAN
#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
use Clone qw(clone);
BEGIN {
eval 'use Scalar::Util qw( weaken isweak );';
if ($@) {
plan skip_all => "Scalar::Util::weaken not available";
exit;
}
}
plan tests => 16;
# GH #15 - Weakened refs always clone as undef
# When cloning a structure with weakened references, Clone should
# preserve the weakness and keep referents alive when strong
# references to them exist elsewhere in the clone graph.
{
package Parent;
sub new { bless { children => [] }, shift }
package Child;
sub new {
my ($class, $parent) = @_;
my $child = bless { parent => $parent }, $class;
Scalar::Util::weaken($child->{parent});
push @{ $parent->{children} }, $child;
return $child;
}
}
# Test 1: Clone from parent side (strong ref to child, weak ref back)
# This is the primary fix: when the referent has strong references
# elsewhere in the clone graph, the weakened ref should survive.
{
my $p = Parent->new();
my $c = Child->new($p);
my $p_clone = clone($p);
ok(defined $p_clone->{children}[0]{parent},
'weakened ref survives when cloning from parent side');
isnt($p_clone, $p, 'cloned parent is a different object');
is($p_clone->{children}[0]{parent}, $p_clone,
'cloned child points to cloned parent (not original)');
ok(Scalar::Util::isweak($p_clone->{children}[0]{parent}),
'weakened ref is still weak after cloning parent');
}
# Test 2: Multiple children with weakened refs to same parent
{
my $p = Parent->new();
my $c1 = Child->new($p);
my $c2 = Child->new($p);
my $p_clone = clone($p);
ok(defined $p_clone->{children}[0]{parent},
'first child weakened ref survives');
ok(defined $p_clone->{children}[1]{parent},
'second child weakened ref survives');
is($p_clone->{children}[0]{parent}, $p_clone->{children}[1]{parent},
'both children point to same cloned parent');
ok(Scalar::Util::isweak($p_clone->{children}[0]{parent}),
'first child ref is weak');
ok(Scalar::Util::isweak($p_clone->{children}[1]{parent}),
'second child ref is weak');
}
# Test 3: Hash with both strong and weak ref to same target
{
my $data = { value => 42 };
my $holder = { strong => $data, weak => $data };
weaken($holder->{weak});
my $cloned = clone($holder);
ok(defined $cloned->{weak}, 'weakened hash value survives when strong ref exists');
is($cloned->{weak}{value}, 42, 'weakened ref points to correct data');
is($cloned->{strong}, $cloned->{weak},
'strong and weak refs point to same cloned object');
ok(!Scalar::Util::isweak($cloned->{strong}),
'strong ref remains strong');
ok(Scalar::Util::isweak($cloned->{weak}),
'weak ref remains weak');
}
# Test 4: Standalone weakened ref with no strong ref in clone graph
# When the referent has no strong references in the clone graph,
# the weakened ref correctly becomes undef (same as Storable::dclone).
{
my $p = Parent->new();
my $c = Child->new($p);
my $c_clone = clone($c);
ok(!defined $c_clone->{parent},
'weakened ref to object with no strong ref in clone becomes undef');
# This is correct: the cloned parent has no independent strong reference,
# so it gets collected when the weak reference is established.
}
# Test 5: Circular weak reference (existing test from t/06-refcnt.t)
{
my $a = bless {}, 'Test::Circular';
my $b = { r => $a };
$a->{r} = $b;
weaken($b->{'r'});
my $c = clone($a);
ok(defined $c->{r}, 'circular weak reference survives cloning');
}
( run in 2.158 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )