Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

New iterative in-order tree walking algorithm

  • Loading branch information...
commit 085d180498f84c72b03028fe03eb2f854939006f 1 parent a5f2db0
@mbethke authored
Showing with 40 additions and 15 deletions.
  1. +40 −15 lib/Net/CIDR/Lookup.pm
View
55 lib/Net/CIDR/Lookup.pm
@@ -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.
Please sign in to comment.
Something went wrong with that request. Please try again.