diff --git a/lib/Net/CIDR/Lookup.pm b/lib/Net/CIDR/Lookup.pm index 8d30998..b057d41 100644 --- a/lib/Net/CIDR/Lookup.pm +++ b/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//''), ($r//''), $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.