File Coverage

blib/lib/Net/IP/Identifier/Binode.pm
Criterion Covered Total %
statement 59 78 75.6
branch 26 44 59.0
condition 3 15 20.0
subroutine 17 20 85.0
pod 4 6 66.6
total 109 163 66.8


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   775 use 5.002;
  4         12  
  4         148  
12 4     4   17 use strict;
  4         7  
  4         125  
13 4     4   41 use warnings;
  4         4  
  4         199  
14              
15             $DB::deep = 150; # IPv6 needs 128 plus some headroom
16              
17             package Net::IP::Identifier::Binode;
18 4     4   22 use Carp;
  4         6  
  4         214  
19 4     4   1009 use Math::BigInt;
  4         22177  
  4         29  
20 4     4   20426 use Moo;
  4         28330  
  4         30  
21 4     4   5191 use namespace::clean;
  4         46134  
  4         36  
22              
23             our $VERSION = '0.110'; # 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 12589 50 33 12589 0 1110829 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 1525     1525 1 10480 my ($self, $path) = @_;
61              
62 1525         1862 my $node;
63             $self->_follow(
64             $path,
65             0,
66             sub { # construction callback
67 34597     34597   36896 my ($self, $path, $level) = @_;
68              
69 34597 100       55214 if ($level < length $path) {
70 33072 100       51024 if (substr($path, $level, 1)) { # next step
71 13809 100       272451 $self->one($self->new) if (not $self->one);
72             }
73             else {
74 19263 100       376724 $self->zero($self->new) if (not $self->zero);
75             }
76             }
77             else {
78 1525         2930 $node = $self; # when we reach the end
79             }
80 34597         259519 return 0; # always continue
81             }
82 1525         12696 );
83 1525         53642 return $node;
84             }
85              
86             sub follow {
87 49     49 1 1943 my ($self, $path, $callback, @extra) = @_;
88              
89 49 50 33     337 croak "Need a code ref\n" if (not $callback or ref $callback ne 'CODE');
90 49         134 return $self->_follow($path, 0, $callback, @extra);
91             }
92              
93             sub _follow {
94 4     4   2301 no warnings 'recursion'; # IPv6 requires at least 128 levels
  4         8  
  4         657  
95 36711     36711   934081 my ($self, $path, $level, $callback, @extra) = @_;
96              
97 36711 50       55630 return if $callback->($self, $path, $level, @extra);
98              
99 36711 100       82776 return $self if ($level >= length $path); # end of the line
100              
101 35178 100       60576 if (substr($path, $level, 1)) { # next step
102 14026 100       268861 return $self->one->_follow($path, $level + 1, $callback, @extra) if ($self->one);
103             }
104             else {
105 21152 100       397081 return $self->zero->_follow($path, $level + 1, $callback, @extra) if ($self->zero);
106             }
107 41         1041 return; # no node at $path
108             }
109              
110             sub traverse_width_first {
111 21     21 1 52 my ($self, $callback, @extra) = @_;
112              
113 21 50 33     155 croak "Need a code ref\n" if (not $callback or ref $callback ne 'CODE');
114 21         94 return $self->_traverse_width_first(0, $callback, @extra);
115             }
116              
117             sub _traverse_width_first {
118 4     4   19 no warnings 'recursion'; # IPv6 requires at least 128 levels
  4         5  
  4         641  
119 1317     1317   32290 my ($self, $level, $callback, @extra) = @_;
120              
121 1317 100       2459 return if $callback->($self, $level, @extra);
122              
123             #$path <<= 1;
124 1307 100       22059 $self->zero->_traverse_width_first($level + 1, $callback, @extra) if ($self->zero);
125             #$path |= 1;
126 1307 100       25957 $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   22 no warnings 'recursion'; # IPv6 requires at least 128 levels
  4         6  
  4         479  
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__