Puede buscar las claves que terminen en '::', lo que indicaría que tiene otros paquetes, o todos los valores son referencias de símbolos.
- Por supuesto, incluso aquí sería difícil distinguir entre un hash y simplemente el almacenamiento de símbolos (por la razón que sea). Estaba hurgando con
B::svref_2object
, pero incluso los símbolos de un alijo almacenado en un hash regular devolverían algo para $sym->can('STASH')
.
Creo que lo que podría hacer es descender a través de la tabla de símbolos y ver si un escondite apunta exactamente a la misma ubicación de memoria.
Algo así como esto:
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::');
}
El rendimiento no fue terribles.
Estaba comenzando a deducir esto de ejecutar 'perl -MDevel :: Peek -e 'Dump (\% a: :), Dump (\% a)''. Gracias por el enlace, así que puedo hacer menos culto a la carga. Sin XS todavía puede hacer algo como '$ is_a_symtable = do {$ sv = B :: svref_2object ($ hashref); ref ($ sv) eq 'B :: HV' && $ sv-> NAME};' – mob