File Coverage

blib/lib/Net/IP/Identifier/Binode.pm
Criterion Covered Total %
statement 51 78 65.3
branch 16 44 36.3
condition 2 15 13.3
subroutine 15 20 75.0
pod 4 6 66.6
total 88 163 53.9


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #===============================================================================
3             # PODNAME: Net::IP::Identifier::Binode
4             # ABSTRACT: A node in the binary tree
5             #
6             # AUTHOR: Reid Augustin (REID)
7             # EMAIL: reid@hellosix.com
8             # CREATED: Mon Oct 6 10:20:33 PDT 2014
9             #===============================================================================
10              
11 4     4   868 use 5.002;
  4         12  
  4         165  
12 4     4   21 use strict;
  4         6  
  4         149  
13 4     4   52 use warnings;
  4         5  
  4         247  
14              
15             $DB::deep = 150; # IPv6 needs 128 plus some headroom
16              
17             package Net::IP::Identifier::Binode;
18 4     4   19 use Carp;
  4         7  
  4         298  
19 4     4   1105 use Math::BigInt;
  4         19252  
  4         32  
20 4     4   15732 use Moo;
  4         19274  
  4         37  
21 4     4   4971 use namespace::clean;
  4         48146  
  4         26  
22              
23             our $VERSION = '0.106'; # VERSION
24              
25             has zero => (
26             is => 'rw',
27             isa => \&isnode,
28             );
29             has one => (
30             is => 'rw',
31             isa => \&isnode,
32             );
33             has payload => (
34             is => 'rw',
35             );
36              
37             sub isnode {
38 6 50 33 6 0 520 die if defined $_[0] and ref $_[0] ne __PACKAGE__;
39             }
40              
41             sub bin_to_ip {
42 0     0 0 0 my ($bin) = @_;
43              
44 0         0 my @results;
45 0         0 my $max = length $bin;
46 0         0 for (my $ii = 0; ; $ii++) {
47 0 0       0 if ($ii % 8 == 0) {
48 0 0       0 last if ($ii >= $max);
49 0         0 push @results, 0;
50             }
51 0 0       0 my $b = $ii < $max ? substr($bin, $ii, 1) : 0;
52 0         0 $results[-1] <<= 1;
53 0         0 $results[-1] |= $b;
54             }
55 0         0 return join '.', @results;
56             }
57              
58             our $path = Math::BigInt->new(0);
59             sub construct {
60 3     3 1 6935 my ($self, $path) = @_;
61              
62 3         5 my $node;
63             $self->_follow(
64             $path,
65             0,
66             sub { # construction callback
67 12     12   13 my ($self, $path, $level) = @_;
68              
69 12 100       23 if ($level < length $path) {
70 9 100       16 if (substr($path, $level, 1)) { # next step
71 3 50       69 $self->one($self->new) if (not $self->one);
72             }
73             else {
74 6 100       122 $self->zero($self->new) if (not $self->zero);
75             }
76             }
77             else {
78 3         5 $node = $self; # when we reach the end
79             }
80 12         80 return 0; # always continue
81             }
82 3         25 );
83 3         22 return $node;
84             }
85              
86             sub follow {
87 3     3 1 1537 my ($self, $path, $callback, @extra) = @_;
88              
89 3 50 33     20 croak "Need a code ref\n" if (not $callback or ref $callback ne 'CODE');
90 3         8 return $self->_follow($path, 0, $callback, @extra);
91             }
92              
93             sub _follow {
94 4     4   3122 no warnings 'recursion'; # IPv6 requires at least 128 levels
  4         10  
  4         958  
95 24     24   452 my ($self, $path, $level, $callback, @extra) = @_;
96              
97 24 50       35 return if $callback->($self, $path, $level, @extra);
98              
99 24 100       98 return $self if ($level >= length $path); # end of the line
100              
101 18 100       33 if (substr($path, $level, 1)) { # next step
102 6 50       103 return $self->one->_follow($path, $level + 1, $callback, @extra) if ($self->one);
103             }
104             else {
105 12 50       211 return $self->zero->_follow($path, $level + 1, $callback, @extra) if ($self->zero);
106             }
107 0           return; # no node at $path
108             }
109              
110             sub traverse_width_first {
111 0     0 1   my ($self, $callback, @extra) = @_;
112              
113 0 0 0       croak "Need a code ref\n" if (not $callback or ref $callback ne 'CODE');
114 0           return $self->_traverse_width_first(0, $callback, @extra);
115             }
116              
117             sub _traverse_width_first {
118 4     4   27 no warnings 'recursion'; # IPv6 requires at least 128 levels
  4         7  
  4         796  
119 0     0     my ($self, $level, $callback, @extra) = @_;
120              
121 0 0         return if $callback->($self, $level, @extra);
122              
123             #$path <<= 1;
124 0 0         $self->zero->_traverse_width_first($level + 1, $callback, @extra) if ($self->zero);
125             #$path |= 1;
126 0 0         $self->one ->_traverse_width_first($level + 1, $callback, @extra) if ($self->one);
127             #$path >>= 1;
128             }
129              
130             sub traverse_depth_first {
131 0     0 1   my ($self, $callback, @extra) = @_;
132              
133 0 0 0       croak "Need a code ref\n" if (not $callback or ref $callback ne 'CODE');
134 0           $self->_traverse_depth_first(0, $callback, @extra);
135             }
136              
137             sub _traverse_depth_first {
138 4     4   26 no warnings 'recursion'; # IPv6 requires at least 128 levels
  4         8  
  4         558  
139 0     0     my ($self, $level, $callback, @extra) = @_;
140              
141 0           my $stop;
142             #print "path=", $path->as_hex, "\n";
143             #$path <<= 1;
144 0 0         $stop = $self->zero->_traverse_depth_first($level + 1, $callback, @extra) if ($self->zero);
145             #$path |= 1;
146 0 0 0       $stop = $self->one ->_traverse_depth_first($level + 1, $callback, @extra) if (not $stop and $self->one);
147             #$path >>= 1;
148              
149 0 0         $callback->($self, $level, @extra) if (not $stop);
150             }
151              
152             1;
153              
154             __END__