Data-Recursive
view release on metacpan or search on metacpan
src/xs/clone.cc view on Meta::CPAN
CrossData* crossdata = NULL;
if (flags & CloneFlags::TRACK_REFS) {
CrossData data;
crossdata = &data;
_clone(aTHX_ ret, source, crossdata, 0);
auto end = data.map.end();
for (const auto& row : data.weakrefs) { // post process weak refs that appeared before their strong refs
auto it = data.map.find(row.key);
if (it == end) continue;
SvSetSV_nosteal(row.dest, it->second);
sv_rvweaken(row.dest);
}
}
else _clone(aTHX_ ret, source, crossdata, 0);
return ret;
}
static void _clone (pTHX_ SV* dest, SV* source, CrossData*& xdata, I32 depth) {
if (depth > CLONE_MAX_DEPTH) throw std::invalid_argument(
std::string("clone: max depth (") + std::to_string(CLONE_MAX_DEPTH) + ") reached, it looks like you passed a cycled structure"
);
if (SvROK(source)) { // reference
SV* source_val = SvRV(source);
svtype val_type = SvTYPE(source_val);
if (val_type == SVt_PVCV || val_type == SVt_PVIO) { // CV and IO cannot be copied - just set reference to the same SV
SvSetSV_nosteal(dest, source);
if (SvWEAKREF(source)) sv_rvweaken(dest);
return;
}
uint64_t id = PTR2UV(source_val);
if (xdata) {
auto it = xdata->map.find(id);
if (it != xdata->map.end()) {
SvSetSV_nosteal(dest, it->second);
if (SvWEAKREF(source)) sv_rvweaken(dest);
return;
}
if (SvWEAKREF(source)) {
// we can't clone object weakref points to right now, because no strong refs for the object cloned so far, we must wait until the end
xdata->weakrefs.push_back({dest, id});
return;
}
}
GV* cloneGV;
t/clone-weakref.t view on Meta::CPAN
use 5.012;
use warnings;
use Test::More;
use Test::Deep;
use Data::Recursive qw/clone lclone/;
use Scalar::Util qw/weaken isweak/;
subtest 'lclone makes all weak refs strong refs' => sub {
my $data = [1,2,3];
my $val = {data => $data};
weaken($val->{data});
my $copy = lclone($val);
cmp_deeply($copy, {data => [1,2,3]});
isnt $copy->{data}, $val->{data};
ok !isweak($copy->{data});
};
subtest 'weakref to CV/IO' => sub {
my $sub = sub { return 123};
my $io = *STDERR{IO};
my $val = [$sub, $io];
weaken($val->[0]); weaken($val->[1]);
my $copy = clone($val);
cmp_deeply $copy, [$sub, $io], "data ok";
ok isweak($copy->[0]) && isweak($copy->[1]), "ref copied as weak";
};
subtest 'alone weak ref dissapears' => sub {
my $data = [1,2,3];
my $val = {data => $data};
weaken($val->{data});
my $copy = clone($val);
my @a = ({}) x 200;
is $copy->{data}, undef;
};
subtest 'cloning strong before weak' => sub {
my $data = {a => 1};
my $val = [$data, $data];
weaken($val->[1]);
my $copy = clone($val);
cmp_deeply $copy, $val, "data ok";
ok isweak($copy->[1]), "ref copied as weak";
};
subtest 'cloning weak before strong' => sub {
my $data = {a => 1};
my $val = [$data, $data];
weaken($val->[0]);
my $copy = clone($val);
cmp_deeply $copy, $val, "data ok";
ok isweak($copy->[0]), "ref copied as weak";
};
done_testing();
( run in 0.579 second using v1.01-cache-2.11-cpan-65fba6d93b7 )