Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to you distinguish a symbol table from a regular hash variable?

Tags:

glob

perl

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.

like image 234
mob Avatar asked Mar 01 '11 21:03

mob


2 Answers

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 .

  1. char* HvNAME(HV* stash)
like image 193
Eric Strom Avatar answered Nov 02 '22 11:11

Eric Strom


You could look for either keys ending in '::', which would indicate that it has other packages, or all the values are symbol refs.

  • Of course, even here it would be hard to tell a stash from a hash that just storing symbols (for whatever reason). I was poking around with 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.

like image 33
Axeman Avatar answered Nov 02 '22 09:11

Axeman