While not directly answering your question (I really don't see any recursion in the example). Recursion is possible with Inline::C. $self can look like almost anything, it depends on how you set up your code. Here's a very contrived example borrowing from K&R's "Self-referential Structures" paragraph (chapter 6.5 from K&R 1). First is a simplistic pure-perl approach (not that I recommend doing trees this way in perl).
#!/usr/bin/perl -w
package Tnode;
sub new {
my( $class, $word, $count ) = @_;
my $self = {};
$self->{word} = $word;
$self->{count} = $count;
$self->{left} = undef;
$self->{right} = undef;
return bless $self, $class;
}
package main;
die unless @ARGV;
my $root = undef;
while(<>) {
chomp;
$word = $_;
$root = tree( $root, $word );
}
treeprint( $root );
sub tree {
my( $node, $word ) = @_;
if( ! $node ) {
$node = Tnode->new( $word, 1 );
$node->{left} = undef;
$node->{right} = undef;
} elsif( $node->{word} eq $word ) {
$node->{count}++;
} elsif( $word lt $node->{word} ) {
$node->{left} = tree( $node->{left}, $word );
} else {
$node->{right} = tree( $node->{right}, $word );
}
return $node;
}
sub treeprint {
my( $root ) = shift;
if( $root ) {
treeprint( $root->{left} );
printf( "%4d %s\n", $root->{count}, $root->{word} );
treeprint( $root->{right} );
}
}
given a file with a list of words, this script will output
the ascii ordered words with their counts.
Now here's the sample example with the treeprint function
done via inline. Now a couple notes about this example, my
brain could not make the hv_fetch function work correctly, so this example rather ineffeciently uses a for loop to walk the hash entries. And speaking of hashes, we just assume the reference is a hash and blithely cast it as such (not good coding but the attempt here is to show recursion).
#!/usr/bin/perl -w
use Inline C;
package Tnode;
sub new {
my( $class, $word, $count ) = @_;
my $self = {};
$self->{word} = $word;
$self->{count} = $count;
$self->{left} = undef;
$self->{right} = undef;
return bless $self, $class;
}
package main;
die unless @ARGV;
my $root = undef;
while(<>) {
chomp;
$word = $_;
$root = tree( $root, $word );
}
treeprint( $root );
sub tree {
my( $node, $word ) = @_;
if( ! $node ) {
$node = Tnode->new( $word, 1 );
$node->{left} = undef;
$node->{right} = undef;
} elsif( $node->{word} eq $word ) {
$node->{count}++;
} elsif( $word lt $node->{word} ) {
$node->{left} = tree( $node->{left}, $word );
} else {
$node->{right} = tree( $node->{right}, $word );
}
return $node;
}
__END__
__C__
void treeprint( SV *root ) {
HV* hash;
HE* hash_entry;
SV* node;
SV* word;
SV* count;
if( !SvROK(root) )
return;
hash = (HV*)SvRV(root);
node = get_child( hash, "left" );
if( node != NULL ) {
treeprint( node );
}
output( hash );
node = get_child( hash, "right" );
if( node != NULL ) {
treeprint( node );
}
}
SV *get_child( HV *hash, char *key ) {
int num_keys, i;
HE *hash_entry;
SV *sv_key;
SV *sv_val;
num_keys = hv_iterinit(hash);
for (i = 0; i < num_keys; i++) {
hash_entry = hv_iternext(hash);
sv_key = hv_iterkeysv(hash_entry);
sv_val = hv_iterval(hash, hash_entry);
if( strcmp( SvPV( sv_key, PL_na), key ) == 0 ) {
return( sv_val );
}
}
sv_val = NULL;
return sv_val;
}
void output( HV *hash ) {
int num_keys, i;
HE *hash_entry;
SV *sv_key;
SV *sv_val;
int count;
char *word = NULL;
num_keys = hv_iterinit(hash);
for(i = 0; i < num_keys; i++) {
hash_entry = hv_iternext(hash);
sv_key = hv_iterkeysv(hash_entry);
sv_val = hv_iterval(hash, hash_entry);
if( strcmp( SvPV( sv_key, PL_na), "word" ) == 0 ) {
word = SvPV( sv_val, PL_na);
}
if( strcmp( SvPV( sv_key, PL_na), "count" ) == 0 ) {
count = SvIV( sv_val );
}
}
if( word ) {
printf( "%4d %s\n", count, word );
}
}
Now that all being said, a benchmark of the two approaches shows very little difference
Benchmark: timing 50000 iterations of inline, perl...
inline: 13 wallclock secs (12.42 usr + 0.00 sys = 12.42 CPU) @
4025.76/s (n=50000)
perl: 12 wallclock secs (12.27 usr + 0.00 sys = 12.27 CPU) @
4074.98/s (n=50000)
but maybe if I could get hv_fetch to work properly, there would be a noticeable diff.
-derby |