Skip to content

Commit

Permalink
New iterative in-order tree walking algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
mbethke committed Aug 5, 2012
1 parent a5f2db0 commit 085d180
Showing 1 changed file with 40 additions and 15 deletions.
55 changes: 40 additions & 15 deletions lib/Net/CIDR/Lookup.pm
Expand Up @@ -486,21 +486,46 @@ sub _int2dq { join '.', unpack 'C*', pack 'N', shift }
# Walk the tree in depth-first LTR order
sub _walk {
my ($node, $addr, $bits, $cb) = @_;
my ($a, $b) = @$node;

++$bits;
# Check left side
if(__PACKAGE__ eq ref $a) {
$a->_walk($addr, $bits, $cb);
} else {
defined $a and $cb->($addr, $bits, $a);
}
# Check right side
if(__PACKAGE__ eq ref $b) {
$b->_walk($addr | 1 << 32-$bits, $bits, $cb);
} else {
defined $b and $cb->($addr | 1 << 32-$bits, $bits, $b);
}
my ($l, $r);
my @node_stack = ($bits, $node);
#print "================== WALK ==================: ", join(':',caller),"\n";
while(defined($node = pop @node_stack)) {
$bits = pop @node_stack;
#print "LOOP: stack size ".@node_stack."\n";
if(__PACKAGE__ eq ref $node) {
($l, $r) = @$node;
#printf "Popped l=%s r=%s, bits=%d\n", ($l//'<undef>'), ($r//'<undef>'), $bits;
++$bits;

# Check left side
if(__PACKAGE__ eq ref $l) {
#print "L: pushing node=$l, bits=$bits\n";
defined $r and push @node_stack, ($bits, $r);
push @node_stack, ($bits, $l);
#printf "L: addr=%032b (%s)\n", $addr, _int2dq($addr);
next; # Short-circuit back to loop w/o checking $r!
} else {
#defined $l and printf "L: CALLBACK (%s/%d) => %s\n", _int2dq($addr), $bits, $l;
defined $l and $cb->($addr, $bits, $l);
}
} else {
# There was a right-side leaf node on the stack that will end up in
# the "else" branch below
#print "Found leftover right leaf $node\n";
$r = $node;
}

# Check right side
if(__PACKAGE__ eq ref $r) {
#print "R: pushing node=$r, bits=$bits\n";
push @node_stack, ($bits, $r);
$addr |= 1 << 32-$bits;
#printf "R: addr=%032b (%s)\n", $addr, _int2dq($addr);
} else {
#defined $r and printf "R: CALLBACK (%s/%d) => %s\n", _int2dq($addr | 1 << 32-$bits), $bits, $r;
defined $r and $cb->($addr | 1 << 32-$bits, $bits, $r);
}
}
}

# Split a chunk into a minimal number of CIDR blocks.
Expand Down

0 comments on commit 085d180

Please sign in to comment.