D
Dez
I am trying to detect circular references inside a hash. I was thinking
of doing this by tracking the address of the variables. However, the
test program I have below is showing the same address for the scalars in
the hash, while the references in the hash are showing as expected.
Basically, I'm getting a false positive for hash member id and name.
I tried the code at http://www.perlmonks.org/?node_id=406446 but it also
is showing the same address, which I assume is the address of my $ref,
not the address of the variable passed in.
Any ideas?
---------- Output of Test Program -------
parent hash ref = 164306792 type1 = HASH blessed =
key = arr ref = 163412544 type1 = ARRAY blessed =
key = circ ref = 164306812 type1 = SCALAR blessed =
key = circ2 ref = 164306792 type1 = HASH blessed =
key = circ3 ref = 163412544 type1 = ARRAY blessed =
key = code ref = 164340068 type1 = CODE blessed =
key = has ref = 164340768 type1 = HASH blessed =
key = id ref = 164339168 type1 = notaref blessed =
key = name ref = 164339168 type1 = notaref blessed =
key = obj ref = 164306732 type1 = SCALAR blessed = JSON
key = regex ref = 164306712 type1 = REGEXP blessed = Regexp
---------- Test Program Below -----------
use strict;
use warnings;
use B;
use JSON;
my %tmap = qw(
B::NULL SCALAR
B::HV HASH
B::AV ARRAY
B::CV CODE
B::IO IO
B::GV GLOB
B::REGEXP REGEXP
);
sub refaddr($) {
ref($_[0]) ? 0+$_[0] : undef
}
sub chktype {
my $r = shift;
return unless length(ref($r));
my $t = ref(B::svref_2object($r));
return
exists $tmap{$t} ? $tmap{$t}
: length(ref($$r)) ? 'REF'
: 'SCALAR';
}
sub walk($) {
my $ref = shift;
my $type1 = chktype $ref;
my $type2 = ref $ref;
if (!defined $type1) {
$type1 = 'notaref';
}
my $blessed = ($type1 ne $type2) ? $type2 : '';
# if ref is a reference, get address to which it points
my $addr = $type2 ? refaddr $ref : refaddr \$ref;
return "ref = $addr\ttype1 = $type1\tblessed = $blessed\n";
}
my $test_hash = {
name => 'Some Name',
arr => ['a','b','3','5'],
has => {
key1 => 'val1',
key2 => 'val2',
key3 => 'val3'
},
regex => qr/thisisaregex/x,
code => sub {return 1},
id => 4,
obj => JSON->new
};
$test_hash->{circ} = \$test_hash->{name};
$test_hash->{circ2} = $test_hash;
$test_hash->{circ3} = $test_hash->{arr};
print "\n";
print "parent hash\t" . walk $test_hash;
foreach my $key (sort keys %{$test_hash}) {
print "key = $key\t" . walk $test_hash->{$key};
}
print "\n";
of doing this by tracking the address of the variables. However, the
test program I have below is showing the same address for the scalars in
the hash, while the references in the hash are showing as expected.
Basically, I'm getting a false positive for hash member id and name.
I tried the code at http://www.perlmonks.org/?node_id=406446 but it also
is showing the same address, which I assume is the address of my $ref,
not the address of the variable passed in.
Any ideas?
---------- Output of Test Program -------
parent hash ref = 164306792 type1 = HASH blessed =
key = arr ref = 163412544 type1 = ARRAY blessed =
key = circ ref = 164306812 type1 = SCALAR blessed =
key = circ2 ref = 164306792 type1 = HASH blessed =
key = circ3 ref = 163412544 type1 = ARRAY blessed =
key = code ref = 164340068 type1 = CODE blessed =
key = has ref = 164340768 type1 = HASH blessed =
key = id ref = 164339168 type1 = notaref blessed =
key = name ref = 164339168 type1 = notaref blessed =
key = obj ref = 164306732 type1 = SCALAR blessed = JSON
key = regex ref = 164306712 type1 = REGEXP blessed = Regexp
---------- Test Program Below -----------
use strict;
use warnings;
use B;
use JSON;
my %tmap = qw(
B::NULL SCALAR
B::HV HASH
B::AV ARRAY
B::CV CODE
B::IO IO
B::GV GLOB
B::REGEXP REGEXP
);
sub refaddr($) {
ref($_[0]) ? 0+$_[0] : undef
}
sub chktype {
my $r = shift;
return unless length(ref($r));
my $t = ref(B::svref_2object($r));
return
exists $tmap{$t} ? $tmap{$t}
: length(ref($$r)) ? 'REF'
: 'SCALAR';
}
sub walk($) {
my $ref = shift;
my $type1 = chktype $ref;
my $type2 = ref $ref;
if (!defined $type1) {
$type1 = 'notaref';
}
my $blessed = ($type1 ne $type2) ? $type2 : '';
# if ref is a reference, get address to which it points
my $addr = $type2 ? refaddr $ref : refaddr \$ref;
return "ref = $addr\ttype1 = $type1\tblessed = $blessed\n";
}
my $test_hash = {
name => 'Some Name',
arr => ['a','b','3','5'],
has => {
key1 => 'val1',
key2 => 'val2',
key3 => 'val3'
},
regex => qr/thisisaregex/x,
code => sub {return 1},
id => 4,
obj => JSON->new
};
$test_hash->{circ} = \$test_hash->{name};
$test_hash->{circ2} = $test_hash;
$test_hash->{circ3} = $test_hash->{arr};
print "\n";
print "parent hash\t" . walk $test_hash;
foreach my $key (sort keys %{$test_hash}) {
print "key = $key\t" . walk $test_hash->{$key};
}
print "\n";