I know that caller
will give me the file name and line number where a function was called, but how can I get the character or byte offset? It is okay if I must drop down to XS for it (the function will probably wind up being XS anyway).
What I am trying to do is uniquely identify all of the calls to a function, so, if there is a better method than location in the source, I am open to other routes.
The basic intent is to make an each
function that can safely iterate over the same hash. Here is a pure Perl version that is similar to what I am thinking about:
#!/usr/bin/perl
use 5.012;
use warnings;
use Scalar::Util qw/refaddr/;
sub safe_each(\%) {
my $h = shift;
my $key = join "/", (caller)[1,2], refaddr $h;
state %iter;
unless (exists $iter{$key}) {
$iter{$key} = [ keys %$h ];
}
unless (@{$iter{$key}}) {
delete $iter{$key};
return;
}
my $cur = shift @{$iter{$key}};
return wantarray ? ($c开发者_StackOverflowur, $h->{$cur}) : $cur;
}
my %h = (a => 1, b => 2);
while (my ($k, $v) = safe_each %h) {
say "$k => $v";
while (my ($k, $v) = safe_each %h) {
say "\t$k => $v";
}
}
The perl debugger loads all lines of the source files that it needs into the main symbol table under the entry
@::{"_<$path_to_file"}
This way when you reach a breakpoint at line LINE in file FILE, the debugger can display the line of code you are about to execute:
$::{"_<FILE"}[LINE]
But you could also use this information to compute the current character offset into your source file.
sub _get_offset_into_file {
my ($file,$line) = @_;
my *teh_codez = @::{"_<$file"};
my $offset = 0;
# the debugger spoofs line $teh_codez[0], so don't include it in offset calc
$offset += length $_ for @teh_codez[1 .. $line-1];
return $offset
}
You could either run your code under the debugger, or emulate what the debugger does and load the files into memory yourself (then you wouldn't have to use the same "_<" + filename convention, or even use the symbol table at all).
Sorry if this is an answer to a completely different question than the one you are asking.
精彩评论