Is there any way to tell whether a hash reference is referring to a symbol table?
That is, how could the function
sub foo {
my ($hashref) = @_;
...
}
know whether it had been invoked as
foo( \%main:: )
rather than
foo( \%main )
?
The application is a function that sometimes tie
's hash variables, but I'd want to avoid trying to tie a symbol table.
It looks like this can be done from the C API using HvNAME
. The following is from perlapi:
HvNAME
Returns the package name of a stash, or NULL if stash isn't a stash. See SvSTASH , CvSTASH .
- char* HvNAME(HV* stash)
You could look for either keys ending in '::', which would indicate that it has other packages, or all the values are symbol refs.
B::svref_2object
, but even symbols from a stash stored in a regular hash would return something for $sym->can( 'STASH' )
.I think the thing you might do is descend through the symbol table and see if a stash points at the exact same memory location.
Kind of like this:
use Scalar::Util qw<refaddr>;
my %seen;
sub _descend_symtable {
$calls++;
my ( $cand, $stash_name ) = @_;
my $stash = do { no strict 'refs'; \%{ $stash_name }; };
return if $seen{ refaddr( $stash ) }++;
return $stash_name if $cand == $stash;
my $result;
foreach my $s ( grep { m/::$/ } keys %$stash ) {
$result = _descend_symtable( $cand, "$stash_name$s" )
and return $result;
}
return;
}
sub find_in_symtable {
my $needle = shift;
%seen = ();
return _descend_symtable( $needle, 'main::' );
}
The performance wasn't terrible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With